feat(i18n): multi-language support (en/ja/de/es) foundation#1147
feat(i18n): multi-language support (en/ja/de/es) foundation#1147JamieRuderman wants to merge 10 commits into
Conversation
…ito to shared namespace
|
This pull request is automatically being deployed by Amplify Hosting (learn more). |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ed012bfcdc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .init({ | ||
| // The resolved language is driven by redux (ui.setLanguage); 'en' here is a | ||
| // safe boot value overwritten before first paint. | ||
| lng: 'en', |
There was a problem hiding this comment.
Initialize the locale before rendering signed-out screens
For signed-out or first-time users, this hard-coded English locale is never replaced: ui.setLanguage is reached through ui.init, but auth.ts dispatches that only from signedIn, and the language picker is also behind authentication. Consequently the newly translated Cognito sign-in, signup, password-reset, and MFA screens always render in English even when the system locale is Japanese, German, or Spanish. Resolve the persisted/system language during application startup, before the authentication UI is rendered.
Useful? React with 👍 / 👎.
| import { useInterval } from '../../hooks/useInterval' | ||
| import humanize, { HumanizerOptions } from 'humanize-duration' | ||
| import { HumanizerOptions } from 'humanize-duration' | ||
| import { humanizeDuration as humanize } from '../../helpers/dateHelper' |
There was a problem hiding this comment.
Honor the selected locale in every Duration branch
When the selected app language differs from navigator.language, this migration localizes only the humanized branches; the tiered month/year branches and the non-tiered date branch still pass navigator.language directly at lines 52 and 70. For example, selecting Japanese on an English OS produces Japanese short durations but English long dates in the same component. Use the new app locale helper for those native date-formatting branches as well.
Useful? React with 👍 / 👎.
| import { useInterval } from '../../hooks/useInterval' | ||
| import humanize, { HumanizerOptions } from 'humanize-duration' | ||
| import { HumanizerOptions } from 'humanize-duration' | ||
| import { humanizeDuration as humanize } from '../../helpers/dateHelper' |
There was a problem hiding this comment.
Translate the complete relative-duration phrase
For every Duration caller using ago under a non-English app language, the new wrapper translates the duration units but lines 56, 59, and 71 still append the literal English suffix " ago", producing output such as 3 Tage ago; German and Japanese also require different relative-word ordering. Format or translate the complete relative phrase instead of appending an English fragment to the localized duration.
Useful? React with 👍 / 👎.
Summary
Adds a working multi-language (i18n) foundation across all three platforms (web portal, Electron desktop, Capacitor mobile) plus the Electron main process. Supports English (source/fallback) + Japanese, German, Spanish, with a language picker and OS-based auto-detection.
Because untranslated strings fall back to English, the app is shippable at every step — this PR lands the full infrastructure and a proven extraction template; the remaining bulk string extraction can follow incrementally.
What's included
frontend/src/i18n/) withapp/notices/cognitonamespaces. English bundled eagerly; ja/de/es lazy-loaded and code-split per locale. The existing Cognito auth module is folded into the shared instance.languagestate inmodels/ui.tsmirroring the existingthemeModepattern (localStorage, persists across logout). Defaultsystemfollows the OS/browser/device language vianavigator.language, re-resolved each launch.system(the default) matches the OS language on all three platforms; region tags degrade gracefully (ja-JP→ja, unknown→en). Standard "follow OS + in-app override" convention.OptionsPage.tsxwith native endonyms (日本語, Deutsch, Español).electron/src/i18n.ts+electron/src/locales/*.json); language synced from the renderer through the existing preferences channel (no new IPC).humanizeDuration()+getLocale()indateHelper.ts; luxon locale follows the app language.npm run i18n:extract(i18next-parser) andnpm run i18n:check(CI key-parity / empty-English gate).Cognito auth and OptionsPage are fully translated in all four languages (machine-seeded, pending professional review before production promotion).
Verified
{{device}},{{version}}) renders correctly in Japanese with adapted word order; unseeded keys fall back to English (returnEmptyString: false).i18n:checkpasses across all 4 locales / 3 namespaces.Remaining (follow-up work)
.tsxfiles (order: shell/nav → core surfaces → ~41 redux-model notice messages with plural fixes → long tail). Each batch: extract → parser → Sonnet-seed → parity gate.Decisions worth noting
t()return types into a union that breaks existing string usages and dynamic keys; the CI parity check covers correctness instead.🤖 Generated with Claude Code