Как извлечь язык, страну и алфавит из локали
Используйте JavaScript для разбора идентификаторов локалей и получения их отдельных компонентов
Введение
Идентификаторы локалей, такие как en-US, fr-CA и zh-Hans-CN, содержат в одной строке сразу несколько элементов. Эти компоненты указывают, какой язык используется, в каком регионе он применяется и иногда — какая система письма используется.
При разработке интернационализированных приложений часто нужно извлекать эти отдельные компоненты. Например, чтобы показывать пользователям только название языка, группировать локали по регионам или определять, какой алфавит используется. Вместо ручного разбора строк с помощью регулярных выражений, в JavaScript есть API Intl.Locale, который позволяет надёжно получать компоненты.
В этом гайде объясняется, какие компоненты бывают в идентификаторах локалей, как их извлекать с помощью API Intl.Locale и в каких случаях эти компоненты могут пригодиться на практике.
Какие компоненты есть в идентификаторах локалей
Идентификаторы локалей соответствуют стандарту BCP 47, который определяет структуру для описания языков и региональных вариантов. Полный идентификатор локали может содержать несколько компонентов, разделённых дефисами.
Три самых распространённых компонента:
- Язык: основной используемый язык, например, английский, испанский или китайский
- Регион: географический регион, где используется язык, например, США, Канада или Китай
- Скрипт: система письма, используемая для языка, например, латиница, кириллица или иероглифы
Простой идентификатор локали содержит только код языка:
en
Большинство идентификаторов локалей включают язык и регион:
en-US
fr-CA
es-MX
Некоторые идентификаторы локалей включают скрипт, если язык может быть записан в нескольких письменностях:
zh-Hans-CN
zh-Hant-TW
sr-Cyrl-RS
sr-Latn-RS
Понимание этих компонентов помогает принимать решения о резервных языках, выборе контента и настройке пользовательского интерфейса.
Использование Intl.Locale для извлечения компонентов
API Intl.Locale преобразует строки идентификаторов локалей в структурированные объекты. После создания объекта локали вы можете получить доступ к его компонентам через свойства.
Создайте объект локали, передав идентификатор в конструктор:
const locale = new Intl.Locale("en-US");
console.log(locale.language); // "en"
console.log(locale.region); // "US"
Объект локали предоставляет свойства, соответствующие каждому компоненту идентификатора. Эти свойства дают структурированный доступ без необходимости парсить строку.
Извлечение кода языка
Свойство language возвращает языковой компонент идентификатора локали. Это двух- или трёхбуквенный код, который определяет основной язык.
const english = new Intl.Locale("en-US");
console.log(english.language); // "en"
const french = new Intl.Locale("fr-CA");
console.log(french.language); // "fr"
const chinese = new Intl.Locale("zh-Hans-CN");
console.log(chinese.language); // "zh"
Коды языков соответствуют стандарту ISO 639. Распространённые коды: en для английского, es для испанского, fr для французского, de для немецкого, ja для японского и zh для китайского.
Код языка всегда присутствует в корректном идентификаторе локали. Это единственный обязательный компонент.
const languageOnly = new Intl.Locale("ja");
console.log(languageOnly.language); // "ja"
console.log(languageOnly.region); // undefined
Когда вы извлекаете код языка, его можно использовать для выбора переводов, определения правил обработки текста или создания языковых селекторов для пользователей.
Извлечение кода региона
Свойство region возвращает региональный компонент идентификатора локали. Это двухбуквенный код, который определяет географический регион, где используется язык.
const americanEnglish = new Intl.Locale("en-US");
console.log(americanEnglish.region); // "US"
const britishEnglish = new Intl.Locale("en-GB");
console.log(britishEnglish.region); // "GB"
const canadianFrench = new Intl.Locale("fr-CA");
console.log(canadianFrench.region); // "CA"
Коды регионов соответствуют стандарту ISO 3166-1. Для обозначения стран и территорий используются две заглавные буквы. Часто встречающиеся коды: US — для США, GB — для Великобритании, CA — для Канады, MX — для Мексики, FR — для Франции и CN — для Китая.
Код региона влияет на форматирование дат, чисел и валют. В американском английском используется формат даты месяц-день-год и точка как десятичный разделитель. В британском английском — день-месяц-год и запятая для разделения тысяч.
Коды регионов в идентификаторах локалей указывать необязательно. Если регион не задан, свойство region возвращает undefined:
const genericSpanish = new Intl.Locale("es");
console.log(genericSpanish.region); // undefined
Когда вы извлекаете код региона, его можно использовать для настройки регионального форматирования, выбора контента для конкретного региона или отображения информации о местоположении пользователя.
Извлечение кода письменности
Свойство script возвращает компонент идентификатора локали, отвечающий за письменность. Это четырёхбуквенный код, который определяет, какая система письма используется для языка.
const simplifiedChinese = new Intl.Locale("zh-Hans-CN");
console.log(simplifiedChinese.script); // "Hans"
const traditionalChinese = new Intl.Locale("zh-Hant-TW");
console.log(traditionalChinese.script); // "Hant"
const serbianCyrillic = new Intl.Locale("sr-Cyrl-RS");
console.log(serbianCyrillic.script); // "Cyrl"
const serbianLatin = new Intl.Locale("sr-Latn-RS");
console.log(serbianLatin.script); // "Latn"
Коды письменности соответствуют стандарту ISO 15924. Они состоят из четырёх букв, первая из которых — заглавная. Примеры: Latn — латиница, Cyrl — кириллица, Hans — упрощённые иероглифы, Hant — традиционные иероглифы, Arab — арабское письмо.
В большинстве локалей код письменности не указывается, потому что у каждого языка есть система письма по умолчанию. Для английского это латиница, поэтому пишут en вместо en-Latn. Для русского по умолчанию используется кириллица, поэтому пишут ru вместо ru-Cyrl.
Коды письменности используются, когда язык может быть записан несколькими способами. Например, китайский язык использует как упрощённые, так и традиционные иероглифы. Сербский — как кириллицу, так и латиницу. В таких случаях код письменности помогает определить, какую систему письма использовать.
Если в локали явно не указан код письменности, свойство script возвращает undefined:
const english = new Intl.Locale("en-US");
console.log(english.script); // undefined
Когда вы извлекаете код письменности, его можно использовать для выбора шрифтов, настройки рендеринга текста или фильтрации контента по системе письма.
Как понять, что компоненты не определены
Не все идентификаторы локалей содержат все компоненты. Код языка обязателен, а регион и письменность — опциональны.
Если компонент отсутствует в идентификаторе, соответствующее свойство возвращает undefined:
const locale = new Intl.Locale("fr");
console.log(locale.language); // "fr"
console.log(locale.region); // undefined
console.log(locale.script); // undefined
Такое поведение позволяет проверить, указан ли регион или письменность в локали, прежде чем использовать эти значения:
const locale = new Intl.Locale("en-US");
if (locale.region) {
console.log(`Region-specific formatting for ${locale.region}`);
} else {
console.log("Using default formatting");
}
Можно использовать оператор объединения с null для задания значений по умолчанию:
const locale = new Intl.Locale("es");
const region = locale.region ?? "ES";
console.log(region); // "ES"
При построении цепочек резервных локалей проверка на неопределённые компоненты помогает формировать альтернативы:
function buildFallbackChain(identifier) {
const locale = new Intl.Locale(identifier);
const fallbacks = [identifier];
if (locale.region) {
fallbacks.push(locale.language);
}
return fallbacks;
}
console.log(buildFallbackChain("fr-CA")); // ["fr-CA", "fr"]
console.log(buildFallbackChain("fr")); // ["fr"]
Это создаёт список идентификаторов локалей, упорядоченных от самых конкретных к самым общим.
Практические примеры извлечения компонентов
Извлечение компонентов локали решает несколько типичных задач при создании интернационализированных приложений.
Группировка локалей по языку
При отображении списка доступных языков группируйте локали с одинаковым языковым кодом:
const locales = ["en-US", "en-GB", "fr-FR", "fr-CA", "es-ES", "es-MX"];
const grouped = locales.reduce((groups, identifier) => {
const locale = new Intl.Locale(identifier);
const language = locale.language;
if (!groups[language]) {
groups[language] = [];
}
groups[language].push(identifier);
return groups;
}, {});
console.log(grouped);
// {
// en: ["en-US", "en-GB"],
// fr: ["fr-FR", "fr-CA"],
// es: ["es-ES", "es-MX"]
// }
Такой подход помогает пользователям найти нужный региональный вариант языка.
Создание селекторов локалей
При создании интерфейса для выбора языка извлекайте компоненты, чтобы показывать понятные подписи:
function buildLocaleSelector(identifiers) {
return identifiers.map(identifier => {
const locale = new Intl.Locale(identifier);
const languageNames = new Intl.DisplayNames([identifier], {
type: "language"
});
const regionNames = new Intl.DisplayNames([identifier], {
type: "region"
});
return {
value: identifier,
language: languageNames.of(locale.language),
region: locale.region ? regionNames.of(locale.region) : null
};
});
}
const options = buildLocaleSelector(["en-US", "en-GB", "fr-FR"]);
console.log(options);
// [
// { value: "en-US", language: "English", region: "United States" },
// { value: "en-GB", language: "English", region: "United Kingdom" },
// { value: "fr-FR", language: "French", region: "France" }
// ]
Это обеспечивает человекочитаемые метки для каждого варианта локали.
Фильтрация по региону
Когда нужно показать контент для определённого региона, извлеките код региона для фильтрации локалей:
function filterByRegion(identifiers, targetRegion) {
return identifiers.filter(identifier => {
const locale = new Intl.Locale(identifier);
return locale.region === targetRegion;
});
}
const allLocales = ["en-US", "es-US", "en-GB", "fr-FR", "zh-CN"];
const usLocales = filterByRegion(allLocales, "US");
console.log(usLocales); // ["en-US", "es-US"]
Это помогает выбрать подходящие локали для пользователей из конкретной страны.
Проверка совместимости с алфавитом
При выборе шрифтов или отображении текста проверьте алфавит для обеспечения совместимости:
function selectFont(identifier) {
const locale = new Intl.Locale(identifier);
const script = locale.script;
if (script === "Hans" || script === "Hant") {
return "Noto Sans CJK";
} else if (script === "Arab") {
return "Noto Sans Arabic";
} else if (script === "Cyrl") {
return "Noto Sans";
} else {
return "Noto Sans";
}
}
console.log(selectFont("zh-Hans-CN")); // "Noto Sans CJK"
console.log(selectFont("ar-SA")); // "Noto Sans Arabic"
console.log(selectFont("en-US")); // "Noto Sans"
Это гарантирует корректное отображение текста для каждой системы письма.
Реализация языкового фолбэка
Если предпочтительная локаль пользователя недоступна, используйте базовый язык:
function selectBestLocale(userPreference, supportedLocales) {
const user = new Intl.Locale(userPreference);
if (supportedLocales.includes(userPreference)) {
return userPreference;
}
const languageMatch = supportedLocales.find(supported => {
const locale = new Intl.Locale(supported);
return locale.language === user.language;
});
if (languageMatch) {
return languageMatch;
}
return supportedLocales[0];
}
const supported = ["en-US", "fr-FR", "es-ES"];
console.log(selectBestLocale("en-GB", supported)); // "en-US"
console.log(selectBestLocale("fr-CA", supported)); // "fr-FR"
console.log(selectBestLocale("de-DE", supported)); // "en-US"
Это обеспечивает корректную подстановку, если точное совпадение отсутствует.