14 — QA Checklist (i18n Module)
- 1. Runtime contract (must always pass)
- 2. Missing keys / drift
- 3. Placeholder mismatch (highest-value bug class)
- 4. Encoding & Unicode
- 5. Sync across locales
- 6. Performance & offline
- 7. Security & RBAC
- 8. Regression drivers (automated)
- 9. Manual smoke (10 min)
Quality gates for the i18n module. Baseline per 00-shared/10_QA_Baseline.md; runtime contract per
i18n.service.spec.tsandi18n.service.ts:32-49.
1. Runtime contract (must always pass)
-
translate(key)with no locale → English (spec:25-29) -
translate(key)withhicontext → Hindi (spec:31-36) -
interpolation:
translate('leave.requested', {days: 3})→"Leave requested for 3 day(s)."/ Hindi equivalent (spec:38-42) -
unknown key → returns the key literal (
spec:44-46) -
getMessages('xx')→ English catalog (spec:48-51) -
Accept-Language: hi-IN→ localehi;fr→en; absent →en(i18n.middleware.ts:16-17) -
GET /api/v1/i18n/messagesreturns 401 without Bearer token (i18n.controller.ts:8) -
?locale=hireturns hi catalog regardless of header
2. Missing keys / drift
- every shipped-locale file has the same key set (en vs hi parity)
-
CI drift check (planned) fails build when a key is missing in a shipped locale (
IMPLEMENTATION_PLAN.md:845) - runtime missing key shows English, never blank, never crash
-
(planned) editor marks
missinglocales on the key list
3. Placeholder mismatch (highest-value bug class)
- param set equality across locales for every key with params (08 §2)
-
{days}present in value but not in params → runtime prints literal{days}(i18n.service.ts:43) — covered by parity check -
extra
{x}in a translation that source lacks → flagged amber -
malformed braces (
{{days}},{days) — no crash, literal output; documented behavior -
param order differs across locales (e.g. hi puts
{days}first) — must still render correctly (order-insensitive regex)
4. Encoding & Unicode
- all 9 target locales render: Devanagari (hi, mr), Tamil (ta), Telugu (te), Kannada (kn), Malayalam (ml), Gujarati (gu), Bengali (bn)
-
JSON files saved UTF-8; no escaped surrogate corruption (
translations/hi.jsonverified:"संसाधन नहीं मिला।"athi.json:3) -
no mojibake in HTTP response (Content-Type
application/json; charset=utf-8) - Indic text scale to 2.0 without clipping (11 §6)
- no forced Latin keyboard/font on translation fields (07 §8)
-
numbers in translations use locale digits only if the locale does;
{days}values are locale-formatted by the caller (App level)
5. Sync across locales
- editing a key in one locale never touches others (except delete = all)
-
new key in en → appears as
missingfor all other shipped/declared locales - promote/demote locale ((planned)) recomputes coverage ring on all screens
- bulk import ((planned)) validates: duplicate keys, empty values, param drift — rollback on any failure
- concurrent edit conflict (409) → dialog, no silent overwrite (06 §2)
6. Performance & offline
- catalog fetch < 500 ms p95 (small files: 9 keys today)
- app renders from cache when offline; banner shown; no white screens
- list pagination stable at 10k keys ((planned) console)
- no re-fetch loop on repeated 401
7. Security & RBAC
-
no
i18n.*perms exist today (permissions.constants.ts:1-97) — addi18n.key.{read,create,update,delete},i18n.locale.{read,manage}(planned) before console ships - catalog endpoint requires valid JWT; no tenant data leak (catalogs are global by design)
- console endpoints reject cross-tenant key injection (none — global; verify no tenantId path appears)
-
no XSS: catalog values rendered as text, never HTML (
{...}interpolated as text)
8. Regression drivers (automated)
i18n.service.spec.ts— extend with: param order swap, empty value, malformed braces, region-tag resolution,?localeoverride.- Add e2e:
GET /i18n/messagesauth, fallback, encoding (requires MongoDB + Redis,npm run test:e2e). - Key-parity CI script (planned) compares key sets + params across
translations/*.json.
9. Manual smoke (10 min)
- Set phone to
hi-IN→ open app → all strings Hindi. - Set phone to
fr→ all strings English, no errors. - Trigger a leave request notification → check
{days}renders (consumer wiring (planned)). - Admin edits
hivalue with wrong params → Save blocked/amber ((planned)). - Verify
npm run typecheck+npm run lintclean before merge.