24 December 2019

Локализация React приложении

Website developmentJavaScriptReactJSLanguage localisationTypeScript

Всем привет!


До нового года остаются считанные дни. Наткнулся на свой список дел, которые собирался сделать в 2019-м, среди них оказалось и написать статью на Хабр. Самое время заскочить в уходящий вагон).


Сразу оговорюсь, пиарю свой велосипед, если такое Вам не по душе, то можете смело пропускать статью.


Что такое локализация?


Под локализацией здесь и далее будем понимать процесс адаптации приложения под разные языки и регионы. Локализация это не только про перевод текста. Пользователям приятнее видеть привычный формат дат, денежных значений, даже разделители в числах могут играть роль.


Мотивация


Собственно зачем вообще нужно заниматься локализацией приложения? Локализация приложения это то самое пресловутое повышение доступности вашего интерфейса для пользователей, о котором в последнее время так много принято говорить. Локализация расширяет целевую группу на которое ориентировано ваше приложение.


Что хотелось от библиотеки локализации


  1. Поддержка ICU грамматики
  2. Форматирование дат
  3. Форматирование чисел

Что получилось


Ссылка на GitHub.


За основу была взята самая популярная библиотека (согласно звездочка анализу) для локализации React приложении react-intl. Под капотом react-intl используется пакет intl-messageformat-parser который строит AST дерево. Согласно bundlephobia значительный размер как раз и занимает парсер. Он не написан руками, а использует PEG.js. Я написал для этих целей свой, который весит в 6 раз меньше. Очень вероятно, что я мог упустить какой-то кейс, буду благодарен, если кто-нибудь подскажет.


Благодаря отличной поддержке Internationalization API современными браузерами, форматирование дат и чисел решается само собой. Всё что нужно, это хранить где-то текущий язык пользователя, чтобы применять его к форматированию и предоставлять более удобное api, в виде formatSomething(value, options).


Таким образом получился пакет @eo-locale/core который вообще ни привязан к какому либо фреймворку или библиотеке и может использоваться достаточно гибко.


React


Версия для React представляет из себя набор компонентов и хуков.


Чтобы начать использовать eo-locale оберните приложение в Provider.


import { EOLocale } from 'eo-locale';

const locales = [
  {
    language: 'en',
    messages: {
      hello: 'Hello {name}!'
    }
  },
];

<EOLocale.Provider language="en" locales={locales}>
  <span>
    <EOLocale.Text id="hello" name="World" /> // Helo World!
  </span>
</EOLocale.Provider>

Форматирование чисел доступно через проксирование стандартных свойств Intl.NumberFormat


import { EOLocale } from 'eo-locale';

<EOLocale.Number value={1000} />
// 1,000

<EOLocale.Number
  value={1000}
  currency="EUR"
  maximumFractionDigits={2}
  minimumFractionDigits={2}
  style="currency"
/>
// €1,000.00

Аналогичным образом реализовано форматирование дат:


import { EOLocale } from 'eo-locale';

<EOLocale.Date value={new Date(2019, 2, 19)} />
// 3/19/2019

<EOLocale.Date
  value={new Date(2019, 2, 19)}
  day="numeric"
  month="long"
  year="numeric"
  weekday="long"
 />
 // Tuesday, March 19, 2019

Всё вышеперечисленное также можно сделать не через компоненты, а с помощью хука useTranslator:


import { useTranslator } from 'eo-locale';

function SomeComponent() {
  const translator = useTranslator();

  return <div>{translator.formatNumber(1000)}</div>;
}

Одним из важных преимуществ перед другими подобными библиотеками считаю возможность использовать компоненты в качестве props. Например, у вас есть стилизованный компонент Money, который показывает значение в одном цвете, а знак валюты в другом и вам нужно вставить некоторую сумму в локаль:


import { EOLocale } from 'eo-locale';
import { Money } from '...somewhere';

const locales = [
  {
    language: 'en',
    messages: {
      total: 'Total price is {price}'
    }
  },
];

<EOLocale.Text
  id="total"
  price={<Money amount={1000} />}
/>
// Total price is €1,000.00

Есть и возможность отображать plural значения. Она реализована с использованием Intl.PluralRules.


import { EOLocale } from 'eo-locale';

const locales = [
  {
    language: 'en',
    messages: {
      items: '{count, plural, one {You have one item} other {You have {count} items}}'
    }
  },
];

<EOLocale.Text id="items" count={3} />
// You have 3 items

Preact


Все те же возможности реализованы и для Preact в соответствующем пакете.


Некоторые особенности


Библиотека полностью написана на Typescript, поэтому тайпинги поставляются из коробки.


Не так давно столкнулись с проблемой того, что при локализации кодов ошибок, которые присылает сервер отсутствовали переводы на клиенте. Для этого в Provider была добавлена возможность прокинуть обработчик onIdMissing, с помощью которого можно логировать такого рода ошибки.


Заключение


Очень надеюсь, что кому-то библиотека окажется полезной. Буду рад предложениям и здоровой критике. Не забывайте, что даже если сейчас ваш сайт ориентирован только на один язык, то со временем эта ситуация может измениться. Заложить поддержку мультиязычности заранее не требует особых временных затрат, при этом все используемые в приложении тексты будут структурированы.

Tags: javascript typescript react
Hubs: Website development JavaScript ReactJS Language localisation TypeScript
+15
4.7k 61
Comments 10
Ads
Top of the day