Аліаси та нормалізація
Як будь-яке написання коду потрапляє на правильну мову — включно з поламаними.
Коди приходять із експортів TMS, клієнтських API, таблиць і десятиліття накопичених інтеграцій. Вони мало в чому згодні між собою. Нормалізація — це те, що робить їх порівнюваними.
Дві форми коду
Ключ пошуку — нижній регістр, роздільник -, пробіли зрізані. pt_BR, PT-BR, pt-br і pt - br стають pt-br. Аліаси зберігаються в цій формі й звіряються точною рівністю, тож гарячий шлях — це одне індексоване порівняння, а не LIKE-скан.
Канонічна форма — регістр BCP-47: первинний субтег нижнім регістром, скрипт із великої, регіон великими. pt-BR, zh-Hans, sr-Latn-RS. Саме це повертає API і саме це варто зберігати.
Канонізація також виправляє порядок субтегів. Консоль тримає і sr-Latn-RS, і sr-RS-Latn для однієї мови; BCP-47 ставить скрипт перед регіоном, тож обидва парсяться в один тег і рендеряться як sr-Latn-RS.
Виправлення гомогліфів
Перед обчисленням обох форм коди проходять через перевірку гомогліфів.
Це не гіпотетично. База консолі містить сeb для себуанської, де перший символ — U+0441 CYRILLIC SMALL LETTER ES, а не ASCII c. Він виглядає ідентично в будь-якому шрифті й ніколи не збігається з тим, що надсилає викликач, — саме так себуанська стала фактично недосяжною для кількох провайдерів.
Виправлення мапить кириличні літери, візуально ідентичні латинським — а е о р с х у і ј, — і лише коли результат стає чистим ASCII, тож справді кириличне значення лишається недоторканим, а не спотвореним. Повноширинна латиниця (en) згортається через NFKC у тому ж проході.
Звідки беруться аліаси
| Джерело | Приклади | Навіщо |
|---|---|---|
canonical |
власний код мови | завжди присутній |
console |
es-la, ES-LA для es-419 |
усі написання з легасі-бази, включно з програвшими в неоднозначних парах |
curated |
deu, ger, zho, iw, in, ji, mo |
ISO 639-2/3 і застарілі ISO 639-1, які досі шлють експорти TMS |
provider |
написання провайдера, що відрізняється від переможця | тримає програвшу сторону згорнутої пари досяжною |
manual |
те, з чим прийшла нова інтеграція | додається з [[Admin-Panel |
Унікальність
Аліас належить рівно одній мові, глобально. Це забезпечує база даних, а не домовленість.
Це важливо, бо вхідний резолвінг мусить бути функцією. Консоль дозволяла zh-CN бути одночасно в «Chinese (PRC)» і «Chinese (Simplified)», fa-AF — у «Dari» і «Farsi (Afghanistan)», bn-BD — у двох бенгальських рядках. get_language_by_code резолвив це через .first() — невпорядкований запит.
Білдер сіду вирішує кожен конфлікт один раз:
- мова, чий канонічний код і є цим аліасом,
- далі та, яку консоль позначила
is_default, - далі та, у якої більше мапінгів провайдерів — тобто та, яку прод справді використовує,
- далі найменший легасі-id, тобто те, що
.first()віддає сьогодні.
Кожне рішення перелічене в data/seed/REPORT.md, тож ті, що варті суперечки, видимі, а не поховані.
Для чого аліас не потрібен
Для варіантів регістру й роздільників. pt_BR уже збігається з аліасом pt-br; додавати pt_br окремим рядком — надлишково.
Перевірити код, не резолвлячи його
/v1/normalize відповідає на питання без провайдера — що це за мова і як ми її називаємо?
curl "https://languages.service.custom.mt/v1/normalize?language=ZH_HANS"
{ "query": "ZH_HANS", "known": true, "matched_alias": "zh-hans",
"language": { "code": "zh-CN", "name": "Chinese (Simplified)", "aliases": ["chs", "zh-hans", …] } }
На відміну від інших ендпоінтів, невідомий код тут не помилка — known: false приходить із 200. Це дозволяє класифікувати весь список за один прохід, а не ловити 404. Див. Нормалізація вхідних кодів.
Далі
- Language Catalog — що в каталозі
- Resolution Ladder — що відбувається після визначення мови