Skip to content

Commit e8dba8a

Browse files
os-samclaude
andauthored
fix(example-showcase): translate the app sidebar so a zh-CN session stops mixing locales (#9260) (#9597)
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. Claude-Session: https://claude.ai/code/session_017qYPmkKEsfbWY1yVg83p8F Co-authored-by: Claude <noreply@anthropic.com>
1 parent ba0a846 commit e8dba8a

2 files changed

Lines changed: 137 additions & 2 deletions

File tree

examples/app-showcase/src/system/translations/index.ts

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

33
/**
4-
* English + Simplified Chinese labels for the core showcase objects.
4+
* English + Simplified Chinese labels for the core showcase objects — and for
5+
* the app shell those objects are read in.
56
*
67
* Covers EVERY field surfaced as a column on the showcase pages so a list never
78
* mixes locales (the prior bundle translated only a handful, leaving columns
89
* like Project / Assignee / Progress falling back to their English field label
910
* next to translated 状态 / 优先级 — an obvious inconsistency on a zh-CN session).
11+
*
12+
* The `apps.showcase_app` block carries the sidebar — navigation items and
13+
* group headers — for that same reason one level up: the columns were
14+
* translated under an English menu, and the sentence above, scoped to columns,
15+
* is exactly why nothing caught it. This is a description of what this file
16+
* CONTAINS, not a wider guarantee: it does not claim every declared surface of
17+
* the showcase is translated. `scripts/i18n-coverage-baseline.json` is the
18+
* measure of what still is not.
1019
*/
1120
export const ShowcaseTranslationBundle = {
1221
en: {
@@ -650,6 +659,132 @@ export const ShowcaseTranslationBundle = {
650659
},
651660
},
652661
},
662+
// ── The app shell: sidebar navigation ────────────────────────────────
663+
// A THIRD key space, addressed by the navigation node's stable `id`
664+
// regardless of tree depth: `apps.<app>.navigation.<id>.label`, applied by
665+
// `translateApp` (`@objectstack/spec/system/i18n-resolver`) at the `/meta`
666+
// boundary in `@objectstack/rest`. Nothing under `objects.*` answers for
667+
// it — a nav entry whose label was authored ('Projects', not the bare
668+
// `showcase_project`) keeps that authored label, so the object's translated
669+
// `pluralLabel` never reaches the sidebar. Which is why a zh-CN session
670+
// showed translated view tabs, columns, field labels and option values
671+
// under an English sidebar: the bundle carried no app keys at all.
672+
//
673+
// Every labelled node of `ui/apps/index.ts` is here — 49 items and the 8
674+
// `grp_*` group headers, the exact set `os lint` reports for this app.
675+
// `nav_sep_reports` is a separator: it declares no label, so there is
676+
// nothing to translate and no key for it.
677+
//
678+
// Wording reuses the vocabulary this bundle already established rather than
679+
// minting a second word per idea: 项目 / 任务 / 客户 / 联系人 / 发票 / 设置
680+
// from the object blocks, 任务清单 · 工时按状态分布 · 活动时间线 ·
681+
// 工作地点地图 · 看板 · 日历 from `showcase_task._views`, 排期 from its
682+
// `_sections`, 分流 from `showcase_inquiry._views.triage`, 业务单元 from
683+
// the platform bundle's `sys_business_unit`.
684+
apps: {
685+
showcase_app: {
686+
// The app's own name, rendered at the top of the same sidebar
687+
// (`apps.<name>.label`, objectui's `useObjectLabel().appLabel`). Left
688+
// untranslated it reproduces the mixed shell one line above the tree
689+
// this block fixes. Setup and Account translate theirs; Studio keeps
690+
// its product name. This app is named for what it does, not branded,
691+
// so it translates.
692+
label: '功能展示',
693+
navigation: {
694+
// Landing + the page-authoring teaching index — the two ungrouped
695+
// entries above every group.
696+
nav_capability_map: { label: '能力地图' },
697+
nav_start_here: { label: '页面搭建' },
698+
699+
// Workspace — the app working like a real product.
700+
grp_workspace: { label: '工作区' },
701+
nav_my_work: { label: '我的工作' },
702+
// 审批 matches the platform bundle's `group_approvals`; the page is
703+
// the reviewer's queue, not the request list.
704+
nav_review_queue: { label: '审批' },
705+
nav_new_project_wizard: { label: '新建项目(向导)' },
706+
// The object's own `pluralLabel` above (showcase_preference).
707+
nav_settings: { label: '设置' },
708+
709+
// Data Model — one entry per object list. Each reads the word this
710+
// bundle already gives that object.
711+
grp_data: { label: '数据模型' },
712+
nav_projects: { label: '项目' },
713+
nav_tasks: { label: '任务' },
714+
nav_accounts: { label: '客户' },
715+
nav_contacts: { label: '联系人' },
716+
nav_invoices: { label: '发票' },
717+
// `showcase_expense_report` has no translated object label (it sits
718+
// inside check-i18n-coverage's frozen baseline), so this renders the
719+
// nav label directly; 报销单 is the standard word for the document.
720+
nav_expense_reports: { label: '报销单' },
721+
nav_products: { label: '产品' },
722+
nav_teams: { label: '团队' },
723+
nav_categories: { label: '分类' },
724+
nav_business_units: { label: '业务单元' },
725+
nav_field_zoo: { label: '字段动物园' },
726+
nav_cascade: { label: '级联选择' },
727+
728+
// Data slices — the same object under a pre-applied filter. Each
729+
// reads the option label of the value it filters on, so the entry
730+
// says the same word as the cells it lists (进行中 / 紧急 / 评审中,
731+
// from `showcase_task.fields.status|priority.options`).
732+
grp_slices: { label: '数据切片(筛选)' },
733+
nav_slice_in_progress: { label: '进行中的任务' },
734+
nav_slice_urgent: { label: '紧急任务' },
735+
nav_slice_review: { label: '评审中的任务' },
736+
737+
// Analytics.
738+
grp_analytics: { label: '数据分析' },
739+
nav_command_center: { label: '指挥中心(大屏)' },
740+
nav_ops: { label: '交付运营' },
741+
nav_revenue_pulse: { label: '营收概览(带筛选)' },
742+
nav_charts: { label: '图表画廊' },
743+
// View-scoped and report entries whose surface this bundle already
744+
// names: 任务清单 is `showcase_task._views.tabular`, 工时按状态分布
745+
// is `_views.chart` — the same list under the same word.
746+
nav_report_tabular: { label: '任务清单' },
747+
nav_report_summary: { label: '工时按状态分布' },
748+
nav_report_chart: { label: '工时按状态分布(图表)' },
749+
nav_report_matrix: { label: '状态 × 优先级' },
750+
nav_report_joined: { label: '任务总览' },
751+
752+
// The page-authoring gallery, split by authoring KIND. All four
753+
// headers share one word with `nav_start_here` above, exactly as the
754+
// English shares "Authoring" with "Page Authoring".
755+
grp_auth_structured: { label: '页面搭建 · 结构化' },
756+
nav_gallery: { label: '组件画廊' },
757+
nav_styling_gallery: { label: '样式(ADR-0065)' },
758+
nav_page_variables: { label: '页面变量' },
759+
nav_contact_form: { label: '联系表单' },
760+
nav_project_workspace: { label: '新建项目 + 任务' },
761+
nav_task_workbench: { label: '任务工作台' },
762+
nav_task_triage: { label: '任务分流(标签页)' },
763+
// The page's base filter hides completed projects rather than
764+
// matching `status = active`, so this says 进行中 rather than 活跃.
765+
nav_active_projects: { label: '进行中的项目' },
766+
767+
grp_auth_viz: { label: '页面搭建 · 可视化' },
768+
nav_task_all_views: { label: '全部视图' },
769+
nav_task_board: { label: '任务看板' },
770+
nav_task_calendar: { label: '任务日历' },
771+
// 画廊 is objectui's own word for the gallery view type, shared here
772+
// with 组件画廊 / 图表画廊 above.
773+
nav_task_gallery: { label: '任务画廊' },
774+
nav_task_schedule: { label: '团队排期' },
775+
nav_task_timeline: { label: '活动时间线' },
776+
nav_task_map: { label: '工作地点地图' },
777+
778+
grp_auth_html: { label: '页面搭建 · HTML' },
779+
nav_command_center_jsx: { label: '指挥中心' },
780+
781+
grp_auth_react: { label: '页面搭建 · React' },
782+
nav_crm_workbench: { label: 'CRM 工作台 · 主从视图' },
783+
nav_task_desk: { label: '任务处理台 · 抽屉与弹窗' },
784+
nav_renewals_pipeline: { label: '续约管道 · 汇总与区块' },
785+
},
786+
},
787+
},
653788
// See the `en` block: object-less actions resolve ONLY through
654789
// `globalActions`. Translated at birth for the same reason as
655790
// `showcase_action_param_gallery.params.p_assignee` above — this example is

scripts/i18n-coverage-baseline.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"examples/app-crm/objectstack.config.ts": 89,
3-
"examples/app-showcase/objectstack.config.ts": 451,
3+
"examples/app-showcase/objectstack.config.ts": 393,
44
"examples/app-todo/objectstack.config.ts": 120,
55
"packages/platform-objects/scripts/i18n-extract.config.ts": 0,
66
"packages/plugins/plugin-approvals/scripts/i18n-extract.config.ts": 0,

0 commit comments

Comments
 (0)