Skip to content

User locale

The browser sends its current language with each request. The server exposes the resolved language as ctx.locale and stores a user’s chosen locale in the session at login. Magic-link email can use that value for translated text and locale-specific URLs. If no valid request or session locale exists, the app’s boot default applies, then English.

  • The client sends document.documentElement.lang as an X-Locale header. The server uses Accept-Language when that header is absent or invalid.
  • The server exposes it as an always-present ctx.locale; handlers can answer locale-dependently and derive mail locales from it.

2. Session persistence (SessionUser.locale in the JWT)

Section titled “2. Session persistence (SessionUser.locale in the JWT)”
  • The user’s chosen locale is written into the JWT at login (locale claim) and threaded through login / invite-accept / MFA handlers.
  • SessionUser.locale survives requests made without a browser locale signal. Work that explicitly carries that user can use the same value.
  • ctx.locale falls back from the live X-Locale signal to SessionUser.locale, keeping a consistent locale even when a request carries no browser locale.

All auth mails (signup, password-reset, email-verification, invite, account-unlock) render in the requester’s locale:

  • appUrl may be a function (locale) => string to build locale-aware landing paths (e.g. /de/...).
  • Mails derive the locale from ctx.locale / SessionUser.locale, never a hard-coded server default.
  • New outbound mails: always derive locale from ctx.locale (fallback SessionUser.locale), never hard-code a server default.
  • Use appUrl as (locale) => string when the landing path is locale-sensitive.