Как проверить, что идентификатор локали валиден
Проверяйте идентификаторы локалей перед использованием для форматирования дат, чисел и валют
Введение
Если ваше приложение принимает идентификаторы локалей из пользовательского ввода, ответов API или конфигурационных файлов, их нужно проверить на валидность перед использованием. Неверный идентификатор локали приведёт к ошибкам форматирования или неожиданным результатам.
Проверка гарантирует, что строки вроде en-US структурно корректны по международным стандартам. Это предотвращает ошибки во время выполнения при передаче идентификаторов локалей в Intl API или другие библиотеки интернационализации.
В JavaScript есть два встроенных метода для проверки идентификаторов локалей. Оба метода сверяют структуру идентификатора со стандартом BCP 47, который определяет формат языковых тегов.
Что делает идентификатор локали валидным
Идентификатор локали соответствует стандарту BCP 47 для языковых тегов. Этот стандарт определяет структуру и правила для сочетания языка, письменности, региона и расширений.
В корректных идентификаторах локалей компоненты разделяются дефисами, а не подчёркиваниями или другими символами. Код языка должен быть признанным кодом ISO 639, а коды регионов — признанными кодами ISO 3166-1.
Примеры валидных идентификаторов локалей:
en(английский)en-US(американский английский)zh-Hans(упрощённый китайский)zh-Hans-CN(упрощённый китайский, используемый в Китае)en-US-u-ca-gregory(американский английский с григорианским календарём)
Примеры невалидных идентификаторов локалей:
en_US(используется подчёркивание вместо дефиса)english(непризнанный код языка)en-USA(код региона должен состоять из двух букв, а не трёх)EN-us(код языка должен быть в нижнем регистре)abc-XY(такого кода языка не существует)
Методы валидации проверяют эти структурные правила и убеждаются, что коды соответствуют признанным стандартам.
Использование Intl.getCanonicalLocales для валидации
Метод Intl.getCanonicalLocales() валидирует идентификаторы локалей и возвращает их в каноническом виде. Этот метод принимает один идентификатор локали или массив идентификаторов.
const result = Intl.getCanonicalLocales("en-US");
console.log(result);
// Output: ["en-US"]
Метод нормализует ввод, приводя его к стандартному формату. Даже если вы передадите идентификатор локали с неправильным регистром, он вернёт корректную каноническую форму:
const result = Intl.getCanonicalLocales("EN-us");
console.log(result);
// Output: ["en-US"]
Если вы передадите некорректный идентификатор локали, метод выбросит RangeError:
try {
Intl.getCanonicalLocales("en_US");
} catch (error) {
console.error(error.name);
// Output: "RangeError"
console.error(error.message);
// Output: "en_US is not a structurally valid language tag"
}
Эта ошибка означает, что идентификатор не соответствует структуре BCP 47. Вы можете обработать эту ошибку, чтобы корректно реагировать на неверный ввод.
Валидация нескольких идентификаторов локалей
Метод Intl.getCanonicalLocales() принимает массив, чтобы валидировать сразу несколько идентификаторов локалей. Метод возвращает массив канонических форм для всех валидных идентификаторов.
const locales = ["en-US", "fr-FR", "es-MX"];
const result = Intl.getCanonicalLocales(locales);
console.log(result);
// Output: ["en-US", "fr-FR", "es-MX"]
Метод также удаляет дублирующиеся идентификаторы локалей из результата:
const locales = ["en-US", "EN-us", "en-US"];
const result = Intl.getCanonicalLocales(locales);
console.log(result);
// Output: ["en-US"]
Все три значения на входе обозначают одну и ту же локаль, поэтому метод возвращает только одну каноническую форму.
Если хотя бы одна локаль в массиве некорректна, весь метод выбрасывает ошибку:
try {
Intl.getCanonicalLocales(["en-US", "invalid", "fr-FR"]);
} catch (error) {
console.error(error.message);
// Output: "invalid is not a structurally valid language tag"
}
При валидации пользовательских списков проверяйте каждую локаль отдельно, чтобы определить, какие именно идентификаторы некорректны.
Использование конструктора Intl.Locale для валидации
Конструктор Intl.Locale — это ещё один способ валидировать идентификаторы локалей. Если вы создаёте объект локали с некорректным идентификатором, конструктор выбрасывает RangeError.
try {
const locale = new Intl.Locale("en-US");
console.log("Valid locale");
} catch (error) {
console.error("Invalid locale");
}
// Output: "Valid locale"
Конструктор выбрасывает ошибку для неверных идентификаторов:
try {
const locale = new Intl.Locale("en_US");
console.log("Valid locale");
} catch (error) {
console.error("Invalid locale");
console.error(error.message);
}
// Output: "Invalid locale"
// Output: "invalid language subtag: en_US"
В отличие от Intl.getCanonicalLocales(), конструктор Intl.Locale не нормализует регистр. Он требует, чтобы идентификатор был в правильном регистре:
const locale1 = new Intl.Locale("en-US");
console.log(locale1.baseName);
// Output: "en-US"
const locale2 = new Intl.Locale("EN-US");
console.log(locale2.baseName);
// Output: "en-US"
Принимаются как строчные, так и прописные коды языков, а конструктор приводит их к каноническому виду.
Как выбрать способ валидации
Оба метода валидации служат разным целям и предоставляют разные возможности.
Используйте Intl.getCanonicalLocales(), если нужно:
- Нормализовать идентификаторы локалей до канонического вида
- Проверить и удалить дубликаты в списке идентификаторов локалей
- Привести регистр к стандартному формату
- Проверить идентификаторы локалей без создания объектов
Используйте конструктор Intl.Locale, если нужно:
- Проверить идентификатор локали и сразу работать с его свойствами
- Извлечь компоненты, такие как язык, регион или скрипт, из идентификатора
- Создать объект локали для использования с другими Intl API
- Проверять и изменять идентификаторы локалей вместе
Конструктор Intl.Locale мощнее, потому что создаёт объект, с которым можно работать и который можно изменять. Но если вам нужна только валидация и нормализация, Intl.getCanonicalLocales() проще.
Проверка пользовательского ввода
Если вы принимаете идентификаторы локалей от пользователя, обязательно проверьте их перед использованием в приложении. Это поможет избежать ошибок и даст понятную обратную связь, если пользователь ввёл некорректное значение.
function validateUserLocale(input) {
try {
const canonicalLocales = Intl.getCanonicalLocales(input);
return {
valid: true,
locale: canonicalLocales[0]
};
} catch (error) {
return {
valid: false,
error: "Please enter a valid locale identifier like en-US or fr-FR"
};
}
}
const result1 = validateUserLocale("en-US");
console.log(result1);
// Output: { valid: true, locale: "en-US" }
const result2 = validateUserLocale("english");
console.log(result2);
// Output: { valid: false, error: "Please enter a valid locale..." }
Эта функция проверяет ввод и возвращает либо канонический идентификатор локали, либо понятное сообщение об ошибке.
Проверка конфигурационных данных
Приложения часто загружают идентификаторы локалей из конфигурационных файлов или переменных окружения. Проверяйте эти значения при запуске приложения, чтобы заранее выявить ошибки в конфигурации.
function loadLocaleConfig(configLocales) {
const validLocales = [];
const invalidLocales = [];
for (const locale of configLocales) {
try {
const canonical = Intl.getCanonicalLocales(locale);
validLocales.push(canonical[0]);
} catch (error) {
invalidLocales.push(locale);
}
}
if (invalidLocales.length > 0) {
console.warn("Invalid locale identifiers found:", invalidLocales);
}
return validLocales;
}
const config = ["en-US", "fr-FR", "invalid", "es_MX", "de-DE"];
const locales = loadLocaleConfig(config);
console.log(locales);
// Output: ["en-US", "fr-FR", "de-DE"]
// Warning: Invalid locale identifiers found: ["invalid", "es_MX"]
Эта функция отфильтровывает неверные идентификаторы локалей и выводит предупреждение, чтобы приложение продолжило работу с валидными локалями.
Проверка ответов API
При получении идентификаторов локалей из внешних API обязательно проверяйте их перед использованием в приложении. API могут возвращать идентификаторы локалей в нестандартных форматах или с ошибками.
function processApiLocale(apiResponse) {
const locale = apiResponse.preferredLocale;
try {
const validated = new Intl.Locale(locale);
return {
success: true,
language: validated.language,
region: validated.region,
baseName: validated.baseName
};
} catch (error) {
console.error("API returned invalid locale:", locale);
return {
success: false,
fallback: "en-US"
};
}
}
const response1 = { preferredLocale: "fr-CA" };
console.log(processApiLocale(response1));
// Output: { success: true, language: "fr", region: "CA", baseName: "fr-CA" }
const response2 = { preferredLocale: "invalid_locale" };
console.log(processApiLocale(response2));
// Output: { success: false, fallback: "en-US" }
Эта функция проверяет ответ API и извлекает структурированную информацию о локали или возвращает значение по умолчанию, если локаль некорректна.