Skip to content

fix(i18n): add 70 keys that existed only as inline tr() fallbacks#183

Merged
phantomptr merged 2 commits into
mainfrom
fix/i18n-inline-only-keys
Jul 6, 2026
Merged

fix(i18n): add 70 keys that existed only as inline tr() fallbacks#183
phantomptr merged 2 commits into
mainfrom
fix/i18n-inline-only-keys

Conversation

@phantomptr

Copy link
Copy Markdown
Owner

Description

Fixes the user-reported runtime warnings ([i18n] missing key "fs_verify", "profile.username.loading", "fs_crc32", …). These keys were referenced at call sites via tr("key", …, "English fallback") but never added to en.ts, so they rendered the English fallback for every user — including non-English locales — and were permanently untranslatable: the i18n coverage gate only checks translations of en.ts keys, so a key absent from en.ts is invisible to it.

Scope — it was 70, not 7

The 7 in the bug report were just the screens that happened to render. A multi-line-aware scan of every tr("…") call site across client/src, diffed against en.ts, found 70 such keys (the naive single-line scan missed ~half — many are in multi-line tr() calls).

What I did

  • Added all 70 to en.ts with their exact call-site English.
  • For the ones with variables, converted the ${…} template fallbacks to the {var} placeholders the call site's vars object actually supplies ({n}/{name}/{path}/{query}/{id}/{kind}/{time}) — verified against each call site.
  • Allowlisted all 70 across the 17 non-English locales (the established new-key flow: English renders everywhere via the value now; translations land later).

Verification

  • A post-change scan finds zero used-but-missing keys; the 7 originally reported are all present.
  • i18n coverage gate green (18 langs); typecheck + lint + 779 tests pass.
  • The DEV-only runtime warning cannot fire for these anymore — the check is !(key in en), now false for all 70.

Type of Change

  • Bug fix (i18n correctness — non-English users now get translatable strings)

🤖 Generated with Claude Code

phantomptr and others added 2 commits July 6, 2026 03:00
User-reported runtime warnings (`[i18n] missing key "fs_verify"`, etc.):
these keys were referenced at call sites via `tr("key", …, "English
fallback")` but never added to `en.ts`. Consequence: they rendered the
English fallback for EVERY user, including non-English locales — permanently
untranslatable, because the i18n coverage gate only checks translations OF
en.ts keys and can't see a key that isn't in en.ts at all.

Found all 70 by a multi-line-aware scan of every `tr("…")` call site across
`client/src` and diffing against en.ts (the reported 7 were just the screens
that happened to render; the real set is 70, many in multi-line `tr()` calls
the naive scan missed). Added each to en.ts with its exact call-site English,
converting `${…}` template fallbacks to the `{var}` placeholders the call
site's vars object supplies ({n}/{name}/{path}/{query}/{id}/{kind}/{time}),
then allowlisted all 70 across the 17 non-English locales (the established
new-key flow — English renders everywhere via the value; translations land
later).

Verified: a post-change scan finds ZERO used-but-missing keys; the 7
originally reported are all present; i18n coverage gate green (18 langs);
typecheck + lint + 779 tests pass. (The DEV-only runtime warning can't fire
for these anymore — the check is `!(key in en)`, now false for all 70.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Prevents the class of bug the previous commit fixed from recurring. The
i18n coverage gate only validated translations OF en.ts keys, so a key
referenced at a call site with an inline fallback but never added to en.ts
was invisible — it rendered English for all locales, untranslatable, and no
gate caught it (only a DEV-only runtime console.warn on screens actually
rendered).

`i18n-coverage.mjs` now scans client/src for `tr("literal", …)` keys and
fails if any aren't in en.ts, BEFORE the per-language check. Verified: green
with all keys present; removing one key from en.ts fails the gate naming
that exact key. Literal keys only (dynamic `tr(\`x.${k}\`)` skipped, as
find-orphan-i18n.mjs documents); the doc-example keys foo/x are ignored.

This runs in the same `npm run i18n:check` CI step (the client-frontend job)
and `npm run validate`, so it gates every PR with no new ritual.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@phantomptr phantomptr merged commit b88f45c into main Jul 6, 2026
19 checks passed
@phantomptr phantomptr deleted the fix/i18n-inline-only-keys branch July 6, 2026 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant