Работа с названиями языков в JavaScript строится на стандарте BCP 47
и наборе международных правил локализации. В основе лежит задача
преобразования языковых тегов вида en, en-US,
zh-Hans, sr-Cyrl в человекочитаемые названия,
зависящие от выбранной локали отображения.
Ключевым инструментом выступает Intl.DisplayNames,
позволяющий получать корректные локализованные названия языков без
ручных словарей и условных конструкций.
Языковые коды представляют собой структурированные строки, состоящие из нескольких компонентов:
en, ru,
fr, zhUS, GB,
CN, RULatn,
Cyrl, Hans, HantПримеры:
en — английскийen-US — американский английскийen-GB — британский английскийzh-Hans — китайский (упрощённая письменность)zh-Hant — китайский (традиционная письменность)sr-Cyrl — сербский (кириллица)Структура BCP 47 важна тем, что позволяет точно идентифицировать вариант языка, а не только его базовую форму.
Для преобразования языковых кодов в человекочитаемые названия
используется Intl.DisplayNames с параметром:
const displayNames = new Intl.DisplayNames('ru', { type: 'language' });
Первый аргумент определяет локаль вывода, второй — тип отображаемых сущностей.
const dn = new Intl.DisplayNames('ru', { type: 'language' });
dn.of('en'); // "английский"
dn.of('fr'); // "французский"
dn.of('ja'); // "японский"
dn.of('zh'); // "китайский"
Вывод зависит от выбранной локали отображения. Например:
const dn = new Intl.DisplayNames('en', { type: 'language' });
dn.of('ru'); // "Russian"
dn.of('de'); // "German"
При использовании составных кодов учитываются региональные и письменные расширения.
const dn = new Intl.DisplayNames('ru', { type: 'language' });
dn.of('en-US'); // "американский английский"
dn.of('en-GB'); // "британский английский"
dn.of('zh-Hans'); // "китайский (упрощённое письмо)"
dn.of('zh-Hant'); // "китайский (традиционное письмо)"
В разных локалях результат будет различаться:
const dnEn = new Intl.DisplayNames('en', { type: 'language' });
dnEn.of('zh-Hans'); // "Simplified Chinese"
dnEn.of('zh-Hant'); // "Traditional Chinese"
Опция languageDisplay управляет уровнем детализации
отображаемого языка.
Доступные значения:
standard — стандартное название языкаdialect — диалектная форма с акцентом на региональные
различияconst standard = new Intl.DisplayNames('ru', {
type: 'language',
languageDisplay: 'standard'
});
const dialect = new Intl.DisplayNames('ru', {
type: 'language',
languageDisplay: 'dialect'
});
standard.of('en-US');
dialect.of('en-US');
В диалектном режиме чаще проявляется различие между вариантами одного языка, особенно для английского, китайского, португальского.
При передаче некорректного или неизвестного значения поведение зависит от реализации:
const dn = new Intl.DisplayNames('ru', { type: 'language' });
dn.of('qaa'); // поведение зависит от движка
В современных реализациях чаще всего применяется безопасный fallback, не вызывающий ошибок.
Некоторые языки требуют явного указания письменности:
zh-Hans, zh-Hantsr-Cyrl, sr-Latnuz-Cyrl, uz-Latnconst dn = new Intl.DisplayNames('ru', { type: 'language' });
dn.of('sr-Cyrl'); // "сербский (кириллица)"
dn.of('sr-Latn'); // "сербский (латиница)"
Эта детализация критична для интерфейсов, где различие письменности влияет на восприятие текста.
Один и тот же код языка может иметь разные отображения:
const ru = new Intl.DisplayNames('ru', { type: 'language' });
const de = new Intl.DisplayNames('de', { type: 'language' });
ru.of('de'); // "немецкий"
de.of('de'); // "Deutsch"
Таким образом, Intl.DisplayNames не просто переводит
код, а адаптирует его под культурные нормы выбранной локали.
При работе с наборами языков часто используется единый экземпляр
DisplayNames, позволяющий избежать ручных таблиц
соответствий:
const dn = new Intl.DisplayNames('ru', { type: 'language' });
const languages = ['en', 'fr', 'de', 'es', 'ja'];
languages.map(code => dn.of(code));
Результат формируется динамически на основе локали и встроенных данных движка JavaScript.
Языковые коды часто поступают из API, браузерных настроек или баз данных пользователей:
navigator.languageAccept-Language HTTP заголовокconst userLang = 'en-GB';
const dn = new Intl.DisplayNames('ru', { type: 'language' });
dn.of(userLang); // "британский английский"
Составные коды интерпретируются автоматически без дополнительного парсинга.
Intl.Locale позволяет структурировать языковой тег и
извлекать его компоненты:
const locale = new Intl.Locale('zh-Hans-CN');
locale.language; // "zh"
locale.script; // "Hans"
locale.region; // "CN"
В сочетании с Intl.DisplayNames это используется для
построения интерфейсов локализации:
const dn = new Intl.DisplayNames('ru', { type: 'language' });
dn.of(locale.toString()); // "китайский (упрощённое письмо, Китай)"
Создание Intl.DisplayNames включает инициализацию
локализационных данных, поэтому повторное использование экземпляра
предпочтительнее многократного создания:
const dn = new Intl.DisplayNames('ru', { type: 'language' });
// повторное использование
dn.of('en');
dn.of('fr');
dn.of('de');
Это особенно важно при обработке больших списков языков или рендеринге интерфейсов.
Названия языков не являются статическими строками. Они зависят от:
languageDisplayВ разных средах возможны незначительные различия в формулировках, порядке слов и наличии уточнений (например, указание письменности или региона).
При работе с пользовательскими интерфейсами часто требуется нормализация:
const dn = new Intl.DisplayNames('ru', { type: 'language' });
const map = Object.fromEntries(
['en-US', 'en-GB', 'fr', 'de'].map(code => [code, dn.of(code)])
);
Такая структура позволяет строить словари отображения без ручного перевода.
Механизм отображения языков используется в следующих областях:
В этих сценариях критична консистентность отображения и соответствие
международным стандартам, что обеспечивается встроенной поддержкой ICU и
Intl.DisplayNames.