Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/25922-studio-i18n-translation-preview.md
Original file line number Diff line number Diff line change
@@ -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 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.
52 changes: 4 additions & 48 deletions ui/packages/app-shell/src/views/metadata-admin/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,57 +192,13 @@ const DOMAIN_LABELS_ZH: Record<string, string> = {
};

const ENGINE_STRINGS_EN: Record<string, string> = {
'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<string, string> = {
'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). */
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*
Expand Down Expand Up @@ -124,6 +125,8 @@ const FAMILY_FLOOR: Readonly<Record<string, number>> = Object.freeze({
'engine.home.': 1,
'engine.cancel': 1,
'engine.close': 1,
// S6b — the translation preview, the table's last family
'engine.translationPreview.': 20,
});

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
27 changes: 27 additions & 0 deletions ui/packages/i18n/src/namespaces/studio/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3944,6 +3944,33 @@ const STUDIO_EN: Record<string, string> = {
'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;
25 changes: 25 additions & 0 deletions ui/packages/i18n/src/namespaces/studio/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3557,6 +3557,31 @@ const STUDIO_ZH: Record<string, string> = {
'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;
Loading