
Привет, друзья!
В данной статье я хочу рассказать вам об Internationalization API — интерфейсе, предоставляемом браузером, позволяющем выполнять интернационализацию и локализацию веб-приложений.
Статья состоит из 2 частей: теоретической и практической. В теоретической части мы кратко рассмотрим возможности, предоставляемые Internationalization API. В практической — создадим пример локализованного приложения с помощью разработанной мной утилиты.
Теория
Internationalization API предоставляет следующие возможности:
- локализованное (далее предполагается) сравнение строк
- форматирование чисел, включая валюту, различные единицы измерения и проценты
- форматирование даты и времени, включая относительные периоды, такие как завтра, вчера, через неделю и т.д.
- форматирование названий языков, регионов, скриптов и валют
- форматирование списков с соединительным союзом
Иили разделительным союзомИЛИ - "плюрализация" — перевод во множественное число
- преобразование регистра
В настоящее время Internationalization API поддерживается всеми современными браузерами.
Несмотря на то, что в JavaScript существуют такие методы для локализации как:
Array.toLocaleString()String.localeCompare(),.toLocalLowerCase(),.toLocalUpperCase()Number.toLocaleString()Date.toLocaleString(),.toLocaleDateString(),.toLocaleTimeString()
их зачастую оказывается недостаточно.
Кроме того, поведение данных методов определяется конкретной реализацией ECMAScript, т.е. браузером.
Функционал, определенный в Internationalization API, инкапсулирован в объекте Intl. Данный объект не имеет внутреннего метода [[Construct]], поэтому не может вызываться как конструктор с помощью ключевого слова new. Он также не имеет внутреннего метода [[Call]], поэтому не может вызываться как функция.
Intl включает в себя следующие интерфейсы-конструкторы:
Collator— сравнение строкDateTimeFormat— форматирование даты и времениDisplayNames— форматирование названий языков, регионов и т.д. на других языкахListFormat— форматирование списковLocale— определение локалиNumberFormat— форматирование чиселPluralRules— плюрализацияRelativeTimeFormat— форматирование относительных периодов времени
Возможные значения:
Пример получения текущей даты и времени в дефолтной локали
// [] означает текущую локаль (локаль по умолчанию) const currentDateAndTime = new Intl.DateTimeFormat([], { dateStyle: 'short', timeStyle: 'short' }).format() console.log(currentDateAndTime) // 03.08.2021, 15:57
Locale
Конструктор Locale используется для создания экземпляров идентификаторов локали. Первым обязательным аргументом, передаваемым Locale, является локаль, которая может состоять из следующего:
- код языка
- код диалекта
- код региона или страны
- один или несколько уникальных вариантных подтегов (subtags)
- одна или несколько последовательностей из расширения
BCP 47 - последовательность из расширения для частного использования
В большинстве случаев достаточно указать код языка или код языка и код страны через дефис:
const ru = new Intl.Locale('ru-RU')
Вторым опциональным аргументом Locale является объект с настройками:
const ru = new Intl.Locale( 'ru', { region: 'RU', hourCycle: 'h24', calendar: 'gregory' } )
Локаль может быть строкой или объектом. Пустой массив означает использование текущей локали пользователя:
const now = new Intl.DateTimeFormat([], { timeStyle: 'short' }).format()
DateTimeFormat
Конструктор DateTimeFormat используется для форматирования даты и времени. Он принимает локаль и объект с настройками.
Сигнатура
new Intl.DateTimeFormat(locale: object | string | [], options: object).format(date) // [] - локаль по умолчанию // date - дата, время или дата и время
Настройки
| Свойство | Описание |
|---|---|
| timeZone | часовой пояс: UTC, America/New_York, Europe/Paris и т.д. |
| calendar | календарь: chinese, gregory, hebrew, indian, islamic и т.д. |
| numberingSystem | система счисления: arab, beng, fullwide, latin и т.д. |
| localeMatcher | алгоритм для поиска совпадений: lookup, best fit |
| formatMatcher | алгоритм для форматирования: basic, best fit |
| hour12 | если имеет значение true, используется 12-часовой формат |
| hourCycle | часовой формат: h11, h12, h23, h24 |
| dateStyle | стиль форматирования даты: full, long, medium, short |
| weekday | день недели: long, short, narrow |
| day | день месяца: numeric, 2-digit |
| month | месяц: numeric, 2-digit, long, short, narrow |
| year | год: numeric, 2-digit |
| era | эпоха: long, short, narrow |
| timeStyle | стиль форматирования времени: full, long, medium, short |
| hour | часы: numeric, 2-digit |
| minute | минуты: numeric, 2-digit |
| second | секунды: numeric, 2-digit |
| dayPeriod | часть дня (утро, вечер и т.п.): narrow, short, long |
| timeZoneName | название часового пояса (UTC, PTC): long, short |
Настройки localeMatcher и formatMatcher могут передаваться любому конструктору, предоставляемому Intl, но используются редко.
По умолчанию new Intl.DateTimeFormat().format() возвращает текущую дату в кратком виде (dateStyle: short).
Примеры
const formatDateTime = ({ locale = [], date = Date.now(), ...options } = {}) => new Intl.DateTimeFormat(locale, options).format(date) console.log( '\n', // русский formatDateTime(), // 17.08.2021 '\n', // американский английский formatDateTime({ locale: 'en-US', dateStyle: 'short', timeStyle: 'short' }), // 8/17/21, 3:56 PM, '\n', // британский английский formatDateTime({ locale: 'en-GB', dateStyle: 'long', timeStyle: 'short' }), // 17 August 2021 at 15:57 '\n', // японский formatDateTime({ locale: 'ja-JP', dateStyle: 'short' }), // 2021/08/17 '\n', // испанский formatDateTime({ locale: 'es-ES', dateStyle: 'full', timeStyle: 'full' }), // martes, 17 de agosto de 2021, 15:57:49 (hora estándar de Ekaterimburgo) '\n', // французский formatDateTime({ locale: 'fr-FR', weekday: 'long', day: '2-digit', month: 'long', year: 'numeric', hour: '2-digit' }) // mardi 17 août 2021, 15 h )
Другие методы
formatToParts()— возвращает массив объектов, содержащих форматированную дату в виде пар ключ/значение ({ type: 'weekday', value: 'Monday' })formatRange(startDate, endDate)— возвращает диапазон, например,01/10/2022, 10:00 AM - 12:00 PMformatRangeToParts()resolveOptions()— возвращает объект со свойствами, значениями которых являются вычисленные настройки форматирования для локали, даты и времени
RelativeTimeFormat
Конструктор RelativeTimeFormat используется для локализации относительного времени, например, вчера, завтра, на следующей неделе, в прошлом месяце и т.д. Данный метод принимает локаль и объект с настройками.
Сигнатура
new Intl.RelativeTimeFormat(locale, options).format(amount, unit) // amount - количество единиц времени // unit - единица времени: `day`, `month`, `year` и т.д.
Положительное число в amount означает будущее, отрицательное — прошлое.
Настройки
| Свойство | Описание |
|---|---|
| numeric | always — "1 день назад" (дефолтное значение), auto — "вчера" |
| style | long (дефолтное значение), short, narrow |
В данном случае метод format в качестве аргументов принимает число и единицу времени.
Примеры
const formatRelativeTime = ({ locale = [], value = '1 day', ...options } = {}) => { const [amount, unit] = value.split(/[\s_]/) return new Intl.RelativeTimeFormat(locale, options).format(amount, unit) } console.log( '\n', formatRelativeTime(), // через 1 день '\n', formatRelativeTime({ locale: 'en-US', value: '-1 day', numeric: 'auto' }), // yesterday '\n', formatRelativeTime({ locale: 'fr-FR', value: '1 week', style: 'long' }), // dans 1 semaine '\n', formatRelativeTime({ locale: 'ja-JP', value: '-1 month', numeric: 'auto', style: 'long' }) // 先月 )
NumberFormat
Конструктор NumberFormat используется для форматирования чисел, валюты, процентов и единиц измерения, таких как длина, температура и др. Данный метод принимает локаль и объект с настройками.
Сигнатура
new Intl.NumberFormat(locale, options).format(number)
Настройки
| Свойство | Описание |
|---|---|
| style | вид единиц: decimal — число с плавающей точкой, currency — валюта, percent — проценты, unit — единицы измерения. От этой настройки зависят другие |
| notation | стиль форматирования: standard, scientific, engineering, compact |
| numberingSystem | система счисления: arab, beng, deva, fullwide, latn и др. |
| minimumIntegerDigits | минимальное количество цифр целой части числа (от 1 до 21; по умолчанию 1) |
| minimumFractionDigits | минимальное количество цифр после запятой (от 0 до 20; по умолчанию 0) |
| maximumFractionDigits | максимальное количество цифр после запятой (от 0 до 20; по умолчанию наибольшее значение из minimumFractionDigits и 3) |
| minimumSignificantDigits | минимальное количество значащих цифр (от 1 до 21; по умолчанию 1) |
| maximumSignificantDigits | минимальное количество значащих цифр (от 1 до 21; по умолчанию minimumSignificantDigits) |
| signDisplay | отображение символов +/-: auto, never, always, exceptZero |
| useGrouping | если имеет значение false, разделители тысяч будут игнорироваться |
| compactDisplay | форматирование при использовании нотации compact |
| currency | код валюты при использовании стиля currency: USD, EUR, RUB и т.д. |
| currencyDisplay | отображение символа/названия валюты при использовании стиля currency: symbol, narrowSymbol, code, name |
| currencySign | форматирование отрицательных значений при использовании стиля currency: standard, accounting |
| unit | вид единицы измерения: centimeter, meter, minute, hour, byte и т.д. |
| unitDisplay | формат отображения единицы измерения: long, short, narrow |
Примеры
const formatNumber = ({ locale = [], number = 1234.56, ...options } = {}) => new Intl.NumberFormat(locale, options).format(number) console.log( '\n', formatNumber(), '\n', // 1 234,56 formatNumber({ locale: 'en-US' }), '\n', // 1,234.56 formatNumber({ locale: 'de-DE', style: 'currency', currency: 'EUR' }), '\n', // 1.234,56 € formatNumber({ locale: 'fr-FR', style: 'percent' }), '\n', // 123 456 % formatNumber({ locale: 'it-IT', style: 'unit', unit: 'celsius', minimumFractionDigits: 3 }), '\n' // 1.234,560 °C )
DisplayNames
Конструктор DisplayNames используется для форматирования названий языков, диалектов, регионов и валют на другом языке. Данный метод принимает локаль и объект с настройками.
Сигнатура
new Intl.DisplayNames(locale, options).of(localeOf)
Настройки
| Свойство | Описание |
|---|---|
| type | тип названия: language, region, script, currency |
| style | стиль форматирования: long, short, narrow |
| fallback | резерв: code, none |
Обратите внимание: настройка type является обязательной. При этом хорошо поддерживается только type со значением language.
Примеры
const formatName = ({ locale = [], localeOf = 'en-US', type = 'language', ...options } = {}) => new Intl.DisplayNames(locale, { type, ...options }).of(localeOf) console.log( '\n', formatName(), '\n', // американский английский formatName({ localeOf: 'Egyp', type: 'script' }), '\n', // египетская иероглифическая formatName({ locale: 'fr-FR', localeOf: 'AU', type: 'region' }), '\n', // Australie - Авcтралия по-французски formatName({ locale: 'pl-PL', localeOf: 'GBP', type: 'currency', style: 'long' }), '\n' // funt szterling - английские фунты стерлингов на польском )
ListFormat
Конструктор ListFormat используется для форматирования списков путем подстановки соединительного союза И или разделительного союза ИЛИ. Данный метод принимает локаль и объект с настройками.
Сигнатура
new Intl.ListFormat(locale, options).format(list)
Настройки
| Свойство | Описание |
|---|---|
| type | формат вывода: conjunction (и; дефолтное значение), disjunction (или), unit (нет) |
| style | стиль форматирования: long, short, narrow |
Примеры
const browsers = ['Chrome', 'Firefox', 'Safari'] const formatList = ({ locale = [], list = browsers, ...options } = {}) => new Intl.ListFormat(locale, options).format(list) console.log( '\n', formatList(), '\n', // Chrome, Firefox и Safari formatList({ locale: 'en-US', style: 'short' }), '\n', // Chrome, Firefox, & Safari formatList({ locale: 'ja-JP', type: 'disjunction' }), '\n' // Chrome、Firefox、またはSafari )
Collator
Конструктор Collator используется для сравнения строк с учетом локали. Данный метод принимает локаль и объект с настройками.
Сигнатура
new Intl.Collator(locale, options).compare(str1, str2)
Настройки
| Свойство | Описание |
|---|---|
| usage | sort — сортировка (дефолтное значение) или search — поиск |
| sensitivity | чувствительность: base, accent, case, variant |
| collation | сопоставление вариантов для нескольких языков |
| numeric | true означает сравнение чисел |
| ignorePunctuation | true означает игнорирование пунктуации |
| caseFirst | upper — сначала идут строки, начинающиеся с большой буквы, lower — сначала идут строки, начинающиеся с маленькой буквы |
Результат
0— строки равны-1— первая строка "меньше" второй1— первая строка "больше" второй
Примеры
const compareValues = ({ locale = [], values = [], ...options } = {}) => new Intl.Collator(locale, options).compare(...values) console.log( '\n', compareValues({ values: ['a', 'á'], sensitivity: 'base' }), '\n', // 0 -> одинаковые compareValues({ values: ['2', '10'] }), '\n', // 1 -> '2' > '10' compareValues({ values: ['2', '10'], numeric: true }), '\n' // -1 -> 2 < 10 )
PluralRules
Конструктор PluralRules используется для плюрализации (перевода во множественное число). Данный метод принимает локаль и объект с настройками.
Сигнатура
new Intl.PluralRules(locale, options).select(number)
Настройки
| Свойство | Описание |
|---|---|
| type | cardinal — количество элементов (дефолтное значение), ordinal — порядок элемента (первый, второй, третий и т.д.) |
Примеры
const pluralize = ({ locale = [], number = 1, ...options } = {}) => new Intl.PluralRules(locale, options).select(number) console.log( '\n', pluralize(), '\n', // one pluralize({ locale: 'ru-RU', type: 'ordinal' }), '\n' // other )
В настоящее время поддерживается только локаль en-US.
Практика
В данном разделе мы создадим небольшое локализованное приложение с помощью разработанной мной утилиты easy-intl.
Принцип работы утилиты подробно описан в документации. Многие вещи были рассмотрены в теоретической части. Поэтому, с вашего позволения, здесь я опишу только ключевые моменты.
Демо приложения:
Создаем директорию для проекта и устанавливаем easy-intl:
mkdir intl-app cd !$ yarn add easy-intl # or npm i easy-intl
Структура проекта будет следующей:
- intl - options.js - настройки для утилиты - dictionary.js - словарь для кастомной локализации - index.html - style.css - script.js
Как сказал бы Ватсон, все ЭЛЕМЕНТАРНО.
В стилях у нас не будет ничего интересного, поэтому
* { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Montserrat', sans-serif; letter-spacing: 1px; } h1 { margin: 1rem 0; text-align: center; font-size: 2rem; } .container { display: flex; flex-wrap: wrap; justify-content: center; } .card { margin: 1rem; width: 320px; padding: 0.75rem; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } main > .card { position: fixed; top: 10%; left: 50%; transform: translateX(-50%); margin: 1rem auto; box-shadow: none; display: flex; flex-direction: column; justify-content: center; align-items: center; border-radius: 50%; } main > .card img { position: absolute; z-index: -1; width: 100px; opacity: 0.9; filter: brightness(0.9); } select { width: 50px; padding: 0.25rem; font-weight: bold; border-radius: 4px; opacity: 0.95; cursor: pointer; } select:focus-visible { outline: none; } h2 { font-size: 1.4rem; margin: 0.75rem 0; } h3, h4 { margin: 0.5rem 0; } h3 { font-size: 1.2rem; } h4 { font-size: 1.1rem; }
Что касается разметки, то в процессе локализации easy-intl ориентируется на следующие атрибуты:
data-intl_type— тип содержимого для локализации. Возможные значения:
date— дата или время, или дата и времяrelative— относительный период времениnumber— число, включая валюту, проценты и единицы измеренияnames— название языка, региона, валюты и т.д.list— списокcompare— строки для сравненияplural— строка для перевода во множественное числоcustom— строка, которая используется в качестве ключа словаря для кастомной локализации
data-intl_value— собственно, содержимое для локализации; зависит отdata-intl_typedata-intl_options— строковые (inline) настройки для локализации; зависят отdata-intl_type. Данные настройки имеют высший приоритетdata-intl_root— индикатор (атрибут без значения) корневого HTML-элемента для локализации.easy-intlпозволяет выполнять разную локализацию для разных частей приложения — дочерние элементы нижележащего (в иерархииDOM)data-intl_rootне будут локализоваться вышестоящимdata-intl_rootdata-intl_map— по умолчаниюeasy-intlвыполняет локализацию значений свойстваtextContext, а также атрибутовtitleиplaceholderэлементов, имеющих атрибутdata-intl_type. Значение атрибутаdata-intl_mapстановится ключом объектаmapвида{ [data-intl_map]: локализованное data-intl_value }— геттера экземпляраEasyIntl. Данный объект позволяет выполнять ручную локализацию других свойств и атрибутов соответствующих элементов.
Вот как будет выглядеть наша разметка:
<main data-intl_root id="global_root"> <h1 data-intl_type="custom" data-intl_value="main_title" data-intl_map="main_title"> Easy Intl </h1> <section class="card"> <img src="https://cdn-icons-png.flaticon.com/512/814/814513.png" alt="" role="presentation" /> <select id="locale"> <option value="ru-RU">Ru</option> <option value="en-US" selected>En</option> <option value="de-DE">De</option> <option value="ja-JP">Ja</option> </select> </section> <div class="container"> <section class="card"> <h2 data-intl_type="custom" data-intl_value="date_title" data-intl_map="date_title"> Дата и время </h2> <div class="box"> <h3 data-intl_type="custom" data-intl_value="without_options"> Без встроенных настроек </h3> <time data-intl_type="date" data-intl_value="2021-08-16 12:00"></time> </div> <div class="box"> <h3 data-intl_type="custom" data-intl_value="with_options"> Со встроенными настройками </h3> <time data-intl_type="date" data-intl_value="2021-08-16 12:00" data-intl_options="dateStyle: long, timeStyle: 'short'"></time> </div> </section> <section data-intl_root id="local_root" class="card"> <h2 data-intl_type="custom" data-intl_value="date_title"> Дата и время </h2> <div class="box"> <h3 data-intl_type="custom" data-intl_value="without_options"> Без встроенных настроек </h3> <time data-intl_type="date" data-intl_value="2021-08-16 12:00"></time> </div> <div class="box"> <h3 data-intl_type="custom" data-intl_value="with_options"> Со встроенными настройками </h3> <time data-intl_type="date" data-intl_value="2021-08-16 12:00" data-intl_options="day: 'numeric', month: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit'"></time> </div> </section> <section class="card"> <h2 data-intl_type="custom" data-intl_value="relative_title"> Относительное время </h2> <div class="box"> <h3 data-intl_type="custom" data-intl_value="without_options"> Без встроенных настроек </h3> <p data-intl_type="relative" data-intl_value="1 day" data-intl_map="1_day"></p> </div> <div class="box"> <h3 data-intl_type="custom" data-intl_value="with_options"> Со встроенными настройками </h3> <p data-intl_type="relative" data-intl_value="1_day" data-intl_options='numeric: "always"'></p> </div> </section> <section class="card"> <h2 data-intl_type="custom" data-intl_value="number_title">Число</h2> <div class="box"> <h3 data-intl_type="custom" data-intl_value="without_options"> Без встроенных настроек </h3> <p data-intl_type="number" data-intl_value="123.45"></p> </div> <div class="box"> <h3 data-intl_type="custom" data-intl_value="with_options"> Со встроенными настройками </h3> <h4 data-intl_type="custom" data-intl_value="currency_title"> Валюта </h4> <p data-intl_type="number" data-intl_value="123.45" data-intl_options="style: currency; currency: USD"></p> <h4 data-intl_type="custom" data-intl_value="unit_title"> Единица измерения </h4> <p data-intl_type="number" data-intl_value="123.45" data-intl_options="{ style: unit; unit: celsius }"></p> </div> </section> <section class="card"> <h2 data-intl_type="custom" data-intl_value="names_title"> Названия языков и т.д. </h2> <div class="box"> <h3 data-intl_type="custom" data-intl_value="without_options"> Без встроенных настроек </h3> <p data-intl_type="names" data-intl_value="ru"></p> </div> <div class="box"> <h3 data-intl_type="custom" data-intl_value="with_options"> Со встроенными настройками </h3> <p data-intl_type="names" data-intl_value="EUR" data-intl_options="type: currency"></p> </div> </section> <section class="card"> <h2 data-intl_type="custom" data-intl_value="list_title">Список</h2> <div class="box"> <h3 data-intl_type="custom" data-intl_value="without_options"> Без встроенных настроек </h3> <p data-intl_type="list" data-intl_value="Chrome, Firefox, Safari"></p> </div> <div class="box"> <h3 data-intl_type="custom" data-intl_value="with_options"> Со встроенными настройками </h3> <p data-intl_type="list" data-intl_value="[Chrome, 'Firefox', `Safari`]" data-intl_options="type: disjunction"></p> </div> </section> </div> </main>
Здесь у нас имеется следующее:
- два элемента с атрибутом
data-intl_root(с идентификаторамиglobal_rootиlocal_root) - переключатель локали (с идентификатором
locale) — по умолчаниюeasy-intlвыполняет автоматическую локализацию при создании экземпляра и изменении локали. Автоматическую локализацию можно отключить, передав в конструкторEasyIntlнастройкуautorunсо значениемfalse - разделы с датой и временем (один в
global_rootи еще один вlocal_root), относительным временем, числами (число, валюта и единица измерения), названием языка (язык и валюта) и списком - все заголовки имеют атрибут
data-intl_custom— перевод заголовков содержится в словаре - некоторые элементы имеют атрибут
data-intl_map - настройки могут содержать символы
'"{}` и разделяться запятой или точкой запятой. Ключ и значение должны разделяться двоеточием - список может содержать символы
'"[]` и разделяться запятой или точкой запятой
Определим некоторые настройки для глобальной локализации в intl/options.js (некоторые настройки являются дефолтными, но в данном случае большого значения это не имеет):
export default { date: { dateStyle: 'short' }, relative: { numeric: 'auto' }, number: { style: 'decimal' }, names: { type: 'language' }, list: { type: 'conjunction' } }
Определим словарь для заголовков в intl/dictionary.js для русского и американского английского языков:
export default { 'ru-RU': { main_title: 'Пример использования Easy Intl', locale_title: 'Локаль', date_title: 'Дата и время', relative_title: 'Относительное время', number_title: 'Число', currency_title: 'Валюта', unit_title: 'Единицы измерения', names_title: 'Названия языков и т.д.', list_title: 'Список', without_options: 'Без встроенных настроек', with_options: 'Со встроенными настройками' }, 'en-US': { main_title: 'Example of use Easy Intl', locale_title: 'Locale', date_title: 'Date and time', relative_title: 'Relative time', number_title: 'Number', currency_title: 'Currency', unit_title: 'Units', names_title: 'Language names etc.', list_title: 'List', without_options: 'Without inline options', with_options: 'With inline options' } }
Переходим к основному скрипту (script.js). Импортируем EasyIntl, настройки и словарь:
import { EasyIntl } from './node_modules/easy-intl/index.js' import options from './intl/options.js' import dictionary from './intl/dictionary.js'
Создаем экземпляр EasyIntl, передавая в конструктор локаль en-US, селектор корневого элемента для глобальной локализации, словарь и настройки (обратите внимание, что объект настроек должен быть распакован):
const globalIntl = new EasyIntl({ locale: 'en-US', root: '#global_root', dictionary, ...options })
Поскольку мы не определяем настройку autorun со значением false, создание экземпляра EasyIntl приводит к автоматической локализации приложения (за исключением содержимого дочерних элементов local_root).
Прелесть easy-intl (и, конечно, самого Intl) заключается в том, что дефолтная локаль пользователя определяется автоматически. Это означает, что для локализации приложения на языке пользователя достаточно создать экземпляр EasyIntl (разумеется, при условии добавления к необходимым элементам атрибутов data-intl_type и data-intl_value). Поскольку для всех вспомогательных функций, используемых easy-intl, включая, корневой элемент, определены дефолтные настройки (многие дефолтные настройки определяются Intl), для локализации приложения достаточно выполнить:
new EasyIntl()
Посмотрим на локализуемые элементы, карту локализации, в целом, и локализацию основного заголовка, в частности:
console.log(globalIntl.elements) // [h1, h2, h3, ...] console.log(globalIntl.map) /* { 1_day: "tomorrow" date_title: "Date and time" main_title: "Example of use Easy Intl" } */ console.log(globalIntl.map['main_title']) // Example of use Easy Intl
Выполним ручную локализацию содержимого дочерних элементов local_root:
const localIntl = new EasyIntl({ // отключаем автоматическую локализацию autorun: false, dictionary, // передаем другие настройки для даты date: { day: '2-digit', month: 'long', year: 'numeric' } }) // определяем локаль localIntl.locale = 'ja-JP' // определяем корневой элемент localIntl.root = '#local_root' // выполняем локализацию localIntl.localize()
Получаем ссылку на переключатель локали и обрабатываем ее изменение:
const localeSelector = document.querySelector('#locale_selector') localeSelector.onchange = (e) => { // изменение свойства `locale` приводит к автоматической локализации globalIntl.locale = e.target.value }
Приоритет настроек следующий (от минимального к максимальному):
new EasyIntl(options)intl.localize(options)data-intl_options="options"
Получаем вполне работоспособное локализованное приложение:


Пожалуй, это все, чем я хотел поделиться с вами в данной статье.
Если вас заинтересовала утилита easy-intl, не стесняйтесь использовать ее в своих проектах. Как всегда, приветствуется любой фидбэк как в форме личных сообщений, так и на GitHub.
Что касается планов по дальнейшей разработке утилиты, то, кроме небольших доработок, связанных с преобразованием строковых значений атрибутов data-intl_value в пригодный для Intl формат, в них входит добавление типов для TypeScript и, возможно, адаптация утилиты под React в форме хука или связки провайдера и хука.
Как видите, Internationalization API предоставляет довольно интересные возможности, которые при правильном использовании могут существенно облегчить процесс интернационализации и локализации веб-приложений.
Вместе с тем надо понимать, что Internationalization API не предназначен для перевода (его задачи четко обозначены в спецификации), поэтому многие вещи придется делать вручную или прибегать к помощи таких интерфейсов, как Google Cloud Translation API или API Переводчика Яндекса.
Также важно учитывать, что Internationalization API является относительно новым интерфейсом, некоторые его возможности еще находятся в процессе реализации браузерами, и, вероятно, в будущем появятся новые "фичи".
Благодарю за внимание и хорошего дня!

