--- name: internationalization-localization description: Internationalization and localization guidance, including Project Fluent and Fluent Translation List (.ftl) files. Use when adding, changing, reviewing, or testing localized, multilingual, or localization-ready user-facing text, locale negotiation, translation catalogs, plural/select behavior, localized date/number formatting, or Fluent integrations in JavaScript, TypeScript, Python, Rust, or web UI. Do not use for fixed-language copyediting with no localization surface. Consult current official documentation for Fluent binding APIs and use security-review plus security-review-evidence when localized content crosses trust boundaries. --- # Internationalization and Localization Use this skill when software needs to present text, formatting, or UI behavior for more than one locale. Internationalization (i18n) makes the product localizable; localization (l10n) provides locale-specific messages, formats, and conventions. Project Fluent is a localization system and message syntax designed to let localizers express natural-language complexity such as plurals, gender, case, conjugation, and word order in translation files instead of application code. Fluent resources are usually written as Fluent Translation List (`.ftl`) files. ## Use When - Adding or reviewing user-facing strings, message catalogs, locale folders, translation IDs, fallback chains, or locale negotiation. - Writing or editing `.ftl` files, Fluent selectors, variables, terms, attributes, translator comments, or localized number/date formatting. - Integrating Project Fluent through `fluent.js`, `python-fluent`, `fluent-rs`, or framework wrappers built on those packages. - Testing locale-specific output, fallback behavior, missing translations, pseudolocalization, right-to-left/bidirectional layout, or accessibility text. Do not use this skill for copyediting a single fixed-language message with no localization surface. Use language engineering skills for implementation mechanics, [`css-scss-styling`](../css-scss-styling/SKILL.md) for layout and writing-direction styling, [`api-design`](../api-design/SKILL.md) for public locale contract design, [`playwright-e2e`](../playwright-e2e/SKILL.md) for browser-visible localization tests, and [`documentation-engineering`](../documentation-engineering/SKILL.md) for docs-only localization guidance. ## Workflow 1. Inspect local conventions first: existing locale directories, source locale, message ID style, extraction/build scripts, package versions, fallback order, tests, and translation review workflow. 2. Treat American English (`en-US`) as the default/source locale unless the repository explicitly defines another source locale. Keep source messages clear and complete; do not use sentence fragments that force other languages to copy English grammar. 3. Decide whether the project needs full i18n or a smaller scoped change. Use Project Fluent when localizers need control over pluralization, grammatical variants, markup overlays, attributes, or cross-language word order; a simpler key/value library may be enough for a prototype or fixed internal tool. 4. Put language decisions in the catalog, not in application string assembly. Pass structured variables such as counts, dates, names, and states into Fluent; let the locale choose wording and order. 5. Design fallback before implementation. Typical order is requested locale, language fallback when supported, then `en-US`. Test missing-message and missing-variable behavior instead of assuming silent success. 6. Apply the negotiated BCP 47 language and script-aware direction with `lang` and `dir` on the document or localized subtree. Use logical CSS properties; do not infer direction from arbitrary user strings. 7. Consult current official upstream documentation before changing version-sensitive binding APIs, framework adapters, CLI tools, or parser/validator behavior. 8. Verify with the repository's parser, linter, typecheck, unit tests, snapshot tests, E2E tests, or build-time catalog validation. ## Fluent `.ftl` Authoring Rules - Use stable, semantic message IDs: `checkout-submit`, `profile-greeting`, `error-network-timeout`. Avoid IDs that encode English text or UI position. - Prefer complete sentences or complete UI labels. Do not concatenate localized fragments in code. - Use variables/placeables for runtime data: `welcome = Welcome, { $user }!`. Keep variable names meaningful and pass typed values where the runtime supports locale-aware number/date formatting. - Use selectors for plurals, gender, grammatical case, or state. Always include a default variant marked with `*`. ```ftl inbox-count = { $count -> [one] One message *[other] { $count } messages } ``` - Use CLDR plural categories such as `one`, `few`, `many`, and `other` instead of hard-coding English assumptions. Some languages do not use English-style plural forms; Japanese commonly uses one form where English uses singular and plural; Spanish needs gender and agreement in many messages. - Use terms for reusable product vocabulary and brand names: ```ftl -brand-name = ExampleApp about-title = About { -brand-name } ``` - Use parameterized terms only when localizers need grammatical variants, such as case or gender. Do not expose terms directly as user-facing messages. - Use attributes to group text for one UI element, including accessible labels: ```ftl email-input = Email .placeholder = name@example.com .aria-label = Email address ``` - Add translator comments for placeholders, ambiguous terms, character limits, tone, variables, and UI context. Use group or file comments for broader context. - Keep `.ftl` indentation space-based. Preserve Unicode text. Escape literal braces or leading special characters according to Fluent syntax rules. ## Locale and Language Guidance - Use BCP 47 locale tags such as `en-US`, `es`, `es-MX`, `ja`, or `ja-JP`. Store locale-specific files in predictable paths, for example `locales/en-US/app.ftl`, `locales/es/app.ftl`, and `locales/ja/app.ftl`, unless the repository already has a convention. - Keep `en-US` complete. Other locales may be partial only if fallback behavior is intentional, visible in tests, and acceptable for the product. - For Spanish, avoid baking gender, number, or formality choices into code. Let translators choose variants and agreement in `.ftl`. - For Japanese, avoid assumptions about spaces, capitalization, or English plural categories. Let the message own sentence order and politeness level. - Test long strings, short strings, missing translations, bidirectional content, pseudolocalized text, and accessible names. Test a real RTL locale and mixed-direction content, not only a flipped layout. Include screen-reader text and ARIA attributes in localization review when they are user-visible. ## Binding Guidance Use local dependency versions and current upstream docs before changing APIs. - JavaScript/TypeScript: `fluent.js` packages include `@fluent/bundle` for core `FluentBundle`/`FluentResource` formatting, `@fluent/syntax` for parsing and tooling, `@fluent/langneg` for locale negotiation, `@fluent/dom` for DOM localization, and `@fluent/react` for React integration. Use [`javascript-typescript-engineering`](../javascript-typescript-engineering/SKILL.md) for package-manager, build, and type/test mechanics. - Python: `python-fluent` provides `fluent.syntax` for parsing, serialization, AST tooling, and analysis; `fluent.runtime` for `FluentLocalization`, `FluentResourceLoader`, `format_value`, and `format_message`; and `fluent.pygments` for syntax highlighting. Use [`python-engineering`](../python-engineering/SKILL.md) for packaging, typing, tests, and Python implementation structure. - Rust: `fluent-rs` includes crates such as `fluent`, `fluent-bundle`, `fluent-fallback`, `fluent-resmgr`, `fluent-syntax`, `fluent-pseudo`, `fluent-testing`, and `fluent-cli`. Low-level bundles format messages for a locale or locale chain; higher-level fallback/resource-manager crates can own resource loading and fallback. Use [`rust-engineering`](../rust-engineering/SKILL.md) and [`rust-testing-quality`](../rust-testing-quality/SKILL.md) for Rust code and quality gates. ## Testing and Validation - Keep catalog and runtime validation separate. In the catalog lane, parse and add each resource with the repository's pinned binding or parser, checking parse and add-resource errors such as syntax failures, duplicate IDs, or missing default variants. - In the runtime call-site lane, format through the pinned binding with representative arguments; cover selector branches, fallback, locale-specific number/date output, missing translations, unknown message, term, attribute, or function references, and missing-argument/error handling. Format every relevant message and attribute, or use a binding-specific semantic analyzer that proves equivalent reference coverage. Test message IDs and accessible labels at the call sites that render them. - Add regression tests near the code that formats messages; add E2E coverage when locale affects layout, navigation, ARIA names, forms, direction, or user-visible flows. - Use pseudolocalization or long-string fixtures to catch clipped text, concatenation assumptions, and layout coupling. ## Security and Accessibility - Load [`security-review`](../security-review/SKILL.md) and [`security-review-evidence`](../security-review-evidence/SKILL.md) when localized content, locale tags, translation files, templates, Markdown/HTML, user-generated text, remote catalogs, or interpolation cross a trust boundary. - Do not assume Fluent sanitizes output for every sink. Escape or sanitize for the target context, and do not insert translated strings into `innerHTML` unless an official, reviewed overlay mechanism is used safely. - Treat translator-controlled markup and attributes as security-sensitive. In DOM/React integrations, prefer official Fluent overlay/component APIs and allow translated attributes only when the sink is safe and intentional. - Validate and normalize locale inputs before using them in file paths, URLs, cache keys, or database queries. - Localize visible labels, placeholders, titles, errors, and ARIA attributes together so screen-reader and keyboard users receive the same meaning as visual users. ## References - Project Fluent syntax guide: - Fluent specification: - `fluent.js`: - `python-fluent`: - `fluent-rs`: