From c3c8e428c81fac159c7f785f579f33a802da625b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 07:30:13 +0000 Subject: [PATCH] fix(app-shell): the publish sheet names a batch of hooks or translations in words, not the raw type code Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01Utp6CZ2YeJynYaMx8rfBzM --- .changeset/29902-publish-sheet-hook-count.md | 12 ++++++ .../src/preview/DraftChangesPanel.tsx | 5 +++ ...ftChangesPanel.groupHeading-13221.test.tsx | 40 +++++++++++++++++++ ...tChangesPanel.summaryPlural-13147.test.tsx | 9 +++++ ui/packages/i18n/src/locales/ar.ts | 14 +++++++ ui/packages/i18n/src/locales/de.ts | 6 +++ ui/packages/i18n/src/locales/en.ts | 6 +++ ui/packages/i18n/src/locales/es.ts | 8 ++++ ui/packages/i18n/src/locales/fr.ts | 8 ++++ ui/packages/i18n/src/locales/ja.ts | 6 +++ ui/packages/i18n/src/locales/ko.ts | 6 +++ ui/packages/i18n/src/locales/pt.ts | 8 ++++ ui/packages/i18n/src/locales/ru.ts | 10 +++++ ui/packages/i18n/src/locales/zh.ts | 6 +++ 14 files changed, 144 insertions(+) create mode 100644 .changeset/29902-publish-sheet-hook-count.md diff --git a/.changeset/29902-publish-sheet-hook-count.md b/.changeset/29902-publish-sheet-hook-count.md new file mode 100644 index 00000000000..6074fdc83a9 --- /dev/null +++ b/.changeset/29902-publish-sheet-hook-count.md @@ -0,0 +1,12 @@ +--- +'@object-ui/app-shell': patch +'@object-ui/i18n': patch +--- + +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) + +Clause-②: yes (widening) +Metadata-protocol: none + +- **`@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. +- **`@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. diff --git a/ui/packages/app-shell/src/preview/DraftChangesPanel.tsx b/ui/packages/app-shell/src/preview/DraftChangesPanel.tsx index 207bb9f32f9..4b7c507fb48 100644 --- a/ui/packages/app-shell/src/preview/DraftChangesPanel.tsx +++ b/ui/packages/app-shell/src/preview/DraftChangesPanel.tsx @@ -870,6 +870,11 @@ const TYPE_COUNT: Readonly strin // A Studio-authored dataset publishes in the same batch as the report or // dashboard that reads it; without a row it read as the raw type name. dataset: (t, count) => t('preview.changes.typeCount.dataset', { count, defaultValue: '{{count}} datasets' }), + // objectstack#29902 — Studio authors both of these itself: a hook from an + // object's Hooks tab, a translation from the "All metadata" form editor. + hook: (t, count) => t('preview.changes.typeCount.hook', { count, defaultValue: '{{count}} hooks' }), + translation: (t, count) => + t('preview.changes.typeCount.translation', { count, defaultValue: '{{count}} translations' }), }; function summaryTypeSegment(t: Translate, type: string, count: number): string { diff --git a/ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.groupHeading-13221.test.tsx b/ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.groupHeading-13221.test.tsx index a8c6bd23661..a8db07eade0 100644 --- a/ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.groupHeading-13221.test.tsx +++ b/ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.groupHeading-13221.test.tsx @@ -115,3 +115,43 @@ describe('an object extension group reads its translated name (objectstack#29704 expect(headingTexts(list)).toEqual(['2 object extensions']); }); }); + +/* + * objectstack#29902 — hooks (an object's Hooks tab) and translations (the + * "All metadata" form editor) are types Studio authors itself, yet a batch of + * three hooks read "3 items · 3 hook" (zh 「hook 3」): no count family, so the + * raw-name fallback. Both now read their pack's own word. + */ +describe('a hook or translation group reads its translated name (objectstack#29902)', () => { + const hooks = [ + { type: 'hook', name: 'h_a' }, + { type: 'hook', name: 'h_b' }, + { type: 'hook', name: 'h_c' }, + ]; + + it('en: three hooks head their group "3 hooks"', async () => { + const list = await headingsFor(hooks); + expect(headingTexts(list)).toEqual(['3 hooks']); + }); + + it('zh: three hooks head their group 「钩子 3」', async () => { + const list = await headingsFor(hooks, 'zh'); + await waitFor(() => expect(headingTexts(list)).toEqual(['钩子 3'])); + }); + + it('en: one translation heads its group "1 translation"', async () => { + const list = await headingsFor([{ type: 'translation', name: 'zh-CN' }]); + expect(headingTexts(list)).toEqual(['1 translation']); + }); + + it('zh: two translations head their group 「翻译 2」', async () => { + const list = await headingsFor( + [ + { type: 'translation', name: 'zh-CN' }, + { type: 'translation', name: 'ja-JP' }, + ], + 'zh', + ); + await waitFor(() => expect(headingTexts(list)).toEqual(['翻译 2'])); + }); +}); diff --git a/ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.summaryPlural-13147.test.tsx b/ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.summaryPlural-13147.test.tsx index 06c273db8a7..eeaeca7e83f 100644 --- a/ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.summaryPlural-13147.test.tsx +++ b/ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.summaryPlural-13147.test.tsx @@ -95,6 +95,15 @@ describe('Pending changes summary — each type agrees with its count (objectui# await waitFor(() => expect(summary).toHaveTextContent(/^2 项 · 流程 2$/)); }); + it('objectstack#29902: three hook drafts read "3 items · 3 hooks"', async () => { + const summary = await summaryFor([ + { type: 'hook', name: 'h_a' }, + { type: 'hook', name: 'h_b' }, + { type: 'hook', name: 'h_c' }, + ]); + expect(summary).toHaveTextContent(/^3 items · 3 hooks$/); + }); + it('CONTROL: a type with no count family keeps its raw name, unpluralised', async () => { const summary = await summaryFor([ { type: 'st_unknown_kind', name: 'u_a' }, diff --git a/ui/packages/i18n/src/locales/ar.ts b/ui/packages/i18n/src/locales/ar.ts index f7f66efbae5..b7dbecd1c61 100644 --- a/ui/packages/i18n/src/locales/ar.ts +++ b/ui/packages/i18n/src/locales/ar.ts @@ -5077,6 +5077,20 @@ const ar = { dataset_few: 'مجموعات بيانات {{count}}', dataset_many: 'مجموعات بيانات {{count}}', dataset_other: 'مجموعات بيانات {{count}}', + hook: 'خطافات {{count}}', + hook_zero: 'خطافات {{count}}', + hook_one: 'خطاف {{count}}', + hook_two: 'خطافات {{count}}', + hook_few: 'خطافات {{count}}', + hook_many: 'خطافات {{count}}', + hook_other: 'خطافات {{count}}', + translation: 'ترجمات {{count}}', + translation_zero: 'ترجمات {{count}}', + translation_one: 'ترجمة {{count}}', + translation_two: 'ترجمات {{count}}', + translation_few: 'ترجمات {{count}}', + translation_many: 'ترجمات {{count}}', + translation_other: 'ترجمات {{count}}', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/de.ts b/ui/packages/i18n/src/locales/de.ts index decad288cde..9f5bf9fb420 100644 --- a/ui/packages/i18n/src/locales/de.ts +++ b/ui/packages/i18n/src/locales/de.ts @@ -4608,6 +4608,12 @@ const de = { dataset: '{{count}} Datensätze', dataset_one: '{{count}} Datensatz', dataset_other: '{{count}} Datensätze', + hook: '{{count}} Hooks', + hook_one: '{{count}} Hook', + hook_other: '{{count}} Hooks', + translation: '{{count}} Übersetzungen', + translation_one: '{{count}} Übersetzung', + translation_other: '{{count}} Übersetzungen', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/en.ts b/ui/packages/i18n/src/locales/en.ts index 9ba9c6ae612..d8ae1898044 100644 --- a/ui/packages/i18n/src/locales/en.ts +++ b/ui/packages/i18n/src/locales/en.ts @@ -4070,6 +4070,12 @@ const en = { dataset: '{{count}} datasets', dataset_one: '{{count}} dataset', dataset_other: '{{count}} datasets', + hook: '{{count}} hooks', + hook_one: '{{count}} hook', + hook_other: '{{count}} hooks', + translation: '{{count}} translations', + translation_one: '{{count}} translation', + translation_other: '{{count}} translations', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/es.ts b/ui/packages/i18n/src/locales/es.ts index f22af5ce0c2..1b554c2492f 100644 --- a/ui/packages/i18n/src/locales/es.ts +++ b/ui/packages/i18n/src/locales/es.ts @@ -4726,6 +4726,14 @@ const es = { dataset_one: '{{count}} conjunto de datos', dataset_many: '{{count}} de conjuntos de datos', dataset_other: '{{count}} conjuntos de datos', + hook: '{{count}} hooks', + hook_one: '{{count}} hook', + hook_many: '{{count}} de hooks', + hook_other: '{{count}} hooks', + translation: '{{count}} traducciones', + translation_one: '{{count}} traducción', + translation_many: '{{count}} de traducciones', + translation_other: '{{count}} traducciones', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/fr.ts b/ui/packages/i18n/src/locales/fr.ts index c216cdab8b9..b15d5a2c6f4 100644 --- a/ui/packages/i18n/src/locales/fr.ts +++ b/ui/packages/i18n/src/locales/fr.ts @@ -4722,6 +4722,14 @@ const fr = { dataset_one: '{{count}} jeu de données', dataset_many: '{{count}} de jeux de données', dataset_other: '{{count}} jeux de données', + hook: '{{count}} hooks', + hook_one: '{{count}} hook', + hook_many: '{{count}} de hooks', + hook_other: '{{count}} hooks', + translation: '{{count}} traductions', + translation_one: '{{count}} traduction', + translation_many: '{{count}} de traductions', + translation_other: '{{count}} traductions', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/ja.ts b/ui/packages/i18n/src/locales/ja.ts index 2c2f9ba76a8..32249e6b65b 100644 --- a/ui/packages/i18n/src/locales/ja.ts +++ b/ui/packages/i18n/src/locales/ja.ts @@ -4610,6 +4610,12 @@ const ja = { dataset: 'データセット {{count}}', dataset_one: 'データセット {{count}}', dataset_other: 'データセット {{count}}', + hook: 'フック {{count}}', + hook_one: 'フック {{count}}', + hook_other: 'フック {{count}}', + translation: '翻訳 {{count}}', + translation_one: '翻訳 {{count}}', + translation_other: '翻訳 {{count}}', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/ko.ts b/ui/packages/i18n/src/locales/ko.ts index 530c8bb2d76..ca90ff3079b 100644 --- a/ui/packages/i18n/src/locales/ko.ts +++ b/ui/packages/i18n/src/locales/ko.ts @@ -4607,6 +4607,12 @@ const ko = { dataset: '데이터 세트 {{count}}', dataset_one: '데이터 세트 {{count}}', dataset_other: '데이터 세트 {{count}}', + hook: '후크 {{count}}', + hook_one: '후크 {{count}}', + hook_other: '후크 {{count}}', + translation: '번역 {{count}}', + translation_one: '번역 {{count}}', + translation_other: '번역 {{count}}', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/pt.ts b/ui/packages/i18n/src/locales/pt.ts index c9c734753f3..4d98b368131 100644 --- a/ui/packages/i18n/src/locales/pt.ts +++ b/ui/packages/i18n/src/locales/pt.ts @@ -4721,6 +4721,14 @@ const pt = { dataset_one: '{{count}} conjunto de dados', dataset_many: '{{count}} de conjuntos de dados', dataset_other: '{{count}} conjuntos de dados', + hook: '{{count}} hooks', + hook_one: '{{count}} hook', + hook_many: '{{count}} de hooks', + hook_other: '{{count}} hooks', + translation: '{{count}} traduções', + translation_one: '{{count}} tradução', + translation_many: '{{count}} de traduções', + translation_other: '{{count}} traduções', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/ru.ts b/ui/packages/i18n/src/locales/ru.ts index f251e5e8654..8e63054e416 100644 --- a/ui/packages/i18n/src/locales/ru.ts +++ b/ui/packages/i18n/src/locales/ru.ts @@ -4853,6 +4853,16 @@ const ru = { dataset_few: 'Наборы данных: {{count}}', dataset_many: 'Наборы данных: {{count}}', dataset_other: 'Наборы данных: {{count}}', + hook: 'Хуки: {{count}}', + hook_one: 'Хук: {{count}}', + hook_few: 'Хуки: {{count}}', + hook_many: 'Хуки: {{count}}', + hook_other: 'Хуки: {{count}}', + translation: 'Переводы: {{count}}', + translation_one: 'Перевод: {{count}}', + translation_few: 'Переводы: {{count}}', + translation_many: 'Переводы: {{count}}', + translation_other: 'Переводы: {{count}}', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records. diff --git a/ui/packages/i18n/src/locales/zh.ts b/ui/packages/i18n/src/locales/zh.ts index c7f54ab82ad..fae88e11ff4 100644 --- a/ui/packages/i18n/src/locales/zh.ts +++ b/ui/packages/i18n/src/locales/zh.ts @@ -3529,6 +3529,12 @@ const zh = { dataset: '数据集 {{count}}', dataset_one: '数据集 {{count}}', dataset_other: '数据集 {{count}}', + hook: '钩子 {{count}}', + hook_one: '钩子 {{count}}', + hook_other: '钩子 {{count}}', + translation: '翻译 {{count}}', + translation_one: '翻译 {{count}}', + translation_other: '翻译 {{count}}', }, // objectui#12929 — the unchecked choice under an added object field whose // literal default the batch publish can write into the existing records.