Home/Languages/Language Catalog ENУКРРУС API Reference (ReDoc) ↗

Language Catalog

What is in the catalog, where it came from, and what to do with the odd rows.

348 languages, 237 aliases, seeded from the legacy console database and curated from there.

Browsing it

curl "https://languages.service.custom.mt/v1/languages?q=portuguese"
curl "https://languages.service.custom.mt/v1/languages?kind=regional&limit=50"
curl "https://languages.service.custom.mt/v1/languages/pt-BR"

q matches the name, the canonical code and every alias, so Brazil, pt-br and por-br all find the same row.

What a language row carries

Field Meaning
code canonical BCP-47 code — store this one
name English display name
kind base (no qualifier) or regional
base_language_code for a regional variant, the language it qualifies
script, region parsed out of the code, for filtering
is_active false for rows kept for traceability but not usable
also_known_as names folded in when duplicate console rows merged
aliases every inbound spelling that resolves here
legacy_language_ids the cabinet_language.id values this row came from

legacy_language_ids is the audit trail back to the console. More than one id means the seed merged duplicates.

Merges

Five pairs of console rows described the same language under different ids and were folded together:

Canonical Kept Folded in
fa Persian (41) Persian (222) — a straight duplicate
uk Ukrainian (320) Ukrainian (Ukraine uk) (162)
zh-CN Chinese (Simplified) (217) Chinese (PRC) (271)
zh-TW Chinese (Traditional) (176) Chinese (Taiwan) (278)
nb Norwegian (Bokmal) (221) Norwegian (Norway) (203)

Both ids stay in legacy_language_ids and the discarded name is kept in also_known_as, so a lookup by either console id still lands correctly.

Inactive rows

Six console rows had neither a two-letter abbreviation nor any region code — no code at all, so nothing could ever resolve to them:

Serbian (Cyrillic-Trados) · Chinese (SmartCat) · Serbian (Cyrillic-XTM) · Serbian (Latin-Trados) · Chinese (Hong Kong-2) · Chin

They are imported with a placeholder x-… code and is_active: false rather than dropped, so the information is not lost and an operator can give them a real code from the admin panel. Filter them out with ?active=true.

Most are integration-specific duplicates of languages that already exist (Serbian (Cyrillic-Trados) is sr-Cyrl). Chin is a real language family that never got a code.

Choosing the canonical code

Where a language had several spellings, the canonical one is chosen by:

  1. a usable two-letter abbreviation — those rows are the ISO 639-1 base languages,
  2. otherwise: the console's is_default flag, an explicit human choice,
  3. then fewer subtags — a canonical code should carry no qualifier it does not need. Cebuano is ceb, not ceb-Latn-PH; Serbian Cyrillic is sr-Cyrl, not sr-Cyrl-RS. The dropped qualifiers stay as aliases, so precision is preserved on the way in,
  4. then the most textbook BCP-47 spelling,
  5. then the lowest legacy id — what the console's unordered .first() returns today, so ties keep current behaviour.

Note this is not how a provider's outbound code is chosen. What a provider's API accepts is a fact about that API, and shortness is irrelevant to it — see Providers and Vendors.

Known gaps worth fixing

The catalog inherited the console's blind spots. These are visible in the admin panel's coverage view and are good first edits:

Baidu and traditional Chinese

Baidu uses its own code set (zh, cht, jp, kor), not BCP-47. With no explicit row, zh-TW falls back to zh — which is what production sends today, and it is wrong: Baidu wants cht. Pinning it takes one edit; see Pin a provider code.

[!warning] DeepL's regional English and Portuguese DeepL has three explicit rows (zh-CN, zh-TW, pt-BR). en-GB falls back to en, though DeepL accepts and distinguishes EN-GB and EN-US.

Neither is a regression — both match what the console does now. They are simply now visible.

Next