---
id: react/translating
title: Translating & Values
---

`useTranslation(ns?)` returns `{ t, ready }` — `t` with `t.rich` / `t.markdown` attached. Vanilla equivalents are `Stift.scope` / `Stift.t`. Hook contract: [Setup & Boot Modes](./setup.md).

## Calling `t`

```tsx
const { t } = useTranslation('checkout')

t('title') // scoped: bare keys in `checkout`
t('title', { count: 3 }) // values fill {params} and drive select/plural
```

Multi-namespace scope (first namespace with the key wins) and rendering for a locale without switching are vanilla-side APIs — same semantics, see the [Overview](../getting-started/overview.md) snippets.

Keys, param shapes, and locales are literal types once the generator emits `stift.gen.d.ts` — typos and wrong params are compile errors. A cache miss returns the raw key, records it in `store.missingKeys`, reports `hooks.onError({ code: 'missing-key' })`, and kicks a background load so the next read resolves. ICU select/plural/offset work through the default engine. Authoring the messages: [Messages & Keys](../authoring/messages.md), [ICU Select & Plural](../authoring/icu-select-plural.md).

## Declared vs undeclared params

- **Declared** in `params.context` ([stift.config.ts](../configuration/config-file.md)) → **optional at call sites**. The app supplies them once — from the user profile via `setParam`, per-locale defaults, or a `<LocaleScope>` — and `t()` auto-merges them.
- **Undeclared** → **always required** at the call site. There is no strictness dial.

`setParam` validates against the declared `values`; an invalid value is rejected and reported via the runtime hooks.

## Grammatical agreement via LocaleScope

```tsx
import { LocaleScope } from '@secundus-studio/stift-react'

<LocaleScope context={{ gender: 'male' }}>{/* t() auto-merges these */}</LocaleScope>
```

`<LocaleScope context={...}>` lexically scopes grammatical-agreement params; an explicit param at a call site always wins. Per-locale defaults (`defaults: { all: …, ar: … }`) are recomputed whenever the active locale switches and inherit down the dialect chain.

## Rich text and markdown

Author tags in the message ([ICU Select & Plural](../authoring/icu-select-plural.md)), wire components in the UI:

```tsx
t.rich('rich.demo', { strong: (children) => <strong>{children}</strong>, a: (children) => <a href={url}>{children}</a> })
t.markdown('changelog.entry')
```

## Formatting with useFormatter

`useFormatter()` returns formatting functions only (locale/direction come from `useLocale()`): numbers, dates, times, relative time, and lists, all locale-aware. Measurement categories (`formatLength`, `formatMass`, …) convert from base units to the active unit: [Units](./units.md).

## Next

- Measurement units and pickers → [Units](./units.md)
- Declaring params/units in config → [stift.config.ts](../configuration/config-file.md)
- Missing-key/param logs in the panel → [Devtools](../tooling/devtools.md)
