Intl.Locale API
Разбирайте, изменяйте и анализируйте идентификаторы локалей с помощью структурированных JavaScript-объектов
Введение
Когда вы разрабатываете приложения для разных языков и регионов, вы сталкиваетесь с идентификаторами локалей, такими как en-US, fr-FR или zh-Hans-CN. Эти строки встречаются в API браузера, HTTP-заголовках и пользовательских настройках. Они содержат информацию о языке, регионе, системе письма и предпочтениях форматирования.
API Intl.Locale преобразует эти непонятные строки в структурированные объекты, которые можно просматривать и изменять. Вместо ручного разбора строк или попыток угадать, что значит zh-Hans-CN, вы создаёте объект локали и напрямую читаете его свойства.
В этом руководстве объясняется, как работают идентификаторы локалей, как использовать API Intl.Locale для работы с ними и в каких случаях структурированные объекты локалей реально помогают решать задачи.
Как устроены идентификаторы локалей
Идентификатор локали — это строка, которая определяет культурные предпочтения для форматирования дат, чисел, валют и текста. Идентификатор состоит из нескольких компонентов, разделённых дефисами.
Наиболее распространённая структура соответствует стандарту BCP 47:
language-script-region-variant-extensions
Все компоненты, кроме кода языка, являются необязательными.
Коды языков
Коды языков используют две или три буквы из ISO 639. Примеры:
en— английскийes— испанскийfr— французскийde— немецкийja— японскийzh— китайскийar— арабский
Код языка всегда пишется строчными буквами и стоит первым в идентификаторе.
Коды регионов
Коды регионов обозначают географические области с помощью двух заглавных букв из ISO 3166-1. Они указывают, какой вариант языка использовать:
en-USдля американского английскогоen-GBдля британского английскогоes-ESдля европейского испанскогоes-MXдля мексиканского испанскогоfr-FRдля французского во Францииfr-CAдля канадского французского
Коды регионов меняют правила форматирования. Американский английский использует MM/DD/YYYY даты, а британский английский — DD/MM/YYYY.
Коды письменности
Коды письменности указывают систему письма с помощью четырёх букв, первая из которых заглавная. Это важно для языков, которые могут быть записаны разными алфавитами:
zh-Hansдля упрощённых китайских иероглифовzh-Hantдля традиционных китайских иероглифовsr-Cyrlдля сербского на кириллицеsr-Latnдля сербского на латинице
В большинстве локалей код письменности опускается, потому что язык подразумевает скрипт по умолчанию. Например, английский по умолчанию использует латиницу, поэтому пишут en вместо en-Latn.
Теги расширения
Теги расширения добавляют настройки форматирования к идентификаторам локалей. Они начинаются с -u-, за которым следуют пары ключ-значение:
en-US-u-ca-gregory-nu-latn-hc-h12
Популярные ключи расширения:
caдля календарной системы (gregory,buddhist,islamic)nuдля системы счисления (latn,arab,hanidec)hcдля формата времени (h12,h23,h11,h24)
Расширения позволяют настраивать отображение данных без изменения языка или региона.
Создание объектов локали
Конструктор Intl.Locale принимает строку идентификатора локали и возвращает структурированный объект:
const locale = new Intl.Locale("en-US");
console.log(locale.language); // "en"
console.log(locale.region); // "US"
Вы также можете передать объект options, чтобы переопределить или добавить свойства:
const locale = new Intl.Locale("en", {
region: "GB",
hourCycle: "h23"
});
console.log(locale.baseName); // "en-GB"
console.log(locale.hourCycle); // "h23"
Конструктор выбрасывает RangeError, если идентификатор некорректен:
try {
const invalid = new Intl.Locale("invalid-locale-code");
} catch (error) {
console.error(error.message); // "invalid language subtag: invalid"
}
Эта проверка позволяет отлавливать некорректные идентификаторы локалей до передачи их в форматтеры.
Чтение свойств локали
Объекты локали предоставляют свойства, соответствующие компонентам строки идентификатора. Все свойства доступны только для чтения.
Основные свойства
Свойство language возвращает код языка:
const locale = new Intl.Locale("fr-CA");
console.log(locale.language); // "fr"
Свойство region возвращает код региона:
const locale = new Intl.Locale("fr-CA");
console.log(locale.region); // "CA"
Свойство script возвращает код письма, если он указан:
const locale = new Intl.Locale("zh-Hans-CN");
console.log(locale.script); // "Hans"
Свойство baseName возвращает полный основной идентификатор без расширений:
const locale = new Intl.Locale("en-US-u-ca-gregory-nu-latn");
console.log(locale.baseName); // "en-US"
Используйте baseName, если вам нужен язык и регион, но не важны предпочтения форматирования.
Свойства расширений
Свойства расширений возвращают значения из тега расширения -u- или undefined, если не указано.
Свойство calendar возвращает используемую календарную систему:
const locale = new Intl.Locale("ar-SA-u-ca-islamic");
console.log(locale.calendar); // "islamic"
Свойство numberingSystem возвращает используемую систему счисления:
const locale = new Intl.Locale("ar-EG-u-nu-arab");
console.log(locale.numberingSystem); // "arab"
Свойство hourCycle возвращает предпочтение формата времени:
const locale = new Intl.Locale("en-US-u-hc-h23");
console.log(locale.hourCycle); // "h23"
Свойство caseFirst возвращает предпочтение регистра для сортировки:
const locale = new Intl.Locale("en-US-u-kf-upper");
console.log(locale.caseFirst); // "upper"
Свойство numeric показывает, включена ли числовая сортировка:
const locale = new Intl.Locale("en-US-u-kn-true");
console.log(locale.numeric); // true
Эти свойства позволяют узнать настройки форматирования без ручного разбора строки расширения.
Запрос информации о локали
API Intl.Locale предоставляет методы, которые возвращают массивы доступных опций для локали. Эти методы помогают строить пользовательские интерфейсы и проверять варианты форматирования.
Доступные календари
Метод getCalendars() возвращает системы календарей, которые обычно используются для этой локали:
const locale = new Intl.Locale("th-TH");
const calendars = locale.getCalendars();
console.log(calendars); // ["buddhist", "gregory"]
Первый элемент — это календарь по умолчанию. В тайских локалях по умолчанию используется буддийский календарь, но также применяется григорианский.
Доступные типы сортировки
Метод getCollations() возвращает типы сортировки строк:
const locale = new Intl.Locale("de-DE");
const collations = locale.getCollations();
console.log(collations); // ["phonebk", "emoji", "eor"]
В немецком языке есть телефонная сортировка, которая отличается от стандартной сортировки Unicode.
Доступные форматы времени
Метод getHourCycles() возвращает форматы часовых циклов:
const locale = new Intl.Locale("en-US");
const hourCycles = locale.getHourCycles();
console.log(hourCycles); // ["h12"]
В американском английском по умолчанию используется 12-часовой формат времени. Во многих других локалях возвращается ["h23"] для 24-часового формата.
Доступные системы счисления
Метод getNumberingSystems() возвращает системы счисления, которые обычно используются для этой локали:
const locale = new Intl.Locale("ar-EG");
const numberingSystems = locale.getNumberingSystems();
console.log(numberingSystems); // ["arab", "latn"]
В арабских локалях часто поддерживаются как арабско-индийские, так и латинские цифры.
Направление текста
Метод getTextInfo() возвращает информацию о порядке текста:
const locale = new Intl.Locale("ar-SA");
const textInfo = locale.getTextInfo();
console.log(textInfo.direction); // "rtl"
Языки с письмом справа налево, такие как арабский и иврит, возвращают "rtl". Языки с письмом слева направо возвращают "ltr".
Недели и их структура
Метод getWeekInfo() возвращает структуру недели для локали:
const locale = new Intl.Locale("en-US");
const weekInfo = locale.getWeekInfo();
console.log(weekInfo.firstDay); // 7 (Sunday)
console.log(weekInfo.weekend); // [6, 7] (Saturday, Sunday)
console.log(weekInfo.minimalDays); // 1
Структура недели различается в зависимости от региона. В США неделя начинается с воскресенья, а в большинстве европейских стран — с понедельника.
Часовые пояса
Метод getTimeZones() возвращает часовые пояса для региона локали:
const locale = new Intl.Locale("en-US");
const timeZones = locale.getTimeZones();
console.log(timeZones); // ["America/New_York", "America/Chicago", ...]
Этот метод возвращает идентификаторы часовых поясов IANA для кода региона.
Максимизация идентификаторов локалей
Метод maximize() добавляет вероятные подметки, чтобы создать полный идентификатор. Он определяет недостающие коды письма и региона на основе языковых данных.
Если вы указываете только код языка, maximize() добавляет наиболее распространённые письмо и регион:
const locale = new Intl.Locale("en");
const maximized = locale.maximize();
console.log(maximized.baseName); // "en-Latn-US"
Для английского по умолчанию используется латинское письмо и регион США, так как это самые частые ассоциации.
Максимизация для китайского зависит от письма:
const simplified = new Intl.Locale("zh-Hans");
const maximized = simplified.maximize();
console.log(maximized.baseName); // "zh-Hans-CN"
const traditional = new Intl.Locale("zh-Hant");
const maximizedTrad = traditional.maximize();
console.log(maximizedTrad.baseName); // "zh-Hant-TW"
Упрощённый китайский ассоциируется с Китаем, а традиционный — с Тайванем.
Используйте maximize() для нормализации пользовательского ввода или сравнения идентификаторов локалей. Это делает неявную информацию явной.
Минимизация идентификаторов локалей
Метод minimize() удаляет избыточные подметки, чтобы создать самый короткий эквивалентный идентификатор. Он убирает коды письма и региона, если они совпадают с вероятными по умолчанию.
Если в локали используются стандартные письмо и регион, minimize() удаляет их:
const locale = new Intl.Locale("en-Latn-US");
const minimized = locale.minimize();
console.log(minimized.baseName); // "en"
Латинское письмо и регион США — это значения по умолчанию для английского, поэтому их можно убрать без потери информации.
Для локалей с нестандартными регионами minimize() сохраняет регион:
const locale = new Intl.Locale("en-Latn-GB");
const minimized = locale.minimize();
console.log(minimized.baseName); // "en-GB"
Для британского английского нужен код региона, так как он отличается от стандартного.
Используйте minimize(), чтобы создавать компактные идентификаторы для хранения или URL, сохраняя смысл.
Преобразование в строки
Метод toString() возвращает полный идентификатор локали, включая расширения:
const locale = new Intl.Locale("en-US", {
calendar: "gregory",
numberingSystem: "latn",
hourCycle: "h12"
});
console.log(locale.toString()); // "en-US-u-ca-gregory-hc-h12-nu-latn"
Строковое представление подходит для передачи в другие API Intl или для хранения в конфигурации.
Также можно неявно преобразовать объекты локали в строки:
const locale = new Intl.Locale("fr-FR");
const formatter = new Intl.DateTimeFormat(locale);
Конструктор DateTimeFormat принимает объекты локали напрямую и вызывает toString() внутри себя.
Практические сценарии
API Intl.Locale решает несколько типовых задач при создании интернационализированных приложений.
Создание селекторов локалей
Селекторы локалей позволяют пользователям выбирать язык и регион. API Intl.Locale помогает парсить и валидировать выбор пользователя:
function createLocaleSelector(locales) {
const options = locales.map(identifier => {
const locale = new Intl.Locale(identifier);
const displayName = new Intl.DisplayNames([identifier], { type: "language" });
return {
value: locale.toString(),
label: displayName.of(locale.language),
region: locale.region
};
});
return options;
}
const options = createLocaleSelector(["en-US", "en-GB", "fr-FR", "es-MX"]);
console.log(options);
// [
// { value: "en-US", label: "English", region: "US" },
// { value: "en-GB", label: "English", region: "GB" },
// { value: "fr-FR", label: "French", region: "FR" },
// { value: "es-MX", label: "Spanish", region: "MX" }
// ]
Валидация ввода локали
Если вы принимаете идентификаторы локалей из пользовательского ввода или конфигов, валидируйте их перед использованием:
function validateLocale(identifier) {
try {
const locale = new Intl.Locale(identifier);
return {
valid: true,
locale: locale.toString(),
language: locale.language,
region: locale.region
};
} catch (error) {
return {
valid: false,
error: error.message
};
}
}
console.log(validateLocale("en-US")); // { valid: true, locale: "en-US", ... }
console.log(validateLocale("invalid")); // { valid: false, error: "..." }
Извлечение языка для fallback
При реализации цепочек fallback извлекайте код языка без региона:
function getLanguageFallback(identifier) {
const locale = new Intl.Locale(identifier);
const fallbacks = [locale.toString()];
if (locale.region) {
const languageOnly = new Intl.Locale(locale.language);
fallbacks.push(languageOnly.toString());
}
fallbacks.push("en");
return fallbacks;
}
console.log(getLanguageFallback("fr-CA"));
// ["fr-CA", "fr", "en"]
Это создаёт цепочку fallback: сначала пробуется конкретная локаль, затем язык без региона, затем язык по умолчанию.
Настройка форматтеров
Используйте объекты локали для настройки форматтеров Intl с нужными параметрами:
function createFormatter(baseLocale, options = {}) {
const locale = new Intl.Locale(baseLocale, {
calendar: options.calendar || "gregory",
numberingSystem: options.numberingSystem || "latn",
hourCycle: options.hourCycle || "h23"
});
return {
date: new Intl.DateTimeFormat(locale),
number: new Intl.NumberFormat(locale),
locale: locale.toString()
};
}
const formatter = createFormatter("ar-SA", {
calendar: "islamic",
numberingSystem: "arab"
});
console.log(formatter.locale); // "ar-SA-u-ca-islamic-nu-arab"
Определение пользовательских предпочтений
API браузера предоставляют строки локали, которые можно проанализировать, чтобы понять предпочтения пользователя:
function getUserPreferences() {
const userLocale = new Intl.Locale(navigator.language);
const hourCycles = userLocale.getHourCycles();
const calendars = userLocale.getCalendars();
const textInfo = userLocale.getTextInfo();
return {
language: userLocale.language,
region: userLocale.region,
preferredHourCycle: hourCycles[0],
preferredCalendar: calendars[0],
textDirection: textInfo.direction
};
}
const preferences = getUserPreferences();
console.log(preferences);
// { language: "en", region: "US", preferredHourCycle: "h12", ... }
Это создаёт профиль предпочтений пользователя на основе настроек их браузера.
Поддержка браузеров
API Intl.Locale работает во всех современных браузерах. Chrome, Firefox, Safari и Edge полностью поддерживают конструктор, свойства и методы, описанные в этом руководстве.
Более новые методы, такие как getCalendars(), getCollations(), getHourCycles(), getNumberingSystems(), getTextInfo(), getTimeZones() и getWeekInfo() требуют более новых версий браузеров. Перед использованием этих методов проверьте таблицы совместимости браузеров, если вы поддерживаете старые версии.
Node.js поддерживает API Intl.Locale, начиная с версии 12, с полной поддержкой методов в версии 18 и выше.
Итоги
API Intl.Locale преобразует строки идентификаторов локалей в структурированные объекты, которые можно просматривать и изменять. Вместо ручного разбора строк вы создаёте объекты локалей и читаете их свойства.
Основные понятия:
- Идентификаторы локалей содержат компоненты языка, письма, региона и расширения
- Конструктор
Intl.Localeпроверяет идентификаторы и создаёт объекты - Свойства, такие как
language,regionиcalendar, предоставляют структурированный доступ - Методы, такие как
getCalendars()иgetHourCycles(), возвращают доступные опции - Методы
maximize()иminimize()нормализуют идентификаторы - Объекты локалей работают напрямую с другими API
Intl
Используйте API Intl.Locale при создании селекторов локалей, валидации пользовательского ввода, реализации цепочек резервирования или настройке форматтеров. Это стандартный способ работы с идентификаторами локалей в JavaScript-приложениях.