feat(ui): locale persistence + i18n completeness guards (F3)
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>
This commit is contained in:
@@ -106,15 +106,36 @@ function isLocale(value: string): value is Locale {
|
||||
return SUPPORTED_LOCALES.some((entry) => entry.code === value);
|
||||
}
|
||||
|
||||
/** `localStorage` key holding the user's explicit locale choice. */
|
||||
export const LOCALE_STORAGE_KEY = "galaxy-locale";
|
||||
|
||||
function readStoredLocale(): Locale | null {
|
||||
if (typeof localStorage === "undefined") return null;
|
||||
const value = localStorage.getItem(LOCALE_STORAGE_KEY);
|
||||
return value !== null && isLocale(value) ? value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialLocale resolves the boot locale: an explicit stored choice
|
||||
* wins, otherwise the browser/system preference, otherwise the default.
|
||||
*/
|
||||
function initialLocale(): Locale {
|
||||
return readStoredLocale() ?? detectInitialLocale();
|
||||
}
|
||||
|
||||
class I18nStore {
|
||||
locale: Locale = $state(detectInitialLocale());
|
||||
locale: Locale = $state(initialLocale());
|
||||
|
||||
/**
|
||||
* setLocale changes the active locale. Components reading
|
||||
* setLocale changes the active locale and persists the choice to
|
||||
* `localStorage`, so it survives a reload. Components reading
|
||||
* `i18n.t(...)` re-render automatically through the rune.
|
||||
*/
|
||||
setLocale(next: Locale): void {
|
||||
this.locale = next;
|
||||
if (typeof localStorage !== "undefined") {
|
||||
localStorage.setItem(LOCALE_STORAGE_KEY, next);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user