feat(i18n): translate the four highest-traffic namespaces into the eight trailing locales (#2872 part a) - #2903
Merged
Conversation
…ght trailing locales (#2872 part a) Backfills `console`, `home`, `topbar` and `layout` — 193 keys x 8 packs, 1,544 strings — so a ja/ko/de/fr/es/pt/ru/ar admin sees the AI console, the home screen, the top bar and the system navigation in their own language instead of silently falling back to English. The gap in those eight packs drops from 469-471 keys to 277-279; en and zh stay at exact parity. This is the "high-frequency namespaces only" strategy, not a full backfill: `grid` (101), `gantt` (58), `dashboard` (25) and the long tail stay on English fallback and remain tracked under #2872. Four keys are deliberately NOT translated, and that is the load-bearing part of this change: console.ai.planApproveMessage console.ai.planApproveDefaultsMessage console.ai.planAnswerMessage console.ai.changesConfirmMessage These are not labels — they are text a button TRANSMITS to the agent, and the cloud confirm gate (service-ai-studio confirm-gate.ts APPROVAL_RE) decides whether it reads as approval. It recognises Chinese and English, nothing else. AiChatPage picks them by the language of the CONVERSATION, not the UI, so the t() call is expected to miss in every non-Chinese pack and fall through to its English defaultValue. Translating them would make a German user's "Build it" send German, the gate stop matching, and the agent re-propose instead of building — the button looks inert while nothing visibly errors. #2900 shipped exactly that bug for changesConfirmMessage, which had been added to all ten packs; this removes it from the eight and restores the English fallback. A new guard pins the invariant in both directions and was mutation-tested against re-adding an outbound key and against dropping an ordinary label. Translations are model-generated and would benefit from native review; every string's placeholder set was verified programmatically against the English source. Co-Authored-By: Claude Opus 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 28, 2026 05:56
3 tasks
os-zhuang
pushed a commit
that referenced
this pull request
Jul 28, 2026
…ently erode #2903 translated `console`, `home`, `topbar` and `layout` into all ten packs. Nothing stopped that from decaying: `fallbackLng: 'en'` means dropping a key from `de` renders English, which reads as "not translated yet" rather than "we lost this", and the missing-key handler is dev-only so CI never sees it. This is #2872's P3 applied only to the namespaces that are actually complete. Full parity would fail today by ~277 keys per pack with no action attached — a broken build, not a guard. Widen RATCHETED_NAMESPACES as each remaining namespace is translated, not before. Asserts both directions, because the packs have drifted both ways before: every ratcheted en key exists in the other nine packs, and no pack defines a ratcheted key en lacks (#2872 part b was exactly that, 74 keys deep, hidden behind a component-private fallback so English "happened to" render). The four outbound agent messages are excluded — they are deliberately absent from the eight non-gate packs, and outbound-agent-messages.test.ts owns that invariant; the two guards would otherwise contradict each other. A non-vacuity assertion pins the ratchet at >300 keys and requires every named namespace to contribute, so a rename cannot reduce the file to a no-op. Mutation-tested in both directions: removing topbar.offline from fr fails the first, adding an en-less key to fr fails the second. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TubWYdWquVkS9dj733sDmC
os-zhuang
added a commit
that referenced
this pull request
Jul 28, 2026
…rejects, + parity ratchet (#2905) * fix(i18n): the change card's Confirm button sent text the cloud gate rejects The English `console.ai.changesConfirmMessage` was "Confirm the changes — apply what you just proposed." The cloud confirm gate (service-ai-studio confirm-gate.ts APPROVAL_RE) recognises `apply (this|the) change` — not "apply what". The message therefore failed the gate, and failing it is silent: the agent re-proposes instead of applying and the Confirm button on the change card just looks inert. This hit English conversations AND all eight locales that fall back to English for that key. Now "Confirm — apply the change you just proposed." — singular, so it still matches if the gate ever tightens to a word boundary. The Chinese string always matched (确认修改) and is unchanged. The same literal lives in four places (locale pack, prop default, its doc comment, AiChatPage defaultValue); all four move together. Why the existing guard missed it: i18n.test.ts mirrored only the CHINESE clause of APPROVAL_RE, and the English half was weakened to "starts with Confirm, contains apply" because nothing in this repo could see the real pattern. That assertion passed against a string the gate rejected — green guard, broken feature. The mirror is now verbatim and covers both clauses, driving an it.each over every outbound approval message in zh and en. Two supporting tests keep it honest: the gate must stay narrow (a plain build request is not approval), and planAnswerMessage must NOT match, since it answers a structure question rather than granting blanket approval. Verified by running the real regex against every outbound string, and by mutation-testing the new guard against the exact string that shipped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TubWYdWquVkS9dj733sDmC * test(i18n): ratchet the four backfilled namespaces so they cannot silently erode #2903 translated `console`, `home`, `topbar` and `layout` into all ten packs. Nothing stopped that from decaying: `fallbackLng: 'en'` means dropping a key from `de` renders English, which reads as "not translated yet" rather than "we lost this", and the missing-key handler is dev-only so CI never sees it. This is #2872's P3 applied only to the namespaces that are actually complete. Full parity would fail today by ~277 keys per pack with no action attached — a broken build, not a guard. Widen RATCHETED_NAMESPACES as each remaining namespace is translated, not before. Asserts both directions, because the packs have drifted both ways before: every ratcheted en key exists in the other nine packs, and no pack defines a ratcheted key en lacks (#2872 part b was exactly that, 74 keys deep, hidden behind a component-private fallback so English "happened to" render). The four outbound agent messages are excluded — they are deliberately absent from the eight non-gate packs, and outbound-agent-messages.test.ts owns that invariant; the two guards would otherwise contradict each other. A non-vacuity assertion pins the ratchet at >300 keys and requires every named namespace to contribute, so a rename cannot reduce the file to a no-op. Mutation-tested in both directions: removing topbar.offline from fr fails the first, adding an en-less key to fr fails the second. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TubWYdWquVkS9dj733sDmC --------- Co-authored-by: Claude <noreply@anthropic.com>
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 free
to 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.
Implements the "high-frequency namespaces only" strategy chosen for #2872 part (a).
Backfills
console,home,topbarandlayout— 193 keys × 8 packs = 1,544 strings — so a ja/ko/de/fr/es/pt/ru/ar admin sees the AI console, home screen, top bar and system navigation in their own language instead of silently falling back to English.Not a full backfill by design:
grid(101),gantt(58),dashboard(25) and the long tail stay on English fallback and remain tracked under #2872.The load-bearing part: four keys deliberately left untranslated
These are not labels. They are text a button transmits to the agent, and the cloud confirm gate (
service-ai-studioconfirm-gate.tsAPPROVAL_RE) decides whether that text reads as approval. It recognises Chinese and English — nothing else.zh.tsalready documents this:AiChatPagetherefore selects them by the language of the conversation, not the UI, and thet()call is expected to miss in every non-Chinese pack and fall through to its EnglishdefaultValue. Translating them would be an outright regression: a German user's "Build it" would start sending German, the gate would stop matching, and the agent would re-propose instead of building — inert button, nothing visibly erroring.Important
This fixes a regression I introduced in #2900. That PR added
changesConfirmMessageto all ten packs, so onmaintoday a German/Japanese/Russian user clicking Confirm on the change card sends translated text the gate cannot match. This PR removes it from the eight and restores the English fallback.I found it only because this backfill forced me to classify every
console.aikey as label-vs-outbound. Worth noting for the record — the same category error is what the new guard now prevents.packages/i18n/src/__tests__/outbound-agent-messages.test.tspins the invariant in both directions: the four keys must be absent from the eight packs and present inen/zh— plus a third assertion that every otherconsole.ailabel is translated, so the narrow exception can't quietly become an excuse for leaving surrounding labels in English.Verification
turbo build: 44/44 — the check that caught the fix(i18n): unconditional Chinese in the chatbot confirm card and field inspector (#2884, #2885) #2900 build break.defails it, and deleting an ordinaryconsole.ailabel fromdefails the non-vacuity assertion. Both restored after.'developer-tools', and values wrapping to the next line) before touching any file.{{count}},{{app}},{{n}}, …) verified programmatically per string against the English source; spot-checked rendered output across all nine packs.Note
@object-ui/plugin-map#type-checkfails locally withmaplibre-gl@6.0.0 has no default export. It is pre-existing — reproduces on cleanorigin/mainwith my changes stashed — and is not in CI's path (turbo buildcovers this repo's build). Unrelated to i18n; flagging rather than folding an unrelated fix into this PR.Translation quality
Translations are model-generated. Terminology follows each pack's existing conventions, and locale-appropriate quotation marks are used (
「」ja,„"de,« »fr,«»ru/es). They would still benefit from native review before anyone treats them as final — flagging plainly rather than implying they are professionally translated.Generated by Claude Code