FormatJS — набор библиотек для интернационализации (i18n) и локализации (l10n) JavaScript-приложений. Основная задача экосистемы — корректное отображение текста, дат, времени, чисел, валют и сообщений на разных языках и в разных регионах.
FormatJS предоставляет:
Экосистема активно использует возможности Intl API,
встроенного в JavaScript.
При разработке многоязычных приложений возникают типовые сложности:
new Date().toLocaleDateString('en-US')
// 5/28/2026
new Date().toLocaleDateString('de-DE')
// 28.5.2026
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(1000)
Результат:
$1,000.00
Для Германии:
1.000,00 $
Русский язык:
Английский язык:
Разные языки имеют разные синтаксические конструкции. Простая конкатенация строк становится непригодной.
Плохой подход:
'Hello ' + username
Экосистема состоит из нескольких пакетов.
| Пакет | Назначение |
|---|---|
react-intl |
Интернационализация React-приложений |
intl-messageformat |
Форматирование ICU-сообщений |
@formatjs/intl |
Полифиллы Intl API |
@formatjs/cli |
Инструменты командной строки |
babel-plugin-formatjs |
Извлечение сообщений |
eslint-plugin-formatjs |
Проверка правил локализации |
FormatJS строится поверх стандартного JavaScript API
Intl.
Основные классы:
| API | Назначение |
|---|---|
Intl.DateTimeFormat |
Форматирование даты |
Intl.NumberFormat |
Форматирование чисел |
Intl.RelativeTimeFormat |
Относительное время |
Intl.ListFormat |
Форматирование списков |
Intl.PluralRules |
Правила множественного числа |
Пример:
const formatter = new Intl.DateTimeFormat('ru-RU')
formatter.format(new Date())
FormatJS упрощает использование этих механизмов и объединяет их в единую систему.
Ключевая технология FormatJS — стандарт ICU MessageFormat.
ICU позволяет:
import {IntlMessageFormat} from 'intl-messageformat'
const msg = new IntlMessageFormat(
'Привет, {name}!',
'ru'
)
msg.format({
name: 'Алексей'
})
Результат:
Привет, Алексей!
const msg = new IntlMessageFormat(
'Цена: {price, number}',
'ru'
)
msg.format({
price: 1500
})
Результат:
Цена: 1 500
const msg = new IntlMessageFormat(
'Стоимость: {price, number, ::currency/USD}',
'ru'
)
msg.format({
price: 199
})
Результат:
Стоимость: 199,00 $
const msg = new IntlMessageFormat(
'Дата: {date, date, long}',
'ru'
)
msg.format({
date: new Date()
})
const msg = new IntlMessageFormat(
'Время: {time, time, short}',
'ru'
)
msg.format({
time: new Date()
})
Pluralization — одна из наиболее сложных задач локализации.
const msg = new IntlMessageFormat(
`{count, plural,
one {# item}
other {# items}
}`,
'en'
)
const msg = new IntlMessageFormat(
`{count, plural,
one {# товар}
few {# товара}
many {# товаров}
other {# товара}
}`,
'ru'
)
Примеры:
msg.format({ count: 1 })
1 товар
msg.format({ count: 3 })
3 товара
msg.format({ count: 10 })
10 товаров
Позволяют выбирать текст по условию.
const msg = new IntlMessageFormat(
`{gender, select,
male {Он вошёл}
female {Она вошла}
other {Они вошли}
}`,
'ru'
)
ICU поддерживает сложные комбинации.
const msg = new IntlMessageFormat(
`{count, plural,
one {{gender, select,
male {Он добавил # файл}
female {Она добавила # файл}
other {Добавлен # файл}
}}
other {{gender, select,
male {Он добавил # файлов}
female {Она добавила # файлов}
other {Добавлено # файлов}
}}
}`,
'ru'
)
Наиболее популярная часть FormatJS — библиотека
react-intl.
Установка:
npm install react-intl
IntlProvider хранит текущую локаль и словарь
переводов.
import {IntlProvider} fr om 'react-intl'
<IntlProvider
locale="ru"
messages={{
hello: 'Привет'
}}
>
<App />
</IntlProvider>
import {FormattedMessage} fr om 'react-intl'
<FormattedMessage id="hello" />
Результат:
Привет
<FormattedMessage
id="welcome"
values={{
name: 'Иван'
}}
/>
Сообщение:
{
welcome: 'Добро пожаловать, {name}'
}
import {FormattedNumber} from 'react-intl'
<FormattedNumber value={1000} />
<FormattedNumber
value={199}
style="currency"
currency="USD"
/>
import {FormattedDate} from 'react-intl'
<FormattedDate
value={new Date()}
year="numeric"
month="long"
day="2-digit"
/>
import {FormattedTime} from 'react-intl'
<FormattedTime value={new Date()} />
import {FormattedRelativeTime} from 'react-intl'
<FormattedRelativeTime
value={-1}
unit="day"
/>
Результат:
1 день назад
Хук предоставляет доступ к API интернационализации.
import {useIntl} from 'react-intl'
function Product() {
const intl = useIntl()
return (
<div>
{intl.formatMessage({
id: 'title'
})}
</div>
)
}
Позволяет централизованно описывать сообщения.
import {defineMessages} from 'react-intl'
export default defineMessages({
hello: {
id: 'app.hello',
defaultMessage: 'Привет'
}
})
defaultMessage — текст по умолчанию.
{
id: 'button.save',
defaultMessage: 'Сохранить'
}
Если перевод отсутствует, используется значение
defaultMessage.
Хорошая практика — использовать namespace-структуру.
Пример:
auth.login.title
auth.login.button
profile.settings.language
cart.total
Наиболее распространённый формат — JSON.
{
"app.title": "Магазин",
"cart.total": "Итого"
}
{
"app.title": "Store",
"cart.total": "Total"
}
<IntlProvider
locale={locale}
messages={messages[locale]}
>
<App />
</IntlProvider>
Для больших приложений переводы загружаются лениво.
async function loadLocale(locale) {
return import(`./locales/${locale}.json`)
}
Часто локали разделяются по чанкам.
locales/
en.json
ru.json
de.json
Webpack/Vite создают отдельные файлы.
FormatJS CLI умеет автоматически находить сообщения.
Установка:
npm install @formatjs/cli --save-dev
formatjs extract "src/**/*.{js,jsx,ts,tsx}"
CLI анализирует код и извлекает:
defineMessages()
<FormattedMessage />
intl.formatMessage()
formatjs extract \
"src/**/*.{ts,tsx}" \
--out-file lang/en.json
babel-plugin-formatjs помогает:
defaultMessage из production;eslint-plugin-formatjs проверяет:
id;Некоторые браузеры не поддерживают части Intl.
FormatJS предоставляет полифиллы:
npm install @formatjs/intl-pluralrules
npm install @formatjs/intl-relativetimeformat
Особенно важны:
FormatJS совместим с SSR.
Поддерживаются:
<IntlProvider
locale="ru"
messages={messages}
>
<App />
</IntlProvider>
На сервере и клиенте должна использоваться одинаковая локаль.
FormatJS активно кеширует форматтеры.
Создание Intl.NumberFormat дорого:
new Intl.NumberFormat()
Поэтому FormatJS переиспользует экземпляры.
const formatter = new Intl.NumberFormat('ru')
Повторное использование быстрее создания новых объектов.
Часто используется структура:
/ru/products
/en/products
/de/products
FormatJS не управляет роутингом напрямую, но легко интегрируется с роутерами.
Переводится:
{
"auth.invalidPassword": "Неверный пароль"
}
<FormattedDate
value={new Date()}
timeZone="Europe/Moscow"
/>
new Intl.ListFormat('ru').format([
'JavaScript',
'TypeScript',
'React'
])
Результат:
JavaScript, TypeScript и React
new Intl.RelativeTimeFormat('ru').format(-5, 'minute')
Результат:
5 минут назад
new Intl.DisplayNames(['ru'], {
type: 'language'
}).of('en')
Результат:
английский
Плохо:
'Hello ' + name
Правильно:
Hello {name}
Плохо:
<button>Сохранить</button>
Правильно:
<FormattedMessage id="button.save" />
Плохо:
`${count} товаров`
Правильно:
{count, plural, ...}
В больших проектах появляются:
FormatJS используется вместе с:
Пример:
src/
locales/
en.json
ru.json
i18n/
messages.ts
provider.tsx
В TypeScript часто типизируют ключи.
type MessageIds =
| 'app.title'
| 'cart.total'
Крупные проекты автоматически генерируют типы из JSON-переводов.
react-intl работает и в React Native, но требует
дополнительных polyfill.
new Intl.NumberFormat('ru', {
style: 'unit',
unit: 'kilometer'
}).format(10)
Результат:
10 км
new Intl.NumberFormat('ru', {
notation: 'compact'
}).format(1200000)
Результат:
1,2 млн
Node.js поддерживает Intl из коробки.
Пример:
import {IntlMessageFormat} from 'intl-messageformat'
| Термин | Значение |
|---|---|
| i18n | Интернационализация |
| l10n | Локализация |
Интернационализация — подготовка приложения к разным языкам.
Локализация — адаптация под конкретный регион.
Используется ICU и Intl.
Работает вне React.
Подходит для enterprise-приложений.
Особенно важна для славянских языков.
Поддерживаются:
Синтаксис MessageFormat непрост:
{count, plural, one {...} other {...}}
При плохой организации JSON-файлы быстро разрастаются.
Все строки должны проходить через систему локализации.
| Библиотека | Особенности |
|---|---|
| FormatJS | ICU, мощная pluralization |
| i18next | Гибкость, множество плагинов |
| LinguiJS | Компактность |
| Polyglot.js | Простота |
| vue-i18n | Решение для Vue |
FormatJS особенно эффективен в:
FormatJS развивается вместе с JavaScript Intl API.
Появляются:
Все пользовательские строки должны: