Как собрать идентификаторы локалей из компонентов
Формируйте идентификаторы локалей, комбинируя коды языка, письма и региона в JavaScript
Введение
Идентификаторы локалей, такие как en-US или zh-Hans-CN, содержат информацию о языке, системе письма и регионе. Иногда нужно формировать такие идентификаторы программно, а не использовать фиксированную строку. Например, вы можете дать пользователям возможность выбрать язык и регион отдельно, а затем объединить их в корректный идентификатор локали.
Конструктор Intl.Locale в JavaScript позволяет собирать идентификаторы локалей из отдельных компонентов. Вы можете указать язык, письмо и регион как отдельные параметры, и конструктор соберёт их в корректный формат.
В этом гайде рассказывается, как собирать идентификаторы локалей из компонентов, когда это может пригодиться и как обрабатывать нестандартные случаи.
Компоненты идентификатора локали
Идентификаторы локалей состоят из компонентов, разделённых дефисами. Каждый компонент отражает определённый аспект культурных предпочтений.
Код языка определяет, какой язык будет использоваться. Обычно это две или три строчные буквы по стандарту ISO 639:
en— английскийes— испанскийfr— французскийzh— китайскийar— арабский
Код письма определяет систему письма. Это четыре буквы, первая — заглавная, по стандарту ISO 15924:
Hans— упрощённые китайские иероглифыHant— традиционные китайские иероглифыCyrl— кириллицаLatn— латиница
Код региона определяет географическую область. Это две заглавные буквы по ISO 3166-1 или три цифры по UN M.49:
USдля Соединённых ШтатовGBдля ВеликобританииCNдля КитаяMXдля Мексики
Эти компоненты объединяются в определённом порядке: сначала язык, затем письменность, затем регион. Например, zh-Hans-CN означает китайский язык, упрощённая письменность, регион — Китай.
Создание локалей только с языком и регионом
Самый частый сценарий — это комбинация кода языка и региона. В большинстве приложений не нужно указывать письменность, потому что у каждого языка есть письменность по умолчанию.
Вы можете создать локаль, передав код языка первым аргументом и объект опций с регионом:
const locale = new Intl.Locale("en", {
region: "US"
});
console.log(locale.toString());
// Output: "en-US"
Это создаёт идентификатор локали для американского английского.
Вы можете создать разные региональные варианты одного и того же языка:
const usEnglish = new Intl.Locale("en", { region: "US" });
const britishEnglish = new Intl.Locale("en", { region: "GB" });
const canadianEnglish = new Intl.Locale("en", { region: "CA" });
console.log(usEnglish.toString()); // "en-US"
console.log(britishEnglish.toString()); // "en-GB"
console.log(canadianEnglish.toString()); // "en-CA"
Каждый вариант использует один и тот же язык, но разные региональные форматы.
Создание локалей с языком, письменностью и регионом
Для некоторых языков требуется явное указание кода письменности. Китайский, сербский и ещё несколько языков используют несколько систем письма. Чтобы избежать неоднозначности, нужно указывать письменность.
Вы можете добавить компонент письменности в объект опций:
const simplifiedChinese = new Intl.Locale("zh", {
script: "Hans",
region: "CN"
});
console.log(simplifiedChinese.toString());
// Output: "zh-Hans-CN"
Это создаёт локаль для упрощённого китайского, используемого в Китае.
Традиционный китайский использует другую письменность и регион:
const traditionalChinese = new Intl.Locale("zh", {
script: "Hant",
region: "TW"
});
console.log(traditionalChinese.toString());
// Output: "zh-Hant-TW"
Код письменности различает эти две системы письма.
В сербском языке используются как кириллица, так и латиница. Нужно указать, какую письменность использовать:
const serbianCyrillic = new Intl.Locale("sr", {
script: "Cyrl",
region: "RS"
});
const serbianLatin = new Intl.Locale("sr", {
script: "Latn",
region: "RS"
});
console.log(serbianCyrillic.toString()); // "sr-Cyrl-RS"
console.log(serbianLatin.toString()); // "sr-Latn-RS"
Обе локали используют сербский язык в Сербии, но с разными системами письма.
Создание локалей на основе выбора пользователя
В пользовательских интерфейсах часто можно выбрать язык и регион отдельно. Эти выборы можно объединить в идентификатор локали.
Рассмотрим форму настроек с двумя выпадающими списками:
function buildLocaleFromSelections(languageCode, regionCode) {
const locale = new Intl.Locale(languageCode, {
region: regionCode
});
return locale.toString();
}
const userLocale = buildLocaleFromSelections("es", "MX");
console.log(userLocale);
// Output: "es-MX"
Это создаёт идентификатор локали на основе независимых выборов.
Вы можете проверить корректность выбора, отлавливая ошибки конструктора:
function buildLocaleFromSelections(languageCode, regionCode) {
try {
const locale = new Intl.Locale(languageCode, {
region: regionCode
});
return {
success: true,
locale: locale.toString()
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
const valid = buildLocaleFromSelections("fr", "CA");
console.log(valid);
// Output: { success: true, locale: "fr-CA" }
const invalid = buildLocaleFromSelections("invalid", "XX");
console.log(invalid);
// Output: { success: false, error: "..." }
Конструктор выбрасывает RangeError, если какой-либо компонент некорректен.
Формирование локалей с необязательными компонентами
Не для каждой локали нужны все компоненты. Можно опустить те, которые не требуются.
Локаль только с языком не указывает регион и письменность:
const locale = new Intl.Locale("fr");
console.log(locale.toString());
// Output: "fr"
Это означает французский язык без указания конкретного региона или письменности.
Можно включать компоненты в зависимости от ввода пользователя:
function buildLocale(language, options = {}) {
const localeOptions = {};
if (options.region) {
localeOptions.region = options.region;
}
if (options.script) {
localeOptions.script = options.script;
}
const locale = new Intl.Locale(language, localeOptions);
return locale.toString();
}
console.log(buildLocale("en"));
// Output: "en"
console.log(buildLocale("en", { region: "US" }));
// Output: "en-US"
console.log(buildLocale("zh", { script: "Hans", region: "CN" }));
// Output: "zh-Hans-CN"
Функция формирует самый простой корректный идентификатор локали на основе доступной информации.
Переопределение компонентов в существующих локалях
Можно взять существующий идентификатор локали и изменить отдельные компоненты. Это удобно, если нужно поменять только одну часть, оставив остальные без изменений.
Второй аргумент конструктора переопределяет компоненты из первого аргумента:
const baseLocale = new Intl.Locale("en-US");
const withDifferentRegion = new Intl.Locale(baseLocale, {
region: "GB"
});
console.log(withDifferentRegion.toString());
// Output: "en-GB"
В новой локали сохраняется язык, но меняется регион.
Можно переопределить несколько компонентов:
const original = new Intl.Locale("zh-Hans-CN");
const modified = new Intl.Locale(original, {
script: "Hant",
region: "TW"
});
console.log(modified.toString());
// Output: "zh-Hant-TW"
Это меняет и письменность, и регион, сохраняя язык.
Добавление предпочтений форматирования к созданным локалям
Помимо языка, письменности и региона, локали могут включать настройки форматирования. Эти параметры определяют, как отображаются даты, числа и другие значения.
Вы можете добавить предпочтения календаря при создании локали:
const locale = new Intl.Locale("ar", {
region: "SA",
calendar: "islamic"
});
console.log(locale.toString());
// Output: "ar-SA-u-ca-islamic"
console.log(locale.calendar);
// Output: "islamic"
Предпочтение календаря отображается как расширение Unicode в строке идентификатора.
Можно указать несколько предпочтений форматирования:
const locale = new Intl.Locale("en", {
region: "US",
calendar: "gregory",
numberingSystem: "latn",
hourCycle: "h12"
});
console.log(locale.toString());
// Output: "en-US-u-ca-gregory-hc-h12-nu-latn"
Конструктор сортирует ключи расширений в алфавитном порядке.
Эти предпочтения влияют на то, как форматтеры отображают данные:
const locale = new Intl.Locale("ar", {
region: "EG",
numberingSystem: "arab"
});
const formatter = new Intl.NumberFormat(locale);
console.log(formatter.format(12345));
// Output: "١٢٬٣٤٥" (Arabic-Indic numerals)
Предпочтение системы счисления определяет, какие цифры будут отображаться.
Проверка комбинаций компонентов
Не все комбинации языка, письма и региона имеют смысл. Конструктор принимает любые синтаксически корректные компоненты, но некоторые комбинации могут не представлять реальные локали.
Конструктор проверяет только синтаксис, но не семантическую корректность:
// Syntactically valid but semantically questionable
const locale = new Intl.Locale("en", {
script: "Arab",
region: "JP"
});
console.log(locale.toString());
// Output: "en-Arab-JP"
Это создаёт локаль для английского языка на арабском письме в Японии. Идентификатор валиден по BCP 47, но не отражает реальную локаль.
Вы можете использовать метод maximize(), чтобы проверить, соответствует ли локаль распространённым шаблонам:
const locale = new Intl.Locale("en", { region: "JP" });
const maximized = locale.maximize();
console.log(maximized.toString());
// Output: "en-Latn-JP"
Метод добавляет наиболее вероятное письмо для языка. Если результат соответствует ожидаемым шаблонам, комбинация считается разумной.
Чтение компонентов из созданных локалей
После создания локали вы можете получить её компоненты как свойства.
Свойство language возвращает код языка:
const locale = new Intl.Locale("fr", { region: "CA" });
console.log(locale.language);
// Output: "fr"
Свойство region возвращает код региона:
const locale = new Intl.Locale("fr", { region: "CA" });
console.log(locale.region);
// Output: "CA"
Свойство script возвращает код письма, если он указан:
const locale = new Intl.Locale("zh", {
script: "Hans",
region: "CN"
});
console.log(locale.script);
// Output: "Hans"
Если скрипт не указан, свойство возвращает undefined:
const locale = new Intl.Locale("en", { region: "US" });
console.log(locale.script);
// Output: undefined
Свойство baseName возвращает полный идентификатор без расширений:
const locale = new Intl.Locale("ar", {
region: "SA",
calendar: "islamic",
numberingSystem: "arab"
});
console.log(locale.baseName);
// Output: "ar-SA"
Это даёт вам часть идентификатора язык-скрипт-регион без настроек форматирования.
Преобразование идентификаторов локалей в строки
Метод toString() возвращает полный идентификатор локали в виде строки:
const locale = new Intl.Locale("es", { region: "MX" });
const identifier = locale.toString();
console.log(identifier);
// Output: "es-MX"
Вы можете использовать эту строку с другими Intl API:
const locale = new Intl.Locale("de", { region: "DE" });
const formatter = new Intl.NumberFormat(locale.toString());
const price = 1234.56;
console.log(formatter.format(price));
// Output: "1.234,56"
Форматтер принимает строковое представление.
Большинство Intl API также принимают объекты локалей напрямую:
const locale = new Intl.Locale("de", { region: "DE" });
const formatter = new Intl.NumberFormat(locale);
API вызывает toString() внутренне при необходимости.
Практические сценарии использования
Сборка идентификаторов локалей из компонентов решает несколько типичных задач в интернационализированных приложениях.
Создание селекторов локалей
В пользовательских интерфейсах часто позволяют выбирать язык и регион отдельно. Вы объединяете эти выборы:
function createLocaleFromPicker(languageSelect, regionSelect) {
const language = languageSelect.value;
const region = regionSelect.value;
const locale = new Intl.Locale(language, { region });
return locale.toString();
}
// User selects "Spanish" and "Mexico"
const selectedLocale = createLocaleFromPicker(
{ value: "es" },
{ value: "MX" }
);
console.log(selectedLocale);
// Output: "es-MX"
Генерация вариантов локалей
Можно сгенерировать несколько региональных вариантов из одного языкового кода:
function generateRegionalVariants(languageCode, regionCodes) {
return regionCodes.map(regionCode => {
const locale = new Intl.Locale(languageCode, {
region: regionCode
});
return locale.toString();
});
}
const englishVariants = generateRegionalVariants("en", [
"US",
"GB",
"CA",
"AU",
"NZ"
]);
console.log(englishVariants);
// Output: ["en-US", "en-GB", "en-CA", "en-AU", "en-NZ"]
Это создаёт список идентификаторов локалей для разных англоязычных регионов.
Сборка локалей из параметров URL
В URL часто кодируются предпочтения локали как отдельные параметры. Можно собрать локаль из этих параметров:
function getLocaleFromURL(url) {
const params = new URL(url).searchParams;
const language = params.get("lang");
const region = params.get("region");
if (!language) {
return null;
}
const options = {};
if (region) {
options.region = region;
}
try {
const locale = new Intl.Locale(language, options);
return locale.toString();
} catch (error) {
return null;
}
}
const locale1 = getLocaleFromURL("https://example.com?lang=fr®ion=CA");
console.log(locale1);
// Output: "fr-CA"
const locale2 = getLocaleFromURL("https://example.com?lang=ja");
console.log(locale2);
// Output: "ja"
Нормализация идентификаторов локалей
Вы можете нормализовать идентификаторы локалей, разобрав и пересобрав их:
function normalizeLocale(identifier) {
try {
const locale = new Intl.Locale(identifier);
return locale.toString();
} catch (error) {
return null;
}
}
console.log(normalizeLocale("EN-us"));
// Output: "en-US"
console.log(normalizeLocale("zh_Hans_CN"));
// Output: null (invalid separator)
Конструктор нормализует регистр и проверяет структуру.
Настройка форматтеров с учётом предпочтений пользователя
Вы можете создавать идентификаторы локалей с учётом пользовательских настроек форматирования:
function buildFormatterLocale(language, region, preferences) {
const locale = new Intl.Locale(language, {
region,
hourCycle: preferences.use24Hour ? "h23" : "h12",
numberingSystem: preferences.numberingSystem
});
return locale;
}
const userPreferences = {
use24Hour: true,
numberingSystem: "latn"
};
const locale = buildFormatterLocale("fr", "FR", userPreferences);
const timeFormatter = new Intl.DateTimeFormat(locale, {
hour: "numeric",
minute: "numeric"
});
const now = new Date("2025-10-15T14:30:00");
console.log(timeFormatter.format(now));
// Output: "14:30" (24-hour format)
Локаль включает параметры форматирования из пользовательских настроек.
Когда собирать локали из компонентов
Сборка локалей из компонентов полезна в определённых случаях. Используйте этот подход, если у вас есть отдельные данные о языке и регионе, при обработке пользовательского ввода или при программном создании вариантов локалей.
Используйте строку напрямую для фиксированных локалей:
// Good for fixed locales
const locale = new Intl.Locale("en-US");
Собирайте из компонентов, если значения приходят из переменных:
// Good for dynamic locales
const locale = new Intl.Locale(userLanguage, {
region: userRegion
});
Конструктор проверяет компоненты и создаёт корректно отформатированный идентификатор.
Поддержка браузеров
Конструктор Intl.Locale работает во всех современных браузерах. Chrome, Firefox, Safari и Edge поддерживают этот конструктор и объект опций для сборки локалей из компонентов.
Node.js поддерживает Intl.Locale, начиная с версии 12, с полной поддержкой всех опций конструктора с версии 14 и выше.
Итоги
Конструктор Intl.Locale собирает идентификаторы локалей из отдельных компонентов. В качестве первого аргумента передаётся языковой код, а скрипт, регион и параметры форматирования указываются в объекте опций.
Ключевые моменты:
- Идентификаторы локалей состоят из компонентов языка, скрипта и региона
- Конструктор принимает объект опций со свойствами
language,scriptиregion - Можно переопределить компоненты существующей локали, передав её первым аргументом
- Форматные параметры, такие как
calendarиhourCycle, отображаются как расширения Unicode - Метод
toString()возвращает полную строку идентификатора - Свойства
language,regionиscriptпозволяют читать компоненты - Конструктор проверяет синтаксис, но не семантическую корректность
Используйте этот подход, когда формируете локали на основе пользовательского ввода, создаёте региональные варианты или комбинируете отдельные выборы языка и региона. Для фиксированных локалей вместо этого используйте строковые литералы.