Internationalization & RTL Design (i18n)
This skill makes a Chwezi artifact survive translation and direction change without a redesign. It treats locale (script direction, string length, number/date/currency format, font coverage) as a design constraint present from the first layout decision — not a late-stage retrofit. The cheapest i18n is the layout that was never hard-coded to English-LTR in the first place.
Internationalization (i18n) is the engineering/design work that makes localization possible; localization (l10n) is the per-locale translation/adaptation. This skill owns i18n: the direction-agnostic, length-tolerant, locale-formatted layout. It co-activates with every group because direction and expansion touch grids, type, components, forms, and copy alike.
Use When
- Designing or building any UI/document that ships in, or could later ship in, more than one language — especially if one is RTL (Arabic, Hebrew, Persian/Farsi, Urdu) or a CJK script.
- A request mentions RTL,
dir="rtl", bidirectional/bidi text, mirroring, logical CSS properties, string/translation expansion, overflow/truncation in another language, locale number/date/currency/percent formatting, pluralization, ICU MessageFormat, orlang. - Auditing an English-only layout for translation-readiness before strings are sent out.
- Choosing or pairing fonts that must cover non-Latin scripts (Arabic, Hebrew, CJK, Cyrillic,
Devanagari) — coordinate with
01-typography-and-fonts/font-selection-and-pairing.
Do Not Use When
- The work is purely the wording of one English string →
10-content-design-and-ux-writing/ux-writing-and-microcopy(this skill sizes the space a string needs and formats data, it does not write copy). - The work is purely font licensing/embedding mechanics →
01-typography-and-fonts/*(this skill names the coverage requirement; that group owns the file/licence). - The work is general responsive breakpoints unrelated to language →
03-layout-grid-and-composition/responsive-and-adaptive-layout(though string expansion is a sibling cause of overflow — cross-reference it). - The work is WCAG conformance generally →
accessibility-wcag-2-2-compliance(this skill cites it forlang/dirand reflow, but does not own the audit).
Required Inputs
| Input | Supplied by | Required? | Why |
|---|---|---|---|
| Target locales and scripts | Product/localisation owner | yes | Defines direction and coverage |
| UI or document flow and strings | Design/content team | yes | Exposes expansion and bidi risks |
| Formatting and font requirements | Domain and typography owners | yes | Covers data and glyph behaviour |
Workflow
Apply the direction, expansion, formatting, and verification phases below. Stop release when a target locale cannot complete a critical task or required script coverage is missing.
- The target locales (or "unknown / might expand later" — design defensively then).
- Which targets are RTL and which scripts are in play (Latin, Arabic, Hebrew, CJK, Cyrillic…).
- Whether the artifact is UI (web/app), a document (DOCX/PDF/PPTX), or both.
- The longest expected strings, or permission to budget from
references/string-expansion-budgets.md. - Locale formatting needs: dates, times, numbers, currency, percentages, units, names, addresses.
A. Direction & layout (build it direction-agnostic)
- Set language and direction at the root.
<html lang="ar" dir="rtl">(ordir="auto"where mixed). Thelangattribute is also an accessibility requirement (WCAG 3.1.1) — seeaccessibility-wcag-2-2-complianceanddoctrine/references/wcag-2.2-criteria.md. - Use logical, not physical, properties — everywhere. Replace
margin-left→margin-inline-start,padding-right→padding-inline-end,left:→inset-inline-start,text-align: left→text-align: start,float: left→float: inline-start. Logical properties flip automatically withdir; physical ones do not. This single discipline does ~80% of RTL mirroring for free. Seereferences/rtl-mirroring-rules.md. - Mirror the layout, but know what does NOT mirror. The reading axis, navigation, progress,
and most directional icons flip; but media playback controls, clocks, charts with a time
x-axis, phone numbers, code, and brand logos generally do not. Apply the full
what-mirrors-vs-doesn't table in
references/rtl-mirroring-rules.md— getting this wrong is the #1 amateur RTL mistake (mirroring a play button or a line chart). - Handle bidirectional (bidi) runs. LTR fragments inside RTL text (URLs, emails, numbers,
Latin brand names, code) need isolation — use
<bdi>,unicode-bidi: isolate, or the Unicode isolate marks — or punctuation and digits will jump to the wrong end. - Mirror motion and gesture. Slide-in/out, carousel advance, swipe-to-dismiss, and
back-navigation directions invert in RTL. Coordinate with
08-motion-and-interaction.
B. Expansion & contraction (give every string room to grow)
- Budget expansion from real data, never eyeball it. Short UI strings can grow +200–300%
from English; running text averages +30–35% for German/Finnish, with CJK contracting.
Use the per-language, per-length table in
references/string-expansion-budgets.md— never a single flat "+30%" guess, which under-budgets buttons and over-budgets paragraphs. - Design layouts that flex, not fixed boxes. Avoid fixed-width buttons/nav/labels and
single-line assumptions. Let containers wrap to a second line; reserve vertical space.
String expansion is a sibling of responsive overflow — pairs with
03-layout-grid-and-composition/responsive-and-adaptive-layout. - Truncate honestly, and only as a last resort. If truncation is unavoidable, ellipsis +
full text on hover/focus/
title; never truncate so hard the label is ambiguous. Prefer wrapping. Test with the longest budgeted string AND a pseudo-localized string. - Pseudo-localize before any real translation exists. Render
[!!! Ŝéttîngs ñññ !!!]— accented to expose missing Unicode handling, bracketed to expose clipping, padded ~+40% to expose tight boxes. This catches most i18n layout bugs with zero translation cost. - Never concatenate sentences from fragments. Word order differs per language. Use whole,
parameterized messages (ICU MessageFormat) so translators control order; never build
"You have " + n + " items". Handle plurals with ICUpluralcategories (languages have 1–6 plural forms, not just one/many).
C. Locale formatting (let the platform format data)
- Format numbers, dates, currency, percent via the locale API — never hand-roll. Use
Intl.NumberFormat/Intl.DateTimeFormat(web),ICU/CLDR-backed APIs elsewhere. Decimal/grouping separators, date order (DMY vs MDY vs YMD), 12/24-hour, currency symbol position, and digit shaping (Arabic-Indic digits) are all locale-driven. Seereferences/string-expansion-budgets.md§"Formatting that changes by locale". - Currency: symbol, position, and code.
1 234,56 €vs$1,234.56vs١٬٢٣٤٫٥٦. Show the ISO code (USD/EUR/UGX) where ambiguity matters. Never assume$= USD. - Choose fonts that cover the target scripts. A Latin-only face renders tofu (□) for
Arabic/CJK. Specify a script-complete family or an explicit fallback stack; respect the
doctrine's anti-slop and licensing rules — coordinate with
01-typography-and-fonts/font-selection-and-pairinganddoctrine/references/font-groups-and-usage.md. Watch line-height: Arabic and Devanagari need more vertical space than Latin.
D. Verify
- Test in a real RTL locale + a long-expansion locale + a CJK locale + pseudo-locale. Walk the flow: nothing clipped, mirrored correctly (and the no-mirror set NOT mirrored), bidi runs correct, numbers/dates/currency formatted right, no tofu, focus/reflow still pass at 200%/320px.
- Record the before/after decisions. For an RTL conversion, log every element as
mirror / no-mirror / bidi-isolate with the reason — use
examples/rtl-before-after.mdas the template so the rationale survives handoff.
Anti-Patterns
- Physical properties everywhere (
margin-left,left:,text-align: left) — guarantees a broken RTL layout and a full re-edit later. Logical properties from day one instead. - Mirroring things that must not mirror — a flipped play/pause/fast-forward, a mirrored line
chart with a time axis, a reversed clock, a backwards logo, mirrored phone numbers. The
signature amateur RTL bug. See
references/rtl-mirroring-rules.md. - A flat "+30%" expansion guess for everything — under-budgets short labels/buttons (which grow 200%+) and over-budgets paragraphs. Budget by length band, per language.
- Fixed-width buttons and single-line labels — overflow or clip the moment a longer language arrives. Design flexible containers.
- Hard truncation with no recovery — ellipsis that hides meaning and offers no hover/full text.
- Sentence-building by string concatenation —
"Deleted " + n + " files"is untranslatable; word order and plural rules break. Use ICU MessageFormat withplural. - Hand-rolled date/number/currency formatting —
MM/DD/YYYY,$hard-coded,,decimal assumed. UseIntl/CLDR. Forgetting Arabic-Indic digit shaping. - Latin-only fonts on a multi-script product — renders tofu (□) for Arabic/CJK/Devanagari.
- No bidi isolation — Latin brand names, URLs, and numbers jump to the wrong end of RTL text.
- "We'll add languages later" with English-LTR-hard-coded layout — "later" becomes a rebuild.
Outputs
| Output | Consumer | Evidence / acceptance |
|---|---|---|
| Locale and direction matrix | Product and localisation teams | Script, direction, formats, and exceptions recorded |
| RTL/expansion decision sheet | Designer and engineer | Mirror, no-mirror, bidi, and expansion per element |
| Localised-flow evidence | QA and accessibility | Real RTL, expansion, CJK, and pseudo-locale results |
- A direction-agnostic layout (logical properties, correct
lang/dir, mirrored where appropriate, bidi-isolated where needed) that flips by changing one attribute. - An expansion-tolerant layout sized from real per-language budgets, pseudo-localization-tested.
- Locale-formatted numbers, dates, currency, and percentages via the platform i18n API.
- A recorded RTL/i18n decision sheet (mirror / no-mirror / bidi / expansion per element)
ready for handoff and for the
design-qa-and-pre-launch-reviewgate.
Examples
- See
examples/rtl-before-after.mdfor the required element-by-element decision record.
Quality Standards
- Use logical properties, locale APIs, whole messages, and script-capable font stacks.
- Test at least one real RTL locale, long-expansion locale, CJK locale, and pseudo-locale.
- Block release for clipped meaning, broken bidi order, wrong financial/date semantics, or tofu glyphs.
Decision Rules
| Condition | Decision | Wrong-choice failure |
|---|---|---|
| Element follows reading or navigation flow | Mirror it in RTL | Flow feels reversed or inconsistent |
| Element represents time, code, numbers, brand, or physical reality | Do not mirror; isolate if needed | Meaning or identity is corrupted |
| Short translated control expands heavily | Wrap or provide flexible inline size | Label clips or becomes ambiguous |
| Locale rules differ | Use CLDR-backed platform formatting | Dates, amounts, or plurals are wrong |
Capability Contract
Read and locale inspection are required. Editing and execution are allowed only for authorised implementation/testing. Do not invent translations or approve linguistic quality without a qualified locale reviewer.
Degraded Mode
Without translations, use expansion budgets and pseudo-localisation, marking language quality unverified. Without target-locale rendering, return a conditional decision sheet and test plan rather than a pass.
examples/rtl-before-after.md— a real worked LTR→RTL conversion of an Arabic e-commerce product screen (header, search, breadcrumb, product card, rating, price, qty stepper, reviews, carousel), logging for each element whether it mirrors, stays put, or needs bidi isolation — and the reasoning behind each decision. Use it as the template for any RTL conversion.
References
doctrine/design-doctrine.md— the cross-cutting charter; §3 places this skill in00-cross-cutting-ops-qa-a11y(co-activates with every group). The anti-slop §2 also governs font choice for non-Latin scripts — never fall back silently to a banned default just because a script is "hard".doctrine/references/wcag-2.2-criteria.md—langof page/parts (3.1.1/3.1.2) and reflow at 320px/200% (1.4.10/1.4.4), which RTL and expansion both stress.doctrine/references/font-groups-and-usage.md— script coverage and pairing for non-Latin fonts.references/rtl-mirroring-rules.md— the definitive what-mirrors / what-does-NOT-mirror table, logical-property mapping, and bidi-isolation recipes.references/string-expansion-budgets.md— real per-language, per-length expansion percentages, and the locale-formatting (number/date/currency/percent) reference.- Pairs with
01-typography-and-fonts/font-selection-and-pairing(script coverage),03-layout-grid-and-composition/responsive-and-adaptive-layout(overflow is a sibling problem),08-motion-and-interaction(mirrored motion), andaccessibility-wcag-2-2-compliance(lang/dir, reflow). Enforced one last time bydesign-qa-and-pre-launch-review.