Skip to content

feat(i18n): blocking key-completeness gate — every locale carries every en.json key - #13827

Merged
diegosouzapw merged 2 commits into
release/v3.8.51from
feat/i18n-key-completeness-gate
Sep 16, 2026
Merged

diegosouzapw merged 2 commits into
release/v3.8.51from
feat/i18n-key-completeness-gate

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

Follow-up of the locale expansion (#13044 / #13660 / #13727 / #13782). Both batch-1 and batch-2 catalogs landed with keys absent — 43 and 10 respectively — and nothing noticed until the home-widget test failed weeks later. The two existing gates cannot see this defect:

  • check-ui-keys-coverage enforces an 80 % floor per locale: 43 absent keys out of ~13,000 still read 99.7 %.
  • check-new-key-coverage judges only the keys a PR adds to en.json; a locale batch is generated from the en.json of the day its branch is cut and adds no key itself, while the base keeps adding keys during the days it translates.

This PR adds the absolute complement.

Changes

  • scripts/i18n/check-key-completeness.mjs (npm run i18n:check-keys, --warn for report-only): every src/i18n/messages/<locale>.json must carry exactly the leaf key set of en.json — absent and extra leaves are both reported, per locale, sorted; __MISSING__: placeholders count as present (their content is the ratio gate's business). Exported pure core findIncompleteLocales({ en, locales }) + leafPaths.
  • tests/unit/i18n-key-completeness.test.ts — 5 cases (flattening, identical set, placeholder counts as present, absent leaves, extra leaves + wrong shape).
  • .github/workflows/ci.yml — new step in the i18n-ui-coverage job, right after the new-key gate.
  • docs/architecture/QUALITY_GATES.md — inventory row + section; docs/guides/I18N.md — new section "Keeping catalogs complete and retranslating English copies" (the four gates side by side, the post-merge re-sync command, the --retranslate-identical flow and the rule to allowlist test-pinned product/flag names first).

Validation

Check Result
node --import tsx/esm --test tests/unit/i18n-key-completeness.test.ts 5/5
npm run i18n:check-keys on the release tip OK — 65 locales carry all 13,071 keys of en.json, none extra
npm run check:docs-all green
prettier + eslint on the new/edited files clean

No production code touched (src/, open-sse/, bin/ untouched).

⚠️ base-red inherited: #12732

…ry en.json key

`scripts/i18n/check-key-completeness.mjs` (`npm run i18n:check-keys`) compares
the leaf key set of each locale catalog with en.json and fails on any absent
or extra leaf, whatever the age of the key; `__MISSING__` placeholders count
as present. It is the absolute complement of the two existing gates: the
coverage gate enforces an 80 % floor per locale (43 absent keys out of
~13,000 still read 99.7 %) and the new-key gate judges only the keys a PR
adds to en.json — a locale batch is generated from the en.json of the day
its branch is cut and adds no key itself, which is how batch 1 (#13044)
landed 43 keys short in nine locales and batch 2 (#13660) 10 keys short in
eight. Wired into the i18n-ui-coverage job; documented in QUALITY_GATES.md
and the i18n guide (post-merge re-sync, retranslation with pinned names).
@diegosouzapw
diegosouzapw merged commit d7d010b into release/v3.8.51 Sep 16, 2026
19 of 21 checks passed
@diegosouzapw
diegosouzapw deleted the feat/i18n-key-completeness-gate branch September 16, 2026 05:55
@diegosouzapw diegosouzapw mentioned this pull request Sep 21, 2026
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…ry en.json key (diegosouzapw#13827)

New blocking gate `i18n:check-keys` (`scripts/i18n/check-key-completeness.mjs`): every locale catalog must carry exactly the key set of `en.json`, whatever the age of the key. The percentage and new-key gates let batch 1 (diegosouzapw#13044) ship 43 keys short and batch 2 (diegosouzapw#13660) 10 keys short. Wired into the i18n-ui-coverage job; documented in QUALITY_GATES.md and the i18n guide (post-merge re-sync, retranslation with pinned names).

⚠️ base-red inherited: diegosouzapw#12732
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