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 |
Query facesign://catalog (via the MCP) or GET /langs for the authoritative list at runtime. The catalog is versioned with the platform.
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:
langsspecified: only those languages are allowed. If the browser language matches one, that language is used. OtherwisedefaultLangis used.langsomitted: every language in the catalog is allowed. The browser language picks, falling back todefaultLang(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 for the full rule.
Setting up a multilingual session
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.
// 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.
// 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.
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.
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:
https://your-demo.vercel.app/?lang=it
https://your-demo.vercel.app/?lang=deThis 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) -
langswhitelist set onsession.create -
defaultLangset onsession.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