treeify logo
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 returns Content-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 (fallback fr 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>

  • 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