fix(i18n): six bare pack keys get their consumers' defaults rows (#4396) - #4402
Merged
Conversation
`detail.saving`, `list.resetSortToDefault`, `appDesigner.widgetProperties`, `appDesigner.addWidget`, `appDesigner.modeEdit` and `common.delete` were read through `createSafeTranslation` with neither a row in their hook's defaults table nor an inline `defaultValue` at the call site — the only two fallbacks that path has — so a provider-less host rendered the raw key string. Each key now has a row in its consumer hook's defaults table, byte-identical to the `en` pack value. No pack edits, no new keys, no call-site changes. `common.delete` was the one key PR #4372's census left unattributed; both of its call sites (`FieldDesigner`, `ObjectManager`) resolve through `useDesignerTranslation`, so the row lands in plugin-designer.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Collaborator
Author
|
ACCEPT — PM 复核 (session
Flipping ready + arming auto-merge. Generated by Claude Code |
yinlianghui
marked this pull request as ready for review
August 12, 2026 02:57
This was referenced Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4396
The six keys PR #4372's census left behind — read through
createSafeTranslationwith neither a row in their hook's defaults table nor an inlinedefaultValueat the call site, the only two fallbacks that path has.fallbackT's last resort is the key itself, so a provider-less host rendered the raw key string to the user.All six were fixable in this PR's surface: one row each in the consumer hook's defaults table, byte-identical to the
enpack value. No pack edits, no new keys, no call-site changes.Per-key outcome
detail.savinguseDetailTranslationplugin-detail/src/useDetailTranslation.tslist.resetSortToDefaultuseListViewTranslationplugin-list/src/ListView.tsx(LIST_DEFAULT_TRANSLATIONS)appDesigner.widgetPropertiesuseDesignerTranslationplugin-designer/src/hooks/useDesignerTranslation.tsappDesigner.addWidgetuseDesignerTranslationappDesigner.modeEdituseDesignerTranslationcommon.deleteuseDesignerTranslationEvery census attribution was re-verified against this branch's base rather than trusted: each key still reached through the named hook, still absent from that hook's table, still bare at the call site. None were stale.
common.delete— the one the census did not attributeThe census recorded it only as "outside table, no default", and the claim comment ruled it report-don't-fix if its call site landed in a held surface (notably
packages/components, held by #4386). It does not. Its two call sites areplugin-designer/src/FieldDesigner.tsx:413plugin-designer/src/ObjectManager.tsx:269both
confirmLabel={t('common.delete')}, and both resolve throughuseDesignerTranslation. So the row belongs in plugin-designer's table, beside thecommon.cancel/common.back/common.next/common.close/common.editentries that map already borrows from the shared namespace. Nothing inpackages/componentswas touched.packages/collaborationhas its owncommon.deleterow already (useCollaborationTranslation.ts:110) and is untouched — a separate hook with a separate table.Byte-identity
Each value was resolved by evaluating the
enpack, not by reading the source near a grep hit. That mattered:en.dashboard.addWidgetis'Add widget'whileen.appDesigner.addWidgetis'Add Widget', and the two sit 99 lines apart in the same file. Checked codepoint by codepoint —detail.savingends in U+2026, not three dots:On the #3440 enforcement precedent the card cites: the only mechanical map-vs-pack gate in the repo today is
presence-avatars-i18n.test.tsx's "the collaboration defaults map mirrors the en pack", and it covers the collaboration map only. No equivalent gate exists for these three maps —check:i18n-keysjudges inlinet(key, { defaultValue })options, never acreateSafeTranslationtable, asLIST_DEFAULT_TRANSLATIONS's own #4294 comment already records. No whole-map equality test was added here, because one would land red for a reason outside this card. Measured across all three maps, source rows against the evaluated pack:One drifted row in 372 —
detail.editFieldsInline,'Edit fields inline'in the map against'Edit fields'in the pack. Filed as #4401 rather than fixed here: which side is correct is a copy decision, and generalizing the gate has to allow the deliberate exceptions these maps carry.Tests — red-first, one file per touched package
Three new files, each a dedicated file that never mounts I18nProvider. That is the local convention and it is load-bearing:
createI18ncallsinstance.use(initReactI18next), which registers the instance as react-i18next's module-global default and survives unmount andcleanup(), so one provider mount anywhere in a file makes every later "no provider" render in that file resolve against it — a green file asserting nothing.plugin-detail/src/__tests__/InlineEditSaveBar.savingNoProviderFallback.test.tsxplugin-list/src/__tests__/ListView.resetSortToDefaultNoProviderFallback.test.tsxplugin-designer/src/__tests__/bareKeysNoProviderFallback.test.tsxEach case pairs a positive assertion with a negative one, and each file carries a non-vacuity assertion on a key already in the table (
detail.cancel,list.sortRecords,common.cancel) so the "no raw key" sweeps are facts about the keys rather than about an empty DOM.Pre-fix red evidence
Reverse verification by commit-then-revert: the three map files restored to the fork point, the three test files kept. Predicted before running — all 9 red, each rendering its raw key. Observed: 9 failed / 9.
All six keys directly witnessed in the failure output:
Restoring the three files returns 9/9 green.
Verification
Type-check first failed with
Cannot find module '@object-ui/components'— a fresh worktree with unbuilt dependency dists, not a defect.pnpm --filter '@object-ui/plugin-detail^...' … buildfirst, then clean.Control-byte self-scan beyond the gate over all seven touched files: clean.
Changeset:
.changeset/six-bare-keys-defaults-4396.md, patch on the three packages (user-visible: strings that rendered as raw keys now render English). Nevermajor, per AGENTS.md's version-alignment rule.origin/mainmoved three commits during the work and was merged in; no overlap with these three packages. One of those, #4397, putcommon.selectintopackages/components' own table — the adjacent half of the same family, which is consistent withcommon.deletebelonging to plugin-designer rather than to components.Out of scope
#4401 —
detail.editFieldsInlinerendersEdit fields inlineon a provider-less host andEdit fieldsin the console, because the map row and the pack disagree. The only such row in these three maps (1 of 372, measured above), and no gate can see it. Filed unassigned for triage; this PR adds six rows and deliberately does not touch existing ones.Generated by Claude Code