Core Concepts
Language, alias, provider, mapping — and the one invariant that makes resolution a function.
Four nouns. Everything else in the API is a view over them.
Language
A language the platform can translate, identified by a canonical code in BCP-47 casing: en, pt-BR, zh-Hans, sr-Latn.
Languages come in two kinds:
- base — no qualifier:
en,de,ceb. Its own code is what providers receive; nothing needs configuring. - regional — carries a script, a region or both:
pt-BR,zh-Hans,sr-Latn-RS. These are the ones providers disagree about, and the ones the catalog exists to pin down.
A regional language points at its base (pt-BR → pt), which is what makes the fallback in Resolution Ladder possible.
Why
ceb is a base language
"Base" means no qualifier, not two letters. Cebuano's canonical code is ceb — three letters, no script, no region — so it behaves like en: it needs no per-provider row.
Alias
Any other spelling that resolves to a language. Aliases are stored normalised — lowercase, - separated — and matching is case- and separator-insensitive, so pt_BR matches the alias pt-br without a row of its own.
They come from three places:
- console — every code the legacy database held for that language, including the losing spellings from ambiguous pairs
- curated — ISO 639-2/3 codes (
deu,ger,zho) and deprecated ISO 639-1 ones (iw→he,in→id) that TMS exports still emit - manual — anything an operator adds when a new integration turns up with its own dialect
An alias belongs to exactly one language
alias is globally unique. Inbound resolution has to be a function — the same code must always mean the same language. The console allowed zh-CN to sit on both "Chinese (PRC)" and "Chinese (Simplified)"; the seed builder picks a winner once and records the loser in its report rather than leaving a coin flip on the hot path.
See Aliases and Normalisation.
Provider
A translation engine, identified by the same code provider_credentials uses: deepl_api, openai_api, microsoft_translator.
Model-level rows from the console (OpenAiGPT4o_2024_11_20_Provider, Gemini_2_5_pro_Provider, …) collapse into their vendor's API provider, because language support is a property of the vendor endpoint, not of the checkpoint behind it — and provider_credentials already models the model as a model_id configuration field under one credential. Every collapsed name survives as a provider alias, so the old identifiers keep working.
Each provider also carries a fallback policy, which decides what happens for a regional language nobody has configured. See Fallback Policies.
Mapping
One row: this provider, this language, this code.
Two things about mappings surprise people:
They are overrides, not a support matrix. A missing row means "nothing special to say", not "unsupported". Most languages need no row at all — a base language resolves to its own code. Genuinely unsupported pairs are recorded explicitly, with is_supported: false.
There is exactly one per pair. This is the invariant the service is built on:
What the legacy console did instead
In the console, translation_provider_supported_region_codes is a plain many-to-many between a provider and a region-code row. Nothing stopped one provider from being linked to several codes of the same language, and 446 of 2 467 pairs were — 330 of them with codes differing by more than casing (es-LA / ES-LA / es-419). Django resolved it with .first(): whichever row Postgres happened to return. The code sent to a provider was effectively arbitrary and could change after a VACUUM.
Here, the choice is made once at seed time by documented rules, every runner-up is kept as an inbound alias so nothing that used to resolve stops resolving, and an operator can re-pin any pair from the matrix.
How they fit together
inbound code ──normalise──▶ alias ──▶ LANGUAGE ◀── base language
│
provider name ──normalise──▶ alias ──▶ PROVIDER
│
MAPPING (provider, language) ──▶ code on the wire
│
(missing) ──▶ fallback policy
Next
- Resolution Ladder — the exact order the lookup runs in
- Language Catalog — what is in the catalog and where it came from
- Errors and Conventions — response shapes, versioning, caching