Skip to content

docs(skills): objectui i18n guide keys the built-in packs by platform locale tag (zh-Hans, zh-Hant, pt-BR) - #31043

Draft
objectstack-fleet[bot] wants to merge 2 commits into
mainfrom
claude/project-thread-rm542x
Draft

objectstack-fleet[bot] wants to merge 2 commits into
mainfrom
claude/project-thread-rm542x

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Irene · project thread

Fixes #30911
Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:skills/objectui/guides/i18n.md 不再教已退役的 zh / pt 语言包键:内置语言改为平台语言表 PLATFORM_LOCALES 的 11 个标签(en、zh-Hans、zh-Hant、es、ar、fr、pt-BR、ru、de、ja、ko)及模块路径 @object-ui/i18n/locales/<tag>;setup 示例改用 'zh-Hans' 键;语言切换器改为遍历 PLATFORM_LOCALES,不再手写列表,且以 resolveBuiltInLanguage(language) ?? language 选中当前语言(实例以已存别名如 zh 运行时也能选中);说明已存的 zh / zh-CN / zh-TW / pt 经语言表的读别名(resolveBuiltInLanguage)继续解析。
  • 为什么改:PR feat(i18n)!: the Console's language packs follow the platform locale table, keyed by its tags, and Traditional Chinese (zh-Hant) ships #30902 已把内置包从 zh / pt 改名为 zh-Hans / pt-BR 并新增 zh-Hant,照旧指南写的键和 import 在 main 上不再解析,也提供不了繁体中文。
  • 风险与回滚:只改 skill 文本和一个 changeset;token 天花板不动(1411/1413);回滚即 revert,无运行时影响。
  • 先看:指南的「Built-in locales」段与切换器示例,对照 ui/packages/i18n/src/locales/registry.ts 和 packages/spec/src/system/platform-locales.ts。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs,预期 exit 0,skills/objectui/guides/i18n.md 读数 1411/1413。
  • 需要你做的:skills/** 属 Tier H,需要 os-zhuang 或 hotlong 批准。

What changes

Every tag, path and alias the guide now states was read on main (3fe5f2a02, after PR #30902 at 5bca14fc):

Taught Source on main
The eleven pack keys, in table order packages/spec/src/system/platform-locales.ts ROWS; ui/packages/i18n/src/locales/registry.ts LAZY_LOCALE_LOADERS (typed on PlatformLocaleTag) and BUILT_IN_LANGUAGE_CODES; locales/index.ts builtInLocales ("there is no zh or pt key")
Module @object-ui/i18n/locales/<tag> ui/packages/i18n/package.json export ./locales/*; after pnpm build, dist/locales/zh-Hans.js, zh-Hant.js, pt-BR.js (+ .d.ts) exist
Stored zh / zh-CN → zh-Hans, zh-TW → zh-Hant, pt → pt-BR PLATFORM_LOCALE_READ_ALIASES, read by resolveBuiltInLanguage (registry.ts) through platformLocaleTagOf
"Write the tag" platform-locales.ts: read aliases are "Reads only: a new write uses the table tag itself"
Switcher fed by PLATFORM_LOCALES (tag, label) PlatformLocale interface, exported from @objectstack/spec/system
Switcher value={resolveBuiltInLanguage(language) ?? language} An instance can run in a stored alias (zh from a stored choice via resolveBootstrapConfig, a seeded zh-CN via resolveSeedLanguage); resolveBuiltInLanguage is exported from the package entry (ui/packages/i18n/src/index.ts)

The switcher fence is os:check-marked and compiles against the built types: pnpm --dir ui run check:skill-examples exit 0, --list shows i18n.md:38 marked pass (the @objectstack/spec/system import resolves). The unmarked setup fence's only --measure error is the pre-existing AppContent fragment name; the 'zh-Hans' key type-checks.

The inline-map section (L133 on) is untouched: its zh-CN keys are still valid inline-map keys and it needs no zh-Hant example to stay correct.

Evals swept: skills/objectui/evals/i18n.json has no case grading a zh / pt pack key or path. Its one zh string, must_not_contain: "import zh from './zh.json'", grades an app's own JSON import, not the retired built-in key, so it is left as is.

Token budget

node scripts/check-skills-token-ratchet.mjs: skills/objectui/guides/i18n.md 1413 → 1411 (5652 → 5643 bytes; ceiling 1413, unchanged, headroom 2). Bundle total 228257 → 228255. No ratchet raise; scripts/check-skills-token-ratchet.mjs is not touched.

Growth paid by deleting restatement in the same file, each with its surviving home:

  1. L3 intro "Multi-language support via @object-ui/i18n." Home: the H1 and every fence's import … from '@object-ui/i18n' (first at Setup).
  2. The Setup comment // Auto-detect from navigator on detectBrowserLanguage: true. Home: the option's own name (and its doc on I18nConfig.detectBrowserLanguage in ui/packages/i18n/src/i18n.ts).
  3. The RTL section's fence const { direction } = useObjectTranslation(); // direction: 'ltr' | 'rtl'. Home: the useObjectTranslation hook example, which destructures direction and applies it (<header dir={direction}>); the RTL prose ("The provider updates document.dir…") stays.
  4. Common mistakes bullet "Bundling all locale files upfront — use lazy loading for apps with many languages." Home: § Lazy language loading ("For large apps, load translations on demand instead of bundling all locales").
  5. (review S1 payment) The § Language-aware + responsive page intro "When combining with @object-ui/mobile for responsive layouts:". Home: the section heading ("responsive page") and the fence's import { useBreakpoint } from '@object-ui/mobile'.

Review round 1 (contract review PASS at 291ef83d8, comment 6694588461): S1 fixed in delta commit 450d72405. The switcher's controlled value now resolves a stored alias to its table tag, so an instance running in zh or zh-CN selects 简体中文 instead of falling to the first option. Its +60 bytes are paid by deletion 5. The out-of-scope LocaleSwitcher finding is removed from this body: the seat files it as its own card.

Review tier

dispatch-gates mandates the contract-review tier for skills/** (clause ①); waived by the maintainer's standing order in this project (2026-11-03). The seat runs the contract review.

Gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on head 450d72405 (2 paths vs merge base 9d939c582): 45 commands (the same list as round 1), each run under timeout 900 with NODE_OPTIONS=--max-old-space-size=8192 (raised from the cloud container default heap), exit code captured before any pipe → 45 × exit 0. pnpm --filter @objectstack/spec run check:skill-examples first exited 3 (NOT MEASURED: the spec build predated the rebase onto 9d939c582); after pnpm --filter @objectstack/spec build it exited 0, and that is the recorded code. --ran reconciliation: 45 derived famil(ies) accounted for — 45 run, 0 NOT-MEASURED. Extra, not derived but run by CI (ci.yml): pnpm --dir ui run check:skill-examples → exit 0 after the spec rebuild; --list shows i18n.md:38 marked pass with the new import. Round 1 at 291ef83d8 was also 45 × exit 0 after a full pnpm build (119/119). origin/main has since gained e396095b6 (ui/packages/types only, disjoint), so no merge was needed. node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD → exit 0 before each push.

Ran list
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-doc-route-spelling.mjs --advisory :: exit 0
node scripts/check-doc-route-spelling.mjs --self-test :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-skills-token-ratchet.mjs :: exit 0
node scripts/check-skills-token-ratchet.mjs --self-test :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/ci/snapshot-next.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm --filter @objectstack/spec run check:skill-examples :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:corpus-claim-drift :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 0
pnpm check:dual-build-cjs-loads :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:lean-entry-closure :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-skill-id-lint :: exit 0
pnpm check:published-files :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:role-word :: exit 0
pnpm check:skill-compatibility :: exit 0
pnpm check:skill-frame-sync :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 0
pnpm check:watch-hint-literal :: exit 0

🤖 Generated with Claude Code

https://claude.ai/code/session_01J8VVAjteesTptAwhHn3GuE

… locale tag

The guide still taught the retired `zh` and `pt` pack keys after the
Console's packs moved to the platform locale table. It now lists the
eleven table tags, keys the setup example by `zh-Hans`, feeds the
switcher from `PLATFORM_LOCALES`, and says which stored codes keep
resolving through the table's read aliases.

Paid for by deleting restatement in the same file: the intro line
(package named by every import), the inline navigator comment, the
`direction` re-destructure fence (shown in the hook example), and the
lazy-loading common-mistake bullet (its own section).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8VVAjteesTptAwhHn3GuE
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 6, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract-review-claim: session_01J8VVAj7CvjkGXvgXzd6RZ7 · head 291ef83 · 2026-11-06T20:14Z

The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent. No review seat (lanes/review.md) is seated.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 291ef83d8296d6445c4620aa22dc93c98dad9957
Local-runs: none
Scope: skills/objectui/guides/i18n.md + .changeset/objectui-i18n-guide-locale-tags.md, ui/packages/i18n/src/locales/registry.ts, ui/packages/i18n/src/locales/index.ts, ui/packages/i18n/src/index.ts, ui/packages/i18n/src/i18n.ts, ui/packages/i18n/src/provider.tsx, ui/packages/i18n/src/pickLocalized.ts, ui/packages/i18n/package.json, ui/packages/i18n/tsconfig.json, packages/spec/src/system/platform-locales.ts, packages/spec/src/system/index.ts, packages/spec/package.json, packages/spec/src/ui/i18n.zod.ts, packages/skills/package.json, skills/objectui/evals/i18n.json, skills/objectui/SKILL.md, scripts/check-skills-token-ratchet.mjs, ui/packages/app-shell/src/layout/LocaleSwitcher.tsx, PR #30902 (merged as 5bca14fc2)

Inputs: card #30911 body and its 2 comments (triage, claim); PR #31043 body and file list (2 files, +19 −17); the net diff origin/main...291ef83d8 (merge base 9d939c582, the current origin/main); the head's check-runs. Cited code read on origin/main 9d939c582.

① Derived judgments

Every tag, key, path, API name and behaviour the guide now teaches, against main:

  • The eleven tags, in order (L30: en, zh-Hans, zh-Hant, es, ar, fr, pt-BR, ru, de, ja, ko). Exact. platform-locales.ts ROWS has these 11 tags in this order, and registry.ts LAZY_LOCALE_LOADERS (typed on PlatformLocaleTag) plus BUILT_IN_LANGUAGE_CODES = [...PLATFORM_LOCALE_TAGS] key the packs by them. The order is the table's menu order, not the old guide's grouping.
  • "One pack per row … keyed by tag" (L29–30). True. locales/index.ts builtInLocales has exactly these keys, held to the table with satisfies Record on PlatformLocaleTag.
  • PLATFORM_LOCALES from @objectstack/spec/system (L29, L40). True. It is exported by platform-locales.ts, re-exported at system/index.ts:131, and packages/spec/package.json publishes ./system (import, require and browser arms). The objectui SKILL.md compatibility: line already requires @objectstack/spec 18.x, so the extra import needs no install step.
  • The module path for each tag (L31). Every one resolves. ui/packages/i18n/package.json exports ./locales/* → ./dist/locales/*.js. tsconfig.json sets rootDir: src and outDir: dist, and src/locales/ holds en, zh-Hans, zh-Hant, es, ar, fr, pt-BR, ru, de, ja, ko .ts. There is no zh.ts or pt.ts, so the retired paths really do not resolve. The setup and switcher imports (@object-ui/i18n for I18nProvider, createI18n and useObjectTranslation) resolve through . in src/index.ts.
  • "No zh or pt pack" (L31). True of keys and modules. index.ts says "there is no zh or pt key". The @object-ui/i18n/locales door still exports JS identifiers named zh and pt, but the source says these are identifiers, not pack keys. The sentence stays true.
  • Read aliases: zh and zh-CN → zh-Hans, zh-TW → zh-Hant, pt → pt-BR (L31–32). Exact. PLATFORM_LOCALE_READ_ALIASES holds each of these rows. resolveBuiltInLanguage (registry.ts) reads them through platformLocaleTagOf, and the package entry exports it, so the name in parentheses is real and importable. The provider and createI18n also serve an alias-language instance through fallbackLanguagesFor. The guide does not need that detail.
  • "Write the tag." (L33). True. platform-locales.ts says the aliases are "Reads only: a new write uses the table tag itself".
  • Setup resources: { 'zh-Hans': … } (L14). Correct. createI18n deep-merges resources[lang] over each BUILT_IN_LANGUAGE_CODES bundle, so the zh-Hans key merges into the built-in pack. The old zh key would now have formed a separate non-built-in bundle. With detectBrowserLanguage, a zh-CN browser resolves to zh-Hans through pickInitialLanguage → resolveBuiltInLanguage.
  • Switcher (L49–51): PLATFORM_LOCALES.map(({ tag, label }) => …). The fields are real: the PlatformLocale interface declares tag, label and rtl. changeLanguage(tag) loads the built-in catalogue under its tag (provider.tsx context changeLanguage → loadBuiltInLocale(resolveBuiltInLanguage(lang))). See S1 for one gap in the value binding.

The four restatement deletions:

  1. L3 intro "Multi-language support via @object-ui/i18n." The surviving home is real: the package name is in the H1 subject and in every fence's import, first at Setup L6. No unique fact was lost.
  2. // Auto-detect from navigator. The surviving home is real: the option is named detectBrowserLanguage, and I18nConfig documents it as "Whether to detect browser language automatically (default: true)". pickInitialLanguage reads navigator.language. No fact was lost.
  3. The RTL fence const { direction } = useObjectTranslation(); // direction: 'ltr' | 'rtl'. The surviving home is real: the hook example (L43, L46) destructures direction and applies dir={direction}, the RTL prose keeps "The provider updates document.dir", and Common mistakes keeps dir={direction}. The 'ltr' | 'rtl' union now appears nowhere in the guide, but it is the declared type of getDirection and of the context's direction, and the guide only ever passes the value to dir. No consequential teaching was lost.
  4. Common-mistakes bullet "Bundling all locale files upfront — use lazy loading…". The surviving home is real and says the same thing: § Lazy language loading L60, "For large apps, load translations on demand instead of bundling all locales". No fact was lost.

No statement in the diff is false, and no unique fact was lost.

② Semver level

'@objectstack/skills': patch is right. The diff changes only skill prose, and packages/skills publishes the synced skills/ catalogue (sync-catalog.mjs, files: ["dist", …]). AGENTS.md says "none takes patch", and the recent skills-docs changesets on main (e.g. 29506-title-format-refused-teaching.md) use the same shape. skip-changeset would have been wrong, and it was not used.

Clause-②: no is right. No published schema, export or authorable surface changes. The guide now describes the narrowing that #30902 already shipped and declared; it adds none.

Metadata-protocol: none is right. Nothing changes in what a metadata author can write.

Both lines appear line-initial in the PR body and in the changeset body.

③ Boundary flags

  • Eval set (skills/objectui/evals/i18n.json). No case grades anything the new guide contradicts. Case 1's must_not_contain: "import zh from './zh.json'" grades an app's own JSON import, not a built-in pack key, so leaving it is right. Case 1's must_contain: "lazy" grades the answer: the only lowercase "lazy" in the guide was in deleted bullet 4, but § Lazy language loading still teaches the pattern, so the case stays supported. Case 3's "direction" is still supported by the hook example and Common mistakes after deletion 3.
  • The body's out-of-scope finding is real. On main, ui/packages/app-shell/src/layout/LocaleSwitcher.tsx BUILT_IN_LABELS is keyed en, zh, ja, ko, de, fr, es, pt, ru, ar. It has no zh-Hans, zh-Hant or pt-BR, so localeLabel() names those three through Intl.DisplayNames, not with the table's label. Its doc comment still calls pt-BR "an app-shipped locale". A REST issue search for it finds only the closed i18n phase 2 (Console UI): ui/packages/i18n reads PLATFORM_LOCALES, adds zh-Hant, and moves pack keys to table tags #30511, so it is not filed. It belongs in a card of its own (app-shell, outside this card's surface), not in this PR.
  • Sweep of other skills. The rest of skills/ on the head has no retired zh or pt pack key, path or value="zh".

④ Design judgment

  • The switcher reads the table, not a hand list. It maps PLATFORM_LOCALES, so a tag added to the table appears without editing the guide, and it shows the table's own label. That is what the card asked for (Wanted 1). The hook also exposes offerableLanguages (built-in tags plus app locales from config.resources or loadLocales), which a table-fed menu omits. The card asked for the table, and only the table carries labels, so this is noted, not a finding.

  • S1 (should-fix): the switcher's value={language} can match no option. The fix uses resolveBuiltInLanguage, which the guide's own L33 already names:

    value={resolveBuiltInLanguage(language) ?? language}

    The context's language is the code the instance runs in, and that can be a stored alias. A stored explicit choice zh boots as zh: resolveBootstrapConfig sets defaultLanguage: stored, and zh is exactly what the previous guide's value="zh" switcher wrote. A seed zh-CN boots as zh-CN through resolveSeedLanguage → matchLanguageTag exact hit. A host's changeLanguage(sys_user.locale) behaves the same way. The UI then renders in Chinese while the controlled select has no matching option and shows its first option, "English". The fence is os:check-marked and still compiles. Paying for the extra tokens needs one more same-file deletion, because headroom is 1.

  • The inline-map section (L128–142, zh-CN keys) is consistent with the renamed keys and does not contradict them. The inline map and the pack keys are different questions. InlineLocaleMapSchema admits any BCP-47 tag and its own example and refusal message use zh-CN. pickLocalized({ en, 'zh-CN' }, 'zh-Hans') misses exactly (zh-Hans) and misses on the base (zh), then the regional limb serves the zh-CN entry. "Write the tag" (L33) is scoped to stored and pack codes. Leaving out a zh-Hant example is defensible: a map { 'zh-CN', 'zh-TW' } would be resolved for a zh-Hant viewer by first-key order through that same regional limb, so an example could teach a wrong pick. A zh-Hant viewer of the guide's { en, 'zh-CN' } map is served the Simplified entry by the regional limb. That is existing pickLocalized behaviour that the guide does not misstate.

  • Budget. The head file is 5648 bytes, and ceil(5648/4) = 1412. The ceiling is 1413 (scripts/check-skills-token-ratchet.mjs:1077, unchanged on the head). main is 5652 bytes = 1413. The guide is within the ceiling, with 1 token of headroom and no ratchet raise.

  • Check-runs on the head (53, read 2026-11-06T20:18Z): 36 success, 8 skipped, 9 in progress, 0 failed. The 9 in progress are Test Core 1/8 and 2/8, Lint UI, Type Check UI, Build & E2E UI, Lint · CI, release & engine gates, and Type Check · debt ledger, consumer gates and workspace. Lint · docs & code guards, Check Changeset and the Governed Surface Queue Guard are green. The verdict does not wait on the runs still in progress.

Findings: must-fix none; should-fix S1 (the switcher's value binding for an instance running in a stored alias).

Implemented-by: claude/project-thread-rm542x
Reviewed-by: session_01J8VVAj7CvjkGXvgXzd6RZ7

VERDICT: PASS

… it runs in a stored alias

An instance can run in a stored code such as `zh` or `zh-CN`; the
switcher's `value={language}` then matched no option and the select
showed English over a Chinese page. It now selects
`resolveBuiltInLanguage(language) ?? language`.

Paid for by deleting the responsive-page section's intro sentence,
which restates its heading and the fence's `@object-ui/mobile` import.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8VVAjteesTptAwhHn3GuE
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract-review-claim: session_01J8VVAj7CvjkGXvgXzd6RZ7 · head 450d724 · 2026-11-06T20:36Z

Delta review against the PASS at head 291ef83 (comment 6694588461, should-fix S1). The delta is one commit answering S1 (the switcher's value binding) and paying for it with one same-file restatement deletion, plus the PR body. The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 450d724054f6adde3df14b2c95da5986329ccc84
Local-runs: none
Scope: skills/objectui/guides/i18n.md + .changeset/objectui-i18n-guide-locale-tags.md, ui/packages/i18n/src/index.ts, ui/packages/i18n/src/locales/registry.ts, ui/packages/i18n/src/provider.tsx, packages/spec/src/system/platform-locales.ts, scripts/check-skills-token-ratchet.mjs, issue #31045

This is a delta review of round 1 (PASS at 291ef83d8, one should-fix, S1). The delta is git diff 291ef83d8 450d72405: one commit, 450d72405 "docs(skills): objectui i18n switcher selects the active language when it runs in a stored alias", which touches only skills/objectui/guides/i18n.md (+2 −4). There was no rebase. The merge base with origin/main is still 9d939c582.

e396095b6 ("refactor(types)!: delete nine Spec Report Bridge names nothing reads", #31038) is on origin/main, not in this PR's range. It touches ui/packages/types only, which does not overlap this PR's two paths, so no merge is owed. The net diff against main is still the same two files: .changeset/objectui-i18n-guide-locale-tags.md (unchanged since round 1) and skills/objectui/guides/i18n.md. I re-read the new PR body.

① Derived judgments

  • The new import exists in the @object-ui/i18n entry. The switcher fence now imports { resolveBuiltInLanguage, useObjectTranslation } from '@object-ui/i18n'. ui/packages/i18n/src/index.ts on main re-exports resolveBuiltInLanguage from ./locales/registry.js, next to BUILT_IN_LANGUAGE_CODES and loadBuiltInLocale, and the package's . export serves that entry. Its signature is (lang: string) => string | null, so resolveBuiltInLanguage(language) ?? language is a string, which a select value accepts. The fence is still os:check-marked, and the body reports check:skill-examples i18n.md:38 marked pass with the new import.

  • The binding fixes S1. value={resolveBuiltInLanguage(language) ?? language}. The function reads the code through platformLocaleTagOf and then each shorter prefix, so every alias case that round 1 traced now selects a table tag that has an option:

    • a stored choice zh (booted as zh by resolveBootstrapConfig) selects zh-Hans;
    • a seed zh-CN (booted as zh-CN by resolveSeedLanguage) selects zh-Hans;
    • zh-TW and zh-Hant-TW select zh-Hant;
    • pt selects pt-BR;
    • en-US selects en.

    A table tag resolves to itself, so a plain switch round-trips unchanged. A code with no built-in pack (an app locale such as th) falls back to language. That locale is outside the table-fed menu, as round 1 noted under offerableLanguages. The fix agrees with L33 of the guide, which names resolveBuiltInLanguage as the reader of the read aliases. onChange still writes the table tag, which keeps L33's "Write the tag" true.

  • Deletion 5 lost no unique fact. The deleted line is the § Language-aware + responsive page intro "When combining with @object-ui/mobile for responsive layouts:". The facts it carried are that the package is @object-ui/mobile and that the purpose is responsive layout:

    • the package survives in the fence's import { useBreakpoint } from '@object-ui/mobile';
    • the purpose survives in the heading ("responsive page") and in the fence's isMobile ? mobilePageSchema : desktopPageSchema.

    Nothing else in the sentence appears only there.

  • Nothing from round 1 regressed. The delta changes no other line. The eleven tags, the module paths, the alias sentence, "Write the tag", the setup 'zh-Hans' key, the table-fed map, and round 1's four deletions with their surviving homes are byte-identical to 291ef83d8. The inline-map section (L128–142) sits above the delta's only deletion, so its line numbers are unchanged.

② Semver level

The changeset is unchanged since round 1, and the delta is skill prose only. '@objectstack/skills': patch, Clause-②: no and Metadata-protocol: none remain right. Both lines are still line-initial in the PR body and the changeset body.

③ Boundary flags

  • Eval set. There is no new contact. skills/objectui/evals/i18n.json grades nothing about the switcher's value binding or the responsive section's intro.
  • The out-of-scope finding is now filed. BUILT_IN_LABELS in the app-shell's LocaleSwitcher.tsx is filed as app-shell LocaleSwitcher still labels built-in languages from a hand list keyed by the retired zh / pt codes #31045 (open, "app-shell LocaleSwitcher still labels built-in languages from a hand list keyed by the retired zh / pt codes"). Its body cites this review's confirmation on 291ef83d8. The PR body dropped its out-of-scope section accordingly. Nothing is lost, because the finding now has its own card.
  • Body citation. The body cites "contract review PASS at 291ef83d8, comment 6694588461". (Seat note: the dispatching seat posted the round-1 record as that comment; the reviewer wrote it to a file and did not post it.)

④ Design judgment

  • S1 is resolved. The switcher still reads the table, not a hand list, and its controlled value now selects the active language when the instance runs in a stored alias.
  • Budget. The head file is 5643 bytes, and ceil(5643/4) = 1411 (5643 / 4 = 1410.75). The ceiling is 1413 (scripts/check-skills-token-ratchet.mjs:1077, unchanged on the head), so headroom is 2 and there is no ratchet raise. The delta is +60 bytes for the import and binding, and −65 bytes for deletion 5 (63 bytes of text plus the blank line), a net of −5 bytes from 5648. This agrees with the body's "+60 bytes" and its 1411 reading.
  • Check-runs on the head (59, read 2026-11-06T20:37Z): 47 success, 10 skipped, 2 in progress, 0 failed. Still running: Test Core (1/8), and one Check Changeset run (another Check Changeset run on this head is already green). Lint · docs & code guards and the Governed Surface Queue Guard are green. The verdict does not wait on the two runs still in progress.

Findings: must-fix none; should-fix none (round 1's S1 resolved in 450d72405).

Implemented-by: claude/project-thread-rm542x
Reviewed-by: session_01J8VVAj7CvjkGXvgXzd6RZ7

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

维护者速读

席位核对 — ACCEPT · domain:skills#3 · head 450d724054f6adde3df14b2c95da5986329ccc84

  1. 形态: draft → main,Fixes #30911;'@objectstack/skills': patch,Clause-②: no,Metadata-protocol: none;作者 objectstack-fleet[bot];2 个文件,在认领面之内。
  2. 前提实测: 复核逐项对照 main(platform-locales.ts 表序与别名、registry.ts resolveBuiltInLanguage、@object-ui/i18n 的 ./locales/* 导出、createI18n 合并)确认 11 个标签、模块路径、别名读法与切换器绑定全部成立;该技能 i18n eval 无旧键。
  3. 门禁(钉 head 450d7240): dev 派生门禁 45 条全部 exit 0;check-runs 60 条全部完成,50 success、10 skip、0 failure。check-governed-merges --pr 31043:Tier H(skills/**),42 行。
  4. 接受的偏差: 无。旧 head 一次 TypeScript Type Check 红是推新 head 取消了在跑的子任务,新 head 全绿。
  5. 范围外去向: app-shell LocaleSwitcher.tsx 的 BUILT_IN_LABELS 仍按旧 zh / pt 键给菜单命名,已立卡 app-shell LocaleSwitcher still labels built-in languages from a hand list keyed by the retired zh / pt codes #31045。Skills-docs: self。
  6. 落地条款: Tier H。保持 draft,挂 pm:awaiting-merge,请 os-zhuang、hotlong 审批;获批后本席过落地前检、清标、ready、auto-merge;维护者直合亦可。

@objectstack-fleet objectstack-fleet Bot added the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 6, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue size/s tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills/objectui i18n guide still teaches the zh and pt pack keys that #30511 retires

1 participant