Skip to content

feat(i18n): add runtime-switchable language support#176

Open
srsholmes wants to merge 1 commit into
mainfrom
claude/i18n-language-support-wd6lsd
Open

feat(i18n): add runtime-switchable language support#176
srsholmes wants to merge 1 commit into
mainfrom
claude/i18n-language-support-wd6lsd

Conversation

@srsholmes

Copy link
Copy Markdown
Owner

Introduce an internationalization mechanism for the overlay app and its
plugins, with runtime language switching and per-plugin translation files.

Core (shared singleton in @loadout/ui):

  • Add i18next + react-i18next; new packages/ui/src/i18n.ts hosts one
    i18next instance. Because plugin bundles resolve @loadout/ui to the
    shell's __LOADOUT_SDK global, the shell and every plugin share that
    instance — setLanguage() re-renders the whole tree with no reload.
  • Expose initI18n, setLanguage, ensureNamespace, normalizeLocale,
    usePluginTranslation, SUPPORTED_LANGUAGES (en-gb, zh-cn) and DEFAULT.

Detection / persistence / override:

  • First-run detection: host OS locale (new getSystemLocale RPC) ->
    navigator.language -> English, normalized to a supported code and
    persisted under the language user-config key.
  • Settings > General gains a Language selector that switches at runtime.

Translation files:

  • Shell strings live under the app namespace in
    apps/loadout-overlay/src/overlay/i18n/.json (statically bundled).
  • Plugins ship an i18n/.json folder (flat key/value, one file per
    language, plugin id = namespace), served by the loader at
    /plugins//i18n/.json and lazy-loaded on first use; missing
    keys fall back to English.

Proof of mechanism (full English source + partial Chinese):

  • Wire the Settings screen and the battery-tracker plugin to t() keys.
  • This PR is the mechanism only; bulk translation is left to a follow-up.

Docs + tests:

  • Document the convention in CLAUDE.md.
  • Unit-test normalizeLocale; keep battery-tracker spec green by resolving
    its assertions against the shipped en-gb.json.

Co-Authored-By: Claude Opus 4.8 [email protected]
Claude-Session: https://claude.ai/code/session_01XEKUyS4sptP4hoLgKCDxxu

Introduce an internationalization mechanism for the overlay app and its
plugins, with runtime language switching and per-plugin translation files.

Core (shared singleton in @loadout/ui):
- Add i18next + react-i18next; new packages/ui/src/i18n.ts hosts one
  i18next instance. Because plugin bundles resolve @loadout/ui to the
  shell's __LOADOUT_SDK global, the shell and every plugin share that
  instance — setLanguage() re-renders the whole tree with no reload.
- Expose initI18n, setLanguage, ensureNamespace, normalizeLocale,
  usePluginTranslation, SUPPORTED_LANGUAGES (en-gb, zh-cn) and DEFAULT.

Detection / persistence / override:
- First-run detection: host OS locale (new getSystemLocale RPC) ->
  navigator.language -> English, normalized to a supported code and
  persisted under the `language` user-config key.
- Settings > General gains a Language selector that switches at runtime.

Translation files:
- Shell strings live under the `app` namespace in
  apps/loadout-overlay/src/overlay/i18n/<code>.json (statically bundled).
- Plugins ship an i18n/<code>.json folder (flat key/value, one file per
  language, plugin id = namespace), served by the loader at
  /plugins/<id>/i18n/<code>.json and lazy-loaded on first use; missing
  keys fall back to English.

Proof of mechanism (full English source + partial Chinese):
- Wire the Settings screen and the battery-tracker plugin to t() keys.
- This PR is the mechanism only; bulk translation is left to a follow-up.

Docs + tests:
- Document the convention in CLAUDE.md.
- Unit-test normalizeLocale; keep battery-tracker spec green by resolving
  its assertions against the shipped en-gb.json.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XEKUyS4sptP4hoLgKCDxxu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants