Measured while implementing #3810 (PR aligning 43 inline defaultValue strings and making the call-site gate enforce byte-equality). Not fixed there — the delegated ruling on #3810 took option B as written, i.e. the defaultValue: spelling only. This is the other spelling of the identical mechanism, filed so the measurement does not stay buried in a closed card's comments.
The measurement (first-hand, current origin/main @ 877385a76)
AST sweep of every t(...)/tt(...) call used as the LEFT operand of || or ??, with a literal key:
sites: 24 | keys en defines: 24 | distinct keys: 18
{
"packages/app-shell/src/console/marketplace/MarketplacePackagePage.tsx": 16,
"packages/app-shell/src/views/ObjectView.tsx": 5,
"packages/app-shell/src/layout/ContextSelectors.tsx": 2,
"packages/app-shell/src/views/ActionResultDialog.tsx": 1
}
24 of 24 are on keys en already defines, so t() returns a non-empty string, so the right-hand side never evaluates. Structurally the same dead code #3810 is about, one operator away.
(The earlier comments on #3810 counted 21 for two files; ContextSelectors.tsx and ActionResultDialog.tsx add the three that sweep did not cover.)
Why the new gate does not catch it
The rule that landed for #3810 reads the defaultValue property of a t() call's options argument. These sites carry no options argument at all — the fallback is a sibling expression. scripts/check-i18n-call-site-keys.mjs already holds the AST node, so the criterion could be written as the SEMANTIC one ("a fallback for a key that exists must repeat its value") rather than the syntactic one, with node.parent deciding whether the call is a binary operand.
What it costs, and one edge that is worse than #3810's
Most of the 24 are merely redundant — the dead string equals the pack value. Five say something different, and three of those are the "misleads the reader" shape in full:
| site |
en renders |
dead right-hand side |
MarketplacePackagePage.tsx:675 marketplace.detail.moreOptions |
More install options |
'More options' |
MarketplacePackagePage.tsx:429 marketplace.detail.purgeSuccess |
Removed {{count}} sample record(s). |
`Removed ${removed} sample record(s).` |
MarketplacePackagePage.tsx:453 marketplace.detail.reseedLocalSuccess |
Re-seeded sample data: {{inserted}} inserted, {{updated}} updated. |
`Sample data re-seeded (inserted=${inserted}, updated=${updated}).` |
ObjectView.tsx:939 console.objectView.deleteViewConfirm |
Are you sure you want to delete the view "{{name}}"? This cannot be undone. |
template literal inlining viewLabel |
ContextSelectors.tsx:411 actionDialog.selectPlaceholder |
Select {{label}} |
`Select ${label}…` |
The edge defaultValue does not have: || cannot rescue anything, in either direction. With a provider, the pack wins (dead). With no provider and no initialised i18next instance, react-i18next's not-ready t returns the key itself — truthy — so the right side is still skipped and the user reads a raw console.objectView.delete. So on a provider-less host this spelling degrades strictly worse than the defaultValue spelling, which at least renders English there. Same family as #3865 (createSafeTranslation's provider-less path ignoring the inline default and rendering the raw key); this is the || half of it.
Suggested direction
Widen #3810's rule to the fallback SEMANTICS rather than adding a second rule: when t(literalKey) is the left operand of ||/?? and the key exists in en, require the right operand — where it is a static string — to equal the en value, and treat a template-literal right-hand side whose pack value uses i18next interpolation as a finding in its own right (those five rows). Non-literal right sides (ContextSelectors.tsx:409, whose fallback is a variable) stay counted, not judged, exactly as #3810 treats computed defaults.
Not urgent: nothing a console user hits today, since every one of these keys is in the pack.
Related: #3810 (the defaultValue half, gate + 43 alignments), #3865 (provider-less path renders raw keys), #3546 (slice one deleted the five || sites whose keys were MISSING; these 24 were invisible to it precisely because their keys exist).
Generated by Claude Code
Measured while implementing #3810 (PR aligning 43 inline
defaultValuestrings and making the call-site gate enforce byte-equality). Not fixed there — the delegated ruling on #3810 took option B as written, i.e. thedefaultValue:spelling only. This is the other spelling of the identical mechanism, filed so the measurement does not stay buried in a closed card's comments.The measurement (first-hand, current
origin/main@877385a76)AST sweep of every
t(...)/tt(...)call used as the LEFT operand of||or??, with a literal key:24 of 24 are on keys
enalready defines, sot()returns a non-empty string, so the right-hand side never evaluates. Structurally the same dead code #3810 is about, one operator away.(The earlier comments on #3810 counted 21 for two files;
ContextSelectors.tsxandActionResultDialog.tsxadd the three that sweep did not cover.)Why the new gate does not catch it
The rule that landed for #3810 reads the
defaultValueproperty of at()call's options argument. These sites carry no options argument at all — the fallback is a sibling expression.scripts/check-i18n-call-site-keys.mjsalready holds the AST node, so the criterion could be written as the SEMANTIC one ("a fallback for a key that exists must repeat its value") rather than the syntactic one, withnode.parentdeciding whether the call is a binary operand.What it costs, and one edge that is worse than #3810's
Most of the 24 are merely redundant — the dead string equals the pack value. Five say something different, and three of those are the "misleads the reader" shape in full:
enrendersMarketplacePackagePage.tsx:675marketplace.detail.moreOptionsMore install options'More options'MarketplacePackagePage.tsx:429marketplace.detail.purgeSuccessRemoved {{count}} sample record(s).`Removed ${removed} sample record(s).`MarketplacePackagePage.tsx:453marketplace.detail.reseedLocalSuccessRe-seeded sample data: {{inserted}} inserted, {{updated}} updated.`Sample data re-seeded (inserted=${inserted}, updated=${updated}).`ObjectView.tsx:939console.objectView.deleteViewConfirmAre you sure you want to delete the view "{{name}}"? This cannot be undone.viewLabelContextSelectors.tsx:411actionDialog.selectPlaceholderSelect {{label}}`Select ${label}…`The edge
defaultValuedoes not have:||cannot rescue anything, in either direction. With a provider, the pack wins (dead). With no provider and no initialised i18next instance, react-i18next's not-readytreturns the key itself — truthy — so the right side is still skipped and the user reads a rawconsole.objectView.delete. So on a provider-less host this spelling degrades strictly worse than thedefaultValuespelling, which at least renders English there. Same family as #3865 (createSafeTranslation's provider-less path ignoring the inline default and rendering the raw key); this is the||half of it.Suggested direction
Widen #3810's rule to the fallback SEMANTICS rather than adding a second rule: when
t(literalKey)is the left operand of||/??and the key exists inen, require the right operand — where it is a static string — to equal theenvalue, and treat a template-literal right-hand side whose pack value uses i18next interpolation as a finding in its own right (those five rows). Non-literal right sides (ContextSelectors.tsx:409, whose fallback is a variable) stay counted, not judged, exactly as #3810 treats computed defaults.Not urgent: nothing a console user hits today, since every one of these keys is in the pack.
Related: #3810 (the
defaultValuehalf, gate + 43 alignments), #3865 (provider-less path renders raw keys), #3546 (slice one deleted the five||sites whose keys were MISSING; these 24 were invisible to it precisely because their keys exist).Generated by Claude Code