Uh oh!
There was an error while loading. Please reload this page.
fix(auth): localize the ADR-0069 remediation gate and the auth split-panel (#2870) - #2875
Merged
Merged
Conversation
…panel (#2870) `RemediationOverlay` had no i18n at all — zero `@object-ui/i18n` references. It is the full-screen gate mounted unconditionally at `ConsoleShell.tsx` (`fixed inset-0 z-[200]`, shown on `PASSWORD_EXPIRED` / `MFA_REQUIRED`), and there is no route around it, so a user who could not read English could not get back into the product. That is a usability block, not a cosmetic gap. - New `auth.remediation.*` in all ten locale packs, covering both branches: expired-password (title, three field labels, submit/submitting, mismatch and failure) and MFA enrolment (password step, QR scan copy, backup-code disclosure, code entry, verify/verifying, enrolment and invalid-code failures), plus the shared "sign out instead" exit. - Validation and failure messages are translated where they are raised — they are held in component state and rendered later. - The server-authored `remediationRequired.message` is left alone; only the empty-message fallback is ours to localize. - `auth.layout.*` for the auth split-panel headline and subhead. The forms it wraps were already localized, so it had been rendering half in the user's language and half in English. Both copies of `AuthPageLayout` are fixed: `console/auth/` (what LoginPage / RegisterPage / ForgotPasswordPage import) and `layout/` (byte-identical apart from the import path, and re-exported from the package root, so a downstream consumer would otherwise still get the English one). The duplication itself predates this change and is left alone here. Adds a locale-parity test over both namespaces: identical key set across all ten packs, a non-empty string at every leaf, and prose that differs from English. i18next falls back to `en` silently and its missing-key handler is dev-only, so a key added to one pack and forgotten elsewhere is invisible in whichever locales get checked by hand. Verified by mutation, not just a green run: deleting one `de` key fails the guard, and pasting the English sentence into `ru` fails it too. The guard also caught a real mistake while writing this — a stray `git checkout` wiped the whole Russian block and the test flagged it immediately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TubWYdWquVkS9dj733sDmC
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
os-zhuang
marked this pull request as ready for review
July 27, 2026 15:48
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes#2870.
Why this one is a usability block, not a cosmetic gap
RemediationOverlayhad no i18n at all — zero@object-ui/i18nreferences in the file. It is the ADR-0069 full-screen gate: mounted unconditionally atConsoleShell.tsx:91, rendered asfixed inset-0 z-[200]with a backdrop blur, shown whenever the backend returnsPASSWORD_EXPIREDorMFA_REQUIRED.There is no route around it. A user whose password expires and who cannot read English cannot get back into the product at all. Every other i18n gap found in this sweep degrades to "a label is in the wrong language"; this one locks the user out.
Changes
auth.remediation.*in all ten locale packs, covering both branches of the gate — expired-password (title, three field labels, submit/submitting, mismatch and failure) and MFA enrolment (password step, QR scan copy, backup-code disclosure, code entry, verify/verifying, enrolment and invalid-code failures) — plus the shared "sign out instead" exit. That's ~24 strings, more than the 12 sampled in the issue; the issue listed a subset.Failure messages are translated where they are raised, not where they are rendered, since they are held in component state and surfaced later via
phase-style error state.The server-authored message is left alone.
remediationRequired.messagecomes from the backend; only the empty-message fallback is ours to localize.auth.layout.*for the auth split-panel. The formsAuthPageLayoutwraps were already localized, so the panel had been rendering half in the user's language and half in English.Both copies of AuthPageLayout
There are two, and they are byte-identical apart from the import path:
console/auth/AuthPageLayout.tsx— whatLoginPage/RegisterPage/ForgotPasswordPageactually importlayout/AuthPageLayout.tsx— re-exported from the package root vialayout/index.ts→src/index.ts:83, so it is part of the public@object-ui/app-shellAPIFixing only the first would leave any downstream consumer importing from the package root with the English copy, and leave two identical components with divergent i18n status. Both are fixed. The duplication itself predates this change and is deliberately not addressed here.
Testing
packages/i18n/src/__tests__/authRemediation-locale-parity.test.tscovers both namespaces: identical key set across all ten packs, a non-empty string at every leaf, and prose that differs from English (short labels are excluded — "Continue" is legitimately "Continue" in French).This matters because i18next falls back to
ensilently (fallbackLng: 'en', missing-key handler is dev-only), so a key added to one pack and forgotten in the others is invisible in whichever two locales get checked by hand.Mutation-tested rather than trusted on a green run, in both directions:
auth.remediation.mfa.codeLabelfromde.ts→ failsbackupBodysentence verbatim intoru.ts→ also failsThe guard earned its keep immediately: while cleaning up after those mutations, a stray
git checkout ru.tsreverted the whole Russian block, and the test caught it in the next run rather than letting an entirely un-translated locale ship.Suites:
@object-ui/i18n118 passed,@object-ui/app-shell1865 passed (225 files),turbo type-checkgreen for both packages, ESLint clean with no new warnings.Follow-ups from the same sweep
#2871 (14 files hand-rolling
startsWith('zh'), bypassing the locale packs) and #2872 (357–359 keys missing from eight packs, 74 keys only inzh.ts, no parity test) are tracked separately.🤖 Generated with Claude Code
https://claude.ai/code/session_01TubWYdWquVkS9dj733sDmC
Generated by Claude Code