Regional variants
The concept
Section titled “The concept”A regional variant is a sub-locale (fr-CA, en-GB, pt-BR...) laid on top of a base language (fr, en, pt) per BCP-47. It does not redefine the whole language: it carries only the strings that differ from the parent.
The key principle is parent fallback: a key missing in the variant falls back to the parent language, then to the source.
fr-CA -> fr -> sourceExample: in fr-CA you override email with "courriel"; every other key inherits from fr with no duplication. The CDN serves a merged bundle (the fr base plus the fr-CA overrides).
This is a language dimension, distinct from surfaces (accessibility and device). Surfaces are content layers on a key; regional variants are full languages linked by a parent.
Configuration
Section titled “Configuration”- Declare the variant: add the BCP-47 tag (
fr-CA) to the language catalog. The parent is derived from the tag (fr-CAhasfras its parent); there is no parent field to set. The catalog carries theis_variantandparent_codemetadata (viaGET /v1/languages), from which script and writing direction (RTL) inherit automatically. - Overlay model: translate only what differs from the parent. Everything else inherits, nothing to duplicate.
- BCP-47 fallback chain: resolution follows
variant -> parent -> source(fr-CA -> fr -> source). - Language names:
i18n.nativeName(lng?)returns the endonym (the language's own native name, catalog-sourced, with no dependency onIntl.DisplayNames). For a name localized into the UI language, useIntl.DisplayNames(uiLocale, { type: 'language' }).
SDK side
Section titled “SDK side”Add the BCP-47 tag to your locales (with @sonenta/astro: locales + defaultLocale; in react-i18next the variant comes from the version's CDN manifest). The fr-CA -> fr -> source resolution is automatic, in two layers: the CDN serves the variant as a merged bundle (fr-CA already includes the fr base), and the SDK's fallbackLng chain resolves fr-CA -> fr -> fallbackLng. Point fallbackLng at your source locale for the tail. No per-key code is needed.