Browse docs

Authoring Translations

ICU Select & Plural

ReactVanilla

messageFormat: 'icu-mf1'. Params are derived from the message source per locale and unioned across locales — a param required by any locale is required at every call site.

Interpolation

"greeting": "Hello, {name}!"

renders with t('greeting', { name }). Rendering values: Translating & Values.

Select (enum branches)

The select argument's case labels become the literal union. Always include a catch-all other — it is the required fallback branch.

"greetingNote": "We address you {politeness, select, polite {respectfully} warm {warmly} other {…}}."

Context params (gender/politeness/verbosity) appear in messages as ordinary select arguments, but they are declared in config so the app supplies them once and call sites don't repeat them. Declaring them: stift.config.ts. Supplying them at runtime (setParam, <LocaleScope>): Translating & Values.

Plural and selectordinal

"items": "{count, plural, one {# item} other {# items}}"

{count, plural, …} gives the param type number. Always include other.

Rich text and markdown

Use tags for inline emphasis/links and let the UI render them:

"rich.demo": "This message is <strong>rich</strong> — try the <a>inline link</a>."

Rendered with t.rich('rich.demo', { strong: <strong>…</strong>, a: <a>…</a> }). Markdown messages render via t.markdown(...). Author the message in the locale files; wire the tag components in the UI. Full rendering API: Translating & Values.

Rules that bite

  • Removing other from a select/plural → runtime falls back / missing branch.
  • Renaming a param in one locale but not the default → union rule makes it required everywhere.
  • Translating selector names or param names → breaks every other locale; translate only the strings inside branches.
  • Branching a message on a unit system ({unitSystem, select, metric {…} imperial {…}}) → wrong tool. Store the value in base units and format it; see Units.

Next