Home/Resolving/Resolution Ladder ENУКРРУС API Reference (ReDoc) ↗

Resolution Ladder

The exact order /v1/resolve runs in, and what each match value means.

Resolution is two lookups and a ladder. All of it runs against an in-memory snapshot of the catalog — no query per request.

Step 1 — find the provider

The value you sent is normalised and matched against provider codes, then provider aliases. No match is provider_not_found (404).

Step 2 — find the language

The value you sent is normalised (see Aliases and Normalisation) and matched against canonical codes first, then aliases. Canonical codes are registered first and never overwritten, so an alias can never shadow a real language code.

If nothing matches exactly, the code is progressively shortened:

zh-Hant-HK  →  zh-hant  →  zh-hk  →  zh

Both qualifier axes appear because providers disagree about which one matters — DeepL wants zh-Hans, Papago wants zh-CN. A tag with an unknown qualifier degrades to the language it qualifies rather than 404ing: de-AT-1996 resolves to de-AT, reported in matched_alias.

Still nothing? language_not_found (404).

Step 3 — the ladder

Now that both are known, in order:

1. exact — an explicit row for this pair

Someone configured it. Return its code.

{ "provider": "deepl_api", "language": "zh-CN", "code": "zh-Hans", "match": "exact" }

If that row says is_supported: false, stop here: supported: false, code: null. The pair is known not to work and the request should not be attempted.

2. variant — a less specific tag of the same language has a row

No row for zh-Hant-HK, but one for zh-TW? Use it, and name it in via_language.

{ "language": "zh-Hant-HK", "code": "zh-Hant", "match": "variant", "via_language": "zh-TW" }

3. canonical — the language carries no qualifier

A base language needs no mapping: its own code is the answer.

{ "language": "uk", "code": "uk", "match": "canonical" }

This mirrors the console exactly

get_lang_code_by_provider_and_language starts with if language.abbreviation: return language.abbreviation — it returns the two-letter code before it ever looks at the provider. That is why the console only ever stored codes for regional languages, and why a base language with no row is normal rather than a gap.

4. The provider's fallback policy

Only reached for a regional language with nothing configured. See Fallback Policies for how to choose one.

Policy Result match
base_language the base language's code — pt-BRpt base_language
passthrough the canonical code unchanged passthrough
strict supported: false, code: null

Every provider currently ships with base_language, which is what the console does today (lang_region_list.code[:2]). See Fallback Policies for why strict is not a default.

Reading match as a caller

match Trust level What to do
exact Configured deliberately Use it.
variant Configured for a near tag Use it. Worth pinning if it recurs.
canonical Nothing to decide Use it.
base_language Derived — you lose the region Use it, but if regional fidelity matters to you, check the pair.
passthrough Derived — untested against this API Use it, and watch for provider errors.

Most callers can ignore match entirely and just send code. It is there for the ones that cannot.

Worked example

GET /v1/resolve?provider=deepl_api&language=zh_hant_hk

  1. deepl_api matches a provider code.
  2. zh_hant_hk normalises to zh-hant-hk. No canonical code matches; the chain tries zh-hant — that is an alias of zh-TW. Language = zh-TW, matched_alias: "zh-hant".
  3. DeepL has an explicit row for zh-TWzh-Hant.
{ "query": "zh_hant_hk", "provider": "deepl_api", "language": "zh-TW",
  "code": "zh-Hant", "supported": true, "match": "exact",
  "matched_alias": "zh-hant", "via_language": null }

Try it yourself

The admin panel's Tools page has a live tester that runs this exact code path, so you can check a pair without writing a request.

Next