Skip to content

Commit 7945a3b

Browse files
fix(app-shell): the publish sheet names a batch of hooks or translations in words, not the raw type code (#29902) (#30361)
<!-- claude-projects-attribution: {"github_login":"os-bill"} --> _Requested by **Bill** · [project thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wg4yKv6mvrKDXRuYdcBwp9hK)_ domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG Fixes #29902 Clause-②: yes (widening) — two new count families in the public `@object-ui/i18n` packs: `preview.changes.typeCount.hook`, `preview.changes.typeCount.translation`. Metadata-protocol: none ## 维护者速读 - 改了什么:Studio 发布面板(待发布变更)的汇总行和分组标题,现在把一批钩子、翻译显示成「3 hooks」「钩子 3」「翻译 2」,不再是原始类型码「3 hook」「hook 3」。 - 为什么改:钩子在对象的 Hooks 标签页、翻译在「全部元数据」表单编辑器里由 Studio 自己创作,作者每次发布都看到未翻译、未变复数的类型码,中文界面里还夹着英文。 - 风险与回滚:只加两行计数文案和 10 个语言包的新键,其他类型和未知类型的显示不变;回滚即 revert 本 PR。 - 先看:`ui/packages/app-shell/src/preview/DraftChangesPanel.tsx`(`TYPE_COUNT` 末尾两行)、`ui/packages/i18n/src/locales/zh.ts`(`typeCount.hook` / `typeCount.translation`)。 - 两分钟验证:`cd ui && pnpm exec vitest run packages/app-shell/src/preview/__tests__/DraftChangesPanel.groupHeading-13221.test.tsx`,预期全绿,其中含「3 hooks」「钩子 3」「翻译 2」三条新断言。 - 需要你做的:无,席位落地。 ## What changes - `TYPE_COUNT` in `DraftChangesPanel.tsx` gains a `hook` and a `translation` row, so the summary line and the per-type group heading read the pack's count family instead of the raw `{{n}} {{type}}` fallback. The fallback stays for types with no row (objectui#13147 note above the table). - Every one of the ten packs under `ui/packages/i18n/src/locales/` gains both families, with each CLDR slot its language selects (`es`/`fr`/`pt` `_many`, `ru` `_few`/`_many`, `ar` `_zero`/`_two`/`_few`/`_many`), mirroring the `dataset` rows. zh-CN reads 「钩子 N」 (the platform nav's own word for hooks, `nav_hooks`) and 「翻译 N」. - One changeset: `@object-ui/app-shell` and `@object-ui/i18n`, patch. ### Which types get a row: the enumeration The publish door batches every draft the package holds, whatever its type (`publishPackageDrafts` in `packages/metadata-protocol/src/protocol.ts` reads `repo.listDrafts({ packageId })`, no type filter). A draft can exist only for a type the registry lets a runtime create or overlay: `allowRuntimeCreate` or `supportsOverlay` true in `DEFAULT_METADATA_TYPE_REGISTRY` (`packages/spec/src/kernel/metadata-plugin.zod.ts`). Those types, and who in Studio authors them: | Type | Studio authors it? | Row before | |---|---|---| | object, view, page, dashboard, report, app, flow, permission, action, email_template, object_extension, dataset | yes (pillars, object panels, nav, bundle editor) | yes | | **hook** | yes: `studio-design/ObjectHooksPanel.tsx` saves `hook` drafts | **no, added** | | **translation** | yes: `studio-design/StudioBundleItemEditor.tsx`, listed in `AREA_FORM_EDITOR_TYPES` (`metadataArea.ts`) | **no, added** | | seed, mapping, external_catalog, doc, book, position, tool, skill | no Studio editor of its own (only the generic metadata pages) | no, unchanged (raw fallback) | `picklist`, named on the card, has both flags false: no draft of it can exist, so the publish door never batches one and no row is added. (`agent` keeps its existing row.) ## Acceptance notes - File surface deviation, agreed with the seat before the edit: the claim named the en and zh-CN packs; all ten packs are touched because `ui/packages/i18n/src/__tests__/all-locales-key-parity.test.ts` requires every pack to define every `en` key (and the per-language plural slots). The `dataset` row set the same precedent. ## Verification Head `cf373b6e` (after merging `origin/main` once; the merge touched none of the changed files). <details><summary>Targeted tests (6 files, 79 tests)</summary> `cd ui && pnpm exec vitest run` on `DraftChangesPanel.summaryPlural-13147.test.tsx`, `DraftChangesPanel.groupHeading-13221.test.tsx`, and the i18n `all-locales-key-parity`, `en-zh-key-parity`, `count-families-11445`, `plural-categories-11432` tests: `Test Files 6 passed (6)`, `Tests 79 passed (79)`. </details> <details><summary>Ablation (one, on the tested behaviour)</summary> `node scripts/ablation-replace.mjs` deleted the `hook:` row (anchor 1 → 0, blob 4b7c507 → 9cc8f165): `Tests 3 failed | 11 passed (14)`, the three hook assertions red. Restored: blob back to 4b7c507, `git diff HEAD` empty. </details> <details><summary>Type-check</summary> `pnpm exec turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n --concurrency=2` under the verify lock: `Tasks: 69 successful, 69 total` (app-shell runs `tsc --noEmit` and `tsc -p tsconfig.test.json`). </details> <details><summary>Derived gates (35)</summary> `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 35 families; all 35 ran and exited 0, including `node scripts/check-sdui-manifest.mjs`, `pnpm check:type-check-debt` and `pnpm --dir ui exec vitest run scripts/` (170 files passed). `--ran` reconciliation: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. Repo-wide families are CI's. </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01Utp6CZ2YeJynYaMx8rfBzM)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent dc138a5 commit 7945a3b

14 files changed

Lines changed: 144 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
fix(app-shell): the Studio publish sheet names a batch of hooks or translations in words ("3 hooks", zh 「钩子 3」) instead of the raw type code ("3 hook") (#29902)
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: none
10+
11+
- **`@object-ui/i18n`**: two new count families in every pack, `preview.changes.typeCount.hook` and `preview.changes.typeCount.translation`, with each CLDR slot the pack's language selects.
12+
- **`@object-ui/app-shell`**: the Pending changes / publish sheet's summary line and group headings read those families for `hook` (authored in an object's Hooks tab) and `translation` (authored in Studio's "All metadata" form editor). A type with no family still shows its raw name.

‎ui/packages/app-shell/src/preview/DraftChangesPanel.tsx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,11 @@ const TYPE_COUNT: Readonly<Record<string, (t: Translate, count: number) => strin
870870
// A Studio-authored dataset publishes in the same batch as the report or
871871
// dashboard that reads it; without a row it read as the raw type name.
872872
dataset: (t, count) => t('preview.changes.typeCount.dataset', { count, defaultValue: '{{count}} datasets' }),
873+
// objectstack#29902 — Studio authors both of these itself: a hook from an
874+
// object's Hooks tab, a translation from the "All metadata" form editor.
875+
hook: (t, count) => t('preview.changes.typeCount.hook', { count, defaultValue: '{{count}} hooks' }),
876+
translation: (t, count) =>
877+
t('preview.changes.typeCount.translation', { count, defaultValue: '{{count}} translations' }),
873878
};
874879

875880
function summaryTypeSegment(t: Translate, type: string, count: number): string {

‎ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.groupHeading-13221.test.tsx‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,43 @@ describe('an object extension group reads its translated name (objectstack#29704
115115
expect(headingTexts(list)).toEqual(['2 object extensions']);
116116
});
117117
});
118+
119+
/*
120+
* objectstack#29902 — hooks (an object's Hooks tab) and translations (the
121+
* "All metadata" form editor) are types Studio authors itself, yet a batch of
122+
* three hooks read "3 items · 3 hook" (zh 「hook 3」): no count family, so the
123+
* raw-name fallback. Both now read their pack's own word.
124+
*/
125+
describe('a hook or translation group reads its translated name (objectstack#29902)', () => {
126+
const hooks = [
127+
{ type: 'hook', name: 'h_a' },
128+
{ type: 'hook', name: 'h_b' },
129+
{ type: 'hook', name: 'h_c' },
130+
];
131+
132+
it('en: three hooks head their group "3 hooks"', async () => {
133+
const list = await headingsFor(hooks);
134+
expect(headingTexts(list)).toEqual(['3 hooks']);
135+
});
136+
137+
it('zh: three hooks head their group 「钩子 3」', async () => {
138+
const list = await headingsFor(hooks, 'zh');
139+
await waitFor(() => expect(headingTexts(list)).toEqual(['钩子 3']));
140+
});
141+
142+
it('en: one translation heads its group "1 translation"', async () => {
143+
const list = await headingsFor([{ type: 'translation', name: 'zh-CN' }]);
144+
expect(headingTexts(list)).toEqual(['1 translation']);
145+
});
146+
147+
it('zh: two translations head their group 「翻译 2」', async () => {
148+
const list = await headingsFor(
149+
[
150+
{ type: 'translation', name: 'zh-CN' },
151+
{ type: 'translation', name: 'ja-JP' },
152+
],
153+
'zh',
154+
);
155+
await waitFor(() => expect(headingTexts(list)).toEqual(['翻译 2']));
156+
});
157+
});

‎ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.summaryPlural-13147.test.tsx‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ describe('Pending changes summary — each type agrees with its count (objectui#
9595
await waitFor(() => expect(summary).toHaveTextContent(/^2 项 · 流程 2$/));
9696
});
9797

98+
it('objectstack#29902: three hook drafts read "3 items · 3 hooks"', async () => {
99+
const summary = await summaryFor([
100+
{ type: 'hook', name: 'h_a' },
101+
{ type: 'hook', name: 'h_b' },
102+
{ type: 'hook', name: 'h_c' },
103+
]);
104+
expect(summary).toHaveTextContent(/^3 items · 3 hooks$/);
105+
});
106+
98107
it('CONTROL: a type with no count family keeps its raw name, unpluralised', async () => {
99108
const summary = await summaryFor([
100109
{ type: 'st_unknown_kind', name: 'u_a' },

‎ui/packages/i18n/src/locales/ar.ts‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5083,6 +5083,20 @@ const ar = {
50835083
dataset_few: 'مجموعات بيانات {{count}}',
50845084
dataset_many: 'مجموعات بيانات {{count}}',
50855085
dataset_other: 'مجموعات بيانات {{count}}',
5086+
hook: 'خطافات {{count}}',
5087+
hook_zero: 'خطافات {{count}}',
5088+
hook_one: 'خطاف {{count}}',
5089+
hook_two: 'خطافات {{count}}',
5090+
hook_few: 'خطافات {{count}}',
5091+
hook_many: 'خطافات {{count}}',
5092+
hook_other: 'خطافات {{count}}',
5093+
translation: 'ترجمات {{count}}',
5094+
translation_zero: 'ترجمات {{count}}',
5095+
translation_one: 'ترجمة {{count}}',
5096+
translation_two: 'ترجمات {{count}}',
5097+
translation_few: 'ترجمات {{count}}',
5098+
translation_many: 'ترجمات {{count}}',
5099+
translation_other: 'ترجمات {{count}}',
50865100
},
50875101
// objectui#12929 — the unchecked choice under an added object field whose
50885102
// literal default the batch publish can write into the existing records.

‎ui/packages/i18n/src/locales/de.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4614,6 +4614,12 @@ const de = {
46144614
dataset: '{{count}} Datensätze',
46154615
dataset_one: '{{count}} Datensatz',
46164616
dataset_other: '{{count}} Datensätze',
4617+
hook: '{{count}} Hooks',
4618+
hook_one: '{{count}} Hook',
4619+
hook_other: '{{count}} Hooks',
4620+
translation: '{{count}} Übersetzungen',
4621+
translation_one: '{{count}} Übersetzung',
4622+
translation_other: '{{count}} Übersetzungen',
46174623
},
46184624
// objectui#12929 — the unchecked choice under an added object field whose
46194625
// literal default the batch publish can write into the existing records.

‎ui/packages/i18n/src/locales/en.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4080,6 +4080,12 @@ const en = {
40804080
dataset: '{{count}} datasets',
40814081
dataset_one: '{{count}} dataset',
40824082
dataset_other: '{{count}} datasets',
4083+
hook: '{{count}} hooks',
4084+
hook_one: '{{count}} hook',
4085+
hook_other: '{{count}} hooks',
4086+
translation: '{{count}} translations',
4087+
translation_one: '{{count}} translation',
4088+
translation_other: '{{count}} translations',
40834089
},
40844090
// objectui#12929 — the unchecked choice under an added object field whose
40854091
// literal default the batch publish can write into the existing records.

‎ui/packages/i18n/src/locales/es.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4732,6 +4732,14 @@ const es = {
47324732
dataset_one: '{{count}} conjunto de datos',
47334733
dataset_many: '{{count}} de conjuntos de datos',
47344734
dataset_other: '{{count}} conjuntos de datos',
4735+
hook: '{{count}} hooks',
4736+
hook_one: '{{count}} hook',
4737+
hook_many: '{{count}} de hooks',
4738+
hook_other: '{{count}} hooks',
4739+
translation: '{{count}} traducciones',
4740+
translation_one: '{{count}} traducción',
4741+
translation_many: '{{count}} de traducciones',
4742+
translation_other: '{{count}} traducciones',
47354743
},
47364744
// objectui#12929 — the unchecked choice under an added object field whose
47374745
// literal default the batch publish can write into the existing records.

‎ui/packages/i18n/src/locales/fr.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4728,6 +4728,14 @@ const fr = {
47284728
dataset_one: '{{count}} jeu de données',
47294729
dataset_many: '{{count}} de jeux de données',
47304730
dataset_other: '{{count}} jeux de données',
4731+
hook: '{{count}} hooks',
4732+
hook_one: '{{count}} hook',
4733+
hook_many: '{{count}} de hooks',
4734+
hook_other: '{{count}} hooks',
4735+
translation: '{{count}} traductions',
4736+
translation_one: '{{count}} traduction',
4737+
translation_many: '{{count}} de traductions',
4738+
translation_other: '{{count}} traductions',
47314739
},
47324740
// objectui#12929 — the unchecked choice under an added object field whose
47334741
// literal default the batch publish can write into the existing records.

‎ui/packages/i18n/src/locales/ja.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4616,6 +4616,12 @@ const ja = {
46164616
dataset: 'データセット {{count}}',
46174617
dataset_one: 'データセット {{count}}',
46184618
dataset_other: 'データセット {{count}}',
4619+
hook: 'フック {{count}}',
4620+
hook_one: 'フック {{count}}',
4621+
hook_other: 'フック {{count}}',
4622+
translation: '翻訳 {{count}}',
4623+
translation_one: '翻訳 {{count}}',
4624+
translation_other: '翻訳 {{count}}',
46194625
},
46204626
// objectui#12929 — the unchecked choice under an added object field whose
46214627
// literal default the batch publish can write into the existing records.

0 commit comments

Comments
 (0)