Files
atelier/domains/i18n/first-principles.md
T
Jon Chery 9ebc9c8868 docs(milestone): complete v0.3 — GitOps+Operators/AI-ML/i18n/Compliance
---ci---
project: atelier
phase: 6
milestone: v0.3
status: complete
requirements:
  covered: [ATELIER-60..91]
  partial: []
---/ci---
2026-08-05 03:45:38 +00:00

10 KiB
Raw Blame History

Internationalization (i18n) — First Principles

Grounded in Unicode ICU + CLDR, W3C i18n WG, BCP 47 / RFC 5646, ICU MessageFormat / FormatJS / i18next / Mozilla Fluent, the JavaScript Intl API, and WCAG 2.1 AA. The developer's language is one locale among many, not the neutral form.

1. The Principles

P1. Source Language is a Locale, Not the Default

The developer's own language is one locale among many — it is not the "neutral" or "unlocalized" form of the product. Strings are extracted from day one, addressed by key, and routed through a locale resource layer even when only one locale is populated. Treating the source language as the default produces hidden concatenations, hardcoded grammar assumptions, and a translation debt that compounds until the first second locale arrives — at which point the fix is a rewrite, not a patch. The source locale is en-US (or whatever the team writes in); it is not null. This is the i18n angle on domains/uiux/copywriting.md: copy lives in resources, not in code.

P2. Locale Identifiers are Standardized

Use BCP 47 language tags (en-US, ar-EG, zh-Hans-CN, pt-BR). No ad-hoc locale codes, no two-letter-only hacks, no invented keys. The tag carries language, script (when needed), and region (when needed); it is the contract between the resource layer, the formatting layer, and the runtime. A locale identifier that is not BCP 47 is a key that cannot be resolved by any standard tool, which is a correctness violation. Cross domains/data/schema-design.md: locale identifiers are a data shape with a defined vocabulary.

P3. Resources are External, Not Inline

User-facing strings live in locale resource files (.po, JSON, Fluent .ftl, ICU Resource Bundle), never concatenated inline in code. Inline strings are invisible to the translation pipeline, unversionable as a unit, and untestable for completeness. String concatenation in code ("Welcome, " + name + "!") is the cardinal violation: it bakes in source-language grammar and breaks for every locale with different word order. Resources are the boundary; code addresses strings by key, the resource layer resolves the key to the locale. This is the i18n angle on C4 Locality: strings and their locale-specific consequences live together in the resource, not scattered across code.

P4. Plural and Gender are Parameterized

Plural forms, gender, and select are expressed with ICU MessageFormat (or an equivalent parameterized formatter), never with if (n == 1) branching in code. Plural rules are locale-specific — English has one/other, Arabic has six categories, Russian has three — and a hand-rolled branch encodes exactly one locale's rules while pretending to be universal. The formatter is the contract; the resource carries the variants; the code passes the count and lets the formatter choose. A if (n == 1) plural is a C1 (Correctness) violation masquerading as a shortcut.

P5. Formatting is Locale-Aware

Dates, times, numbers, currencies, units, and relative time are formatted via ICU / CLDR / the JavaScript Intl API — never hand-rolled. A hand-rolled date formatter encodes one locale's conventions and silently produces wrong output for every other locale (mm/dd/yyyy vs dd/mm/yyyy is the canonical failure). CLDR is the source of truth for locale data; Intl is the runtime that exposes it. Formatting correctness is observable: a misformatted date is a wrong answer in the user's locale, even if it is "right" in the developer's. Cross domains/api/error-responses.md for localized error messages at API boundaries.

P6. Text Direction is a Layout Primitive

RTL and bidi are first-class layout concerns, not a CSS afterthought. Logical CSS properties (margin-inline-start, padding-block-end, inset-inline-end) over physical (margin-left, padding-top). The dir attribute is set on the document and on subtrees; the bidi algorithm (UAX #9) handles inline reordering. A layout that assumes LTR is a layout that is wrong for ar, he, fa, ur, and any RTL-mixed context. Text direction is not a skin — it is a structural property of the layout, and fixing it late is a rewrite. This is the i18n angle on domains/uiux/accessibility.md: RTL support is an accessibility concern for non-Latin-script users.

P7. Layout Accommodates Expansion

Translated text expands and contracts — German is ~30% longer than English, Japanese often shorter, RTL mirroring shifts every visual anchor. Layouts are flexible: no fixed pixel widths for text, no truncation without an ellipsis-and-title strategy, no white-space: nowrap on translatable strings. A layout that breaks on a 30% expansion is a layout that is wrong for most of the world's locales. Designing for the worst-case expansion up front is cheaper than reworking every screen when the first long-form locale ships.

P8. Pseudo-Locales Test Early

Test with pseudo-locales (accented, lengthened, RTL-mirrored, brack- enclosed) before real translations arrive. A pseudo-locale run surfaces hardcoded strings, layout overflow, broken concatenation, and LTR assumptions while the fix is still cheap — the translator hasn't been paid yet, and the string freeze hasn't happened. Finding these bugs after real translation is a C5 (Reversibility) violation: the cost of undoing is now a re-translation. Cross domains/testing/fixtures.md and domains/testing/pyramid.md for where pseudo-locales sit in the testing pyramid.

P9. Images and Icons are Cultural

Icons, colors, gestures, and imagery are locale-sensitive. A mailbox icon means "email" in the US and "mail" in Japan — but a green checkmark means "correct" in the West and "incorrect" in some East Asian contexts. A thumbs-up is positive in much of the world and an insult in parts of the Middle East. Avoid locale-bound symbols as universal; parameterize imagery per locale where the symbol is not globally neutral. Icons are not a universal language; they are a locale with a picture. This is a C2 (Clarity) concern: an icon whose meaning changes by locale is unclear to the reader it was not drawn for.

P10. Translation is Reversible and Versioned

Resource files are versioned alongside code; a bad translation is a rollback, not a hot-patch. Every locale resource has a history (what shipped when), a provenance (which translator / which service), and a rollback path. A translation that breaks the UI is reverted to the prior resource version, the same way a code regression is reverted to the prior commit. Translations without version history are anecdote, not artifact — you cannot tell what changed, when, or why. This is the i18n angle on C5 Reversibility applied to the resource layer.

2. Core Principle Trace

Each i18n P-rule derives from one or more core C-rules (C1C8). The matrix extension lands in P4 of the v0.3 plan; the traces below are authoritative.

P-rule Core Why
P1 Source Language is a Locale, Not the Default C2, C1 Clarity of locale intent; correctness of treating source as one-of-many
P2 Locale Identifiers are Standardized C2, C6 Clarity of a standard vocabulary; composability with standard tools
P3 Resources are External, Not Inline C4, C6 Locality of strings and their locale consequences; composability of the resource layer
P4 Plural and Gender are Parameterized C1, C6 Correctness of locale-specific plural rules; composability of the formatter contract
P5 Formatting is Locale-Aware C1, C7 Correctness of formatted output; observability of format correctness
P6 Text Direction is a Layout Primitive C1, C4 Correctness of layout for RTL; locality of direction with the text it governs
P7 Layout Accommodates Expansion C8, C3 Economy of rework; simplicity of flexible layouts over per-locale overrides
P8 Pseudo-Locales Test Early C7, C5 Observability of i18n defects early; reversibility of fixing before translation
P9 Images and Icons are Cultural C1, C2 Correctness of locale-appropriate symbols; clarity of meaning across locales
P10 Translation is Reversible and Versioned C5 Reversibility of the resource layer

3. What Violates These Principles

Violation Principle Breached
A user-facing string hardcoded in source P3 Resources are External, Not Inline
"Welcome, " + name + "!" string concatenation P3 Resources are External, Not Inline
if (n == 1) { return "item"; } else { return "items"; } P4 Plural and Gender are Parameterized
A locale code like en_us or english instead of en-US P2 Locale Identifiers are Standardized
A hand-rolled date formatter (getMonth() + 1 + "/" + getDay()) P5 Formatting is Locale-Aware
margin-left: 10px on a translatable layout P6 Text Direction is a Layout Primitive
A fixed-width text container that overflows on German P7 Layout Accommodates Expansion
First i18n test runs against real translations, not pseudo-locales P8 Pseudo-Locales Test Early
A thumbs-up icon shipped as universally positive P9 Images and Icons are Cultural
Resource files with no git history or no rollback path P10 Translation is Reversible and Versioned
The source language treated as the "unlocalized" default P1 Source Language is a Locale, Not the Default

4. Relationship to Other Domains

i18n is the locale-awareness layer that domains/uiux/ consumes and that domains/api/ surfaces at boundaries. It borrows the testing discipline of domains/testing/ and the data-shape discipline of domains/data/. Cross-links are one-directional (per D-026 extended):

  • domains/uiux/copywriting.md ← P1, P3 (strings live in resources)
  • domains/uiux/accessibility.md ← P6 (RTL is an a11y concern for non-Latin users)
  • domains/uiux/components.md ← P6, P7 (layout primitives that survive direction and expansion)
  • domains/api/error-responses.md ← P5 (localized error messages)
  • domains/data/schema-design.md ← P2, P3 (locale data shapes)
  • domains/testing/fixtures.md ← P8 (pseudo-locale fixtures)
  • domains/testing/pyramid.md ← P8 (pseudo-locale tier mapping)
  • domains/testing/first-principles.md ← P8 (testing discipline for locale)