Engineering guide
Internationalization Architecture and Workflow
Structure internationalized software with externalized messages, Unicode, RTL, locale negotiation, formatting services, explicit fallbacks, and staged delivery.
Reviewed 19 July 2026 · Editorial owner: localization.guide
Internationalization and localization are separate responsibilities
Internationalization (i18n)
Engineering work that makes adaptation possible without rewriting core features: message extraction, Unicode-safe storage, flexible layouts, locale negotiation, formatting services, bidi support, and testable fallbacks.
Localization (l10n)
Adaptation for a specific audience: translation, terminology, imagery, units, legal content, market conventions, locale data, linguistic review, and regional release decisions.
Formatting is not translation, and validation is not formatting. Keep those concerns independently testable so a copy update cannot alter price logic and a locale change cannot mutate stored business data.
Recommended application boundaries
| Layer | Owns | Must not own |
|---|---|---|
| Domain | Canonical amounts, dates, identifiers, rules | Translated labels or display strings |
| Messages | Keys, plurals, selects, context, translator notes | Number/date calculations |
| Locale services | Numbers, dates, lists, display names, collation | Business validation decisions |
| Regional validation | Address/phone metadata and user input rules | UI translation |
| Presentation | Layout, direction, accessible labels, components | Locale inference from hidden globals |
Externalize complete messages
A translator needs the complete thought and its grammatical context. Avoid concatenating fragments such as "You have " + count + " items". Use message syntax that preserves variables, plural branches, and select branches, and attach notes explaining UI context and variable meaning.
// messages/en.json
{
"cart.summary": "{count, plural, =0 {Your cart is empty} one {# item} other {# items}}",
"invite.sent": "Invitation sent to {recipientName}"
}
// Keep stable semantic keys. Do not use the English sentence as the key.
// Translator note: recipientName is a person or team display name.- Validate that every locale has the same variables and required plural/select branches.
- Escape or sanitize variables according to their output context.
- Do not split links, emphasis, or placeholders in ways that force English word order.
Use Unicode throughout—and normalize intentionally
Store, transport, search, render, and log Unicode without lossy conversions. Visually identical text can have different code-point sequences, so choose a documented normalization policy for comparisons and identifiers. Normalization is not transliteration, case folding, or accent removal; apply those separately and only when the product contract requires them.
const displayName = input.normalize("NFC");
// Search normalization is a product decision, not a display mutation.
const searchKey = displayName.normalize("NFKC").toLocaleLowerCase(locale);
// Preserve the original user-visible value when normalization would surprise them.Font coverage is part of the architecture. Define fallback stacks and test shaped scripts, combining marks, variation selectors, emoji sequences, and missing-glyph behavior with production fonts.
Design for RTL and mixed-direction content
- Set the document or component base direction with the HTML `dir` attribute.
- Use CSS logical properties such as `margin-inline-start`, `padding-inline`, and `border-inline-end`.
- Use
dir="auto"or bidi isolation for user-generated names, phone numbers, codes, and other mixed-direction strings. - Mirror arrows that express direction; do not mirror universal media controls, numbers, or brand marks without a design reason.
- Test focus order and reading order independently from visual mirroring.
export function UserLabel({ value }: { value: string }) {
return <bdi dir="auto">{value}</bdi>;
}
// Prefer logical layout utilities/properties.
// padding-inline-start: 1rem;
// inset-inline-end: 0;A small Next.js reference structure
app/
[lang]/
layout.tsx # validates locale; sets lang and dir
page.tsx
i18n/
config.ts # supported locales and default fallback
negotiate.ts # URL/cookie/header negotiation policy
messages.ts # allowlisted dynamic imports
formatters.ts # Intl number/date/list helpers
messages/
en.json
de.json
ar.json
lib/
address/ # versioned regional metadata
phone/ # parsing/validation boundary
tests/
messages.test.ts
locale-fixtures.test.ts
visual/export const supportedLocales = ["en", "de", "ar"] as const;
export type AppLocale = (typeof supportedLocales)[number];
export async function loadMessages(locale: AppLocale) {
switch (locale) {
case "de": return (await import("../messages/de.json")).default;
case "ar": return (await import("../messages/ar.json")).default;
default: return (await import("../messages/en.json")).default;
}
}Make fallback behavior explicit
Unsupported locale
Redirect or negotiate to a documented default, preserve the requested route where possible, and never load arbitrary import paths from an unchecked URL segment.
Missing message
Log a structured error with locale and key, fall back to the source locale in non-regulated UI, and fail the build for critical or newly introduced gaps.
Incomplete regional data
Use flexible input and generic display rather than applying a neighboring country’s validation rules.
Formatter/runtime failure
Use a safe, labeled fallback while preserving canonical data; do not invent a localized value by string replacement.
Localization delivery as a staged system
- Source design: write complete messages, define variables, allow expansion, and design bidi-safe components.
- Extraction: generate catalogs and reject duplicate, obsolete, or structurally invalid messages.
- Translation: provide screenshots, descriptions, terminology, constraints, and plural/select context.
- Review: perform linguistic and subject-matter review on complete workflows, not isolated strings.
- Integration: validate placeholders, compile messages, and package only allowlisted locale resources.
- Locale QA: run pseudo, automated locale fixtures, visual tests, accessibility checks, and regional devices.
- Release and monitoring: gate by locale, track fallback/missing-key errors, collect local feedback, and schedule data updates.
Primary and official sources
- Internationalization guide for the App Router — Next.js
- Structural markup and right-to-left text — W3C Internationalization
- Unicode Normalization Forms — Unicode Consortium
- Internationalization Tag Set 2.0 — W3C
- Unicode Locale Data Markup Language — Unicode Consortium