# Интернационализация, встроенные объекты Intl Общая проблема строк, дат, чисел в JavaScript -- они совершенно не в курсе языков и стран, где находится посетитель. В частности:
Строки
При сравнении сравниваются коды символов, а это неправильно, к примеру, в русском языке оказывается, что `"ё" > "я"` и "а" > "Я", хотя всем известно, что `я` -- последняя буква алфавита и это она должна быть больше любой другой.
Даты
В разных странах принята разная запись дат. Где-то пишут 31.12.2014 (Россия), а где-то 12/31/2014 (США), где-то иначе.
Числа
В одних странах выводятся цифрами, в других -- иероглифами, длинные числа разделяются где-то пробелом, где-то запятой.
Все современные браузеры, кроме IE10- (но есть библиотеки и для него) поддерживает стандарт [ECMA 402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf), предназначенный решить эти проблемы навсегда. [cut] ## Основные объекты
`Intl.Collator`
Умеет правильно сравнивать и сортировать строки.
`Intl.DateTimeFormat`
Умеет форматировать дату и время в соответствии с нужным языком.
`Intl.NumberFormat`
Умеет форматировать числа в соответствии с нужным языком.
## Локаль *Локаль* -- первый и самый важный аргумент всех методов, связанных с интернационализацией. **Локаль описывается строкой из трёх компонентов, которые разделяются дефисом:**
  1. Код языка.
  2. Код способа записи.
  3. Код страны.
На практике не всегда указаны три, обычно меньше:
  1. `ru` -- русский язык, без уточнений.
  2. `en-GB` -- английский язык, используемый в Англии (`GB`).
  3. `en-US` -- английский язык, используемый в США (`US`).
  4. `zh-Hans-CN` -- китайский язык (`zh`), записываемый упрощённой иероглифической письменностью (`Hans`), используемый в китае.
Также через суффикс `-u-*` можно указать расширения локалей, например `"th-TH-u-nu-thai"` -- тайский язык (`th`), используемый в Тайланде (`TH`), с записью чисел тайскими буквами (๐, ๑, ๒, ๓, ๔, ๕, ๖, ๗, ๘, ๙) . Стандарт, который описывает локали -- [RFC 5464](http://tools.ietf.org/html/rfc5646), языки описаны в [IANA language registry](http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry). **Все методы принимают локаль в виде строки или массива, содержащего несколько локалей в порядке предпочтения.** **Если локаль не указана или `undefined` -- берётся локаль по умолчанию, установленная в окружении (браузере).** ### Подбор локали localeMatcher `localeMatcher` -- вспомогательная настройка, которую тоже можно везде указать, она определяет способ подбора локали, если желаемая недоступна. У него два значения: **По умолчанию стоит `"best fit"`.** Если локалей несколько, например `["zh-Hans-CN", "ru-RU"]` то `localeMatcher` пытается подобрать наиболее подходящую локаль для первой из списка (китайская), если не получается -- переходит ко второй (русской) и так далее. Если ни одной не нашёл, например на компьютере не совсем поддерживается ни китайский ни русский, то используется локаль по умолчанию. **Как правило, `"best fit"` является здесь наилучшим выбором.** ## Строки, Intl.Collator [#intl-collator] Синтаксис: ```js // создание var collator = new Intl.Collator([locales, [options] ]) ``` Параметры:
`locales`
Локаль, одна или массив в порядке предпочтения.
`options`
Объект с дополнительными настройками:
**В подавляющем большинстве случаев подходят стандартные параметры, то есть `options` указывать не нужно.** Использование: ```js var result = collator.compare(str1, str2); ``` Результат `compare` имеет значение `1` (больше), `0` (равно) или `-1` (меньше). Например: ```js //+ run var collator = new Intl.Collator(); alert( "ёжик" > "яблоко" ); // true (ёжик больше, что неверно) alert( collator.compare("ёжик", "яблоко") ); // -1 (ёжик меньше, верно) ``` Выше были использованы полностью стандартные настройки. Они различают регистр символа, но это различие можно убрать, если настроить чувствительность `sensitivity`: ```js //+ run var collator = new Intl.Collator(); alert( collator.compare("ЁжиК", "ёжик") ); // 1, разные var collator = new Intl.Collator(undefined, { sensitivity: "accent" } ); alert( collator.compare("ЁжиК", "ёжик") ); // 0, одинаковые ``` ## Даты, Intl.DateFormatter [#intl-dateformatter] Синтаксис: ```js // создание var formatter = new Intl.DateFormatter([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`
**Все локали обязаны поддерживать следующие наборы настроек:** Если указанный формат не поддерживается, то настройка `formatMatcher` задаёт алгоритм подбора наиболее близкого формата: `basic` -- по [стандартным правилам](http://www.ecma-international.org/ecma-402/1.0/#BasicFormatMatcher) и `best fit` -- по умолчанию, на усмотрение окружения (браузера). Использование: ```js var dateString = formatter.format(date); ``` Например: ```js //+ run var date = new Date(2014, 11, 31, 12, 30, 0); var formatter = new Intl.DateTimeFormat("ru"); alert( formatter.format(date) ); // 31.12.2014 var formatter = new Intl.DateTimeFormat("en-US"); alert( formatter.format(date) ); // 12/31/2014 ``` Длинная дата, с настройками: ```js //+ run var date = new Date(2014, 11, 31, 12, 30, 0); var formatter = new Intl.DateTimeFormat("ru", { weekday: "long", year: "numeric", month: "long", day: "numeric" }); alert( formatter.format(date) ); // среда, 31 декабря 2014 г. ``` Только время: ```js //+ run var date = new Date(2014, 11, 31, 12, 30, 0); var formatter = new Intl.DateTimeFormat("ru", { hour: "numeric" , minute: "numeric" , second: "numeric" }); alert( formatter.format(date) ); // 12:30:00 ``` ## Числа: Intl.NumberFormat Форматтер `Intl.NumberFormat` умеет красиво форматировать не только числа, но и валюту, а также проценты. Синтаксис: ```js var formatter = new Intl.NumberFormat([locales [, options] ]); formatter.format(number); // форматирование ``` Параметры, как и раньше -- локаль и опции. Список опций:
Свойство Описание Возможные значения По умолчанию
`localeMatcher` Алгоритм подбора локали `lookup`, `best fit` `best fit`
`style` Стиль форматирования `decimal`, `percent`, `currency` `decimal`
`currency` Алфавитный код валюты См. [Список кодов валюты](http://www.currency-iso.org/en/home/tables/table-a1.html), например `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` `minimumSignificantDigits`
Пример без опций: ```js //+ run var formatter = new Intl.NumberFormat("ru"); alert(formatter.format(1234567890.123)); // 1 234 567 890,123 ``` С ограничением значимых цифр (важны только первые 3): ```js //+ run var formatter = new Intl.NumberFormat("ru", { maximumSignificantDigits: 3 }); alert(formatter.format(1234567890.123)); // 1 230 000 000 ``` C опциями для валюты: ```js var formatter = new Intl.NumberFormat("ru", { style: "currency", currency: "GBP" }); alert( formatter.format(1234.5)); // 1 234,5 £ ``` С двумя цифрами после запятой: ```js var 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]])`
Сравнивает строку с другой, с учётом локали, например: ```js //+ run var str = "ёжик"; alert( str.localeCompare("яблоко", "ru") ); // -1 ```
`Date.prototype.toLocaleString([locales [, options]])`
Форматирует дату в соответствии с локалью, например: ```js //+ run var date = new Date(2014, 11, 31, 12, 00); 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).