Repository navigation
feat(i18n): ship the Console's ten locales and follow the phone language - #169
Merged
Merged
Conversation
Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv Seat verdict: ACCEPT — Head-sha: 维护者速读
席位意见: 范围与卡面一致,语言代码与 Console 一一对应,并有测试钉死。objectstack#29349(全项目语言体系的裁决卡)还没裁,按 hotlong 卡上的说明先用这 10 种,PR 正文里写明了。dev 留了一个开放问题:iOS 上 WebView 的 席位核对
|
This was referenced Nov 2, 2026
Stack #168's connect-by-QR work with the ten-locale shell: the picker keeps the scan button, link prefill and way-back from #168 and the RTL direction from #169; #168's new keys (serverConfig.scan, serverConfig.backTo, scanner.*, permissions.camera) are carried into ja ko de fr es pt ru; app.config.ts localizes the iOS camera prompt in all ten languages. Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv 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.
Fixes #159
Clause-②: no
Metadata-protocol: none
维护者速读
lib/i18n.ts(语言匹配规则,照搬 Console 的matchLanguageTag;删掉了一个无人写入的旧语言覆盖值),lib/rtl.ts(useLayoutDirection),app/_layout.tsx(回到前台时重新识别手机语言)。npx jest __tests__/lib/i18n.test.ts __tests__/components/RtlLayout.test.tsx,预期 2 个测试文件、73 个测试全部通过。What changes
SUPPORTED_LANGUAGESis nowen, zh, ja, ko, de, fr, es, pt, ru, ar, in the Console's order, with the Console language menu's native names. Seven new bundles:locales/{ja,ko,de,fr,es,pt,ru}.json, with the same keys asen.json.matchLanguageTag(exact tag, else its base language) is a port of objectstackui/packages/i18n/src/locales/registry.ts:112-117.detectDeviceLanguagewalks the phone's preferred languages in order (getLocales(),languageTag, elselanguageCode) and takes the first one that resolves to a bundled locale, elseen.zh, because the Console does. The Console has no catalogue keyed by a full tag, sozh-TW,zh-HKandzh-Hant*reachzhthrough the base-language step:registry.ts:112-117(matchLanguageTag) and:136-138(resolveBuiltInLanguage), and the Console's own test says so atui/packages/i18n/src/__tests__/region-locale-fallback-11326.test.tsx:109-112. Read at objectstackorigin/main47718699.followDeviceLanguageOnForeground()(anAppStatelistener started inapp/_layout.tsx) re-detects when the app comes back toactiveand callsi18n.changeLanguagewhen the result differs.syncRTLnow also runs on everylanguageChanged.loadInitialLanguageread a language from MMKV (objectstack-ui/language) that nothing has written since the 2.0 shell rebuild. It would pin the language against the phone and block the live change, so it is removed, together with the store.ar, from the first render.lib/rtl.tsaddslayoutDirection(lang)anduseLayoutDirection(). The server picker root (both steps, so the confirm step inherits it), the offline page root and the app root carry Yoga'sdirectionstyle. UnlikeI18nManager.forceRTL, which applies only after the next launch, this flips rows, start/end insets and natural text alignment at once.syncRTLkeepsI18nManagerin step for whatever reads it, such as the stack transition direction, which therefore follows on the next launch.docs/HYBRID-SHELL.mdgains a## Languagesection. It says the shell's locale set mirrors the Console UI's, gives the matching rule, says there is no picker, and says that once signed in the user's Console locale (sys_user.locale) wins inside the Console.components/shell/ConsoleWebView.tsxis untouched (Bridge: stable install id andpushTokenChangedfor device registration; document the no-Service-Worker rule #163 and feat(shell): act on the Console's ready and routeChanged signals; the shell owns the safe area #166 are in flight there). The WebView's content direction is the Console's owndir.Translations: Console wording vs fresh
Matched to the Console's wording at the same concept (objectstack
ui/packages/i18n/src/locales/CODE.ts, key in brackets):common.ok(common.ok),common.cancel(common.cancel),common.retry(common.retry),common.error(chatbot.toolState.error)errorBoundary.title(console.errors.somethingWentWrong),errorBoundary.message(errors.unknown),errorBoundary.retryandshell.retry(console.errors.tryAgain)serverConfig.connect(auth.remediation.mfa.continue),serverConfig.error.unknown(organization.errors.unknown),shell.loading(common.loading)serverConfirm.signIn.emailPasswordis built fromauth.login.emailLabel+auth.login.passwordLabel, and the sign-in verb inserverConfirm.signInLabel/serverConfirm.confirmfollowsauth.login.submitButton(ja サインイン, de Anmelden, fr Se connecter, es Iniciar sesión, pt Entrar, ru Войти, ko 로그인). The register follows the Console's: es uses usted, pt is Brazilian.Translated fresh: every other key, meaning all of
serverConfig.*exceptconnectanderror.unknown,serverConfirm.*apart from the vocabulary above, andshell.offline*,shell.serverError*andshell.changeServer. These need native-speaker review (see 维护者速读). Thezhandarbundles are unchanged.Tests
__tests__/lib/i18n.test.ts:locales/holds exactly those ten bundles.en.json's key set: the missing-key arbiter with Connect by QR code:objectos://connect?server=…links and the native scanner screen #156 / feat(connect): objectos://connect links and the QR scanner (screen 6) #168.en.matchLanguageTagpins are ported.zh-Hans-CN,pt-BR,es-MX, five Traditional Chinese tags →zh, an unsupported first language falling through to the next supported one, none supported →en, an empty list →en,languageCodewithoutlanguageTag, andgetLocalesthrowing →en.__tests__/components/RtlLayout.test.tsx:direction: rtlunderarandltrunderen.beforeAllcold-load pattern.Gates on head 878238e (after merging origin/main 29c25df)
Reverse checks (each mutation landed on disk, then restored to the HEAD blob with an empty git diff HEAD)
Acceptance notes
fulllocales. If it is E, the codes move to the new platform table once it lands.navigator.language, the first language (ui/packages/i18n/src/i18n.ts:170). The card asks for the first supported language from the ordered list, and its acceptance requires an unsupported first language to fall through. So the shell walks the list and applies the Console's per-tag rule to each entry.mainyet. New native screens should putuseLayoutDirection()on their root, as the picker and offline page do.Accept-Language. On iOS, WKWebView may derive it from the app's declared localizations, and the app declares none (expo-localization'ssupportedLocalesoption is not configured). A signed-out Console could therefore seeenwhile the native screens show the phone's language. The device check under 维护者速读 should look at the Console too. Not filed: this is an unmeasured inference.jest.setup.tsmocksreact-native/Libraries/AppState/AppStatewithout adefault, andreact-native'sAppStategetter readsdefault, soAppStateisundefinedin every test.i18n.test.tssupplies its own mock with adefault. Carrier: none.Verification
npx jest __tests__/lib/i18n.test.ts __tests__/components/RtlLayout.test.tsx→ 73 passed.lib/i18n.ts,lib/rtl.ts,locales/*.json(seven new),app/_layout.tsx,app/server-config.tsx,components/shell/OfflineFallback.tsx,__tests__/**,docs/HYBRID-SHELL.md,.changeset/159-ten-locales.md.Generated by Claude Code