From 531867e730008c5bbbfc5a71e05a36ae2fb09ee6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 03:55:34 +0000 Subject: [PATCH 1/3] feat(ui): the translation preview's strings move into the studio i18n namespace The 22 en and 22 zh engine.translationPreview rows, the last family in app-shell's designer table, move into @object-ui/i18n's studio namespace with their text unchanged. ENGINE_STRINGS_EN / ENGINE_STRINGS_ZH stay declared, now empty, for the slice that retires the table. The namespace pin gains a floor for the moved family. Claude-Session: https://claude.ai/code/session_01JQwxbX3S5QrD29Ghii633f Co-authored-by: Claude --- .../25922-studio-i18n-translation-preview.md | 10 ++++ .../src/views/metadata-admin/i18n.ts | 52 ++----------------- ...ectorStrings.studioNamespace-25922.test.ts | 7 ++- ui/packages/i18n/src/namespaces/studio/en.ts | 27 ++++++++++ ui/packages/i18n/src/namespaces/studio/zh.ts | 25 +++++++++ 5 files changed, 71 insertions(+), 50 deletions(-) create mode 100644 .changeset/25922-studio-i18n-translation-preview.md diff --git a/.changeset/25922-studio-i18n-translation-preview.md b/.changeset/25922-studio-i18n-translation-preview.md new file mode 100644 index 00000000000..f0399536c61 --- /dev/null +++ b/.changeset/25922-studio-i18n-translation-preview.md @@ -0,0 +1,10 @@ +--- +'@object-ui/i18n': patch +--- + +feat(i18n): the translation preview's strings move into the `studio` namespace + +Clause-②: no +Metadata-protocol: none + +- **Last rows of the move ruled on objectstack#25922** (6431032267, Q2 = A; kept by 6431234244). The 22 `engine.translationPreview.*` rows in each language, the last family left in `@object-ui/app-shell`'s private designer table, now live in `@object-ui/i18n/namespaces/studio`, text unchanged. The table is now empty; deleting it is a later slice. Studio reads the same strings; a Chinese viewer sees the translation preview's labels in English for the moment the `zh` catalogue takes to load, as with the earlier slices. No export changes. diff --git a/ui/packages/app-shell/src/views/metadata-admin/i18n.ts b/ui/packages/app-shell/src/views/metadata-admin/i18n.ts index 26fc99a55a7..f7a8ace00dc 100644 --- a/ui/packages/app-shell/src/views/metadata-admin/i18n.ts +++ b/ui/packages/app-shell/src/views/metadata-admin/i18n.ts @@ -192,57 +192,13 @@ const DOMAIN_LABELS_ZH: Record = { }; const ENGINE_STRINGS_EN: Record = { - 'engine.translationPreview.empty': - 'This bundle is empty — add at least one translated string to see the coverage report.', - // One heading per group of the per-app `TranslationDataSchema`, in its order (objectui#11765). - 'engine.translationPreview.category.objects': 'Objects', - 'engine.translationPreview.category.picklists': 'Picklists', - 'engine.translationPreview.category.apps': 'Apps', - 'engine.translationPreview.category.messages': 'Messages', - 'engine.translationPreview.category.globalActions': 'Global Actions', - 'engine.translationPreview.category.dashboards': 'Dashboards', - 'engine.translationPreview.category.datasets': 'Datasets', - 'engine.translationPreview.category.reports': 'Reports', - 'engine.translationPreview.category.pages': 'Pages', - 'engine.translationPreview.category.flows': 'Flows', - 'engine.translationPreview.category.hooks': 'Hooks', - 'engine.translationPreview.category.positions': 'Positions', - 'engine.translationPreview.category.permissions': 'Permission Sets', - 'engine.translationPreview.category.books': 'Doc Books', - 'engine.translationPreview.category.metadataForms': 'Metadata Forms', - 'engine.translationPreview.category.settingsCommon': 'Settings UI', - 'engine.translationPreview.coverage': 'Category coverage:', - 'engine.translationPreview.totalKeys': '{count} total keys', - 'engine.translationPreview.categoryEmpty': 'empty', - 'engine.translationPreview.more': '+{count} more…', - 'engine.translationPreview.keyCountOne': '{{count} key}', - 'engine.translationPreview.keyCountOther': '{{count} keys}', + // Empty since #25922 slice S6b: every row lives in `@object-ui/i18n`'s + // `studio` namespace. Kept until slice S7 retires the table. }; const ENGINE_STRINGS_ZH: Record = { - 'engine.translationPreview.empty': '此语言包为空 —— 至少添加一条译文,即可查看覆盖率报告。', - 'engine.translationPreview.category.objects': '对象', - 'engine.translationPreview.category.picklists': '选项列表', - 'engine.translationPreview.category.apps': '应用', - 'engine.translationPreview.category.messages': '消息', - 'engine.translationPreview.category.globalActions': '全局操作', - 'engine.translationPreview.category.dashboards': '仪表盘', - 'engine.translationPreview.category.datasets': '数据集', - 'engine.translationPreview.category.reports': '报表', - 'engine.translationPreview.category.pages': '页面', - 'engine.translationPreview.category.flows': '流程', - 'engine.translationPreview.category.hooks': '钩子', - 'engine.translationPreview.category.positions': '岗位', - 'engine.translationPreview.category.permissions': '权限集', - 'engine.translationPreview.category.books': '文档书', - 'engine.translationPreview.category.metadataForms': '元数据表单', - 'engine.translationPreview.category.settingsCommon': '设置界面', - 'engine.translationPreview.coverage': '分类覆盖率:', - 'engine.translationPreview.totalKeys': '共 {count} 个键', - 'engine.translationPreview.categoryEmpty': '空', - 'engine.translationPreview.more': '另有 {count} 项…', - 'engine.translationPreview.keyCountOne': '{{count} 个键}', - 'engine.translationPreview.keyCountOther': '{{count} 个键}', + // Empty since #25922 slice S6b: every row lives in `@object-ui/i18n`'s + // `studio` namespace. Kept until slice S7 retires the table. }; /** Whether a locale resolves to Chinese (the only non-English catalog). */ diff --git a/ui/packages/app-shell/src/views/metadata-admin/inspectors/inspectorStrings.studioNamespace-25922.test.ts b/ui/packages/app-shell/src/views/metadata-admin/inspectors/inspectorStrings.studioNamespace-25922.test.ts index 336911e14e5..b8dc6c58bfa 100644 --- a/ui/packages/app-shell/src/views/metadata-admin/inspectors/inspectorStrings.studioNamespace-25922.test.ts +++ b/ui/packages/app-shell/src/views/metadata-admin/inspectors/inspectorStrings.studioNamespace-25922.test.ts @@ -1,11 +1,12 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * objectstack#25922 slices S2 to S6 — the designer rows that moved into + * objectstack#25922 slices S2 to S6b — the designer rows that moved into * `@object-ui/i18n`'s `studio` namespace (every `engine.inspector.*` row; * `engine.packages.*`, `engine.form.*`, `engine.edit.*`; all of * `engine.studio.*`; the data source pages, the field types, the metadata - * preview panes, the flow designer and the rest of the Studio chrome), and + * preview panes, the flow designer, the rest of the Studio chrome and, last, + * the translation preview), and * app-shell's `t()` / `tOptional()` still answer every one of them the way they * did when the rows sat in its own table. * @@ -124,6 +125,8 @@ const FAMILY_FLOOR: Readonly> = Object.freeze({ 'engine.home.': 1, 'engine.cancel': 1, 'engine.close': 1, + // S6b — the translation preview, the table's last family + 'engine.translationPreview.': 20, }); /** diff --git a/ui/packages/i18n/src/namespaces/studio/en.ts b/ui/packages/i18n/src/namespaces/studio/en.ts index 500d0330063..7346f4f2631 100644 --- a/ui/packages/i18n/src/namespaces/studio/en.ts +++ b/ui/packages/i18n/src/namespaces/studio/en.ts @@ -3944,6 +3944,33 @@ const STUDIO_EN: Record = { 'engine.appNav.item': 'Item {n}', 'engine.appNav.itemOne': 'item', 'engine.appNav.itemOther': 'items', + // The translation preview, the designer table's last family: held out of S6 + // while a sibling change added its category.hooks row (#25922 slice S6b). + 'engine.translationPreview.empty': + 'This bundle is empty — add at least one translated string to see the coverage report.', + // One heading per group of the per-app `TranslationDataSchema`, in its order (objectui#11765). + 'engine.translationPreview.category.objects': 'Objects', + 'engine.translationPreview.category.picklists': 'Picklists', + 'engine.translationPreview.category.apps': 'Apps', + 'engine.translationPreview.category.messages': 'Messages', + 'engine.translationPreview.category.globalActions': 'Global Actions', + 'engine.translationPreview.category.dashboards': 'Dashboards', + 'engine.translationPreview.category.datasets': 'Datasets', + 'engine.translationPreview.category.reports': 'Reports', + 'engine.translationPreview.category.pages': 'Pages', + 'engine.translationPreview.category.flows': 'Flows', + 'engine.translationPreview.category.hooks': 'Hooks', + 'engine.translationPreview.category.positions': 'Positions', + 'engine.translationPreview.category.permissions': 'Permission Sets', + 'engine.translationPreview.category.books': 'Doc Books', + 'engine.translationPreview.category.metadataForms': 'Metadata Forms', + 'engine.translationPreview.category.settingsCommon': 'Settings UI', + 'engine.translationPreview.coverage': 'Category coverage:', + 'engine.translationPreview.totalKeys': '{count} total keys', + 'engine.translationPreview.categoryEmpty': 'empty', + 'engine.translationPreview.more': '+{count} more…', + 'engine.translationPreview.keyCountOne': '{{count} key}', + 'engine.translationPreview.keyCountOther': '{{count} keys}', }; export default STUDIO_EN; diff --git a/ui/packages/i18n/src/namespaces/studio/zh.ts b/ui/packages/i18n/src/namespaces/studio/zh.ts index 334c2ec7b9f..ce74e0bf477 100644 --- a/ui/packages/i18n/src/namespaces/studio/zh.ts +++ b/ui/packages/i18n/src/namespaces/studio/zh.ts @@ -3557,6 +3557,31 @@ const STUDIO_ZH: Record = { 'engine.appNav.item': '导航项 {n}', 'engine.appNav.itemOne': '项', 'engine.appNav.itemOther': '项', + // The translation preview, the designer table's last family: held out of S6 + // while a sibling change added its category.hooks row (#25922 slice S6b). + 'engine.translationPreview.empty': '此语言包为空 —— 至少添加一条译文,即可查看覆盖率报告。', + 'engine.translationPreview.category.objects': '对象', + 'engine.translationPreview.category.picklists': '选项列表', + 'engine.translationPreview.category.apps': '应用', + 'engine.translationPreview.category.messages': '消息', + 'engine.translationPreview.category.globalActions': '全局操作', + 'engine.translationPreview.category.dashboards': '仪表盘', + 'engine.translationPreview.category.datasets': '数据集', + 'engine.translationPreview.category.reports': '报表', + 'engine.translationPreview.category.pages': '页面', + 'engine.translationPreview.category.flows': '流程', + 'engine.translationPreview.category.hooks': '钩子', + 'engine.translationPreview.category.positions': '岗位', + 'engine.translationPreview.category.permissions': '权限集', + 'engine.translationPreview.category.books': '文档书', + 'engine.translationPreview.category.metadataForms': '元数据表单', + 'engine.translationPreview.category.settingsCommon': '设置界面', + 'engine.translationPreview.coverage': '分类覆盖率:', + 'engine.translationPreview.totalKeys': '共 {count} 个键', + 'engine.translationPreview.categoryEmpty': '空', + 'engine.translationPreview.more': '另有 {count} 项…', + 'engine.translationPreview.keyCountOne': '{{count} 个键}', + 'engine.translationPreview.keyCountOther': '{{count} 个键}', }; export default STUDIO_ZH; From 13e080330bc7792030614ff20a973f6d8c0b04e4 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 04:00:22 +0000 Subject: [PATCH 2/3] test(ui): block-config-i18n pins the emptied designer table The designer table's floor was "non-empty"; with its last rows moved into the studio namespace it now asserts both tables are empty, so a key moved back would shadow the namespace. The 3,000-key floor over both homes keeps the parser's non-vacuity. Claude-Session: https://claude.ai/code/session_01JQwxbX3S5QrD29Ghii633f Co-authored-by: Claude --- .../previews/__tests__/block-config-i18n.test.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ui/packages/app-shell/src/views/metadata-admin/previews/__tests__/block-config-i18n.test.ts b/ui/packages/app-shell/src/views/metadata-admin/previews/__tests__/block-config-i18n.test.ts index b1bacc77e36..20ede01bd80 100644 --- a/ui/packages/app-shell/src/views/metadata-admin/previews/__tests__/block-config-i18n.test.ts +++ b/ui/packages/app-shell/src/views/metadata-admin/previews/__tests__/block-config-i18n.test.ts @@ -673,17 +673,18 @@ function pageBlockKeys(table: EngineStringTable): string[] { } describe('a retired key leaves BOTH locale tables (objectui#8368)', () => { - it('reads two disjoint, non-empty tables out of i18n.ts', () => { + it('reads two disjoint tables out of i18n.ts, both emptied into the namespace', () => { // The extractor is a source parser, so its silent failure mode is finding // FEWER keys — which would make every assertion below vacuously green over // an empty corpus. Ranges first: overlapping ones would mean the `};` // scan ran past a table and both sets became the same set. - // The table drains slice by slice into the namespace (objectstack#25922), - // so its floor is "non-empty"; the 3,000-key floor is held over both homes - // together, below. + // The table drained slice by slice into the namespace (objectstack#25922) + // and is empty since slice S6b: a key back in it would shadow the + // namespace's copy. The 3,000-key floor, held over both homes together + // below, is what keeps an empty table from reading as a parser gone quiet. expect(EN_TABLE.to).toBeLessThan(ZH_TABLE.from); - expect(EN_TABLE.keys.length).toBeGreaterThan(0); - expect(ZH_TABLE.keys.length).toBeGreaterThan(0); + expect(EN_TABLE.keys).toEqual([]); + expect(ZH_TABLE.keys).toEqual([]); // No duplicates: a key declared twice would be a silent overwrite, and the // set arithmetic below would hide it. expect(EN_TABLE.keys.length).toBe(new Set(EN_TABLE.keys).size); From d53a76b18d0dec439e5d69b7ab0f8d76bb890dae Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 04:42:01 +0000 Subject: [PATCH 3/3] docs(changeset): the translation preview changeset counts 23 rows per language Claude-Session: https://claude.ai/code/session_01JQwxbX3S5QrD29Ghii633f Co-authored-by: Claude --- .changeset/25922-studio-i18n-translation-preview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/25922-studio-i18n-translation-preview.md b/.changeset/25922-studio-i18n-translation-preview.md index f0399536c61..e6511884fcf 100644 --- a/.changeset/25922-studio-i18n-translation-preview.md +++ b/.changeset/25922-studio-i18n-translation-preview.md @@ -7,4 +7,4 @@ feat(i18n): the translation preview's strings move into the `studio` namespace Clause-②: no Metadata-protocol: none -- **Last rows of the move ruled on objectstack#25922** (6431032267, Q2 = A; kept by 6431234244). The 22 `engine.translationPreview.*` rows in each language, the last family left in `@object-ui/app-shell`'s private designer table, now live in `@object-ui/i18n/namespaces/studio`, text unchanged. The table is now empty; deleting it is a later slice. Studio reads the same strings; a Chinese viewer sees the translation preview's labels in English for the moment the `zh` catalogue takes to load, as with the earlier slices. No export changes. +- **Last rows of the move ruled on objectstack#25922** (6431032267, Q2 = A; kept by 6431234244). The 23 `engine.translationPreview.*` rows in each language, the last family left in `@object-ui/app-shell`'s private designer table, now live in `@object-ui/i18n/namespaces/studio`, text unchanged. The table is now empty; deleting it is a later slice. Studio reads the same strings; a Chinese viewer sees the translation preview's labels in English for the moment the `zh` catalogue takes to load, as with the earlier slices. No export changes.