Awesome Test Case Design55 domain playbooks
I18n L10n
Domain: Internationalization / Localization
Build once, ship worldwide. This playbook turns i18n/l10n into repeatable design, contracts, tests, and evidence across languages, scripts, regions, calendars, currencies, and cultural rules.
TL;DR (defaults we recommend)
- Use Unicode everywhere (UTF‑8). Normalize NFC at boundaries.
- Format with CLDR/ICU libs for dates, numbers, currency, lists, plurals.
- Support locale fallback (
zh-SG → zh-Hans → zh → en
) and language negotiation (Accept-Language
, cookie, profile). - Treat RTL as first-class:
dir="rtl"
, mirroring icons, bidirectional text-safe. - Expect text expansion ×1.3 and CJK no-spaces line breaks.
- Use MessageFormat (ICU) for plurals/gender/select.
- Isolate content vs code; use keys and message IDs; never concatenate UI strings.
- Automate pseudo‑localization + coverage + screenshots in CI.
- Keep address/phone/name formats data-driven; avoid validation with hard-coded regexes only.
- Capture evidence: screenshots per locale/dir, pseudo-loc runs, string coverage, a11y checks.
Concepts (quick map)
- Locale: language + region + script (e.g.,
pt-BR
,zh-Hant-TW
). - Internationalization (i18n): code/design to support locales.
- Localization (l10n): translating and adapting content.
- Globalization (g11n): i18n + l10n + business/regulatory.
- CLDR: data for formats; ICU: formatting engine.
Language negotiation & fallback
- Detect via profile, URL, cookie, Accept-Language (ordered).
- Persist choice; do not flip silently.
- Fallback chain example:
zh-SG → zh-Hans → zh → en
. - Content versioning: each string has
message_id
,version
,last_modified
.
Contracts
- API accepts
Accept-Language
and returnsContent-Language
. - Server returns
Vary: Accept-Language
for cacheable responses.
Text, fonts, and scripts
- Use fonts covering Latin + CJK + Arabic + Devanagari where needed; fallback stacks declared.
- Enable font subsetting for performance.
- Handle grapheme clusters (emoji, flags, skin tones).
- Be aware of normalization: compare after NFC; store source and normalized forms where important.
- Avoid uppercasing for Turkish
i/İ/ı/I
issues; use locale-aware case mapping.
Layout & direction (LTR/RTL/bi‑di)
- Mark direction with
dir="ltr|rtl"
on<html>
and isolate user text:bdi
,unicode-bidi: isolate
. - Mirror: arrows, carets, sliders, progress, play icons; not numbers or brand logos.
- Keep numbers LTR with
dir="ltr"
wrappers if mixed. - Cursor and caret movement should follow direction.
Dates, numbers, currency, units
- Format with CLDR/ICU.
- Time zones: store UTC; display user tz; handle DST edges.
- Calendars: primarily Gregorian; if others supported, keep conversion libraries explicit.
- Currency: integer minor units; display with currency symbol/code per locale; respect exponent.
- Units: use metric/imperial per locale; convert and label.
Plurals, gender, select
Use ICU MessageFormat:
{count, plural,
=0 {No items}
one {# item}
other {# items}
}
- Provide gender or select where grammar requires it.
- Do not overfit to English grammar.
Content & translation pipeline
- Extract keys and messages; forbid hard-coded UI text.
- Keep context: screenshots, character limits, description, variables.
- Use TMS (translation management system), glossary, style guides, translation memory.
- QA loop: linguistic review and screenshot sign-off.
SEO & routing for web
- Use locale-aware routes:
/en/…
,/fr/…
. - Set
hreflang
links and canonical URLs. - Localize slugs or use stable ids; provide transliteration for slugs if needed.
- Avoid duplicate content via canonical tags.
Validation & user data
- Names: allow wide Unicode; avoid strict first/last assumptions.
- Addresses: format by country; dynamic fields and order.
- Phones: parse and format with libraries (e.g., libphonenumber).
- Postal codes: country-specific patterns; many countries have none.
- Sorting: locale collation (e.g.,
ä
,ß
,Å
rules differ). - Search: support folding (accents), width differences (full/half), and case.
Pseudo‑localization (fast signal)
- Expand text (
[¡¡ Ɇxƥåñđeđ ťęxť !!]
), insert bi‑di markers, randomize diacritics. - Simulate CJK width and RTL.
- Run pseudo-loc on every PR for key screens.
Performance & rendering
- Preload locale data bundles; chunk per locale.
- Lazy-load large fonts; use font-display: swap; avoid FOIT.
- Cache translations with ETag; invalidate by
message_id
version. - For server-rendered pages, ensure hydration respects locale.
Privacy & compliance
- Consent texts localized and legally reviewed.
- Region rules affect cookies, tracking, age gates, opt-ins.
- Store the consent version shown in that locale.
Observability & evidence
- Capture locale and dir tags in logs/traces.
- Metrics per locale: errors, missing strings, fallbacks, % untranslated.
- Artifact set: screenshots (LTR/RTL), pseudo-loc run, coverage report, a11y results.
MAE Scenarios (copy/adapt)
I-001 Main — Locale negotiation
- Steps: Accept-Language
fr-CA,fr;q=0.8,en;q=0.5
→ sign in - Expected: UI in
fr-CA
(fallbackfr
if needed); preference persisted - Oracles:
Content-Language
, cookies/profile, route prefix/fr-ca/
I-002 Alt — RTL layout + mixed content
- Steps: set
ar
→ enter English product code in a field - Expected: layout mirrored; input remains LTR; caret movement sane
- Oracles: screenshots;
dir
attributes; bidi isolation in DOM
I-003 Alt — Plurals & gender
- Steps: show counts
0,1,2,5
in Polish/Russian/Arabic - Expected: correct plural forms; no English fallback
- Oracles: ICU outputs; unit tests
I-101 Exception — Missing translation keys
- Steps: open new feature in
ja-JP
- Expected: fallback to
en
with marker; telemetry logs a miss - Oracles: missing-keys dashboard;
message_id
reported
I-102 Exception — Date at DST boundary
- Steps: event at
2025-03-10T01:30:00
America/Los_Angeles - Expected: shown correctly; no duplicate or skip
- Oracles: tz test harness; snapshot
I-103 Exception — Address/phone validation
- Steps: ship to
IE
(no postcodes), phone+353…
- Expected: form accepts; formats E.164; label order for IE
- Oracles: libphonenumber parse; address formatter output
I-201 Cross-feature — Pricing + currency + rounding
- Expected: minor units and exponent respected; display symbol/code per locale
- Oracles: currency table; snapshot of formatted amounts
Review checklist (quick gate)
- Negotiation: URL/cookie/Accept‑Language;
Vary
/Content‑Language
headers - Fallback chain defined; untranslated % thresholds
- ICU MessageFormat for plurals/gender/select; no string concatenation
- RTL support:
dir
, mirroring, bidi isolation; mixed LTR in RTL handled - Dates/numbers/currency via CLDR/ICU; time zone tested; DST edges
- Addresses/phones by country; validation with libraries; names Unicode
- Fonts & scripts: coverage, subsetting, performance budget
- Pseudo‑loc in CI; screenshots per locale; coverage dashboards
- SEO: locale routes,
hreflang
, canonical - Privacy: localized notices/consent; region rules
- Evidence artifacts linked in PR
CSV seeds
Locale registry
locale,language,script,region,dir,fallback
en-US,English,Latin,US,ltr,en
fr-CA,French,Latin,CA,ltr,fr
zh-Hans,Chinese,Hans,CN,ltr,zh
zh-Hant-TW,Chinese,Hant,TW,ltr,zh-Hant
ar-SA,Arabic,Arab,SA,rtl,ar
ja-JP,Japanese,Kana/Han,JP,ltr,ja
Plural rules test
locale,values
en,0|1|2|5|10
pl,0|1|2|5|22
ru,0|1|2|5|21
ar,0|1|2|3|11|100
Currency exponent
currency,exponent
USD,2
EUR,2
JPY,0
KWD,3
Address formats (short)
country,lines,postcode,name_order
US,street|city state ZIP,5+4,first last
JP,postal|prefecture|city|street|name,7,lastname firstname
IE,street|locality|county,,first last
SEO hreflang
path,lang
/ ,x-default
/en/ ,en
/fr/ ,fr
/ar/ ,ar
/zh-hans/ ,zh-Hans
Pseudo‑loc transforms
input,output
"Save","[!! Šåṽë !!]"
"Orders","[!! Ōřđęřş !!]"
Templates
String entry
message_id: cart.item.count
description: short label in cart
limit: 24 chars
message:
en: "{count, plural, =0 {No items} one {# item} other {# items}}"
fr: "{count, plural, =0 {Aucun article} one {# article} other {# articles}}"
Translation PR checklist
- Keys extracted
- English updated
- Locales updated
- Screenshots attached
- Pseudo‑loc run attached
- Coverage >= 98% for GA locales
Address form spec
Country: <code>
Fields: <ordered short list>
Validation: <rules + library>
Labels: <localized keys>
Links
- Accessibility (focus order, contrast, screen readers):
../50-non-functional/accessibility-a11y.md
- Compatibility matrix (devices/locales/networks):
../50-non-functional/compatibility-matrix.md
- Payments & currency exponents:
../5-domain-playbooks/payments-and-checkout.md
- Messaging (localized templates, quiet hours):
./messaging-and-notifications.md
- Contracts & Schemas (mark
locale
,currency
,time_zone
fields):../40-api-and-data-contracts/contracts-and-schemas.md