---ci--- project: atelier phase: 6 milestone: v0.3 status: complete requirements: covered: [ATELIER-60..91] partial: [] ---/ci---
7.5 KiB
Testing i18n — Derived Rules
Derives from
domains/i18n/first-principles.md. Covers P8 (Pseudo-Locales Test Early) and the testing-discipline angle on P3 (Resources External), P5 (Formatting Locale-Aware), P6 (Text Direction), and P10 (Translation Versioned). Referenced bylocale-resources.md(missing-key detection) andrtl-bidi.md(RTL coverage tier).
Pseudo-Locales Test Early (P8 Pseudo-Locales Test Early)
-
A pseudo-locale is a synthetic locale that transforms the source strings to surface i18n defects before real translations arrive. Three transforms cover the three defect classes:
Pseudo-locale Transform Surfaces en-XA(accented)Wêlcômê tô thê çhêckôûtStrings not extracted (raw source appears), encoding bugs en-XB(lengthened / "long")Wᴇʟᴄᴏᴍᴇ ᴛᴏ ᴛʜᴇ ᴄʜᴇᴄᴋᴏᴜᴛ──────(~30% longer, bracketed)Layout overflow, fixed widths, truncation en-XC(RTL-mirrored)Source rendered with dir="rtl"and a Latin-in-RTL runLTR-only layout assumptions, physical CSS properties -
Pseudo-locale tests are cheap: they run against source strings, no translator involved, no string freeze required. A failing pseudo- locale run is a bug found at the cheapest possible point in the pipeline. Finding the same bug after real translation is a C5 (Reversibility) violation: the fix now costs a re-translation.
Pseudo-Locale → Testing Pyramid Mapping (IDEATE-28)
-
The testing pyramid (
domains/testing/pyramid.md) has three tiers; i18n tests map to each tier with a distinct signal. The mapping is deliberate: each tier catches a different class of defect, and skipping a tier leaves a blind spot.Pyramid Tier i18n Test Defect Caught Tooling Shape Unit Missing-key detection A key referenced in code but absent from the resource bundle; a key present in the source locale but missing from a target locale Static scan over the resource bundle + code AST; runs per file, no runtime Integration Snapshot per locale Formatted output for a fixture input differs across locales in a way that breaks the contract (wrong plural, wrong date, overflow) Render a known fixture through the formatter per locale; snapshot-diff against the recorded baseline e2e RTL coverage The app renders and is navigable in dir="rtl"; no layout overflow, no off-screen controls, no LTR-pinned anchorsBrowser-driven run against the en-XCpseudo-locale (or a real RTL locale); assert on layout, not just text -
Unit is the broad base (fast, runs on every commit), e2e is the narrow top (slow, runs on PR merge). Integration sits between. This mirrors
domains/testing/pyramid.mdexactly — i18n is not a special case; it is a domain that uses the same tiers.
Unit Tier — Missing-Key Detection (P3 Resources External)
-
A static scan compares the set of keys referenced in code against the keys present in each locale bundle. A key in code but not in
en-USis a P3 violation (the string is not in the resource layer). A key inen-USbut not inar-EGis a coverage gap — the missing-key scan flags it before the locale ships. -
Missing keys fail the build, not the runtime. A missing key that surfaces only when a user switches locale is a defect found in production, which is the most expensive place to find it.
// tool output (illustrative) // missing-key scan [FAIL] ar-EG: key "checkout.cart.item_count" referenced in code, absent from ar-EG.json [FAIL] en-US: key "checkout.cart.total" referenced in Checkout.tsx:42, absent from en-US.json (not extracted) [PASS] en-US, ar-EG, de-DE, zh-Hans-CN: all other keys present
Integration Tier — Snapshot per Locale (P5 Formatting Locale-Aware)
-
For a fixed fixture input, render the formatted output per locale and snapshot it. A change in the snapshot is either an intended change (new CLDR data, new copy) or a regression.
-
The snapshot is per locale, not per format string. The same fixture (
{ count: 1, currency: "EUR", date: 2024-11-07 }) produces different snapshots foren-US,de-DE,ar-EG— and that difference is the assertion. A locale whose snapshot matches the source locale's is a red flag: the formatter is not actually locale-aware.// snapshot — checkout.cart (fixture: count=1, currency=EUR, date=2024-11-07) // en-US "1 item · €1,234.56 · 11/7/2024" // de-DE "1 Artikel · 1.234,56 € · 07.11.2024" // ar-EG "عنصر واحد · ١٬٢٣٤٫٥٦ € · ٧/١١/٢٠٢٤" -
Snapshots are reviewed, not rubber-stamped. A snapshot diff that changes the plural form for
ar-EGis either a CLDR update (verify) or a regression (revert).
e2e Tier — RTL Coverage (P6 Text Direction is a Layout Primitive)
- A browser-driven run against
en-XC(or a real RTL locale likear-EG) asserts that the app is navigable in RTL: no overflow, no off-screen controls, no LTR-pinned anchors. The assertion is on layout, not on text — text correctness is the integration tier's job. - RTL e2e is the narrow top of the i18n pyramid: it is slow, it
requires a browser, and it catches the defects the lower tiers
cannot (the interaction of
dirwith the real layout engine). It runs on PR merge, not on every commit.
Snapshot Discipline (P10 Translation Reversible and Versioned)
- Snapshots are versioned in git. A snapshot that changes because of
a real translation update is a committed diff, reviewed like a
code change. A snapshot that changes because of a regression is a
git revert. - A snapshot that is regenerated and committed without review is a
P10 violation: the snapshot is versioned but the provenance is
opaque. The same discipline applies to snapshots as to resources
(
locale-resources.md).
What Violates i18n Testing Discipline
| Violation | Principle |
|---|---|
| First i18n test runs against real translations, not pseudo-locales | P8 Pseudo-Locales Test Early |
| No missing-key scan — gaps surface only at runtime in production | P3 Resources are External, Not Inline |
| Snapshot per locale that matches the source locale's snapshot | P5 Formatting is Locale-Aware |
| No RTL e2e — "we'll test RTL when we ship an RTL locale" | P6 Text Direction is a Layout Primitive |
| Snapshots regenerated and committed without review | P10 Translation is Reversible and Versioned |
| i18n tests only at e2e (no unit/integration tier) | pyramid inversion — domains/testing/pyramid.md |
| Pseudo-locale run skipped because "it's not a real locale" | P8 Pseudo-Locales Test Early |
Relationship to Other Domains
domains/testing/pyramid.md— the pseudo-locale → pyramid mapping mirrors this domain's unit / integration / e2e tiers exactly.domains/testing/fixtures.md— locale fixtures (a fixed input rendered per locale) are the fixture shape for the integration tier.domains/i18n/locale-resources.md— missing-key detection is the unit-tier scan over the resource bundle this doc defines.domains/i18n/formatting.md— the integration-tier snapshot asserts against the formatter's output.domains/i18n/rtl-bidi.md— the e2e tier exercises the layout rules this doc establishes.domains/uiux/accessibility.md— RTL coverage is an a11y concern; an untested RTL build is an untested a11y surface.