Repository navigation
fix(i18n): a Traditional Chinese session reads and edits the Traditional entry of an inline label map - #31068
Conversation
…olds both Chinese scripts pickLocalized and its write-side twin localeWriteKey now share one limb function that, for a language the platform locale table splits by script (zh-Hans / zh-Hant), prefers a key meaning the session's own table tag (read through platformLocaleTagOf) before falling back to the first sibling. The spec twin resolveI18nLabel takes the same limb so the parity between the two resolvers holds. Maps without a same-script entry and every other language resolve exactly as before. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibxSGAjHBvjATmenUGp
📓 Docs Drift CheckThis PR changes 2 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 180 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 42a7567352d64da3fd17b36a87edb01e8834361c && git checkout 42a7567352d64da3fd17b36a87edb01e8834361c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 3f61e4f8fb567160f839c3269ee95aa89ee4f1db 6e8b63894022174bb53a869f49d38eb05e85173d && git checkout -B drift-repro 3f61e4f8fb567160f839c3269ee95aa89ee4f1db && git merge --no-ff 6e8b63894022174bb53a869f49d38eb05e85173d
node scripts/docs-audit/affected-docs.mjs --json 3f61e4f8fb567160f839c3269ee95aa89ee4f1db
|
|
domain:ui#2 · os-tesla · session_01L9qibxSGAjHBvjATmenUGp Contract-review-claim: session_01L9qibxSGAjHBvjATmenUGp · head 4d0fb81 · 2026-11-07T01:05Z Seat review run on the maintainer's word in the card thread (「你应该使用 pm-dispatch 技能审核和落地pr」, 2026-11-07 01:02Z). Face: published schema ( |
|
domain:ui#2 · os-tesla · session_01L9qibxSGAjHBvjATmenUGp Contract-review-claim withdrawn: session_01L9qibxSGAjHBvjATmenUGp · head 4d0fb81 · 2026-11-07T01:05Z This session authored the diff. Under pm-dispatch the dispatching seat (ui seat 2, session_01L9qibw7DekEe3wx5f3zphf) runs the |
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf Contract-review-claim: session_01L9qibw7DekEe3wx5f3zphf · head 4d0fb81 · 2026-11-07T01:08Z |
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf Contract reviewServed-tier: Inputs: card #30910 (body, triage 6683176666, claim 6684338116, amendment 6684414838, progress request 6695504263, os-dev-report 6700059771), PR #31068 (body, 9-file list, net diff against ① Derived judgments
② Semver level
③ Boundary flagsDev flags (os-dev-report 6700059771 and PR body), each answered:
Unflagged by the dev, raised here: the PR body's "the spec twin, which the nav, app shell, components and service-analytics call, keeps agreeing with ④ Design judgment
Holds: the limb itself. M1 — must-fix. The change splits read from write in the Studio nav designer for a map shape the PR itself names as in reach.
S1 — should-fix. A third limb copy in the coverage gate now disagrees with the twins and its pin is blind to it. S2 — should-fix (prose in the S3 — should-fix (file, do not block). The write side on a ONE-script map still crosses scripts: a Observations, no action: the closed alias list means Implemented-by: VERDICT: FAIL |
…lver shows ownEntryKey asked for the exact tag, else the bare language. Where the resolver now prefers a sibling of the locale's own script over a bare language of the other script, the editor overwrote and cleared the entry it was not showing. It now asks resolveI18nLabel which entry it reads, over a map of each key to its own name, and keeps no copy of the resolver's limbs. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibxSGAjHBvjATmenUGp
… resolver inlineLocaleText now narrows the map to the reader's language and asks resolveI18nLabel, so a zh-Hant reader is covered by its own script's entry rather than by the first zh-* key. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibxSGAjHBvjATmenUGp
…epo home The script-preference row sits before limbs 2 and 3 where the code runs it, and the parity note no longer calls a change a two-repo decision. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibxSGAjHBvjATmenUGp
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf Contract-review-claim: session_01L9qibw7DekEe3wx5f3zphf · head 2d5cae2 · 2026-11-07T02:04Z |
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf Contract reviewServed-tier: Delta review of the FAIL recorded on ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
M1 (first record) — resolved.
S1 (first record) — resolved, with one caveat (S2 below). S2 — should-fix (narrow, pre-existing in another form; fix or state it). The new pin row S1 (this record, ②) — add the Observations, no action: Implemented-by: VERDICT: PASS |
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibxSGAjHBvjATmenUGp
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf Regen-provenance: 6700837928 · |
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf 席位核对 · ACCEPT · 2026-11-07T02:40Z · head
|
Requested by Tesla · project thread
Fixes #30910
Clause-②: no
Metadata-protocol: none
Metadata-protocol is
nonebecause what an author can write is unchanged: the sameInlineLocaleMapSchemakeys and values are accepted, and only which of two existing entries a Chinese session reads and edits moves.维护者速读
pickLocalized(含写入侧setLocalized/clearLocalized)和 spec 的resolveI18nLabel一起改,规则保持一致。zh-*键,台湾、香港用户看到简体,在 Studio 里保存还会覆盖简体作者的文字,繁体那条反而不更新。ui/packages/i18n/src/pickLocalized.ts的localizedEntryKey(读写共用的一处);packages/spec/src/ui/i18n-label-resolver.ts的scriptEntryKey;ui/packages/plugin-list/src/__tests__/i18nLabel-resolver-parity.test.ts新增的两侧一致性行。pnpm --dir ui exec vitest run packages/i18n/src/__tests__/pickLocalized.test.ts,预期全绿,其中 “an entry of the session's own script first” 一组覆盖每种繁简拼写。6e8b6389复核:14 个文件、+498 / −65,无受治理路径,因碰packages/spec/src走 CONTRACT_REVIEW_TIER 契约复审:首轮 FAIL(6700222070,Studio 导航设计器的写入键ownEntryKey仍按旧规则,会在双书写标签上改错条目),修复后 delta 复审 PASS(6700837928),之后只加了一条 changeset(Regen-provenance 已落)。现场:zh-Hant 会话侧栏显示繁体条目。Studio 设计器语言只有 zh-CN / en-US 两值,繁体会话仍按简体设计,已另立 Studio designs a Traditional Chinese session in Simplified, so its label edits land on the Simplified entry #31074。CI 全绿,同意落地。What changes
ui/packages/i18n/src/pickLocalized.ts: one privatelocalizedEntryKeynow answers the first three limbs for bothpickLocalized(read) andlocaleWriteKey(write, and sosetLocalized/clearLocalized). Where the platform locale table splits a language by script, the base and sibling limbs prefer an entry of the session's own script before any other sibling.packages/spec/src/ui/i18n-label-resolver.ts:resolveI18nLabeltakes the same limb (scriptEntryKey), so the spec twin, which the nav, app shell, components and service-analytics call, keeps agreeing withpickLocalizedlimb for limb.@objectstack/spec/system, with no local table.platformLocaleTagOf(code)says which table tag a code means (zh-TW,zh-HK,zh-MOand thezh-Hant-*spellings meanzh-Hant;zh,zh-CN,zh-SGand thezh-Hans-*spellings meanzh-Hans). A base is script-split whenPLATFORM_LOCALE_TAGSholds more than one tag with that base, which today is onlyzh. For any other language the new limb is skipped, sopt,es,en,fr,jaand the rest keep authoring order on the sibling limb, byte-identical tomain.describeblocks inpickLocalized.test.ts,setLocalized.test.tsandclearLocalized.test.ts(five Simplified and five Traditional spellings over six two-script maps, plus byte-identical controls for one-script maps and forpt,es,en,fr,ja); new rows in the plugin-list parity table; the spec test's verbatim reference copy re-pinned to the new blob and given script vectors.{ 'zh-TW', 'zh-CN' }atzhread the Traditional entry). Both now expect the Simplified entry. The spec row was replaced by apt-PT/pt-BRrow that still pins "first sibling in authoring order" for a language the table names once.@object-ui/i18npatch,@objectstack/specpatch,@objectstack/clipatch.ui/packages/app-shell/src/views/metadata-admin/previews/navItemLabel.tsownEntryKeynow owns the entryresolveI18nLabelreads among the map's same-base own entries, so Studio's nav rename and clear act on the entry the designer shows (7422324200);packages/cli/src/utils/i18n-coverage.tsinlineLocaleTextnarrows to the reader's language and returns whatresolveI18nLabelpicks, with a two-script fixture inpackages/cli/test/i18n-inline-locale-map-coverage.test.ts(4b4e003685); resolver prose follows the limb order and the one-repo home (2d5cae2c8d).Tests
Fix commit
7228816bf5, thenorigin/mainmerged (it carries #30902's@object-ui/i18n→@objectstack/specdependency). Suite and gate readings are on the merge head4d0fb81ba5. The ablation was taken on7228816bf5, where the same two source files hold the same blobs.Before / after (unit level, read value and write key)
On
main0e882086:On this branch the same rows read 客戶 / zh-TW, 客戶 / zh-Hant, 客户 / zh-CN, 客户 / zh-CN, and the spec resolver reads 客戶. These are pinned in the new describe blocks. One-script maps (
zhonly,zh-HKonly) read and write the same key as onmain.Suites
pnpm --filter @objectstack/spec exec vitest run src/ui/i18n-label-resolver.test.ts src/system/platform-locales.test.ts: 2 files, 184 tests passed.pnpm --dir ui exec vitest run packages/i18n/src/__tests__/pickLocalized.test.ts packages/i18n/src/__tests__/setLocalized.test.ts packages/i18n/src/__tests__/clearLocalized.test.ts packages/plugin-list/src/__tests__/i18nLabel-resolver-parity.test.ts scripts/__tests__/check-phantom-dependencies.test.ts: 5 files, 276 tests passed.pnpm --filter @objectstack/spec typecheck: exit 0.pnpm --filter @object-ui/i18n type-checkafter building its closure: exit 0.Ablation (one-time proof, mutations restored, blob equals HEAD)
Every leg used
scripts/ablation-replace.mjs.if (script !== undefined)changed to never match) inpickLocalized.ts: 32 tests red across the three i18n files, all of them new A Traditional Chinese console reads and writes the Simplified entry of an inline label map #30910 pins. 0 byte-identical controls red, as expected, because the mutation is the old behaviour.if (sameScript !== undefined) return …changed to never match), spec source suite: 5 red (4 script vectors plus the one-pass agreement test). The reference-copy column stayed green.dist(ablation-dist-preflightfound the marker in 2 built files): 6 red in the plugin-list parity test (5 new rows plus "has no rule divergence left"). After restoring and rebuilding, the preflight--absentreports the marker gone from all 592 built files and the tree clean.Derived gates (`dispatch-gates.mjs --commands`, 83 families)
--ranreconciliation on4d0fb81ba5: 83 derived, 83 run, all exit 0, 0 NOT-MEASURED.Before
mainwas merged (on7228816bf5),check:undeclared-dep-importsand the uiscripts/phantom-deps test were red only because@object-ui/i18ndid not yet declare@objectstack/spec. #30902 added that declaration, and both are green on the merge head.Acceptance notes
6e8b6389, showcase backend + console dev server,nav_projectsrelabelled locally to{ en, zh: '简体项目', 'zh-TW': '繁體專案' }, reverted after): the sidebar shows 繁體專案 inzh-Hant, 简体项目 inzh-CN, Proj EN inen. Studio's nav designer in azh-Hantsession lists 简体项目, because Studio's designer locale is two-valued (useMetadataLocale,metadata-admin/i18n.ts:955, unchanged here): filed as Studio designs a Traditional Chinese session in Simplified, so its label edits land on the Simplified entry #31074 with the one-script write and the CLI empty-entry caveat. The main-side control is NOT MEASURED (it needs amainspec dist rebuild).platformLocaleTagOf, which folds case, sozh-hantalso preferszh-TW. It only reorders keys the case-sensitive base comparison already admitted, soZH-HANTstill matches nozh-*key (pinned).zh-Hant-US) is not guessed at and is not treated as Traditional (pinned). This matches the spec table's closed-list rule.Out of scope
main(ZH-HANTmatches nozh-*key), while the new script limb reads throughplatformLocaleTagOf, which folds case. Folding the base comparison would change matching for every language, so it is outside A Traditional Chinese console reads and writes the Simplified entry of an inline label map #30910 and is left for the contract reviewer to weigh.Verification
Readings as above, on
4d0fb81ba5; on2d5cae2c8d87 derived gates exit 0 (--ran0 NOT-MEASURED), navItemLabel ablation reds 4 pins and 0 controls, CLI ablation reds 2.6e8b6389adds the cli changeset only. The contract review (CONTRACT_REVIEW_TIER) on the head is the seat's, because the diff touchespackages/spec/src.