Uh oh!
There was an error while loading. Please reload this page.
fix(example-showcase): translate the app sidebar so a zh-CN session stops mixing locales - #9597
Merged
Merged
Conversation
…tops mixing locales (#9260) The showcase bundle carried no `apps.*` keys at all, so a zh-CN session rendered translated view tabs, columns, field labels and option values under an English sidebar. Nav labels are their own key space — `apps.<app>.navigation.<id>.label`, applied by `translateApp` at the `/meta` boundary — and nothing under `objects.*` answers for them: a nav entry whose label was authored keeps that authored label, so the object's translated `pluralLabel` never reaches the menu. Adds the zh-CN `apps.showcase_app` block: 49 navigation items, 8 group headers, and the app's own label. That is the exact set `os lint` reported missing (57 `i18n/missing-navigation` + 1 `i18n/missing-app`, zh-CN only — `en` is satisfied by the inline source labels). `nav_sep_reports` is a separator with no label, so it has no key. The example's frozen untranslated count drops 451 -> 393, which `check:i18n-coverage` requires be ratcheted DOWN in the same change. Wording reuses the vocabulary the bundle already established rather than minting a second word per idea. The header comment gains one sentence: it described a columns-only remit, which is exactly why the sidebar gap went unnoticed — the new sentence states what the file now contains without widening it into a guarantee about every declared surface. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017qYPmkKEsfbWY1yVg83p8F
os-sam
marked this pull request as ready for review
August 18, 2026 13:03
Contributor
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32140254326 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
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 freeto 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#9260
On a zh-CN session the showcase app rendered a mixed-locale shell: view tabs, list columns, field labels and option values in Chinese, the left sidebar in English throughout. The bundle carried no
apps.*keys at all, so the sidebar had nothing to fall back on but its English source labels.Why
objects.*could not cover thisNavigation labels are their own key space —
apps.APP_NAME.navigation.NAV_ID.label, addressed by the node's stableidregardless of tree depth. It is applied bytranslateApp(packages/spec/src/system/i18n-resolver.ts) at the/metaboundary in@objectstack/rest, and nothing underobjects.*answers for it: a nav entry whose label was authored (Projects, not the bareshowcase_project) keeps that authored label, so the object's translatedpluralLabelnever reaches the menu. That is why 12 object entries were already translated and all 12 still read English in the sidebar.What changed
examples/app-showcase/src/system/translations/index.tsgains a zh-CNapps.showcase_appblock:grp_*)apps.showcase_app.label)nav_sep_reportsThe counts are measured, not eyeballed:
os lint --jsonon the showcase config reported exactly 57i18n/missing-navigationplus 1i18n/missing-app, zh-CN only. The translated id set was diffed against that reported set — no missing ids, no extra ids.enneeds no entries: the default locale is satisfied by the inline source label (i18n-coverage.ts), and restating it would be the fake translation this bundle's header already warns about.The app's own label is included beyond the card's literal enumeration: it renders at the top of the same sidebar (
useObjectLabel().appLabel), so leaving it English reproduces the mixed shell one line above the tree being fixed. Setup and Account translate theirs, Studio keeps its product name; this app is named for what it does, so it translates.Wording reuses the vocabulary this bundle already established rather than minting a second word per idea — the object words for the object entries,
任务清单/工时按状态分布/活动时间线/工作地点地图fromshowcase_task._viewsfor the entries that open exactly those surfaces,分流fromshowcase_inquiry._views.triage,排期fromshowcase_task._sections,业务单元from the platform bundle. Each non-obvious choice carries its reason inline.The ratchet
scripts/i18n-coverage-baseline.json:examples/app-showcase451 to 393 (exactly the 58 keys above).check:i18n-coveragerejects an un-ratcheted improvement as well as a regression, and its own remedy is--update; the baseline moves down only, and no other config's entry moved.The header sentence
The bundle's header declared a columns-only remit ("EVERY field surfaced as a column", "a list never mixes locales") — which is precisely why nothing caught this: the invariant was scoped narrower than the surface it reads as covering. One sentence is added describing what the file now contains, deliberately not widened into a guarantee that every declared surface of the showcase is translated (it is not — the frozen baseline still counts 393), and pointing at that baseline as the measure of what remains.
Verification
Run after the final commit, on the pushed tree (
883f9a938):node packages/cli/bin/run.js lint examples/app-showcase/objectstack.config.ts --json—i18n/issues 451 to 393;i18n/missing-navigation57 to 0,i18n/missing-app1 to 0, zero remaining keys undertranslations.zh-CN.apps.node scripts/check-i18n-coverage.mjs— before the baseline update it went red on exactly this change ("untranslated declared strings improved 451 to 393 — ratchet DOWN"); after--update:OK (12 config(s), 602 baselined untranslated string(s), none new)pnpm --filter @objectstack/example-showcase --filter @objectstack/lint test— 21 files / 334 tests and 74 files / 2088 tests, all passing (packages/lintimports this bundle invalidate-translatable-sections.test.ts)pnpm --filter @objectstack/example-showcase typecheck— cleanpnpm check:cross-package-test-inputs— OK (12 packages read outside themselves, all declared)pnpm check:i18n— OK (9 packages, all bundles in sync). It does not cover this file: its population ispackages/**directories owning ascripts/i18n-extract.config.ts, and no example has one. Run rather than assumed.pnpm check:app-nav-i18n— OK (10 contributors, 53 mergedsetupnav ids, 4 locales). Also untouched by this diff, and run for the same reason: it computes its own population, so no path derivation can clear it.node scripts/check-nul-bytes.mjs— OK (6160 files)Gate union re-derived with
node scripts/pm/dispatch-gates.mjs(no path arguments) against the committed diff:check:cross-package-test-inputsandcheck:i18n-coverage, both green above. Theexamples/**path pulls incheck:cross-package-test-inputs— apackages/**card would not see it — becausepackages/lintdeclares this example file as a cross-package test input.No changeset: nothing published changes (
@objectstack/example-showcaseisprivate: true; the other file is repo tooling). Using this repo's real mechanism for that — theskip-changesetlabel.Generated by Claude Code