CAAL supports multiple languages across all components: voice pipeline (STT, LLM, TTS), web frontend, and mobile app. Language is configured globally — changing it in any client propagates to the voice agent automatically.
| Code | Language | Frontend | Mobile | Voice (STT/TTS) | Prompts |
|---|---|---|---|---|---|
en |
English | Yes | Yes | Yes | Yes |
fr |
French | Yes | Yes | Yes | Yes |
it |
Italian | Yes | Yes | Yes | Yes |
pt |
Portuguese (BR) | Yes | Yes | Yes | Yes |
When CAAL starts for the first time, a language selector appears before the setup wizard. This ensures the entire setup experience is in the user's preferred language.
The selector sets a CAAL_LOCALE cookie and saves the language to backend settings. If a user opens CAAL from a new browser after setup, the cookie is automatically synced from backend settings.
- Open Settings (gear icon)
- Under the Agent tab, find the Language dropdown
- Select the desired language
- The page reloads automatically with the new locale
- Open Settings
- Tap the Language selector
- Choose the desired language
- The app refreshes immediately
curl -X POST http://localhost:8889/settings \
-H "Content-Type: application/json" \
-d '{"settings": {"language": "fr"}}'Edit settings.json at the project root and set the language field:
{
"language": "fr"
}The agent reads this on each new session — no restart required.
settings.json (language: "fr")
|
+-- Frontend: CAAL_LOCALE cookie --> next-intl --> French UI
|
+-- Mobile: LocaleProvider --> Flutter intl --> French UI
|
+-- Voice Agent:
+-- STT: language="fr" parameter to Whisper
+-- LLM: French system prompt (prompt/fr/default.md)
+-- TTS: French voice (Piper siwis-medium)
+-- Wake greetings: prompt/fr/greetings.txt
+-- Date/time: French formatting in context
- User changes language in any client (web, mobile, or API)
- Client sends
POST /settingswith{"settings": {"language": "fr"}} - Backend saves to
settings.json - Frontend sets a
CAAL_LOCALEcookie and reloads - Mobile updates its
LocaleProviderstate - The next voice session reads the updated setting at startup
When a voice session starts, the language setting affects:
- STT: The
languageparameter is passed to Whisper (Groq or Speaches), improving transcription accuracy for the target language. - System Prompt: Loaded from
prompt/{language}/default.md. The French prompt includes "Reponds toujours en francais" to ensure the LLM responds in French. - TTS Voice: Automatically selects a language-appropriate Piper voice. Kokoro TTS auto-switches to Piper for non-English languages.
- Wake Greetings: Loaded from
prompt/{language}/greetings.txt(one greeting per line). Falls back to English if the language file doesn't exist. - Date/Time Context: Injected into the system prompt using localized formatting (e.g., "mercredi 21 janvier 2026", "15 heures 30").
| Language | Piper Voice | Description |
|---|---|---|
en |
piper-en_US-ryan-high |
Male, US English, high quality |
fr |
piper-fr_FR-siwis-medium |
Female, French, medium quality |
it |
piper-it_IT-paola-medium |
Female, Italian, medium quality |
pt |
piper-pt_BR-faber-medium |
Male, Brazilian Portuguese, medium quality |
If Kokoro TTS is configured but the language is not English, the agent automatically switches to Piper with the appropriate voice.
To add support for a new language (e.g., German de):
Create the prompt directory and files:
prompt/de/
default.md # German system prompt (include "Antworte immer auf Deutsch")
greetings.txt # One wake greeting per line
Example greetings.txt:
Hallo!
Ja?
Was kann ich für dich tun?
Hey!
Was gibt's?
a) TTS voice mapping — Add a Piper voice in src/caal/settings.py:
PIPER_VOICE_MAP: dict[str, str] = {
"en": "speaches-ai/piper-en_US-ryan-high",
"fr": "speaches-ai/piper-fr_FR-siwis-medium",
"it": "speaches-ai/piper-it_IT-paola-medium",
"de": "speaches-ai/piper-de_DE-thorsten-high", # add this
}b) Date/time formatting — Add formatter functions in src/caal/utils/formatting.py following the pattern of _format_date_french() and _format_time_french(). Then add the language condition in format_date_speech_friendly() and format_time_speech_friendly().
a) Locale config — Add 'de' to the locales array in frontend/src/i18n/config.ts:
export const locales = ['en', 'fr', 'de'] as const;b) Message file — Create frontend/messages/de.json using en.json as a template. Translate all values.
c) Language selectors — Add the language to both dropdown arrays:
In frontend/components/settings/settings-panel.tsx:
const LANGUAGES = [
{ code: 'en', label: 'English' },
{ code: 'fr', label: 'Français' },
{ code: 'de', label: 'Deutsch' }, // add this
] as const;In frontend/components/setup/language-selector.tsx:
const LANGUAGES = [
{ code: 'en', label: 'English' },
{ code: 'fr', label: 'Français' },
{ code: 'de', label: 'Deutsch' }, // add this
] as const;d) Piper model download — Add the model to the PIPER_MODELS map in language-selector.tsx:
const PIPER_MODELS: Record<string, string> = {
fr: 'speaches-ai/piper-fr_FR-siwis-medium',
de: 'speaches-ai/piper-de_DE-thorsten-high', // add this
};And in settings-panel.tsx handleLanguageChange:
const piperModels: Record<string, string> = {
fr: 'speaches-ai/piper-fr_FR-siwis-medium',
de: 'speaches-ai/piper-de_DE-thorsten-high', // add this
};a) ARB file — Create mobile/lib/l10n/app_de.arb using app_en.arb as a template. Translate all values. Run flutter gen-l10n.
b) Locale provider — Add the locale in mobile/lib/providers/locale_provider.dart:
static const supportedLocales = [Locale('en'), Locale('fr'), Locale('de')];c) Language option — Add the dropdown entry in mobile/lib/screens/settings_screen.dart.
Ensure the Piper TTS model is available. Either pre-install it or let Speaches download it on first use:
curl -X POST http://localhost:8000/v1/models/speaches-ai/piper-de_DE-thorsten-high| # | What | Where |
|---|---|---|
| 1 | System prompt | prompt/{lang}/default.md |
| 2 | Wake greetings | prompt/{lang}/greetings.txt |
| 3 | Piper voice mapping | src/caal/settings.py → PIPER_VOICE_MAP |
| 4 | Date/time formatting | src/caal/utils/formatting.py |
| 5 | Locale config | frontend/src/i18n/config.ts → locales |
| 6 | UI translations | frontend/messages/{lang}.json |
| 7 | Settings language list | frontend/components/settings/settings-panel.tsx → LANGUAGES |
| 8 | Setup language list | frontend/components/setup/language-selector.tsx → LANGUAGES |
| 9 | Piper model download maps | language-selector.tsx + settings-panel.tsx + setup-wizard.tsx → PIPER_MODELS/piperModels |
| 10 | Mobile translations | mobile/lib/l10n/app_{lang}.arb |
| 11 | Mobile locale provider | mobile/lib/providers/locale_provider.dart |
| 12 | Mobile settings dropdown | mobile/lib/screens/settings_screen.dart |
| Component | File | Purpose |
|---|---|---|
| Settings | src/caal/settings.py |
Language storage, prompt/greetings loading, voice map |
| Voice | voice_agent.py |
Pipeline config |
| Formatting | src/caal/utils/formatting.py |
Localized date/time |
| Webhooks | src/caal/webhooks.py |
/settings and /greetings API endpoints |
| Prompt EN | prompt/en/default.md |
English system prompt |
| Prompt FR | prompt/fr/default.md |
French system prompt |
| Prompt IT | prompt/it/default.md |
Italian system prompt |
| Greetings EN | prompt/en/greetings.txt |
English wake greetings |
| Greetings FR | prompt/fr/greetings.txt |
French wake greetings |
| Greetings IT | prompt/it/greetings.txt |
Italian wake greetings |
| Prompt PT | prompt/pt/default.md |
Portuguese (BR) system prompt |
| Greetings PT | prompt/pt/greetings.txt |
Portuguese (BR) wake greetings |
| Frontend config | frontend/src/i18n/config.ts |
Locale list |
| Frontend request | frontend/src/i18n/request.ts |
Cookie-based locale detection |
| Frontend EN | frontend/messages/en.json |
English UI translations |
| Frontend FR | frontend/messages/fr.json |
French UI translations |
| Frontend IT | frontend/messages/it.json |
Italian UI translations |
| Frontend PT | frontend/messages/pt.json |
Portuguese (BR) UI translations |
| Language selector | frontend/components/setup/language-selector.tsx |
Pre-wizard language choice |
| Settings panel | frontend/components/settings/settings-panel.tsx |
In-app language switching |
| Mobile provider | mobile/lib/providers/locale_provider.dart |
Locale state management |
| Mobile EN | mobile/lib/l10n/app_en.arb |
English mobile translations |
| Mobile FR | mobile/lib/l10n/app_fr.arb |
French mobile translations |
| Mobile IT | mobile/lib/l10n/app_it.arb |
Italian mobile translations |
| Mobile PT | mobile/lib/l10n/app_pt.arb |
Portuguese (BR) mobile translations |