Skip to content

Commit 226c988

Browse files
docs(skills): objectui i18n guide keys the built-in packs by platform locale tag (zh-Hans, zh-Hant, pt-BR) (#31043)
<!-- claude-projects-attribution: {"github_login":"huangyiirene"} --> _Requested by **Irene** · [project thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67xE9wgHWTh9Jrvm1WVhqbLKh)_ 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 #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. <details><summary>Ran list</summary> ``` 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 ``` </details> 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01J8VVAjteesTptAwhHn3GuE <!-- signed: domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7 --> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent cef3b8f commit 226c988

2 files changed

Lines changed: 21 additions & 21 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the objectui i18n guide teaches the platform locale table's tags (`zh-Hans`, `zh-Hant`, `pt-BR`) for the built-in packs, a language switcher fed by `PLATFORM_LOCALES`, and the read aliases that keep a stored `zh` / `zh-CN` / `zh-TW` / `pt` resolving
6+
7+
Clause-②: no
8+
Metadata-protocol: none

‎skills/objectui/guides/i18n.md‎

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# ObjectUI Internationalization (i18n)
22

3-
Multi-language support via `@object-ui/i18n`.
4-
53
## Setup
64

75
```typescript
@@ -10,10 +8,10 @@ import { I18nProvider, createI18n } from '@object-ui/i18n';
108
const i18n = createI18n({
119
defaultLanguage: 'en',
1210
fallbackLanguage: 'en',
13-
detectBrowserLanguage: true, // Auto-detect from navigator
11+
detectBrowserLanguage: true,
1412
resources: {
1513
en: { common: { save: 'Save', cancel: 'Cancel' } },
16-
zh: { common: { save: '保存', cancel: '取消' } },
14+
'zh-Hans': { common: { save: '保存', cancel: '取消' } },
1715
},
1816
});
1917

@@ -28,27 +26,29 @@ function App() {
2826

2927
## Built-in locales
3028

31-
The package includes translations for:
32-
- English (`en`), Chinese (`zh`), Japanese (`ja`), Korean (`ko`)
33-
- German (`de`), French (`fr`), Spanish (`es`), Portuguese (`pt`)
34-
- Russian (`ru`), Arabic (`ar`)
29+
One pack per row of the platform locale table (`PLATFORM_LOCALES`, `@objectstack/spec/system`),
30+
keyed by tag: `en`, `zh-Hans`, `zh-Hant`, `es`, `ar`, `fr`, `pt-BR`, `ru`, `de`, `ja`, `ko`
31+
(`@object-ui/i18n/locales/<tag>`). No `zh` or `pt` pack: a stored `zh` / `zh-CN` resolves
32+
to `zh-Hans`, `zh-TW` to `zh-Hant` and `pt` to `pt-BR` via the table's read aliases
33+
(`resolveBuiltInLanguage`). Write the tag.
3534

3635
## useObjectTranslation hook
3736

3837
<!-- os:check -->
3938
```typescript
40-
import { useObjectTranslation } from '@object-ui/i18n';
39+
import { resolveBuiltInLanguage, useObjectTranslation } from '@object-ui/i18n';
40+
import { PLATFORM_LOCALES } from '@objectstack/spec/system';
4141

4242
function Header() {
4343
const { t, language, changeLanguage, direction } = useObjectTranslation();
4444

4545
return (
4646
<header dir={direction}>
4747
<h1>{t('common.appTitle')}</h1>
48-
<select value={language} onChange={(e) => changeLanguage(e.target.value)}>
49-
<option value="en">English</option>
50-
<option value="zh">中文</option>
51-
<option value="ar">العربية</option>
48+
<select value={resolveBuiltInLanguage(language) ?? language} onChange={(e) => changeLanguage(e.target.value)}>
49+
{PLATFORM_LOCALES.map(({ tag, label }) => (
50+
<option key={tag} value={tag}>{label}</option>
51+
))}
5252
</select>
5353
</header>
5454
);
@@ -75,11 +75,6 @@ For large apps, load translations on demand instead of bundling all locales:
7575

7676
RTL is automatic for Arabic, Hebrew, and other RTL languages. The provider updates `document.dir` when the language changes.
7777

78-
```typescript
79-
const { direction } = useObjectTranslation();
80-
// direction: 'ltr' | 'rtl'
81-
```
82-
8378
For Tailwind layout adjustments, use RTL-aware utilities:
8479

8580
```html
@@ -153,8 +148,6 @@ that travels without a bundle carries its own languages.
153148

154149
## Language-aware + responsive page
155150

156-
When combining with `@object-ui/mobile` for responsive layouts:
157-
158151
```typescript
159152
import { I18nProvider } from '@object-ui/i18n';
160153
import { useBreakpoint } from '@object-ui/mobile';
@@ -176,7 +169,6 @@ function App() {
176169

177170
## Common mistakes
178171

179-
- Bundling all locale files upfront — use lazy loading for apps with many languages.
180172
- Forgetting `dir={direction}` on root elements — RTL layout won't apply.
181173
- Using `{key, defaultValue}` translation objects — that key-reference vocabulary was retired.
182174
`@objectstack/spec` rejects the object with its own message: *an inline

0 commit comments

Comments
 (0)