Как удалить избыточную информацию из идентификаторов локалей
Используйте метод minimize для создания компактных идентификаторов локалей без потери смысла
Введение
Идентификаторы локалей, такие как en-Latn-US и zh-Hans-CN, содержат несколько компонентов, которые указывают язык, письменность и регион. Однако не все эти компоненты необходимы для идентификации локали. Некоторые компоненты избыточны, так как их можно вывести из других частей идентификатора.
Метод minimize() удаляет эти избыточные компоненты, чтобы создать самый короткий эквивалент идентификатора локали. Это позволяет получить компактные идентификаторы, которые сохраняют смысл, уменьшают объем хранения и улучшают читаемость.
Понимание избыточности в идентификаторах локалей
Идентификатор локали становится избыточным, когда он явно указывает информацию, которая уже подразумевается другими компонентами. Избыточность возникает, потому что для каждого языка существуют вероятные значения по умолчанию для письменности и региона.
Рассмотрим идентификатор en-Latn-US. Этот идентификатор указывает:
- Язык: английский (
en) - Письменность: латиница (
Latn) - Регион: Соединенные Штаты (
US)
Английский язык используется только с латиницей, и если регион не указан, по умолчанию для английского языка принимается Соединенные Штаты. Таким образом, компоненты письменности и региона избыточны, так как они совпадают с вероятными значениями по умолчанию для английского языка. Идентификатор en передает ту же информацию.
Этот же принцип применим и к другим языкам. Например, корейский (ko) пишется на хангыле (Kore) и в основном используется в Южной Корее (KR). Идентификатор ko-Kore-KR содержит избыточную информацию, так как ko сам по себе подразумевает эти значения по умолчанию.
Как работает метод minimize
Метод minimize() доступен для экземпляров Intl.Locale. Он анализирует идентификатор локали и удаляет компоненты, которые совпадают с вероятными значениями по умолчанию.
const locale = new Intl.Locale("en-Latn-US");
const minimized = locale.minimize();
console.log(minimized.baseName);
// Вывод: "en"
Метод возвращает новый экземпляр Intl.Locale с удаленными избыточными подметками. Он не изменяет исходный объект локали.
Процесс минимизации следует алгоритму Unicode CLDR "Remove Likely Subtags". Этот алгоритм использует базу данных вероятных ассоциаций подметок, чтобы определить, какие компоненты можно удалить без потери информации.
Компоненты, затронутые минимизацией
Метод minimize() влияет только на основные компоненты локали: язык, письменность и регион. Он не удаляет и не изменяет подметки расширения Unicode, которые указывают предпочтения форматирования.
const locale = new Intl.Locale("en-Latn-US-u-ca-gregory-nu-latn");
const minimized = locale.minimize();
console.log(minimized.toString());
// Вывод: "en-u-ca-gregory-nu-latn"
Расширения календаря (ca-gregory) и системы чисел (nu-latn) остаются неизменными. Удаляются только избыточные компоненты письменности (Latn) и региона (US).
Примеры минимизации
Разные идентификаторы локалей минимизируются до разной длины в зависимости от того, какие компоненты являются избыточными.
Удаление письменности и региона
Когда и письменность, и регион совпадают с настройками по умолчанию, оба удаляются:
const english = new Intl.Locale("en-Latn-US");
console.log(english.minimize().baseName);
// Вывод: "en"
const korean = new Intl.Locale("ko-Kore-KR");
console.log(korean.minimize().baseName);
// Вывод: "ko"
const japanese = new Intl.Locale("ja-Jpan-JP");
console.log(japanese.minimize().baseName);
// Вывод: "ja"
Сохранение нестандартных регионов
Когда регион отличается от стандартного, он остается в минимизированном идентификаторе:
const britishEnglish = new Intl.Locale("en-Latn-GB");
console.log(britishEnglish.minimize().baseName);
// Вывод: "en-GB"
const canadianFrench = new Intl.Locale("fr-Latn-CA");
console.log(canadianFrench.minimize().baseName);
// Вывод: "fr-CA"
const mexicanSpanish = new Intl.Locale("es-Latn-MX");
console.log(mexicanSpanish.minimize().baseName);
// Вывод: "es-MX"
Компонент письменности удаляется, так как он совпадает с настройками по умолчанию, но регион сохраняется, так как он указывает на нестандартный вариант языка.
Сохранение нестандартных письменностей
Когда письменность отличается от стандартной, она остается в минимизированном идентификаторе:
const simplifiedChinese = new Intl.Locale("zh-Hans-CN");
console.log(simplifiedChinese.minimize().baseName);
// Вывод: "zh-Hans"
const traditionalChinese = new Intl.Locale("zh-Hant-TW");
console.log(traditionalChinese.minimize().baseName);
// Вывод: "zh-Hant"
const serbianCyrillic = new Intl.Locale("sr-Cyrl-RS");
console.log(serbianCyrillic.minimize().baseName);
// Вывод: "sr-Cyrl"
Для китайского языка требуется компонент письменности, чтобы различать упрощенные и традиционные варианты. Для сербского языка требуется компонент письменности, чтобы различать кириллицу и латиницу.
Уже минимальные идентификаторы
Когда идентификатор локали уже минимален, метод возвращает эквивалентную локаль без изменений:
const minimal = new Intl.Locale("fr");
console.log(minimal.minimize().baseName);
// Вывод: "fr"
Связь с maximize
Метод minimize() является обратным к maximize(). Метод maximize() добавляет вероятные подтеги для создания полного идентификатора, в то время как minimize() удаляет избыточные подтеги для создания компактного идентификатора.
Эти методы образуют пару, которая позволяет выполнять двунаправленное преобразование между полными и компактными формами:
const compact = new Intl.Locale("en");
const complete = compact.maximize();
console.log(complete.baseName);
// Вывод: "en-Latn-US"
const compactAgain = complete.minimize();
console.log(compactAgain.baseName);
// Вывод: "en"
Переход от компактной формы к полной и обратно к компактной воспроизводит исходную форму.
Однако не все локали возвращаются к своей точной исходной форме после такого перехода. Метод создает каноническую минимальную форму, а не сохраняет исходную структуру:
const locale = new Intl.Locale("en-US");
const maximized = locale.maximize();
console.log(maximized.baseName);
// Вывод: "en-Latn-US"
const minimized = maximized.minimize();
console.log(minimized.baseName);
// Вывод: "en"
Исходный идентификатор en-US содержал нерезервированный регион, но после максимизации и минимизации он становится en. Это происходит потому, что Соединенные Штаты являются вероятным регионом по умолчанию для английского языка.
Когда использовать minimize
Используйте minimize(), когда вам нужны компактные идентификаторы локалей, которые остаются однозначными. Минимизация полезна в нескольких сценариях.
Хранение предпочтений локали
Минимизированные идентификаторы сокращают объем хранимых данных в базах данных, локальном хранилище или конфигурационных файлах:
function saveUserLocale(localeString) {
const locale = new Intl.Locale(localeString);
const minimized = locale.minimize().toString();
localStorage.setItem("userLocale", minimized);
}
saveUserLocale("en-Latn-US");
// Сохраняет "en" вместо "en-Latn-US"
Это уменьшает объем хранимых данных без потери информации.
Создание читаемых URL
Минимизированные идентификаторы создают более чистые URL для выбора языка:
function createLocalizedURL(path, localeString) {
const locale = new Intl.Locale(localeString);
const minimized = locale.minimize().baseName;
return `/${minimized}${path}`;
}
const url = createLocalizedURL("/products", "en-Latn-US");
console.log(url);
// Вывод: "/en/products"
URL /en/products более читаем, чем /en-Latn-US/products.
Сравнение идентификаторов локалей
Минимизация помогает определить, представляют ли два идентификатора локалей одну и ту же локаль:
function areLocalesEquivalent(locale1String, locale2String) {
const locale1 = new Intl.Locale(locale1String).minimize();
const locale2 = new Intl.Locale(locale2String).minimize();
return locale1.toString() === locale2.toString();
}
console.log(areLocalesEquivalent("en", "en-Latn-US"));
// Вывод: true
console.log(areLocalesEquivalent("en-US", "en-Latn-US"));
// Вывод: true
console.log(areLocalesEquivalent("en-US", "en-GB"));
// Вывод: false
Минимизация создает каноническую форму, которая позволяет проводить прямое сравнение.
Нормализация пользовательского ввода
При приеме идентификаторов локалей от пользователей или внешних систем минимизируйте их до стандартной формы:
function normalizeLocale(localeString) {
try {
const locale = new Intl.Locale(localeString);
return locale.minimize().toString();
} catch (error) {
return null;
}
}
console.log(normalizeLocale("en-US"));
// Вывод: "en"
console.log(normalizeLocale("en-Latn-US"));
// Вывод: "en"
console.log(normalizeLocale("en-GB"));
// Вывод: "en-GB"
Эта функция принимает различные формы одной и той же локали и возвращает их в согласованном представлении.
Комбинирование минимизации с другими операциями над локалями
Метод minimize() работает с другими функциями Intl.Locale, создавая гибкую обработку локалей.
Минимизация после изменения свойств локали
При создании локали из компонентов минимизируйте её, чтобы удалить ненужные части:
const locale = new Intl.Locale("en", {
region: "US",
script: "Latn"
});
const minimized = locale.minimize();
console.log(minimized.baseName);
// Вывод: "en"
Это гарантирует, что итоговый идентификатор будет максимально компактным, насколько это позволяют входные компоненты.
Сохранение расширений при минимизации
Расширения остаются неизменными при минимизации, что позволяет минимизировать основные компоненты, сохраняя предпочтения форматирования:
function createCompactLocaleWithPreferences(language, region, preferences) {
const locale = new Intl.Locale(language, {
region: region,
...preferences
});
return locale.minimize().toString();
}
const localeString = createCompactLocaleWithPreferences("en", "US", {
hourCycle: "h23",
calendar: "gregory"
});
console.log(localeString);
// Вывод: "en-u-ca-gregory-hc-h23"
Основные компоненты минимизируются до en, но расширения календаря и часового формата остаются.