> ## Documentation Index
> Fetch the complete documentation index at: https://docs.facesign.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Languages & Localization

> Supported languages, language resolution, prompt style for multilingual flows, and currency formatting.

FaceSign supports 13 languages out of the box. The avatar speaks the resolved language and the wrapper UI adapts. You author prompts in English; the runtime translates the avatar's speech into the resolved session language.

## Supported languages

|      | Language              | Code    |
| ---- | --------------------- | ------- |
| 🇬🇧 | English (default)     | `en`    |
| 🇮🇹 | Italian               | `it`    |
| 🇩🇪 | German                | `de`    |
| 🇫🇷 | French                | `fr`    |
| 🇪🇸 | Spanish               | `es`    |
| 🇵🇹 | Portuguese            | `pt`    |
| 🇷🇺 | Russian               | `ru`    |
| 🇯🇵 | Japanese              | `ja`    |
| 🇮🇩 | Indonesian            | `id`    |
| 🇳🇴 | Norwegian             | `no`    |
| 🇨🇳 | Chinese (Simplified)  | `zh`    |
| 🇹🇼 | Chinese (Traditional) | `zh-TW` |
| 🇭🇰 | Chinese (Cantonese)   | `zh-HK` |

<Note>
  Query `facesign://catalog` (via the MCP) or `GET /langs` for the authoritative list at runtime. The catalog is versioned with the platform.
</Note>

## How language resolution works

The session picks the spoken language and the wrapper UI language from the end user's `navigator.language`, normalized against the session's `langs` whitelist:

* **`langs` specified:** only those languages are allowed. If the browser language matches one, that language is used. Otherwise `defaultLang` is used.
* **`langs` omitted:** every language in the catalog is allowed. The browser language picks, falling back to `defaultLang` (default: `en`).

### BCP-47 normalization

FaceSign normalizes `navigator.language` before matching. A few examples:

| Browser sends | Matches in `langs` | Why                                                |
| ------------- | ------------------ | -------------------------------------------------- |
| `zh-tw`       | `zh-TW`            | Case-insensitive                                   |
| `zh-Hans`     | `zh`               | Script tag alias — Simplified Chinese              |
| `zh-Hant`     | `zh-TW`            | Script tag alias — Traditional Chinese             |
| `fr-CA`       | `fr`               | Base-language fallback — Canadian French → French  |
| `en-GB`       | `en`               | Base-language fallback — British English → English |
| `es-MX`       | `es`               | Base-language fallback — Mexican Spanish → Spanish |

Author prompts and outcome conditions in **English** regardless of which languages your deployment supports — the runtime translates the avatar's speech into the resolved session language. Mixing authoring languages across nodes makes the avatar flip languages mid-flow. See [Conversation Rules](/docs/guides/conversation-rules) for the full rule.

## Setting up a multilingual session

```javascript title="Create a multilingual session" wrap theme={null}
const { session, clientSecret } = await client.session.create({
  flow,
  avatarId,
  langs: ['en', 'it', 'de'],   // whitelist: the avatar speaks any of these
  defaultLang: 'en',            // fallback when browser lang isn't in langs
})
```

Omit `langs` to allow every catalog language. The exported Next.js app detects the user's browser language automatically and forwards it to the session — no extra code required beyond `langs` and optionally `defaultLang`.

## Prompt style: `Say:` vs descriptive

This is the most important decision for multilingual flows. Both styles are written in English and both get translated into the session language at runtime; the difference is whether the LLM rephrases freely or sticks close to the source wording.

<Tabs>
  <Tab title="Descriptive (natural phrasing)">
    ```javascript title="Descriptive — paraphrased freely in the target language" wrap theme={null}
    // The LLM generates fresh sentences in the resolved session language
    prompt: "Warmly greet the user and tell them their transfer has been flagged for PSD3 verification. Ask if they're ready."
    ```

    Descriptive prompts let the LLM rephrase naturally in each target language. **Prefer descriptive prompts for multilingual deployments.**
  </Tab>

  <Tab title="Say: (constrained wording)">
    ```javascript title="Say: — verbatim-wording directive" wrap theme={null}
    // Say: keeps the translation close to the source sentence
    prompt: "Say: Hi! Your transfer's been flagged for verification. Ready?"
    ```

    `Say:` constrains the avatar to stay close to the source wording. The runtime still translates the text into the resolved session language, but the verbatim directive produces stiffer, more source-aligned translations. Use when exact wording matters — for example legal disclaimers or brand copy.
  </Tab>
</Tabs>

<Warning>
  **Prefer descriptive prompts for multilingual demos.** Both `Say:` and descriptive prompts get translated into the resolved session language, but `Say:`'s verbatim-wording directive produces stiffer translations tied to the English source. Descriptive prompts let the LLM rephrase naturally in each target language.
</Warning>

## Amount and currency formatting

Currency formatting differs by locale. If you bake amounts into your UI strings, match the user's locale:

| Locale                             | Format for 15,000 |
| ---------------------------------- | ----------------- |
| `en`, `ja`, `zh`, `zh-TW`, `zh-HK` | `15,000`          |
| `it`, `de`, `es`, `pt`, `id`       | `15.000`          |
| `fr`, `ru`, `no`                   | `15 000`          |

For numeric data, prefer `Intl.NumberFormat` at render time over hard-coded strings.

## Adding your own UI translations

The exported app contains exactly the `uiStrings` your AI assistant generated at export time — there are no built-in defaults. Add or change scenario copy (product name, merchant names, your own product voice) by editing the UI strings in the exported app. Keep the key set identical across every language block. Missing keys fall back to English at runtime.

## Testing without changing your browser language

Exported apps honor a `?lang=XX` query parameter that overrides both the wrapper UI and the avatar's spoken language. Append it to any demo URL:

```bash title="Test language override" wrap theme={null}
https://your-demo.vercel.app/?lang=it
https://your-demo.vercel.app/?lang=de
```

This makes it easy to verify multilingual behavior without reconfiguring your browser's language preferences.

## Multilingual deployment checklist

* [ ] Conversation prompts are descriptive, not `Say:` (required for translation)
* [ ] `langs` whitelist set on `session.create`
* [ ] `defaultLang` set on `session.create`
* [ ] UI strings cover every language in `langs`
* [ ] Currency, date, and number formats are locale-appropriate
* [ ] Tested in each target language with the browser's primary language set accordingly, or via `?lang=XX`

## Next steps

<CardGroup cols={2}>
  <Card title="Flows" href="/docs/reference/concepts#flows">
    Complete English-only and multilingual example flows
  </Card>

  <Card title="Verification Patterns" href="/docs/guides/verification-patterns">
    Common flow patterns for real-world use cases
  </Card>

  <Card title="Customization" href="/docs/guides/customize-branding">
    Customize UI text and branding
  </Card>
</CardGroup>
