# Languages

> Offer your coworker in more than English — choose the supported languages + a default, pass the user's language at mint, and let end-users switch in the built-in picker.

Coworkkit is closed-loop, so multi-language is **one setting**, not three: you say which languages a coworker offers, and we drive the whole voice stack — speech recognition, the brand voice, and what the agent says — in the resolved language. There are two levels of control: you choose what a coworker *offers*; each end-user picks theirs per session.

## 1 · Offer languages (the portal)

In your coworker's **Configure** tab, choose the **supported languages** and a **default**. Only languages we have verified for the selected voice are offered, and the default must be one of the supported set. A coworker left with a single language behaves exactly as before — nothing to change.

That is the entire setup. A coworker configured for German now recognizes German, speaks with a German voice, and replies in German.

## 2 · Pass the user's language at mint

If your app already knows a user's language, project it at mint — the one trusted, server-side place you hand us per-user context. Add it to `mintSession`:

```ts
// your token route (server-side)
const session = await mintSession(process.env.COWORKKIT_API_KEY!, {
  userId: user.id,
  user: { languageCode: user.locale }, // e.g. "de-DE"
});
```

We validate `languageCode` against the coworker's supported set: a supported language is used, anything else falls back to the default. We **never store it** — your app stays the source of truth for who your user is (see [the closed loop](/docs/how-it-works)).

To let the built-in picker (below) and the browser locale reach your token route, forward the context `getToken` receives:

```tsx
getToken={(ctx) =>
  fetch("/api/coworkkit/session", {
    method: "POST",
    body: JSON.stringify({ language: ctx?.language }),
  }).then((r) => r.json())
}
```

## 3 · Let end-users switch (the built-in picker)

When a coworker offers more than one language, the button's settings panel shows a language picker — no work for you. A user's choice is remembered in their browser (per app), so a returning user keeps it; we store nothing server-side, and cross-device preference stays your app's job. Switching mid-call restarts the session — language is fixed when the agent starts — and only after the user confirms.

With no explicit choice, a walk-up user's **browser locale** is requested automatically: if it is supported, they get their language on the very first session, with zero integration work.

## Resolution — it never lands on nothing

- the user's pick (the picker, or your mint `languageCode`) — if it is supported; otherwise
- the browser locale — if it is supported; otherwise
- the coworker's default.

## Localizing the button's own text

The agent's speech follows the session language automatically, and so does the SDK's own interface text — the button tooltips, the "enable sound" prompt, the caption labels. To pin that text to a specific language regardless of the session, set the `locale` prop:

```tsx
<CoworkkitProvider getToken={getToken} locale="de-DE">
```

## A note on your glossary

Your [package](/docs/actions-surfaces) — tone, app description, boundaries — carries its spirit into any language: an English-authored persona still shapes a German session. The one exception is the **glossary**. Its say-X-not-Y pairs are literal words, so author them in the language your users will speak; cross-language, they apply best-effort.
