UX-46: the NL pages show Dutch status rows, banners, settings notes and wizard lines; the peak forecast label drops "(W)".
Cause of the English fallback.Controller.checks() built every status row as an English string, and status_payload(lang) passed lang only to homeview.build() (titles). The settings notes (validate._advise) and the wizard checks (setup_checks) never received a language at all. messages.peak_forecast_unit(..., "nl") existed but nothing called it with "nl".
Fix, at the point where the language is known. Rows and banners are built once with their Dutch beside them (messages.Bi, a str that is its English text with .nl). status_payload() picks one by lang (one place), logs and callers keep seeing English. Notes carry Note.nl; /config/validate picks by the posted lang for the settings notes, the wizard list and the device note.
Label. "(W)" dropped from peak_forecast_entity in en.yaml, nl.yaml and the DOCS.md table. No option key, value, logic or control code changes; EN text is unchanged except that label (EN /status checks, banner and attention are identical to base in a side by side run).
Tests. New test_ux46.py: every row and banner has a Dutch twin that follows STYLE (length, jargon, no English words); every _advise() call has nl; the real validator's 109 notes all have Dutch; end to end Home (status payload) and /config/validate over HTTP in both languages; labels. 7 mutations each caught (in the dev report).
Found, not fixed (out of scope). On release/1.0 the setup wizard's last step throws TypeError in the browser: ui_text has no settings.setup.shadow (removed in 2d2b6af) but settings.jsshadowRow() reads it. Browser proof injects that one string.
Not translated, listed in the dev report: Home installer-details table labels/values (rows), the event line under the buttons, refusals, the legacy banner on a failed Home view.
UX-46: the NL pages show Dutch status rows, banners, settings notes and wizard lines; the peak forecast label drops "(W)".
**Cause of the English fallback.** `Controller.checks()` built every status row as an English string, and `status_payload(lang)` passed `lang` only to `homeview.build()` (titles). The settings notes (`validate._advise`) and the wizard checks (`setup_checks`) never received a language at all. `messages.peak_forecast_unit(..., "nl")` existed but nothing called it with "nl".
**Fix, at the point where the language is known.** Rows and banners are built once with their Dutch beside them (`messages.Bi`, a `str` that is its English text with `.nl`). `status_payload()` picks one by `lang` (one place), logs and callers keep seeing English. Notes carry `Note.nl`; `/config/validate` picks by the posted `lang` for the settings notes, the wizard list and the device note.
**Label.** "(W)" dropped from `peak_forecast_entity` in en.yaml, nl.yaml and the DOCS.md table. No option key, value, logic or control code changes; EN text is unchanged except that label (EN `/status` checks, banner and attention are identical to base in a side by side run).
**Tests.** New `test_ux46.py`: every row and banner has a Dutch twin that follows STYLE (length, jargon, no English words); every `_advise()` call has `nl`; the real validator's 109 notes all have Dutch; end to end Home (status payload) and `/config/validate` over HTTP in both languages; labels. 7 mutations each caught (in the dev report).
**Found, not fixed (out of scope).** On release/1.0 the setup wizard's last step throws `TypeError` in the browser: `ui_text` has no `settings.setup.shadow` (removed in 2d2b6af) but `settings.js` `shadowRow()` reads it. Browser proof injects that one string.
Not translated, listed in the dev report: Home installer-details table labels/values (`rows`), the event line under the buttons, refusals, the legacy banner on a failed Home view.
🤖 Generated with [Claude Code](https://claude.ai/code)
https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
Rows and banners are built once with their Dutch beside them (messages.Bi)
and status_payload() picks one by the page's language. Settings notes and the
wizard's checks carry a Dutch twin (Note.nl) that /config/validate picks by
the posted language. The peak forecast label drops "(W)" in EN and NL.
Co-Authored-By: Claude <noreply@anthropic.com>
Text only. "stroom te opnemen" -> "stroom op te nemen"; Developer Tools is
"Ontwikkelhulpmiddelen" in HA and ui_text; the green stuck-meter row no longer
starts "Vastgelopen meter:"; maintenance banner names the phase in Dutch;
double "dan" in the device note; plainer peak reserve, peak guard, refused
commands and missing-entity wording. Two stale comments now say the banner
and Home bodies follow the page's language.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UX-46 review (Opus), reviewed c1809b4, then pushed text-only fixes as ae0ef42.
No behaviour change: confirmed. Demo base e077ae7 vs head, same fixtures: /status?lang=en and /status are identical (only event clock differs), the index page is identical, config/model?lang=en differs only in the two places that show the label, and config/validate (en) is identical apart from the new nl key on notes/setup. On NL /status the check ids, ok/warn flags and level match base. Bi is a str equal to the English, so logs, JSON, MQTT and notifications still get the English. No option key, value or control code changed.
Findings
#
Sev
Where
What
State
1
Medium
app/messages.py:1241 row_battery_refuses
"weigert stroom te opnemen" is ungrammatical
fixed: "stroom op te nemen"
2
Medium
app/messages.py:705 row_freeze_on
the green "check is on" row began "Vastgelopen meter:", which reads like an alarm. "gelijk" was also ambiguous
fixed: "Controle op vastgelopen meter: alarm na 10 minuten ongewijzigd boven 4 465 W, omvormerlimiet"
3
Low
app/messages.py:793
"Ontwikkelaarstools": HA and our ui_text say "Ontwikkelhulpmiddelen"
fixed
4
Low
app/messages.py:567 banner_maintenance
NL banner kept the English phase ("Onderhoud: drain")
fixed: leegmaken / opladen / vol houden (as in ui_text)
5
Low
app/web.py:110 DEVICE_NOTE_NL
"dan" appeared twice
fixed
6
Low
app/messages.py, app/validate.py
wording: benoemd, "vraagt 1 200 W van de batterij", "buiten beschouwing" / "buiten de regeling gelaten", "Het huis trekt de batterij nog leger", "rust", "is niet uitgevoerd", "terwijl ... die noemt", "meldt niet in kWh", "het net blijft op nul"
fixed (list in the report)
7
Low
app/main.py:7601, app/homeview.py:1078
comments said the banner and the Home row body stay English, but the code now picks the page language
fixed (comment only)
8
Low
app/web.py:108-110, app/setuponly.py:57-62
test gap: no test covers DEVICE_NOTE_NL or the setup-only pick. Two mutations of mine survive (R1, R3)
not fixed, a follow-up test is suggested
9
Info
out of scope
the out-of-scope list is reasonable. Refusals (problems) and the event line under the buttons are visible to the home owner and are still English on NL pages: worth a follow-up card
-
10
Info
settings.js shadowRow()
wizard step 6 throws Cannot read properties of undefined (reading 'name') on base e077ae7 too (EN and NL). Pre-existing, not fixed here
-
Checks
Mutations: M1, M2 and M4 from the dev were each caught. Mine: R2 (pick never Dutch) and R4 (meter note NL = EN) were caught; R1 (device note) and R3 (setup-only) survived, see #8.
Browser (Playwright 1.55): NL and EN Home, settings and wizard ran 22 checks with 0 failures and no page errors. The wizard needed the dev's one-string injection because of #10.
Offline suite in goodwe-addon-checks:1 (--network none, test_freeze on the rig hwsim): 81 of 81 PASS on ae0ef42.
CI on ae0ef42: run 1368 checks / unit success (81 PASS) and run 1369 infra-pin / fresh success.
Verdict: approve with the text fixes. Merging ae0ef42.
**UX-46 review (Opus)**, reviewed c1809b4, then pushed text-only fixes as ae0ef42.
**No behaviour change: confirmed.** Demo base e077ae7 vs head, same fixtures: `/status?lang=en` and `/status` are identical (only event clock differs), the index page is identical, `config/model?lang=en` differs only in the two places that show the label, and `config/validate` (en) is identical apart from the new `nl` key on `notes`/`setup`. On NL `/status` the check ids, ok/warn flags and level match base. `Bi` is a `str` equal to the English, so logs, JSON, MQTT and notifications still get the English. No option key, value or control code changed.
**Findings**
| # | Sev | Where | What | State |
|---|---|---|---|---|
| 1 | Medium | app/messages.py:1241 `row_battery_refuses` | "weigert stroom te opnemen" is ungrammatical | fixed: "stroom op te nemen" |
| 2 | Medium | app/messages.py:705 `row_freeze_on` | the green "check is on" row began "Vastgelopen meter:", which reads like an alarm. "gelijk" was also ambiguous | fixed: "Controle op vastgelopen meter: alarm na 10 minuten ongewijzigd boven 4 465 W, omvormerlimiet" |
| 3 | Low | app/messages.py:793 | "Ontwikkelaarstools": HA and our ui_text say "Ontwikkelhulpmiddelen" | fixed |
| 4 | Low | app/messages.py:567 `banner_maintenance` | NL banner kept the English phase ("Onderhoud: drain") | fixed: leegmaken / opladen / vol houden (as in ui_text) |
| 5 | Low | app/web.py:110 `DEVICE_NOTE_NL` | "dan" appeared twice | fixed |
| 6 | Low | app/messages.py, app/validate.py | wording: benoemd, "vraagt 1 200 W van de batterij", "buiten beschouwing" / "buiten de regeling gelaten", "Het huis trekt de batterij nog leger", "rust", "is niet uitgevoerd", "terwijl ... die noemt", "meldt niet in kWh", "het net blijft op nul" | fixed (list in the report) |
| 7 | Low | app/main.py:7601, app/homeview.py:1078 | comments said the banner and the Home row body stay English, but the code now picks the page language | fixed (comment only) |
| 8 | Low | app/web.py:108-110, app/setuponly.py:57-62 | test gap: no test covers `DEVICE_NOTE_NL` or the setup-only `pick`. Two mutations of mine survive (R1, R3) | not fixed, a follow-up test is suggested |
| 9 | Info | out of scope | the out-of-scope list is reasonable. Refusals (`problems`) and the event line under the buttons are visible to the home owner and are still English on NL pages: worth a follow-up card | - |
| 10 | Info | settings.js `shadowRow()` | wizard step 6 throws `Cannot read properties of undefined (reading 'name')` on base e077ae7 too (EN and NL). Pre-existing, not fixed here | - |
**Checks**
- Mutations: M1, M2 and M4 from the dev were each caught. Mine: R2 (`pick` never Dutch) and R4 (meter note NL = EN) were caught; R1 (device note) and R3 (setup-only) survived, see #8.
- Browser (Playwright 1.55): NL and EN Home, settings and wizard ran 22 checks with 0 failures and no page errors. The wizard needed the dev's one-string injection because of #10.
- Offline suite in goodwe-addon-checks:1 (`--network none`, test_freeze on the rig hwsim): 81 of 81 PASS on ae0ef42.
- CI on ae0ef42: run 1368 `checks / unit` success (81 PASS) and run 1369 `infra-pin / fresh` success.
Verdict: approve with the text fixes. Merging ae0ef42.
admin
merged commit 90bc9017b2 into release/1.02026-10-22 06:10:37 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
UX-46: the NL pages show Dutch status rows, banners, settings notes and wizard lines; the peak forecast label drops "(W)".
Cause of the English fallback.
Controller.checks()built every status row as an English string, andstatus_payload(lang)passedlangonly tohomeview.build()(titles). The settings notes (validate._advise) and the wizard checks (setup_checks) never received a language at all.messages.peak_forecast_unit(..., "nl")existed but nothing called it with "nl".Fix, at the point where the language is known. Rows and banners are built once with their Dutch beside them (
messages.Bi, astrthat is its English text with.nl).status_payload()picks one bylang(one place), logs and callers keep seeing English. Notes carryNote.nl;/config/validatepicks by the postedlangfor the settings notes, the wizard list and the device note.Label. "(W)" dropped from
peak_forecast_entityin en.yaml, nl.yaml and the DOCS.md table. No option key, value, logic or control code changes; EN text is unchanged except that label (EN/statuschecks, banner and attention are identical to base in a side by side run).Tests. New
test_ux46.py: every row and banner has a Dutch twin that follows STYLE (length, jargon, no English words); every_advise()call hasnl; the real validator's 109 notes all have Dutch; end to end Home (status payload) and/config/validateover HTTP in both languages; labels. 7 mutations each caught (in the dev report).Found, not fixed (out of scope). On release/1.0 the setup wizard's last step throws
TypeErrorin the browser:ui_texthas nosettings.setup.shadow(removed in2d2b6af) butsettings.jsshadowRow()reads it. Browser proof injects that one string.Not translated, listed in the dev report: Home installer-details table labels/values (
rows), the event line under the buttons, refusals, the legacy banner on a failed Home view.🤖 Generated with Claude Code
https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
UX-46 review (Opus), reviewed
c1809b4, then pushed text-only fixes asae0ef42.No behaviour change: confirmed. Demo base
e077ae7vs head, same fixtures:/status?lang=enand/statusare identical (only event clock differs), the index page is identical,config/model?lang=endiffers only in the two places that show the label, andconfig/validate(en) is identical apart from the newnlkey onnotes/setup. On NL/statusthe check ids, ok/warn flags and level match base.Biis astrequal to the English, so logs, JSON, MQTT and notifications still get the English. No option key, value or control code changed.Findings
row_battery_refusesrow_freeze_onbanner_maintenanceDEVICE_NOTE_NLDEVICE_NOTE_NLor the setup-onlypick. Two mutations of mine survive (R1, R3)problems) and the event line under the buttons are visible to the home owner and are still English on NL pages: worth a follow-up cardshadowRow()Cannot read properties of undefined (reading 'name')on basee077ae7too (EN and NL). Pre-existing, not fixed hereChecks
picknever Dutch) and R4 (meter note NL = EN) were caught; R1 (device note) and R3 (setup-only) survived, see #8.--network none, test_freeze on the rig hwsim): 81 of 81 PASS onae0ef42.ae0ef42: run 1368checks / unitsuccess (81 PASS) and run 1369infra-pin / freshsuccess.Verdict: approve with the text fixes. Merging
ae0ef42.