|
| 1 | +--- |
| 2 | +"@objectstack/platform-objects": patch |
| 3 | +--- |
| 4 | + |
| 5 | +fix(platform-objects): translate the Setup app's runtime-contributed navigation, and gate it on the merged app instead of a static walk (#5750) |
| 6 | + |
| 7 | +Under `zh-CN`, four of the Setup app's ~50 sidebar entries rendered in English — |
| 8 | +`Packages`, `Delegations (OOO)`, `Webhooks`, `HTTP Deliveries` — and it was not a |
| 9 | +client-side fallback: the server's own merged `app` metadata carried the English |
| 10 | +literals. Sitting in a screen of Chinese menu items, they read like words that |
| 11 | +were simply never meant to be translated. |
| 12 | + |
| 13 | +Two different causes, both now fixed: |
| 14 | + |
| 15 | +- **`nav_packages` was translated in the wrong app's namespace.** A |
| 16 | + `nav_packages: { label: '软件包' }` existed under `apps.studio.navigation`. |
| 17 | + Setup contributes an entry with the same id (package administration is an |
| 18 | + operator concern, ADR-0084) and looks it up under |
| 19 | + `apps.setup.navigation.nav_packages` — a different subtree, so the lookup |
| 20 | + missed and the author's `'Packages'` literal won. Both entries are legitimate; |
| 21 | + the Setup one has been added and the Studio one left alone. |
| 22 | +- **The other three had no translation anywhere.** `nav_approval_delegations` |
| 23 | + (`@objectstack/plugin-approvals`), `nav_webhooks` and `nav_http_deliveries` |
| 24 | + (`@objectstack/plugin-webhooks`) are contributed at runtime by the capability |
| 25 | + plugins that own the objects, and no locale file carried a label for them. |
| 26 | + |
| 27 | +Four more were found by the new gate below, invisible to the one-locale browser |
| 28 | +session that reported this: `nav_capabilities`, `nav_settings_localization`, |
| 29 | +`nav_settings_company` and `nav_datasources` were translated in `zh-CN` **only**, |
| 30 | +so `ja-JP` and `es-ES` menus showed English there too. All eight ids are now |
| 31 | +labelled in all four locales (`en`, `zh-CN`, `ja-JP`, `es-ES`). |
| 32 | + |
| 33 | +**Why nothing caught it, which is the part worth keeping.** The Setup app is a |
| 34 | +shell of empty group anchors whose entries arrive at runtime (ADR-0029 D7), so a |
| 35 | +static walk sees none of them. Both existing gates knew this and each named the |
| 36 | +*other* as the owner: `app-nav-translation-parity.test.ts` excluded Setup and |
| 37 | +deferred to "the coverage ratchet", while `platform-objects`' extract config |
| 38 | +deferred the same labels to that ratchet "baselined at 0 for this package". The |
| 39 | +ratchet runs `os lint` over **static** stack configs, so its 0 meant "not looked |
| 40 | +at here", not "checked, clean" — and it reported OK the whole time. |
| 41 | + |
| 42 | +A new gate closes the handoff — `pnpm check:app-nav-i18n` |
| 43 | +(`packages/cli/scripts/check-app-nav-i18n.mjs`, wired into `lint.yml`). It boots |
| 44 | +the real composition, merges the navigation contributions through the same |
| 45 | +`applyNavContributions` path the `/api/v1/meta/app` read uses, and asserts every |
| 46 | +merged nav id carries a label in every locale the platform bundle declares — so |
| 47 | +the next plugin-contributed entry cannot leak the same way. It also fails when a |
| 48 | +declared contributor lands no nav id at all, because fewer merged ids means |
| 49 | +fewer ids checked: a contributor that silently stops contributing would |
| 50 | +otherwise make the gate greener rather than redder. The two comments that |
| 51 | +delegated to the ratchet now say what actually owns these labels. |
| 52 | + |
| 53 | +No authoring change: plugin nav `label` values stay plain English literals, and |
| 54 | +translations continue to live in `apps.setup.navigation` in this package. |
0 commit comments