Intl API в JavaScript опирается на строгую систему обработки
параметров конфигурации, которая определяет поведение форматирования
локализованных данных. Практически каждый конструктор
(Intl.DateTimeFormat, Intl.NumberFormat,
Intl.Collator, Intl.PluralRules,
Intl.RelativeTimeFormat, Intl.ListFormat)
принимает объект опций, который проходит многоуровневую валидацию до
того, как используется в реальной локализации.
Первый этап обработки опций связан с приведением входного значения к объекту.
Если передано undefined, используется пустой объект:
new Intl.NumberFormat("ru")
new Intl.NumberFormat("ru", undefined)
Оба варианта эквивалентны.
Если передан примитив, он преобразуется через
Object(...):
new Intl.NumberFormat("ru", 42)
// эквивалентно new Number(42) как объекту
На этом этапе возможна ошибка:
TypeError, если значение не может быть приведено к
объекту (например, null)new Intl.NumberFormat("ru", null) // TypeError
После приведения к объекту выполняется извлечение опций через
внутренний механизм, аналогичный Get в спецификации
ECMAScript.
Ключевой момент: доступ к свойствам осуществляется динамически, поэтому геттеры могут быть выполнены:
const options = {
minimumFractionDigits: {
valueOf() {
return 2;
}
}
};
Валидация не требует «плоского» объекта — допускаются вычисляемые значения.
Intl API приводит многие параметры к строгим строковым наборам значений. Этот процесс называется каноникализацией.
Пример:
new Intl.DateTimeFormat("ru", {
hourCycle: "H24"
});
Значение "H24" будет преобразовано в каноническое
"h24" или заменено на дефолтное в зависимости от
реализации.
localeMatcher: "best fit" |
"lookup"formatMatcher: "basic" |
"best fit"hourCycle: "h11" | "h12" |
"h23" | "h24"numberingSystem: "latn",
"arab", "deva" и др.calendar: "gregory",
"islamic", "buddhist" и др.Некорректные значения приводят к откату к значениям по умолчанию.
Часть опций проходит числовую проверку диапазона. Это особенно
характерно для Intl.NumberFormat.
new Intl.NumberFormat("ru", {
minimumFractionDigits: -1
});
Такое значение приводит к исключению RangeError,
поскольку допустимый диапазон — от 0 до 20.
Типичные диапазонные проверки:
minimumFractionDigits ∈ [0, 20]maximumFractionDigits ∈ [0, 20]minimumSignificantDigits ∈ [1, 21]maximumSignificantDigits ∈ [1, 21]Также проверяется логическая согласованность:
{
minimumFractionDigits: 5,
maximumFractionDigits: 2
}
Подобная конфигурация может быть исправлена или отклонена в пользу корректировки значений.
Валидация Intl API учитывает взаимные ограничения параметров. Некоторые опции не могут существовать независимо.
Если заданы значащие цифры, дробные игнорируются:
{
minimumFractionDigits: 2,
maximumFractionDigits: 4,
minimumSignificantDigits: 3
}
В этом случае fractionDigits может быть
проигнорирован.
Опции dateStyle и timeStyle конфликтуют с
детализированными полями:
{
dateStyle: "full",
year: "numeric"
}
year будет игнорироваться, поскольку стиль
форматирования имеет приоритет.
Intl API игнорирует неизвестные ключи, не выбрасывая ошибок.
new Intl.NumberFormat("ru", {
unknownOption: true
});
Такой код валиден, но unknownOption не влияет на
результат.
Это поведение обеспечивает обратную совместимость и устойчивость API.
Хотя локали формально не являются частью опций, они тесно связаны с их валидацией.
new Intl.DateTimeFormat("xx-XX", {
timeZone: "Europe/Mars"
});
Если локаль или таймзона не поддерживаются:
"en-US")При этом ошибки не обязательны — Intl стремится к деградации, а не к падению.
Intl.DateTimeFormat выполняет строгую проверку
таймзоны:
new Intl.DateTimeFormat("ru", {
timeZone: "Invalid/Zone"
});
Результат:
RangeError, если таймзона не существует в IANA
базеДопустимые значения соответствуют IANA Time Zone Database:
Europe/MoscowAsia/AlmatyUTCНекоторые опции приводятся к логическому типу через абстрактное преобразование:
new Intl.NumberFormat("ru", {
useGrouping: "0"
});
Строка "0" интерпретируется как truthy, поэтому
группировка включится.
Корректный способ:
{
useGrouping: false
}
Числовые параметры проходят через ToNumber, что создаёт
неожиданные эффекты:
new Intl.NumberFormat("ru", {
minimumFractionDigits: "3"
});
Строка "3" будет преобразована в число
3.
Но:
{
minimumFractionDigits: "3abc"
}
даст NaN и приведёт к использованию значений по
умолчанию или ошибке в зависимости от поля.
Различие между undefined и null
критично:
undefined → значение игнорируется, используется
дефолтnull → чаще приводит к TypeError или
конвертации в объектnew Intl.NumberFormat("ru", {
style: undefined
});
эквивалентно отсутствию style.
Некоторые конструкторы выполняют нормализацию с приоритетами:
style)Пример приоритета:
new Intl.NumberFormat("ru", {
style: "currency",
currency: "USD",
minimumFractionDigits: 10
});
Здесь style: "currency" активирует валютный режим,
который может ограничить влияние других числовых параметров.
Внутренне Intl использует алгоритмы:
ToObject(options)Get(options, property)ToStringCanonicalizeLocaleListКаждый этап строго определён спецификацией ECMA-402.
Особенно важен шаг CanonicalizeLocaleList, который
влияет на доступные варианты форматирования и косвенно участвует в
обработке опций.
Конфликтующие опции не всегда приводят к ошибке. Чаще происходит переопределение:
new Intl.Collator("ru", {
usage: "sort",
sensitivity: "base",
ignorePunctuation: true
});
Если комбинация невалидна, Intl выбирает ближайшую допустимую конфигурацию.
Важно, что часть проверок выполняется не в момент создания объекта, а при первом использовании:
const fmt = new Intl.DateTimeFormat("ru", {
timeZone: "Europe/Moscow"
});
// здесь ещё нет ошибки
fmt.format(new Date());
Это означает:
Система обработки опций Intl API характеризуется следующими принципами: