Repository navigation
Configuration
Louis Wright edited this page Oct 14, 2026
·
3 revisions
📄 Mirrors
docs/configuration.mdin the main repo — the repo version is canonical.
Status: planned / pre-release. This page documents the intended API of next-tongue. Nothing is published yet; names may change before v1.0. See ROADMAP.
All options live in tongue.config.ts at the project root. It is read at build time by withTongue and the CLI (tongue build), and a serialisable subset (locales, default locale, routing) is inlined into the proxy and runtime — the config file itself is never shipped to the browser.
import { defineConfig } from 'next-tongue/config';
export default defineConfig({
// Required
locales: ['en', 'de', 'fr'], // BCP 47 tags; order is used for hreflang and localeParams()
defaultLocale: 'en', // must be in locales; the source language for extract/translate
// Messages
messages: './messages/{locale}.json', // or './messages/{locale}/{namespace}.json'
fallback: { 'de-AT': 'de' }, // per-locale fallback chain; ends at defaultLocale (default: CLDR parents)
timeZone: 'Europe/Berlin', // zone for static/server date formatting (default: 'UTC'), see ADR 0008
sources: [async () => fetchFromDb()], // build-time DB/CMS messages, merged with files (v0.4), see database-messages.md
sourcesOnError: 'fail', // 'fail' | 'use-cache'
pseudo: { locale: 'en-XA', enabled: 'dev', expand: 0.35 }, // pseudo-localisation (v0.2), see dev-tools.md
// Client delivery (ADR 0009)
client: { split: 'none' }, // 'none' (all locales of used keys) | 'locale' (opt-in, later)
devOverlay: true, // dev-only panel, stripped from production (v0.3)
// Routing (see routing-and-proxy.md)
routing: {
prefix: 'as-needed', // 'always' | 'as-needed' | 'never' (default: 'as-needed')
localeDetection: true, // Accept-Language + cookie, in proxy.ts only (default: true)
localeCookie: { name: 'TONGUE_LOCALE', maxAge: 60 * 60 * 24 * 365, sameSite: 'lax' }, // or false
domains: [ // optional, overrides prefix per domain
{ domain: 'example.de', defaultLocale: 'de', locales: ['de'] },
],
pathnames: { // optional localized pathnames
'/about': { de: '/ueber-uns', fr: '/a-propos' },
},
},
// Formatting presets used by getFormat()/useFormat() and ICU {x, number, ::preset}
formats: {
number: { price: { style: 'currency', currency: 'EUR' } },
dateTime: { short: { dateStyle: 'medium' } },
},
// Compiler
outDir: '.tongue', // generated modules + types (default: '.tongue')
strict: {
missing: 'error', // 'error' | 'warn' | 'off' — key missing in a locale
unused: 'warn', // key never referenced in source
mismatch: 'error', // ICU args/plural categories differ from defaultLocale
a11y: 'error', // missing <html lang>/dir (tongue check, v0.4)
bidi: 'warn', // bidi issues in RTL messages (tongue check, v0.4)
stale: 'warn', // source changed since translation (tongue.lock hashes)
length: 'warn', // target longer than $meta.maxLength (v0.4)
},
// CLI: tongue translate (see ai-translation.md)
translate: {
baseURL: 'https://api.openai.com/v1', // any OpenAI-compatible endpoint
model: 'gpt-4.1-mini',
apiKeyEnv: 'TONGUE_API_KEY', // name of the env var; the key is never stored in config
glossary: './tongue.glossary.json',
lockfile: './tongue.lock',
context: 'A B2B invoicing app. Formal tone (Sie in German).',
},
});| Option | Type | Default | Notes |
|---|---|---|---|
locales |
readonly string[] |
— (required) | Validated as BCP 47. Becomes the Locale union type. |
defaultLocale |
Locale |
— (required) | |
messages |
string |
'./messages/{locale}.json' |
Must contain {locale}; may contain {namespace}. JSON in v0.1; JSONC and YAML are under consideration for v0.3. |
fallback |
Partial<Record<Locale, Locale>> |
CLDR parent locales | Resolved at compile time — missing keys are filled from the chain, so there is no runtime lookup. Without an entry, a locale falls back along CLDR parent locales (de-AT → de, zh-Hant-HK → zh-Hant, never across scripts such as zh-Hant → zh-Hans), then defaultLocale. Explicit entries override. |
timeZone |
IANA zone string | 'UTC' |
Passed explicitly to every Intl.DateTimeFormat; the server's default zone is never used. Override per call with getFormat(locale, { timeZone }) or per subtree with <TongueProvider timeZone>. See ADR 0008. |
sources |
Array<() => Promise<Record<Locale, Record<string, Record<string, string>>>>> |
[] |
Build-time database/CMS messages, merged after files in order, then compiled and typed. See Database messages. |
sourcesOnError |
'fail' | 'use-cache' |
'fail' |
'use-cache' reuses .tongue/sources.json from the last successful build. |
pseudo |
{ locale?: string; enabled?: 'dev' | 'always' | false; expand?: number } | boolean |
false |
Adds a pseudo-locale (default en-XA) generated from defaultLocale; true = { locale: 'en-XA', enabled: 'dev', expand: 0.35 }. Never part of localeParams() in production unless 'always'. See Dev tools. |
client.split |
'none' | 'locale' |
'none' |
'locale' (opt-in, after the benchmark) splits per-key modules per locale with dynamic imports; see ADR 0009. |
devOverlay |
boolean |
true |
Dev-only overlay; never included in production builds. See Dev tools. |
routing.prefix |
'always' | 'as-needed' | 'never' |
'as-needed' |
'as-needed' redirects /{defaultLocale}/* to /*. 'never' (v0.4) requires cookie- or domain-based routing. output: 'export' supports only 'always'. |
routing.localeDetection |
boolean |
true |
Only the proxy reads headers/cookies. |
routing.localeCookie |
{ name, maxAge, sameSite?, secure?, path? } | false |
{ name: 'TONGUE_LOCALE', maxAge: 1y, sameSite: 'lax', path: '/' } |
sameSite: 'strict' is allowed but discouraged: the cookie is then not sent on cross-site navigation, so returning visitors from external links get the detected locale instead of the one they chose (next-international#453). secure defaults to true on HTTPS. |
routing.domains |
DomainConfig[] |
undefined |
|
routing.pathnames |
Record<string, Partial<Record<Locale, string>>> |
undefined |
Typed: Link href only accepts known internal pathnames when set. |
formats |
{ number?, dateTime?, list? } |
{} |
Intl options by preset name. |
outDir |
string |
'.tongue' |
Git-ignore it. |
strict.* |
'error' | 'warn' | 'off' |
see above | Used by both the build and tongue check. |
translate.* |
object | undefined |
Only read by tongue translate. |
| Variable | Used by | Purpose |
|---|---|---|
TONGUE_API_KEY (configurable) |
tongue translate |
LLM API key |
TONGUE_DEBUG=1 |
withTongue, CLI |
Verbose compiler logs |
Guides
- Getting Started
- Configuration
- Routing and Proxy
- Server Components
- Client Components
- Server Actions
- ICU Messages
- Type Safety
- Cache Components and PPR
- Static Export
- Metadata SEO and hreflang
- Database and CMS Messages
- Dev Tools
- Translator Workflow
- Per-user Preferred Language
- CLI
- AI Translation
- Testing
- VS Code Extension
- Migration from next intl
- Migration from next international (deferred)
Reference