v0.252.0 — the sentences the program builds follow the language (R-557 slice 2 release A)
gates / gates (push) Successful in 23s
gates / gates (push) Successful in 23s
Slice 1 translated the dashboard's markup. The sentences the program BUILDS were still Hungarian literals in Go, so an English household clicked an English button and was answered in Hungarian. 226 of them move into the bundle here. A flash was the hard part: it travels inside the redirect URL and is rendered by a DIFFERENT request, so it now carries a bundle key plus its parameters. A link minted by an older controller carries prose and is shown verbatim — never a raw key, never dropped. Also converted: page data and view-model text, the internal/api JSON answers, the alert banners (Alert.MessageKey, rendered on the way out of GetAlerts), 237 country names at display, and the four page titles built around an app name (R-566 closed). Hungarian is byte-identical, and that is measured rather than read: scripts/i18n_go_parity.py freezes every Go literal at the base commit (7 467) and refuses a key whose Hungarian is not that text, byte for byte. Three decoys, each seen to convict. Its own first version filtered the capture through an ASCII-Hungarian word list and missed seven real literals — the R-565 class. The filter is gone. Nothing on the wire moved, and wire goldens now hold it there: the report's health warnings and every notify event message stay Hungarian, because the hub MAILS the controller's sentence when it has no entry of its own. Slice 3 (R-558) owns those. MinAgent: 0.131.0 (unchanged). No hub release needed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
+29
-4
@@ -3614,7 +3614,7 @@ without reaching `Images()`.
|
||||
|
||||
---
|
||||
|
||||
### 18. Dashboard language (i18n) (v0.247.0–v0.250.0)
|
||||
### 18. Dashboard language (i18n) (v0.247.0–v0.252.0)
|
||||
|
||||
Design: `felhom.eu/documentation/architecture/10-localisation.md`. Inventory:
|
||||
`felhom.eu/documentation/audits/I18N-INVENTORY-2026-09-17.md`.
|
||||
@@ -3622,8 +3622,10 @@ Design: `felhom.eu/documentation/architecture/10-localisation.md`. Inventory:
|
||||
**What a household sees:** Hungarian by default, and since v0.250.0 a **Magyar / English** switch in the
|
||||
sidebar footer of every dashboard page. Every template is converted (v0.247.0 three pages, v0.248.0
|
||||
apps and settings, v0.249.0 backups, v0.250.0 storage, sharing, sign-in, claim, guest share, catch-all,
|
||||
debug). Server-built messages (flash lines, errors, labels built in Go), three page titles built in Go
|
||||
around an app name, and catalog copy stay Hungarian (slices 2 and 5).
|
||||
debug). Since **v0.252.0** the sentences the program BUILDS follow the language too — flash lines, page
|
||||
data, the JSON the page's script reads, the alert banners, the country names, and the four page titles
|
||||
built around an app name. Still Hungarian: `fmt.Errorf` messages (release B), text persisted by a
|
||||
background run (release C), catalog copy (slice 5), and **everything the hub reads** (see below).
|
||||
|
||||
- **Bundles:** `internal/i18n/locales/hu.json` (authoritative, every key) and `en.json`, embedded.
|
||||
Flat `key → text`; a value may carry template actions (`{{.RecoveryAbandonDate}}`) and inline
|
||||
@@ -3648,11 +3650,34 @@ around an app name, and catalog copy stay Hungarian (slices 2 and 5).
|
||||
literal by `TestHandlerTitleKeysMatchHungarianTitle`); non-Hungarian sets override the copy-producing
|
||||
template funcs (`stateLabel`, `timeAgo`, `timeAgoStr`, `nextRunLabel`, `statusText`, `infraMeta`) from
|
||||
the bundle. The Hungarian funcs are untouched.
|
||||
- **Go-side messages (v0.252.0):** `Bundle.Msgf` fills a message's own printf verbs; English reorders
|
||||
with Go's explicit argument indexes (`%[2]s`), so the Hungarian value stays the format string the code
|
||||
always had. Handlers use `s.msg(r, key, …)`; background and view-model builders take a `lang` and use
|
||||
`s.msgLang`; the API has the same pair (`internal/api/i18n_api.go`). `s.bundle()` falls back to the
|
||||
embedded `i18n.Shared()`, so a Server built without `loadTemplates` still renders sentences.
|
||||
- **Flash lines (v0.252.0):** a flash travels in the redirect URL and is rendered by the NEXT request,
|
||||
so it carries a bundle KEY plus repeated `fa` parameters (`?flash=flash.share.enabled&fa=…`), built
|
||||
with `flashQuery` and resolved with `s.flashFrom`. A value the bundle does not know — a link minted by
|
||||
an older controller — is shown verbatim, never as a key and never dropped.
|
||||
- **Alert banners (v0.252.0):** an alert is built by a background health cycle and read minutes later,
|
||||
so `Alert` carries `MessageKey` + `MessageArgs` (and `LinkTextKey`) and `GetAlerts(lang)` renders on
|
||||
the way out. An alert with no key renders `Message` verbatim — which is how the two exceptions work.
|
||||
- **Country names (v0.252.0):** `country.<ISO2>` keys, translated at DISPLAY in `internal/api/geo.go`
|
||||
and re-sorted per language. The `internal/cloudflare` table is untouched: it validates codes, and the
|
||||
report puts codes (never names) on the wire.
|
||||
- **NOT translated — it is not ours:** the report's `health.warnings` / `health.issues` and every
|
||||
`notify` event `message`. The hub composes the household's e-mail from those and falls back to the
|
||||
controller's own sentence when it has no entry (`FormatCustomerEmail`), so translating them here would
|
||||
change an e-mail nobody asked to change. They follow the language in slice 3 (R-558). Pinned by wire
|
||||
goldens in `internal/monitor` and `internal/notify`.
|
||||
- **Report:** the hub report carries `"language"` (always present). No hub release reads it yet.
|
||||
- **Tools and gates:** `scripts/i18n_extract.py` converts a template (moves each Hungarian run into
|
||||
hu.json, leaves a marker); `scripts/i18n_missing_gate.py` (in `controller_gates.py`) checks keys
|
||||
exist, no orphans, the English gap and the formal „ön" count only shrink (ratchets), no pleading
|
||||
English. The emoji, native-confirm, secret-in-markup and retrieval-promise gates read templates
|
||||
English. `scripts/i18n_go_parity.py` (v0.252.0, in `controller_gates.py`) freezes every Go string
|
||||
literal at slice 2's base commit (`scripts/i18n_go_base.json`) and refuses a key whose Hungarian is not
|
||||
that text byte for byte; `scripts/i18n_go_keys.json` records what each key replaced. Three decoys.
|
||||
The emoji, native-confirm, secret-in-markup and retrieval-promise gates read templates
|
||||
**expanded** through `scripts/i18n_bundle.py`; mojibake scans the bundles.
|
||||
- **Coverage:** `TestI18nParityCoversEveryMarker` fails when any marker occurrence is rendered by no
|
||||
parity case. Fixtures are written only when missing (`-update-i18n-golden`, `-i18n-golden-only`).
|
||||
|
||||
Reference in New Issue
Block a user