feat(ui): localisation completeness — persistence + parity guards (F3) #28

Merged
developer merged 1 commits from feature/ui-finalize-f3-i18n into development 2026-05-22 06:57:23 +00:00
Owner

F3 — Localisation completeness

From ui/PLAN-finalize.md F3. An audit found the client already
i18n-first, so this stage is small: it closes the persistence gap and
adds structural guards against translation drift.

Findings

  • 0 hard-coded template strings, 0 hard-coded TS user strings.
  • Exactly one hard-coded UI attribute — the battle-scene
    aria-label="battle scene" — now routed through i18n.
  • en/ru already share an identical 692-key set (no drift).

What changed

  • Locale persistence: i18n.setLocale writes localStorage
    (galaxy-locale); the store boots from stored choice > browser
    detection > default
    , so a language switch survives reloads (an
    unrecognised stored value is ignored). Previously the choice was lost
    on reload.
  • tests/i18n-completeness.test.ts: en/ru key-set parity (a key in
    one locale but not the other fails), non-empty values, and the
    persistence round-trip.
  • Battle-scene aria-labelgame.battle.scene_label (en + ru).
  • Docs: ui/docs/i18n.md; F3 marked done in ui/PLAN-finalize.md.

A noisy literal-text lint was deliberately skipped — the structural
parity test plus the existing compile-time Record<keyof typeof en,…>
annotation and the i18n-first convention already cover drift.

Verification

pnpm check 0/0; pnpm test 740 passing (5 new).

🤖 Generated with Claude Code

## F3 — Localisation completeness From `ui/PLAN-finalize.md` F3. An audit found the client already i18n-first, so this stage is small: it closes the persistence gap and adds structural guards against translation drift. ### Findings - **0** hard-coded template strings, **0** hard-coded TS user strings. - Exactly **one** hard-coded UI attribute — the battle-scene `aria-label="battle scene"` — now routed through i18n. - en/ru already share an identical **692-key** set (no drift). ### What changed - **Locale persistence**: `i18n.setLocale` writes `localStorage` (`galaxy-locale`); the store boots from *stored choice > browser detection > default*, so a language switch survives reloads (an unrecognised stored value is ignored). Previously the choice was lost on reload. - **`tests/i18n-completeness.test.ts`**: en/ru key-set parity (a key in one locale but not the other fails), non-empty values, and the persistence round-trip. - Battle-scene `aria-label` → `game.battle.scene_label` (en + ru). - Docs: `ui/docs/i18n.md`; F3 marked done in `ui/PLAN-finalize.md`. A noisy literal-text lint was deliberately skipped — the structural parity test plus the existing compile-time `Record<keyof typeof en,…>` annotation and the i18n-first convention already cover drift. ### Verification `pnpm check` 0/0; `pnpm test` 740 passing (5 new). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
developer added 1 commit 2026-05-22 06:48:25 +00:00
feat(ui): locale persistence + i18n completeness guards (F3)
Tests · UI / test (push) Waiting to run
Tests · UI / test (pull_request) Successful in 2m11s
1e62837c68
An audit found the client already i18n-first: one hard-coded UI string
(the battle-scene aria-label, now keyed) and en/ru already share an
identical 692-key set.

- Persist the locale: i18n.setLocale writes localStorage (galaxy-locale)
  and the store boots from stored > browser detection > default, so a
  language switch survives reloads.
- tests/i18n-completeness.test.ts: en/ru key-set parity, non-empty
  values, and locale persistence.
- Docs: ui/docs/i18n.md; mark F3 done in ui/PLAN-finalize.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
developer merged commit 87d524fb89 into development 2026-05-22 06:57:23 +00:00
developer deleted branch feature/ui-finalize-f3-i18n 2026-05-22 06:57:23 +00:00
Sign in to join this conversation.