feat: i18n coverage test suite (key coverage, source coverage, hardcoded strings) - #6
Closed
saiththerobo wants to merge 6 commits into
Closed
feat: i18n coverage test suite (key coverage, source coverage, hardcoded strings)#6saiththerobo wants to merge 6 commits into
saiththerobo wants to merge 6 commits into
Conversation
- Add frontend/src/locales/i18n.test.js: two-suite test (node --test) that checks (1) every key present in every locale file and (2) no two locales share the same value for a key unless explicitly whitelisted. Whitelist maps each key to the exact language pairs allowed to be identical (brand names, technical placeholders, legitimate shared words across Romance languages). - de.json: add 47 missing keys — inbox rules UI and default-reply prefs. - es/fr/it/ru/zhCN: add ~50 missing keys each — security activity log, SSO password-login toggle, and default-reply prefs. Also translate sidebar.folderMenu.renameFavorite, admin.sso.allowInsecure, and admin.sso.allowInsecureDesc which were left as English in all locales.
Explains the two failure types (missing keys, duplicate values), how to fix each, and when to translate vs whitelist.
…ys to en/de - Remove I18N_TEST_HELP.md, fold the guide into a JSDoc block at the top of i18n.test.js so it stays co-located with the test logic. - Add admin.security.allow* and mailPolicy* keys to en.json and de.json (forward-ported from feat/allow-private-host; the other locales already had these from the earlier translation pass).
- Suite 3: every locale key must appear in frontend source at least once. Handles i18next plural suffixes (_one/_other/etc.) by searching for the base key. Dynamic keys referenced via variables (t(tab.labelKey)) are listed in DYNAMIC_KEYS. - Remove 11 dead keys confirmed absent from all source files: admin.about.title, admin.accounts.presetMicrosoft, admin.rules.enabledToggle, common.close, common.copied, compose.minimize, messageList.markAllRead, notifications.undo, thread.collapse, thread.messages_one, thread.messages_other - 739 tests, 0 failures
…trings
Suite 4 scans JSX source for user-visible string literals not wrapped in
t(). Two patterns are checked: (a) title/placeholder/aria-label/alt
attributes with plain string values, and (b) text nodes between JSX tags.
Filters exclude JS code patterns (parens, || / &&) and a small HARDCODED_OK
set covers intentional non-translations (brand name, email format markers).
Violations fixed — 18 new locale keys added across all 7 locales:
compose.toolbar.* (minimize, close, attachFile, textColor, insertLink,
insertImage, insertTable, removeColor, apply, removeTable)
messageList.emptyInbox/emptyInboxDesc/noAccounts/noAccountsDesc/composeAriaLabel
common.dismiss
admin.security.qrCodeAlt
message.emailFrameTitle
Source changes: AdminPanel (Loading…, QR code alt), ComposeModal (toolbar
tooltips and popup labels), MessageList (empty states, aria-labels, delete
title), MessagePane (iframe title), NotificationToasts (dismiss aria-label).
Also removes the now-redundant I18N_TEST_HELP.md (content is in the test).
758 tests, 0 failures.
Source coverage (dead keys) now runs before key coverage so a developer cleans up dead keys before adding missing translations. Order: source coverage → key coverage → value uniqueness → hardcoded strings.
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
frontend/src/locales/i18n.test.js— a zero-dependency test (Node built-innode:test) with four suites that run withnode --test src/locales/i18n.test.jsSuites (in fix-priority order)
Suite 1 — source coverage: every locale key must appear at least once in the frontend source. Handles i18next plural suffixes (
_one/_other) by searching for the base key. Run this first — dead keys should be deleted before adding missing translations.Suite 2 — key coverage: every key in any locale file must exist in all locale files. Catches missing translations when a new feature adds keys to
en.jsonwithout updating the others.Suite 3 — value uniqueness: no two locales may share the same translated string unless explicitly whitelisted. Catches copy-pasted English values left untranslated. The
SAME_VALUE_ALLOWEDmap documents every permitted duplicate with the exact language pairs and a comment explaining why (brand names, borrowed words, Romance-language convergences, etc.).Suite 4 — hardcoded strings: scans
.jsxfiles for user-visible string literals not wrapped int(). Checkstitle,placeholder,aria-label,altattributes and JSX text nodes. False-positive filters exclude JS operators, parenthesised expressions, and a smallHARDCODED_OKset for intentional non-translations.Changes alongside the test
Test result
758 tests, 0 failures