Общая проблема строк, дат, чисел в JavaScript – они «не в курсе» языка и особенностей стран, где находится посетитель.
В частности:
- Строки
- При сравнении сравниваются коды символов, а это неправильно, к примеру, в русском языке оказывается, что
"ё" > "я"
и"а" > "Я"
, хотя всем известно, чтоя
– последняя буква алфавита и это она должна быть больше любой другой. - Даты
- В разных странах принята разная запись дат. Где-то пишут 31.12.2014 (Россия), а где-то 12/31/2014 (США), где-то иначе.
- Числа
- В одних странах выводятся цифрами, в других – иероглифами, длинные числа разделяются где-то пробелом, где-то запятой.
Все современные браузеры, кроме IE10 (но есть библиотеки и для него) поддерживают стандарт ECMA 402, предназначенный решить эти проблемы навсегда.
Основные объекты
Intl.Collator
- Умеет правильно сравнивать и сортировать строки.
Intl.DateTimeFormat
- Умеет форматировать дату и время в соответствии с нужным языком.
Intl.NumberFormat
- Умеет форматировать числа в соответствии с нужным языком.
Локаль
Локаль – первый и самый важный аргумент всех методов, связанных с интернационализацией.
Локаль описывается строкой из трёх компонентов, которые разделяются дефисом:
- Код языка.
- Код способа записи.
- Код страны.
На практике не всегда указаны три, обычно меньше:
ru
– русский язык, без уточнений.en-GB
– английский язык, используемый в Англии (GB
).en-US
– английский язык, используемый в США (US
).zh-Hans-CN
– китайский язык (zh
), записываемый упрощённой иероглифической письменностью (Hans
), используемый в Китае.
Также через суффикс -u-*
можно указать расширения локалей, например "th-TH-u-nu-thai"
– тайский язык (th
), используемый в Таиланде (TH
), с записью чисел тайскими буквами (๐, ๑, ๒, ๓, ๔, ๕, ๖, ๗, ๘, ๙) .
Стандарт, который описывает локали – RFC 5646, языки описаны в IANA language registry.
Все методы принимают локаль в виде строки или массива, содержащего несколько локалей в порядке предпочтения.
Если локаль не указана или undefined
– берётся локаль по умолчанию, установленная в окружении (браузере).
Подбор локали localeMatcher
localeMatcher
– вспомогательная настройка, которую тоже можно везде указать, она определяет способ подбора локали, если желаемая недоступна.
У него два значения:
"lookup"
– означает простейший порядок поиска путём обрезания суффикса, напримерzh-Hans-CN
→zh-Hans
→zh
→ локаль по умолчанию."best fit"
– использует встроенные алгоритмы и предпочтения браузера (или другого окружения) для выбора подходящей локали.
По умолчанию стоит "best fit"
.
Если локалей несколько, например ["zh-Hans-CN", "ru-RU"]
то localeMatcher
пытается подобрать наиболее подходящую локаль для первой из списка (китайская), если не получается – переходит ко второй (русской) и так далее. Если ни одной не нашёл, например на компьютере не совсем поддерживается ни китайский ни русский, то используется локаль по умолчанию.
Как правило, "best fit"
является здесь наилучшим выбором.
Строки, Intl.Collator
Синтаксис:
// создание
let collator = new Intl.Collator([locales, [options]])
Параметры:
locales
-
Локаль, одна или массив в порядке предпочтения.
options
-
Объект с дополнительными настройками:
-
localeMatcher
– алгоритм выбора подходящей локали. -
usage
– цель сравнения: сортировка"sort"
или поиск"search"
, по умолчанию"sort"
. -
sensitivity
– чувствительность: какие различия в символах учитывать, а какие – нет, варианты:base
– учитывать только разные символы, без диакритических знаков и регистра, например:а ≠ б
,е = ё
,а = А
.accent
– учитывать символы и диакритические знаки, например:а ≠ б
,е ≠ ё
,а = А
.case
– учитывать символы и регистр, например:а ≠ б
,е = ё
,а ≠ А
.variant
– учитывать всё: символ, диакритические знаки, регистр, например:а ≠ б
,е ≠ ё
,а ≠ А
, используется по умолчанию.
-
ignorePunctuation
– игнорировать знаки пунктуации:true/false
, по умолчаниюfalse
. -
numeric
– использовать ли численное сравнение:true/false
, еслиtrue
, то будет12 > 2
, иначе12 < 2
. -
caseFirst
– в сортировке должны идти первыми прописные или строчные буквы, варианты:"upper"
(прописные),"lower"
(строчные) или"false"
(стандартное для локали, также является значением по умолчанию). Не поддерживается IE11.
-
В подавляющем большинстве случаев подходят стандартные параметры, то есть options
указывать не нужно.
Использование:
let result = collator.compare(str1, str2);
Результат compare
имеет значение 1
(больше), 0
(равно) или -1
(меньше).
Например:
let collator = new Intl.Collator();
alert( "ёжик" > "яблоко" ); // true (ёжик больше, что неверно)
alert( collator.compare("ёжик", "яблоко") ); // -1 (ёжик меньше, верно)
Выше были использованы полностью стандартные настройки. Они различают регистр символа, но это различие можно убрать, если настроить чувствительность sensitivity
:
let collator1 = new Intl.Collator();
alert( collator1.compare("ЁжиК", "ёжик") ); // 1, разные
let collator2 = new Intl.Collator(undefined, {
sensitivity: "accent"
});
alert( collator2.compare("ЁжиК", "ёжик") ); // 0, одинаковые
Даты, Intl.DateTimeFormat
Синтаксис:
// создание
let formatter = new Intl.DateTimeFormat([locales, [options]])
Первый аргумент – такой же, как и в Collator
, а в объекте options
мы можем определить, какие именно части даты показывать (часы, месяц, год…) и в каком формате.
Полный список свойств options
:
Свойство | Описание | Возможные значения | По умолчанию |
---|---|---|---|
localeMatcher |
Алгоритм подбора локали |
lookup , best fit
|
best fit
|
formatMatcher |
Алгоритм подбора формата | basic , best fit |
best fit |
hour12 |
Включать ли время в 12-часовом формате | true -- 12-часовой формат, false -- 24-часовой |
|
timeZone |
Временная зона | Временная зона, например Europe/Moscow |
UTC |
weekday |
День недели | narrow , short , long |
|
era |
Эра | narrow , short , long |
|
year |
Год | 2-digit , numeric |
undefined или numeric |
month |
Месяц | 2-digit , numeric , narrow , short , long |
undefined или numeric |
day |
День | 2-digit , numeric |
undefined или numeric |
hour |
Час | 2-digit , numeric |
|
minute |
Минуты | 2-digit , numeric |
|
second |
Секунды | 2-digit , numeric |
|
timeZoneName |
Название таймзоны (нет в IE11) | short , long |
Все локали обязаны поддерживать следующие наборы настроек:
- weekday, year, month, day, hour, minute, second
- weekday, year, month, day
- year, month, day
- year, month
- month, day
- hour, minute, second
Если указанный формат не поддерживается, то настройка formatMatcher
задаёт алгоритм подбора наиболее близкого формата: basic
– по стандартным правилам и best fit
– по умолчанию, на усмотрение окружения (браузера).
Использование:
let dateString = formatter.format(date);
Например:
let date = new Date(2014, 11, 31, 12, 30, 0);
let formatter1 = new Intl.DateTimeFormat("ru");
alert( formatter1.format(date) ); // 31.12.2014
let formatter2 = new Intl.DateTimeFormat("en-US");
alert( formatter2.format(date) ); // 12/31/2014
Длинная дата, с настройками:
let date = new Date(2014, 11, 31, 12, 30, 0);
let formatter = new Intl.DateTimeFormat("ru", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
alert( formatter.format(date) ); // среда, 31 декабря 2014 г.
Только время:
let date = new Date(2014, 11, 31, 12, 30, 0);
let formatter = new Intl.DateTimeFormat("ru", {
hour: "numeric",
minute: "numeric",
second: "numeric"
});
alert( formatter.format(date) ); // 12:30:00
Числа, Intl.NumberFormat
Форматтер Intl.NumberFormat
умеет красиво форматировать не только числа, но и валюту, а также проценты.
Синтаксис:
let formatter = new Intl.NumberFormat([locales[, options]]);
formatter.format(number); // форматирование
Параметры, как и раньше – локаль и опции.
Список опций:
Свойство | Описание | Возможные значения | По умолчанию |
---|---|---|---|
localeMatcher |
Алгоритм подбора локали | lookup , best fit |
best fit |
style |
Стиль форматирования | decimal , percent , currency |
decimal |
currency |
Алфавитный код валюты | См. Список кодов валюты, например USD |
|
currencyDisplay |
Показывать валюту в виде кода, локализованного символа или локализованного названия | code , symbol , name |
symbol |
useGrouping |
Разделять ли цифры на группы | true , false |
true |
minimumIntegerDigits |
Минимальное количество цифр целой части | от 1 до 21
|
21 |
minimumFractionDigits |
Минимальное количество десятичных цифр | от 0 до 20 |
для чисел и процентов 0 , для валюты зависит от кода. |
maximumFractionDigits |
Максимальное количество десятичных цифр | от minimumFractionDigits до 20 . |
для чисел max(minimumFractionDigits, 3) , для процентов 0 , для валюты зависит от кода. |
minimumSignificantDigits |
Минимальное количество значимых цифр | от 1 до 21 |
1 |
maximumSignificantDigits |
Максимальное количество значимых цифр | от minimumSignificantDigits до 21 |
21 |
Пример без опций:
let formatter = new Intl.NumberFormat("ru");
alert( formatter.format(1234567890.123) ); // 1 234 567 890,123
С ограничением значимых цифр (важны только первые 3):
let formatter = new Intl.NumberFormat("ru", {
maximumSignificantDigits: 3
});
alert( formatter.format(1234567890.123) ); // 1 230 000 000
С опциями для валюты:
let formatter = new Intl.NumberFormat("ru", {
style: "currency",
currency: "GBP"
});
alert( formatter.format(1234.5) ); // 1 234,5 £
С двумя цифрами после запятой:
let formatter = new Intl.NumberFormat("ru", {
style: "currency",
currency: "GBP",
minimumFractionDigits: 2
});
alert( formatter.format(1234.5) ); // 1 234,50 £
Методы в Date, String, Number
Методы форматирования также поддерживаются в обычных строках, датах, числах:
String.prototype.localeCompare(that [, locales [, options]])
-
Сравнивает строку с другой, с учётом локали, например:
let str = "ёжик"; alert( str.localeCompare("яблоко", "ru") ); // -1
Date.prototype.toLocaleString([locales [, options]])
-
Форматирует дату в соответствии с локалью, например:
let date = new Date(2014, 11, 31, 12, 0); alert( date.toLocaleString("ru", { year: 'numeric', month: 'long' }) ); // Декабрь 2014
Date.prototype.toLocaleDateString([locales [, options]])
-
То же, что и выше, но опции по умолчанию включают в себя год, месяц, день
Date.prototype.toLocaleTimeString([locales [, options]])
-
То же, что и выше, но опции по умолчанию включают в себя часы, минуты, секунды
Number.prototype.toLocaleString([locales [, options]])
-
Форматирует число, используя опции
Intl.NumberFormat
.
Все эти методы при запуске создают соответствующий объект Intl.*
и передают ему опции, можно рассматривать их как укороченные варианты вызова.
Старые IE
В IE10 рекомендуется использовать полифил, например библиотеку https://github.com/andyearnshaw/Intl.js.