Как работать с языковыми тегами, такими как en-US и fr-CA

Поймите структуру и значение языковых тегов BCP 47, чтобы принимать более обоснованные решения по интернационализации

Введение

Языковые теги — это стандартизированные коды, которые идентифицируют конкретные языки и их региональные вариации. Эти теги используются во всей работе по интернационализации. Когда вы определяете предпочтительный язык пользователя, браузер возвращает языковые теги. Когда вы форматируете даты или числа, вы передаете языковые теги в API Intl. Когда вы загружаете переводы, вы используете языковые теги, чтобы определить, какой контент отображать.

Понимание того, как работают эти теги, помогает принимать более обоснованные решения о выборе языка, поведении при отсутствии данных и организации контента. Этот урок объясняет структуру языковых тегов и показывает, как работать с ними в JavaScript.

Что такое языковые теги

Языковой тег — это строка, такая как en, en-US или zh-Hans-CN, которая идентифицирует язык и, при необходимости, указывает сценарий и регион. Эти теги соответствуют стандарту BCP 47, который поддерживается Рабочей группой по инженерным задачам Интернета (IETF) и Управлением по присвоению номеров в Интернете (IANA).

BCP 47 расшифровывается как "Best Current Practice 47" (Лучшие текущие практики 47). Стандарт определяет, как создавать языковые теги из более мелких компонентов, называемых подтегами. Каждый подтег представляет собой определенный аспект языка, например, какой язык используется, какая система письма применяется или с какой страной он связан.

Каждый язык программирования и библиотека интернационализации используют теги BCP 47. Эта согласованность означает, что вы можете использовать одни и те же языковые идентификаторы во всем вашем приложении: от определения языка в браузере до серверного форматирования и имен файлов перевода.

Структура языковых тегов

Языковые теги состоят из подтегов, разделенных дефисами. Три наиболее распространенных подтега — это язык, сценарий и регион. Эти подтеги всегда появляются в этом конкретном порядке, если они присутствуют.

Подтег языка идет первым и является единственным обязательным компонентом. Он использует двух- или трехбуквенный код из стандарта ISO 639. Например, en представляет английский, fr — французский, а zh — китайский.

Подтег сценария идет вторым, если он присутствует. Он использует четырехбуквенный код из стандарта ISO 15924, который идентифицирует систему письма. Например, Latn представляет латинский алфавит, Cyrl — кириллицу, а Hans — упрощенные китайские иероглифы.

Подтег региона идет последним, если он присутствует. Он использует двухбуквенный код из стандарта ISO 3166-1, который обычно представляет страну. Например, US представляет Соединенные Штаты, CA — Канаду, а CN — Китай.

Примеры распространённых языковых тегов

Вот примеры, демонстрирующие различные уровни специфичности, которые можно выразить с помощью языковых тегов.

Простые теги, содержащие только язык:

  • en - английский (без указания конкретного региона или письменности)
  • fr - французский (без указания конкретного региона или письменности)
  • es - испанский (без указания конкретного региона или письменности)

Теги с указанием языка и региона:

  • en-US - английский, используемый в Соединённых Штатах
  • en-GB - английский, используемый в Великобритании
  • fr-CA - французский, используемый в Канаде
  • es-MX - испанский, используемый в Мексике

Теги с указанием языка, письменности и региона:

  • zh-Hans-CN - китайский с упрощёнными иероглифами, используемый в Китае
  • zh-Hant-TW - китайский с традиционными иероглифами, используемый на Тайване
  • sr-Latn-RS - сербский с латинским алфавитом, используемый в Сербии
  • sr-Cyrl-RS - сербский с кириллицей, используемый в Сербии

Уровень специфичности, который вам нужен, зависит от вашего приложения. Если вы только переводите текст, вам может понадобиться указание только языка и региона. Если вы работаете с языками, использующими несколько систем письма, вам понадобятся подтеги для письменности.

Конвенции написания языковых тегов

Языковые теги нечувствительны к регистру. Теги en-US, EN-US, en-us и En-Us представляют один и тот же язык. Однако существуют общепринятые правила использования заглавных и строчных букв, которые делают теги более читаемыми.

Подтеги языка обычно пишутся строчными буквами. Пишите en, а не EN или En.

Подтеги письменности обычно пишутся с заглавной первой буквой. Пишите Latn, а не latn или LATN.

Подтеги региона обычно пишутся заглавными буквами. Пишите US, а не us или Us.

Следование этим правилам делает теги более читаемыми и соответствует формату, используемому в документации и спецификациях. Однако ваш код должен принимать языковые теги независимо от регистра, так как формат официально нечувствителен к регистру.

Разбор языковых тегов с помощью JavaScript

JavaScript предоставляет конструктор Intl.Locale для разбора языковых тегов и извлечения их компонентов. Этот конструктор принимает строку с языковым тегом и возвращает объект со свойствами для каждого подтега.

const locale = new Intl.Locale("en-US");

console.log(locale.language);
// Вывод: "en"

console.log(locale.region);
// Вывод: "US"

Объект Intl.Locale имеет свойства для каждого компонента языкового тега. Эти свойства возвращают undefined, если соответствующий подтег отсутствует в исходном теге.

const simple = new Intl.Locale("fr");
console.log(simple.language);
// Вывод: "fr"

console.log(simple.region);
// Вывод: undefined

Вы можете разбирать теги с подтегами скрипта таким же образом.

const complex = new Intl.Locale("zh-Hans-CN");

console.log(complex.language);
// Вывод: "zh"

console.log(complex.script);
// Вывод: "Hans"

console.log(complex.region);
// Вывод: "CN"

Эта возможность разбора полезна, когда вам нужно принимать решения на основе конкретных компонентов языкового тега. Например, вы можете загружать разные шрифты в зависимости от скрипта или показывать различный контент в зависимости от региона.

Когда использовать конкретные или общие теги

Выбор уровня специфичности для языковых тегов зависит от того, какие аспекты языка и культуры ваше приложение должно учитывать.

Используйте только языковые теги, такие как en или fr, когда у вас есть единый перевод, подходящий для всех носителей этого языка. Это распространено для приложений с ограниченным бюджетом на локализацию или для языков с минимальными региональными различиями.

Используйте языковые и региональные теги, такие как en-US или fr-CA, когда вам нужно учитывать региональные различия в словарном запасе, орфографии или культурных особенностях. Британский и американский английский используют разные написания многих слов. Канадский и европейский французский имеют различия в словарном запасе и выражениях.

Используйте языковые, скриптовые и региональные теги, такие как zh-Hans-CN, когда вы работаете с языками, использующими несколько систем письма. Китайский язык может быть написан упрощенными или традиционными иероглифами. Сербский язык может быть написан латиницей или кириллицей. Подтег скрипта различает эти варианты.

Извлечение языковых кодов для файлов перевода

Многие системы перевода организуют файлы по языковым кодам. Вы можете извлечь только язык и регион из полного языкового тега, чтобы определить, какой файл перевода загрузить.

const userLanguage = "zh-Hans-CN";
const locale = new Intl.Locale(userLanguage);

const translationKey = `${locale.language}-${locale.region}`;
console.log(translationKey);
// Вывод: "zh-CN"

Этот подход работает даже в том случае, если языковой тег пользователя содержит компоненты, которые вам не нужны для выбора файла.

Некоторые приложения используют только языковой код без региона.

const userLanguage = "fr-CA";
const locale = new Intl.Locale(userLanguage);

const translationKey = locale.language;
console.log(translationKey);
// Вывод: "fr"

Структура, которую вы выбираете для имен файлов перевода, должна соответствовать тому, как вы извлекаете компоненты из языковых тегов.

Использование языковых тегов с API Intl

API Intl принимает языковые теги напрямую во всех своих конструкторах. Вам не нужно разбирать тег самостоятельно, если только вам не нужно анализировать конкретные компоненты.

const date = new Date("2025-03-15");

const usFormat = new Intl.DateTimeFormat("en-US").format(date);
console.log(usFormat);
// Вывод: "3/15/2025"

const gbFormat = new Intl.DateTimeFormat("en-GB").format(date);
console.log(gbFormat);
// Вывод: "15/03/2025"

API Intl использует языковой тег для определения, какие правила форматирования применять. Разные регионы форматируют даты, числа и валюты по-разному, даже если они говорят на одном языке.

Вы можете передать языковой тег, полученный из браузера, напрямую в конструкторы Intl.

const userLanguage = navigator.language;
const formatter = new Intl.NumberFormat(userLanguage);

console.log(formatter.format(1234.5));
// Вывод зависит от языка
// Для "en-US": "1,234.5"
// Для "de-DE": "1.234,5"

Это наиболее распространенный шаблон в клиентской интернационализации. Определите язык пользователя, а затем используйте этот языковой тег во всем приложении для соответствующего форматирования контента.

Обработка недопустимых языковых тегов

Intl.Locale выбрасывает RangeError, если передан недопустимый языковой тег. Вы должны обрабатывать эту ошибку при работе с языковыми тегами из ненадежных источников.

try {
  const locale = new Intl.Locale("invalid-tag-format");
} catch (error) {
  console.log(error.name);
  // Вывод: "RangeError"

  console.log(error.message);
  // Вывод: "недопустимый языковой тег: invalid-tag-format"
}

Большинство языковых тегов из браузеров являются допустимыми, но пользовательский ввод или внешние источники данных могут содержать некорректные теги. Оборачивание конструктора в обработку ошибок предотвращает сбои приложения из-за таких тегов.