You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0f920b9
Browse filesBrowse the repository at this point in the historyBrowse files
fix(i18n): a Traditional Chinese session reads and edits the Traditional entry of an inline label map (#31068)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoKnw5nKcC7y1QqoHK4wxk2W)_Fixes#30910
Clause-②: no
Metadata-protocol: none
Metadata-protocol is `none` because what an author can write is
unchanged: the same `InlineLocaleMapSchema` keys and values are
accepted, and only which of two existing entries a Chinese session reads
and edits moves.
## 维护者速读
- 改了什么:内联多语言标签同时写了简体和繁体时,繁体中文会话(zh-Hant / zh-TW /
zh-HK)现在读到、编辑的都是繁体那一条;简体会话同理只取简体。客户端 `pickLocalized`(含写入侧 `setLocalized`
/ `clearLocalized`)和 spec 的 `resolveI18nLabel` 一起改,规则保持一致。
- 为什么改:之前两边都取作者写下的第一个 `zh-*` 键,台湾、香港用户看到简体,在 Studio
里保存还会覆盖简体作者的文字,繁体那条反而不更新。
-
风险与回滚:只影响同一张标签里同时有两种中文书写的情况;只有一种书写的标签、以及所有非中文语言,结果与改前逐字节相同(有测试钉住)。回滚即还原本
PR。
- 先看:`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” 一组覆盖每种繁简拼写。
- 需要你做的:无,席位落地。
- **席位意见**:ui 席 2 对照 head `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 两值,繁体会话仍按简体设计,已另立
#31074。CI 全绿,同意落地。
## What changes
- `ui/packages/i18n/src/pickLocalized.ts`: one private
`localizedEntryKey` now answers the first three limbs for both
`pickLocalized` (read) and `localeWriteKey` (write, and so
`setLocalized` / `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`: `resolveI18nLabel`
takes the same limb (`scriptEntryKey`), so the spec twin, which the nav,
app shell, components and service-analytics call, keeps agreeing with
`pickLocalized` limb for limb.
- **How the script split is derived:** both readings come from
`@objectstack/spec/system`, with no local table.
`platformLocaleTagOf(code)` says which table tag a code means (`zh-TW`,
`zh-HK`, `zh-MO` and the `zh-Hant-*` spellings mean `zh-Hant`; `zh`,
`zh-CN`, `zh-SG` and the `zh-Hans-*` spellings mean `zh-Hans`). A base
is script-split when `PLATFORM_LOCALE_TAGS` holds more than one tag with
that base, which today is only `zh`. For any other language the new limb
is skipped, so `pt`, `es`, `en`, `fr`, `ja` and the rest keep authoring
order on the sibling limb, byte-identical to `main`.
- Limb order where the split applies: exact tag, then the bare base key
when it means the session's tag, then the first sibling that means it,
then the base key whatever it means, then the first sibling. A map with
no entry of the session's script resolves as before.
- Tests: new `describe` blocks in `pickLocalized.test.ts`,
`setLocalized.test.ts` and `clearLocalized.test.ts` (five Simplified and
five Traditional spellings over six two-script maps, plus byte-identical
controls for one-script maps and for `pt`, `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.
- Two existing vectors pinned the defect itself (`{ 'zh-TW', 'zh-CN' }`
at `zh` read the Traditional entry). Both now expect the Simplified
entry. The spec row was replaced by a `pt-PT` / `pt-BR` row that still
pins "first sibling in authoring order" for a language the table names
once.
- Changesets: `@object-ui/i18n` patch, `@objectstack/spec` patch,
`@objectstack/cli` patch.
- Review widening (contract review 6700222070, claim amendment
6700234158):
`ui/packages/app-shell/src/views/metadata-admin/previews/navItemLabel.ts`
`ownEntryKey` now owns the entry `resolveI18nLabel` reads 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.ts` `inlineLocaleText` narrows to
the reader's language and returns what `resolveI18nLabel` picks, with a
two-script fixture in
`packages/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`, then `origin/main` merged (it carries #30902's
`@object-ui/i18n` → `@objectstack/spec` dependency). Suite and gate
readings are on the merge head `4d0fb81ba5`. The ablation was taken on
`7228816bf5`, where the same two source files hold the same blobs.
<details><summary>Before / after (unit level, read value and write
key)</summary>
On `main` `0e882086`:
```
zh-CN+zh-TW lang=zh-Hant read=客户 writeKey=zh-CN
zh-Hans+zh-Hant lang=zh-TW read=客户 writeKey=zh-Hans
zh-TW+zh-CN lang=zh-Hans read=客戶 writeKey=zh-TW
zh-TW+zh-CN lang=zh read=客戶 writeKey=zh-TW
spec resolveI18nLabel zh-CN+zh-TW at zh-Hant read=客户
```
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 (`zh` only, `zh-HK` only) read and
write the same key as on `main`.
</details>
<details><summary>Suites</summary>
- `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-check` after building its closure: exit 0.
</details>
<details><summary>Ablation (one-time proof, mutations restored, blob
equals HEAD)</summary>
Every leg used `scripts/ablation-replace.mjs`.
- Client limb (`if (script !== undefined)` changed to never match) in
`pickLocalized.ts`: 32 tests red across the three i18n files, all of
them new #30910 pins. 0 byte-identical controls red, as expected,
because the mutation is the old behaviour.
- Spec limb (`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.
- The same spec mutation, rebuilt into `dist` (`ablation-dist-preflight`
found 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 `--absent` reports the marker gone from all
592 built files and the tree clean.
</details>
<details><summary>Derived gates (`dispatch-gates.mjs --commands`, 83
families)</summary>
`--ran` reconciliation on `4d0fb81ba5`: 83 derived, 83 run, all exit 0,
0 NOT-MEASURED.
Before `main` was merged (on `7228816bf5`),
`check:undeclared-dep-imports` and the ui `scripts/` phantom-deps test
were red only because `@object-ui/i18n` did not yet declare
`@objectstack/spec`. #30902 added that declaration, and both are green
on the merge head.
</details>
## Acceptance notes
- **Live check (head `6e8b6389`, showcase backend + console dev server,
`nav_projects` relabelled locally to `{ en, zh: '简体项目', 'zh-TW': '繁體專案'
}`, reverted after):** the sidebar shows 繁體專案 in `zh-Hant`, 简体项目 in
`zh-CN`, Proj EN in `en`. Studio's nav designer in a `zh-Hant` session
lists 简体项目, because Studio's designer locale is two-valued
(`useMetadataLocale`, `metadata-admin/i18n.ts:955`, unchanged here):
filed as #31074 with the one-script write and the CLI empty-entry
caveat. The main-side control is NOT MEASURED (it needs a `main` spec
dist rebuild).
- Case: the script preference asks `platformLocaleTagOf`, which folds
case, so `zh-hant` also prefers `zh-TW`. It only reorders keys the
case-sensitive base comparison already admitted, so `ZH-HANT` still
matches no `zh-*` key (pinned).
- A script-subtag spelling the alias table does not name (`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
- Finding, not filed: the base-language comparison in both twins is
case-sensitive on `main` (`ZH-HANT` matches no `zh-*` key), while the
new script limb reads through `platformLocaleTagOf`, which folds case.
Folding the base comparison would change matching for every language, so
it is outside #30910 and is left for the contract reviewer to weigh.
## Verification
Readings as above, on `4d0fb81ba5`; on `2d5cae2c8d` 87 derived gates
exit 0 (`--ran` 0 NOT-MEASURED), navItemLabel ablation reds 4 pins and 0
controls, CLI ablation reds 2. `6e8b6389` adds the cli changeset only.
The contract review (CONTRACT_REVIEW_TIER) on the head is the seat's,
because the diff touches `packages/spec/src`.
<!-- signed: domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf
-->
---------
Co-authored-by: Claude <noreply@anthropic.com>
fix(cli): i18n coverage reads a two-script inline label map the way the renderer does
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
For an inline locale map that carries both Chinese scripts, the text the coverage report reads for a reader locale now equals what the renderer shows: a `zh-Hant` reader of `{ en, 'zh-CN', 'zh-TW' }` is read from `zh-TW`, not from the first `zh-*` key. Every other map and language reads as before.
fix(i18n): a Traditional Chinese session reads and edits the Traditional entry of an inline label map
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
`pickLocalized`, `setLocalized` and `clearLocalized` now prefer an entry of the session's own script where the platform locale table splits a language by script. In a `zh-Hant` (or `zh-TW`, `zh-HK`) session, a label written as `{ en: 'Customer', 'zh-CN': '客户', 'zh-TW': '客戶' }` shows `客戶` and an edit replaces the `zh-TW` entry; before, both took the first `zh-*` key in authoring order, so a Traditional session showed the Simplified text and an edit overwrote it. A `zh-Hans`, `zh-CN` or bare `zh` session prefers the Simplified entry the same way.
11
+
12
+
Which tag a key means comes from `platformLocaleTagOf` in `@objectstack/spec/system`, and the preference applies only to a language the table names more than once (`zh` today). A map without an entry of the session's script, and every other language, resolve exactly as before. What an author can write is unchanged.
fix(spec): `resolveI18nLabel` prefers an inline label entry of the locale's own script
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
Where the platform locale table splits a language by script (`zh-Hans`, `zh-Hant`), `resolveI18nLabel` now reads an entry of the requested locale's script before an entry of the other one: `zh-Hant`, `zh-TW` or `zh-HK` over `{ 'zh-CN': '客户', 'zh-TW': '客戶' }` answers `客戶` in any authoring order, and `zh`, `zh-CN` or `zh-Hans` answers `客户`. It used to take the first `zh-*` key. The script a key means is read from `platformLocaleTagOf`. A map without an entry of the locale's script, and every language the table names once, resolve exactly as before. This keeps the resolver limb for limb with objectui's `pickLocalized`, which takes the same change. The `InlineLocaleMapSchema` keys an author can write are unchanged.
0 commit comments