Как создавать идентификаторы локалей из компонентов
Создавайте идентификаторы локалей, комбинируя коды языка, скрипта и региона в 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());
// Вывод: "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());
// Вывод: "zh-Hans-CN"
Это создаёт локаль для упрощённого китайского, используемого в Китае.
Традиционный китайский использует другой скрипт и регион:
const traditionalChinese = new Intl.Locale("zh", {
script: "Hant",
region: "TW"
});
console.log(traditionalChinese.toString());
// Вывод: "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);
// Вывод: "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);
// Вывод: { success: true, locale: "fr-CA" }
const invalid = buildLocaleFromSelections("invalid", "XX");
console.log(invalid);
// Вывод: { success: false, error: "..." }
Конструктор выбрасывает RangeError, если какой-либо компонент недействителен.
Создание локалей с необязательными компонентами
Не каждая локаль требует всех компонентов. Вы можете опустить компоненты, которые не нужны.
Локаль, содержащая только язык, исключает регион и скрипт:
const locale = new Intl.Locale("fr");
console.log(locale.toString());
// Вывод: "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"));
// Вывод: "en"
console.log(buildLocale("en", { region: "US" }));
// Вывод: "en-US"
console.log(buildLocale("zh", { script: "Hans", region: "CN" }));
// Вывод: "zh-Hans-CN"
Функция создает самый простой допустимый идентификатор локали на основе доступной информации.
Переопределение компонентов в существующих локалях
Вы можете использовать существующий идентификатор локали и переопределить определённые компоненты. Это полезно, когда нужно изменить одну часть, сохранив остальные без изменений.
Второй аргумент конструктора переопределяет компоненты из первого аргумента:
const baseLocale = new Intl.Locale("en-US");
const withDifferentRegion = new Intl.Locale(baseLocale, {
region: "GB"
});
console.log(withDifferentRegion.toString());
// Вывод: "en-GB"
Новая локаль сохраняет язык, но изменяет регион.
Вы можете переопределить несколько компонентов:
const original = new Intl.Locale("zh-Hans-CN");
const modified = new Intl.Locale(original, {
script: "Hant",
region: "TW"
});
console.log(modified.toString());
// Вывод: "zh-Hant-TW"
Это изменяет как скрипт, так и регион, сохраняя язык.
Добавление предпочтений форматирования к созданным локалям
Помимо языка, скрипта и региона, локали могут включать предпочтения форматирования. Эти предпочтения определяют, как отображаются даты, числа и другие значения.
Вы можете добавить предпочтения календаря при создании локали:
const locale = new Intl.Locale("ar", {
region: "SA",
calendar: "islamic"
});
console.log(locale.toString());
// Вывод: "ar-SA-u-ca-islamic"
console.log(locale.calendar);
// Вывод: "islamic"
Предпочтение календаря отображается как расширение Unicode в строке идентификатора.
Вы можете указать несколько предпочтений форматирования:
const locale = new Intl.Locale("en", {
region: "US",
calendar: "gregory",
numberingSystem: "latn",
hourCycle: "h12"
});
console.log(locale.toString());
// Вывод: "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));
// Вывод: "١٢٬٣٤٥" (арабские-индийские цифры)
Предпочтение системы нумерации определяет, какие цифры отображаются.
Проверка комбинаций компонентов
Не все комбинации языка, письменности и региона имеют смысл. Конструктор принимает любые синтаксически корректные компоненты, но некоторые комбинации могут не представлять реальные локали.
Конструктор проверяет синтаксис, но не семантическую корректность:
// Синтаксически корректно, но семантически сомнительно
const locale = new Intl.Locale("en", {
script: "Arab",
region: "JP"
});
console.log(locale.toString());
// Вывод: "en-Arab-JP"
Этот код создает локаль для английского языка на арабской письменности в Японии. Идентификатор является допустимым согласно BCP 47, но он не представляет реальную локаль.
Вы можете использовать метод maximize(), чтобы проверить, соответствует ли локаль общепринятым шаблонам:
const locale = new Intl.Locale("en", { region: "JP" });
const maximized = locale.maximize();
console.log(maximized.toString());
// Вывод: "en-Latn-JP"
Метод добавляет наиболее вероятную письменность для языка. Если результат соответствует ожидаемым шаблонам, комбинация считается разумной.
Чтение компонентов из созданных локалей
После создания локали вы можете получить доступ к её компонентам через свойства.
Свойство language возвращает код языка:
const locale = new Intl.Locale("fr", { region: "CA" });
console.log(locale.language);
// Вывод: "fr"
Свойство region возвращает код региона:
const locale = new Intl.Locale("fr", { region: "CA" });
console.log(locale.region);
// Вывод: "CA"
Свойство script возвращает код письменности, если он указан:
const locale = new Intl.Locale("zh", {
script: "Hans",
region: "CN"
});
console.log(locale.script);
// Вывод: "Hans"
Если письменность не указана, свойство возвращает undefined:
const locale = new Intl.Locale("en", { region: "US" });
console.log(locale.script);
// Вывод: undefined
Свойство baseName возвращает полный идентификатор без расширений:
const locale = new Intl.Locale("ar", {
region: "SA",
calendar: "islamic",
numberingSystem: "arab"
});
console.log(locale.baseName);
// Вывод: "ar-SA"
Это свойство предоставляет часть идентификатора, включающую язык, письменность и регион, без учета предпочтений форматирования.
Преобразование идентификаторов локалей в строки
Метод toString() возвращает полный идентификатор локали в виде строки:
const locale = new Intl.Locale("es", { region: "MX" });
const identifier = locale.toString();
console.log(identifier);
// Вывод: "es-MX"
Вы можете использовать эту строку с другими API Intl:
const locale = new Intl.Locale("de", { region: "DE" });
const formatter = new Intl.NumberFormat(locale.toString());
const price = 1234.56;
console.log(formatter.format(price));
// Вывод: "1.234,56"
Форматтер принимает строковое представление.
Большинство API Intl также принимают объекты локалей напрямую:
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();
}
// Пользователь выбирает "Испанский" и "Мексика"
const selectedLocale = createLocaleFromPicker(
{ value: "es" },
{ value: "MX" }
);
console.log(selectedLocale);
// Вывод: "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);
// Вывод: ["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);
// Вывод: "fr-CA"
const locale2 = getLocaleFromURL("https://example.com?lang=ja");
console.log(locale2);
// Вывод: "ja"
Нормализация идентификаторов локалей
Вы можете нормализовать идентификаторы локалей, анализируя и пересоздавая их:
function normalizeLocale(identifier) {
try {
const locale = new Intl.Locale(identifier);
return locale.toString();
} catch (error) {
return null;
}
}
console.log(normalizeLocale("EN-us"));
// Вывод: "en-US"
console.log(normalizeLocale("zh_Hans_CN"));
// Вывод: null (недопустимый разделитель)
Конструктор нормализует регистр и проверяет структуру.
Настройка форматтеров с учетом предпочтений пользователя
Вы можете создавать идентификаторы локалей с форматированием на основе пользовательских настроек:
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));
// Вывод: "14:30" (24-часовой формат)
Локаль включает настройки форматирования из пользовательских предпочтений.
Когда создавать локали из компонентов
Создание локалей из компонентов полезно в определенных сценариях. Используйте этот подход, если у вас есть отдельные данные о языке и регионе, если вы обрабатываете пользовательский ввод или программно создаете варианты локалей.
Используйте строку для фиксированных локалей:
// Подходит для фиксированных локалей
const locale = new Intl.Locale("en-US");
Создавайте из компонентов, если значения поступают из переменных:
// Подходит для динамических локалей
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, позволяют читать компоненты - Конструктор проверяет синтаксис, но не семантическую корректность
Используйте этот подход для создания локалей на основе пользовательского ввода, генерации региональных вариантов или комбинирования отдельных языковых и региональных настроек. Для фиксированных локалей используйте строковые литералы.