test(control-plane): validate t() keys resolve against the i18n catalog - #2232
Merged
Conversation
Add a vitest guard that walks every src .ts/.tsx file, resolves each
useTranslations("ns") binding, and asserts every static t("key") /
t.rich("key") reference maps to a leaf key in en.json. This closes the
gap between the two existing i18n checks: messages.test.ts only compares
locale catalogs against each other (a key missing from *every* catalog,
en included, passes parity), and find-untranslated.ts does the inverse
(flags strings *not* wrapped in t()). Neither walked from a t() call
site back to the catalog, so a missing key only surfaced as a runtime
next-intl error in the browser.
Runs under the existing `npm test` step in the build-control-plane CI
job, so no workflow change is needed.
The guard immediately surfaced 14 keys referenced by the curation
feature (#1976) but missing from all 10 catalogs (filterActive,
filterInvalidated, invalidatedHint, invalidatedFactsTitle, and the
memoryDetailPanel curation*/editField* set). Add translations for all
locales so the suite is green. Supersedes #2226, which patched only
filterActive.
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.
Summary
Adds a CI guard that validates translation keys referenced in code resolve against the message catalog — the gap that let
dataView.filterActive(#2226) ship missing.The control plane already had two i18n checks, but a missing key fell straight between them:
messages.test.tsonly compares locale catalogs against each other (en is the baseline). A key missing from every catalog — en included — passes parity unnoticed.find-untranslated.ts(i18n:check) does the inverse: it flags hardcoded strings not wrapped int(...), and explicitly skips anything insidet().Neither one ever walked from a
t("key")call site back to the catalog, so at()reference with no entry anywhere only surfaced as a runtime next-intl error in the browser — invisible to CI.What this adds
tests/messages/used-keys.test.ts— a vitest guard that:.ts/.tsxundersrc, parses with the TypeScript AST.useTranslations("ns")binding to its namespace.t("key")/t.rich("key")reference maps to a leaf key inen.json, reportingfile:linefor any miss.Dynamic keys (
t(a_${x})),t.has()(the sanctioned presence-probe), and unknown bindings are skipped to avoid false positives. It runs under the existingnpm teststep in thebuild-control-planeCI job — no workflow change needed.Fixes it surfaced
The guard immediately caught 14 keys referenced by the curation feature (#1976) but missing from all 10 catalogs — #2226 patched only one of them:
dataView.filterActive,dataView.filterInvalidated,dataView.invalidatedHintdocumentsView.invalidatedFactsTitlememoryDetailPanel.curationActions/curationEdit/curationReasonLabel/curationRevert/curationSave/curationStateInvalidatedmemoryDetailPanel.editFieldContext/editFieldOccurredEnd/editFieldOccurredStart/editFieldTypeTranslations added for all 10 locales so the suite is green.
Supersedes #2226 (which added only
filterActive) — that PR can be closed.Tests
npx vitest run(67 passed, incl. the new guard + existing parity)npm run i18n:check./scripts/hooks/lint.sh