fix(homepage): restore missing common.* i18n keys and add a key-completeness test (closes #238) - #263
Open
dchaudhari7177 wants to merge 1 commit into
Conversation
common.unknown and common.heartbeatDataIncomplete were added in ff1ada1 and removed again in 8c1be9c, in a hunk unrelated to that PR's subject. Four call sites still reference them, and LanguageContext.t() returns the key path when the leaf is not renderable, so the dashboard rendered the literal text common.heartbeatDataIncomplete in both locales -- exactly when the backend is degraded and a readable message matters most. Restore both keys in both locales with their original wording, recovered from the deleting commit rather than rewritten. Add homepage/src/__tests__/i18nKeyCompleteness.test.ts, which scans every t('...') literal in the homepage source and asserts it resolves to renderable text in every locale. Renderable means a string or a plural form carrying a string 'other' branch, mirroring what t() can actually return -- without that, the intentional dashboard.modulesListed plural object reports as missing. The suite also asserts it found call sites at all, so a scan that stops matching fails loudly instead of passing vacuously, and that the locales stay structurally in step. Lesson recorded in docs/11-risks-and-technical-debt per CLAUDE.md. Refs schutera#238
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.
Addresses #238 (auto-close keyword kept in the title only, per CLAUDE.md's rule about bodies).
The restore
common.unknownandcommon.heartbeatDataIncomplete, in bothenandde.The wording is recovered from
8c1be9c, not rewritten — I pulled the exact bytes out of the deleting commit so the strings are byte-identical to what shipped inff1ada1, including the em dashes and the literal UTF-8 umlauts (the file mixesüescapes and literal characters; these particular strings were literal). They also go back in their original position, betweenofflineandloading, so the diff is a clean revert of the accidental hunk rather than an append.Confirmed the four call sites the issue names:
ModulePanel.tsx:208,DashboardPage.tsx:379,DashboardPage.tsx:537forcommon.unknown, andDashboardPage.tsx:164for the degraded banner.The guard
New
homepage/src/__tests__/i18nKeyCompleteness.test.ts: walkshomepage/src/**/*.tsx?(skipping__tests__, which may reference deliberately-absent keys), extracts every single-quotedt('...')literal, and asserts each resolves in every locale.Three things it does that a naive version would not, all found while writing it:
It accepts plural forms.
isRenderable()mirrors whatLanguageContext.t()can actually return — a string, or an object with a stringotherbranch thatt()selects viaIntl.PluralRules. Without that, the test reportsdashboard.modulesListedas missing, which is wrong: it is an intentional{ one, other }object, and the comment above it intranslations.tsexplains exactly why German needs it. Arrays likesetup.stepLabelsstay excluded, since those are read withuseTranslationRaw(), nott().It asserts it found something.
expect(callSites.length).toBeGreaterThan(20)guards the scan itself. This earned its place immediately: my first version used__dirname, which is undefined under vitest's ESM loader, so the walk returned zero files — and every other assertion passed vacuously. Without that guard I would have shipped a test that could never fail.It checks locale parity. A flattened key list per locale must be identical, so a key added to
enonly is caught before a user sees the English string in a German UI.Verifying the guard actually catches this bug
Deleting the restored
encommon.unknownagain makes it fail with the key and its call sites:and the parity test fires too. Restoring returns it to green.
Docs
docs/11-risks-and-technical-debt/README.mdgains a "Lessons learned" entry in the required What happened / Why / How to avoid format, per CLAUDE.md's mandatory docs gate. The lesson worth keeping is the general one: a graceful fallback needs a test that notices when it fires.t()degrading to the key path instead of throwing is what made this invisible to the type checker, the 191-test suite and the build simultaneously.make check-citations→ 7 OK, 0 problems.Verification
cd homepage && npx vitest run→ 33 files, 198 tests, 0 failures, including the 5 new ones.One deviation to flag
CLAUDE.md's end-of-implementation gate asks for the
senior-reviewersubagent. I was not able to run it in my environment, so this PR has not been through that gate — please treat it as un-reviewed by that standard. Everything else in the gate (tests,make check-citations, docs update, branch/commit conventions) has been done.