---
id: authoring/icu-select-plural
title: ICU Select & Plural
---

`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

```jsonc
"greeting": "Hello, {name}!"
```

renders with `t('greeting', { name })`. Rendering values: [Translating & Values](../react/translating.md).

## 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.

```jsonc
"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](../configuration/config-file.md). Supplying them at runtime (`setParam`, `<LocaleScope>`): [Translating & Values](../react/translating.md).

## Plural and selectordinal

```jsonc
"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:

```jsonc
"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](../react/translating.md).

## 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](../react/units.md).

## Next

- Per-dialect value overrides → [Dialects](./dialects.md)
- Declaring context params and units in config → [stift.config.ts](../configuration/config-file.md)
