Лестница резолвинга
Точный порядок работы /v1/resolve и что означает каждое значение match.
Резолвинг — это два поиска и лестница. Всё работает на снапшоте каталога в памяти: ни одного запроса к базе на запрос пользователя.
Шаг 1 — найти провайдера
Присланное значение нормализуется и сверяется с кодами провайдеров, затем с их алиасами. Нет совпадения — provider_not_found (404).
Шаг 2 — найти язык
Присланное значение нормализуется (см. Aliases and Normalisation) и сверяется сначала с каноническими кодами, потом с алиасами. Канонические коды регистрируются первыми и никогда не перезаписываются, так что алиас не может затенить настоящий код языка.
Если точного совпадения нет, код постепенно укорачивается:
zh-Hant-HK → zh-hant → zh-hk → zh
Обе оси квалификаторов присутствуют, потому что провайдеры не согласны, какая из них важна: DeepL хочет zh-Hans, Papago хочет zh-CN. Тег с неизвестным квалификатором деградирует до языка, который он уточняет, а не падает в 404: de-AT-1996 резолвится в de-AT, что видно в matched_alias.
Всё равно ничего? language_not_found (404).
Шаг 3 — лестница
Теперь, когда оба известны, по порядку:
1. exact — явная строка для этой пары
Кто-то настроил. Возвращаем её код.
{ "provider": "deepl_api", "language": "zh-CN", "code": "zh-Hans", "match": "exact" }
Если в строке is_supported: false — останавливаемся: supported: false, code: null. Пара известна как нерабочая, запрос делать не нужно.
2. variant — менее специфичный тег того же языка имеет строку
Нет строки для zh-Hant-HK, но есть для zh-TW? Берём её и называем в via_language.
{ "language": "zh-Hant-HK", "code": "zh-Hant", "match": "variant", "via_language": "zh-TW" }
3. canonical — язык без квалификатора
Базовому языку маппинг не нужен: его собственный код и есть ответ.
{ "language": "uk", "code": "uk", "match": "canonical" }
Это точно повторяет консоль
get_lang_code_by_provider_and_language начинается с if language.abbreviation: return language.abbreviation — он возвращает двухбуквенный код ещё до того, как посмотрит на провайдера. Именно поэтому консоль хранила коды только для региональных языков, и именно поэтому базовый язык без строки — норма, а не пробел.
4. Fallback policy провайдера
Достигается только для регионального языка, для которого ничего не настроено. Как выбирать — Fallback Policies.
| Политика | Результат | match |
|---|---|---|
base_language |
код базового языка — pt-BR → pt |
base_language |
passthrough |
канонический код без изменений | passthrough |
strict |
supported: false, code: null |
— |
Все провайдеры сейчас едут на base_language — это то, что консоль делает сегодня (lang_region_list.code[:2]). Почему strict не дефолт — Fallback Policies.
Как читать match на стороне вызывающего
match |
Уровень доверия | Что делать |
|---|---|---|
exact |
Настроено осознанно | Использовать. |
variant |
Настроено для близкого тега | Использовать. Стоит закрепить, если повторяется. |
canonical |
Нечего решать | Использовать. |
base_language |
Выведено — регион потерян | Использовать, но если региональная точность критична — проверьте пару. |
passthrough |
Выведено — не проверено против этого API | Использовать и следить за ошибками провайдера. |
Большинство вызывающих может вообще игнорировать match и просто отправлять code. Он для тех, кто не может.
Разобранный пример
GET /v1/resolve?provider=deepl_api&language=zh_hant_hk
deepl_apiсовпадает с кодом провайдера.zh_hant_hkнормализуется вzh-hant-hk. Канонического совпадения нет; цепочка пробуетzh-hant— это алиасzh-TW. Язык =zh-TW,matched_alias: "zh-hant".- У DeepL есть явная строка для
zh-TW→zh-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 }
Попробуйте сами
На странице Tools в админке есть живой тестер, выполняющий тот же код, — можно проверить пару, не пиша запрос.
Далее
- Fallback Policies — для чего каждая политика
- Закрепить код провайдера — как превратить выведенный ответ в
exact