JavaScript

Intl  —  глобальный объект для форматирования строк, чисел и дат с учётом языка пользователя. Он работает над отображением зависящей от языка информации.

Интернационализация  —  способ разработки, при котором адаптация для родного языка пользователя происходит без изменения кода.

Разработчикам не нужно поставлять килобайты языковых баз данных прямо в пакетах. Intl имеет конструкторы и методы, принимающие региональный стандарт, называемый также локалью, как один из параметров и форматирующие данные в соответствии с ним. В консоли Intl выглядит так:

Skillbox
{getCanonicalLocales: ƒ, DateTimeFormat: ƒ, NumberFormat: ƒ, Collator: ƒ, v8BreakIterator: ƒ, …}
Collator: ƒ Collator()
DateTimeFormat: ƒ DateTimeFormat()
ListFormat: ƒ ListFormat()
Locale: ƒ Locale()
NumberFormat: ƒ NumberFormat()
PluralRules: ƒ PluralRules()
RelativeTimeFormat: ƒ RelativeTimeFormat()
Segmenter: ƒ Segmenter()
getCanonicalLocales: ƒ getCanonicalLocales()
v8BreakIterator: ƒ v8BreakIterator()
__proto__: Object

Collator, DateTimeFormat, ListFormat, NumberFormat, PluralRules, RelativeTimeFormat  —  конструкторы пространства имён Intl. Они принимают два аргумента  —  локаль и опции (options). Локаль должна быть строкой BCP 47 или массивом таких строк. Если интересно узнать больше о BCP 47, ниже выдержка из MDN:

Языковая метка BCP 47 определяет язык и его минимальный код. В наиболее общей форме она содержит (по порядку) код языка, код письменности и код страны или региона через дефисы. Метка не учитывает регистр, но для кодов письменности, страны и региона рекомендуется верхний регистр, а для всего остального нижний.

Объект locale по умолчанию соответствует локали среды выполнения. Примеры локалей:

  • en  —  английский.
  • hi  —  хинди.
  • ta-in  —  тамильский, Индия.

Объект options не обязателен и его структура варьируется для разных конструкторов. В основном он используется для предоставления дополнительной информации о форматировании.

В этой статье описываются некоторые новые API, добавленные в пространство имён Intl. Они были анонсированы на Google I/O 2019. Давайте рассмотрим их детально.

Intl.RelativeTimeFormat

RelativeTimeFormat преобразует трудно читаемую строку во фразу с относительным временем. Посмотрим в действии с английской локалью:

const rtf = new Intl.RelativeTimeFormat('en', {numeric: 'auto'})
rtf.format(-1,'month') // "last month"
rtf.format(0,'month') // "this month"
rtf.format(1,'month') // "next month"
rtf.format(-1,'week') // "next month"
rtf.format(0,'week') // "this week"
rtf.format(1,'week') // "next week"
rtf.format(-1,'day') // "yesterday"
rtf.format(0,'day') // "today"
rtf.format(1,'day') // "tomorrow"

Обратите внимание на en, первый аргумент Intl.RelativeTimeFormat. Возможные значения numeric в опциях: always и auto. C always дата всегда формируется числами:

rtf.format(-1, 'month') // 1 месяц назад.  

Хотите использовать относительное время для тамильского? Сделайте это!

const rtf = new Intl.RelativeTimeFormat('ta-in', {numeric: 'auto'})
rtf.format(-1, 'month')
"கடந்த மாதம்"
rtf.format(0, 'month')
"இந்த மாதம்"
rtf.format(1, 'month')
"அடுத்த மாதம்"
rtf.format(-1, 'week')
"கடந்த வாரம்"
rtf.format(0, 'week')
"இந்த வாரம்"
rtf.format(1, 'week')
"அடுத்த வாரம்"
rtf.format(-1, 'day')
"நேற்று"
rtf.format(0, 'day')
"இன்று"
rtf.format(1, 'day')
"நாளை"

Для удобства есть строки с относительным временем:yesterday, today, tomorrow(вчера, сегодня, завтра) и так далее! Поддерживается в Chrome 71 и FireFox 65.

Intl.ListFormat

ListFormat  —  конструктор для объединения строк, использующий конъюнкцию и дизъюнкцию, чтобы сформировать понятную фразу.

Intl.ListFormat с английской локалью и опциями по умолчанию:

const characters = ['Harry Potter', 'Ron Weasly','Hermonie Granger']
const ltf = new Intl.ListFormat('en')
ltf.format(characters)
"Harry Potter, Ron Weasly, and Hermonie Granger"

format соединяет строки массива characters в одну новую строку с and. Без ListFormat пришлось бы писать служебные функции для размещения запятых и союзов “и” в соответствующих местах. API Intl.ListFormat позволяет с лёгкостью форматировать строки! Форматирование настраивается через options:

const characters = ['Harry Potter', 'Ron Weasly','Hermonie Granger']
const ltf = new Intl.ListFormat('en', {type: 'disjunction'})
ltf.format(characters)
"Harry Potter, Ron Weasly, or Hermonie Granger"

disjunction объединяет строки исключающим or. 

Возможные значения свойств options:

  • type: conjunction, disjunction и unit, conjunction по умолчанию. unit используется для списков единичных элементов, например:
const characters = ['Harry Potter', 'Ron Weasly','Hermonie Granger']
const ltf = new Intl.ListFormat('en', {type: 'unit'})
ltf.format(characters)
"Harry Potter, Ron Weasly, Hermonie Granger"
  • style: long и short (или narrow)

ListFormat API доступен в Chrome 72.

Intl.NumberFormat

Насколько большим может быть число?

123456789123456789 * 11 // Печатает 1358024680358024700

Результат операции выше не может оканчиваться нулём! Похоже, нам нужно что-то ещё для больших чисел. Хорошая новость: для них у нас есть BigInt:

123456789123456789n * 11n // Печатает 1358024680358024679n

Теперь правильно! 

Большие числа неудобно читать без разделителей. В этом нам поможет Intl.NumerFormat, добавляющий языкозависимые разделители. Работает он так:

const nfEn = new Intl.NumberFormat('en')
nfEn.format(1000000000) // "1,000,000,000"
const nfFr = new Intl.NumberFormat('fr')
nfFr.format(1000000000) // "1 000 000 000"

Числа форматируются в зависимости от локали. Разряды разделяются запятыми для en и пробелами для fr.

Можно использовать options в конструкторе, чтобы настроить форматирование. Например:

  • style: decimal, currency и percent. По умолчанию decimal;
  • currency: код валюты используется для денежных знаков. Вот так: USD, INR;
  • currencyDisplay: symbol и code, по умолчанию symbol.
    Можете проверить свойства здесь. Они доступны в Chrome, FireFox и Safari.

Ниже опишем ещё более впечатляющий API: Intl.DateTimeFormat

Intl.DateTimeFormat

Intl.DateTimeFormat API создан для дат и времени. Новый в API метод formatRange может использоваться так:

const df = new Intl.DateTimeFormat('en', {
    year: 'numeric',
    month: 'short',
    day: 'numeric'
})
const startDate = new Date('01-06-2019')
const endDate = new Date('10-06-2019')
df.formatRange(startDate, endDate) // Печатает Jun 1-10 2019

Вы можете удалить много обслуживающих функций из вашего пакета и просто использовать диапазоны дат!

Обратите внимание, как formatRange группирует даты одного месяца. Пожалуйста, запомните: эта функция пока доступна через флаг Chrome и скоро будет добавлена по умолчанию.

В options доступны timeZone, era, year, month, day, hour, minute, second и многое другое.

Итоги

Мы рассмотрели добавленные в Intl функции:

 1. Intl.RelativeTimeFormat API для генерации фраз о моментах времени.
2. Intl.ListFormat API для конструирования фраз из массивов строк.
3. Intl.NumberFormat может использоваться для форматирования больших чисел с учётом особенностей их отображения в языке.
4. Метод formatRange в Intl.DateTimeFormat для языкозависимого отображения даты и времени.

Читайте также:


Перевод статьи Ankita Masand: New Intl APIs in JavaScript