FormatJS предоставляет унифицированный подход к интернационализации
приложений, объединяя форматирование сообщений, дат, чисел и
плюрализации в рамках единого API. В React-экосистеме ключевым
механизмом доступа к этим возможностям становятся хуки, работающие
поверх intl-контекста.
Основой является IntlProvider, который прокидывает
объект intl во всё дерево компонентов. Этот объект содержит
методы форматирования и текущую локаль, а хуки лишь предоставляют
удобный доступ к нему без необходимости использования
injectIntl или HOC.
useIntl:
доступ к низкоуровневому API интернационализацииuseIntl возвращает экземпляр объекта intl,
содержащий полный набор методов FormatJS:
formatMessageformatDateformatTimeformatNumberformatPluralformatRelativeTimeformatDisplayNameГлавная задача хука — предоставить прямой доступ к API интернационализации внутри функциональных компонентов.
import { useIntl } from 'react-intl';
function Header() {
const intl = useIntl();
return (
<h1>
{intl.formatMessage({
id: 'app.title',
defaultMessage: 'Главная страница'
})}
</h1>
);
}
useIntl не принимает аргументов и возвращает один и тот
же объект intl в рамках текущего контекста.
Основной сценарий использования — работа с
formatMessage.
const intl = useIntl();
const label = intl.formatMessage(
{
id: 'button.save',
defaultMessage: 'Сохранить'
},
{
filename: 'document.txt'
}
);
Второй аргумент позволяет передавать параметры интерполяции:
{
"button.save": "Сохранить файл {filename}"
}
Результат: Сохранить файл document.txt
const intl = useIntl();
const price = intl.formatNumber(1999.99, {
style: 'currency',
currency: 'USD'
});
const date = intl.formatDate(new Date(), {
year: 'numeric',
month: 'long',
day: '2-digit'
});
Эти методы используют Intl.NumberFormat и
Intl.DateTimeFormat под капотом, обеспечивая локализованное
форматирование без ручной настройки.
intl.formatMessage(
{
id: 'cart.items',
defaultMessage: 'В корзине {count, plural, one {# товар} few {# товара} many {# товаров} other {# товаров}}'
},
{
count: 3
}
);
ICU Message Syntax позволяет выражать сложные правила без внешней логики.
useIntlintlОбъект intl стабилен в пределах одного рендера локали.
Однако изменение locale в IntlProvider
приводит к пересозданию контекста и повторному рендеру компонентов.
Частое вызовы formatMessage внутри render-функции
допустимы, но при больших списках предпочтительнее мемоизация:
const intl = useIntl();
const columns = useMemo(() => [
intl.formatMessage({ id: 'table.name' }),
intl.formatMessage({ id: 'table.price' })
], [intl]);
useFormatMessage:
специализированный хук для сообщенийuseFormatMessage — более узкий и декларативный хук,
предоставляющий функцию форматирования сообщений без необходимости
обращения к объекту intl.
Он предназначен для упрощения кода, когда требуется только
formatMessage.
import { useFormatMessage } from 'react-intl';
function Button() {
const formatMessage = useFormatMessage();
return (
<button>
{formatMessage({
id: 'button.submit',
defaultMessage: 'Отправить'
})}
</button>
);
}
useIntl| Характеристика | useIntl |
useFormatMessage |
|---|---|---|
| Доступ к API | Полный intl объект |
Только formatMessage |
| Гибкость | Максимальная | Ограниченная |
| Размер кода | Больше | Меньше |
| Сценарий | Сложная интернационализация | Простые текстовые вставки |
const formatMessage = useFormatMessage();
const text = formatMessage(
{
id: 'greeting.user',
defaultMessage: 'Привет, {name}'
},
{
name: 'Alex'
}
);
Хук удобно использовать в UI-библиотеках:
function UserCard({ name }) {
const t = useFormatMessage();
return (
<div>
{t({ id: 'user.name', defaultMessage: 'Имя' })}: {name}
</div>
);
}
useIntlИспользуется, когда требуется:
locale, timeZoneuseFormatMessageИспользуется, когда:
Оба хука опираются на единый формат ICU Message Syntax.
{t({ id: 'order.summary', defaultMessage: 'Заказ {id} на сумму {price}' }, { id: 42, price: '$10' })}
intl.formatMessage({
id: 'status.message',
defaultMessage: '{status, select, success {Успешно} error {Ошибка} other {Неизвестно}}'
}, {
status: 'success'
});
formatMessage({
id: 'files.count',
defaultMessage: '{count, plural, one {# файл} few {# файла} many {# файлов} other {# файлов}}'
}, {
count: 5
});
При обновлении locale в IntlProvider:
intluseIntl и
useFormatMessage, перерисовываютсяЭто обеспечивает реактивность интерфейса без ручного управления состоянием переводов.
useIntlimport { useIntl, IntlShape } from 'react-intl';
const intl: IntlShape = useIntl();
type Messages = {
'app.title': string;
'button.save': string;
};
Хотя FormatJS не требует строгой типизации ключей, в крупных проектах часто применяется генерация типов из JSON-файлов локализации.
IntlProviderИспользование хуков без провайдера приводит к ошибке выполнения:
useIntl требует контекст react-intluseFormatMessageНежелательно создавать объект сообщения внутри глубоко вложенных render-функций без мемоизации:
intl.formatMessage({ id: 'key' }); // допустимо
но в больших списках предпочтительнее:
const msg = useMemo(
() => intl.formatMessage({ id: 'key' }),
[intl]
);
function Component() {
const t = useFormatMessage();
return <div>{t({ id: 'text' })}</div>;
}
Минимальная зависимость от intl-API.
function Component() {
const intl = useIntl();
return intl.formatNumber(1000);
}
Используется для компонентов с разноплановой локализацией.
function Component() {
const intl = useIntl();
const t = useFormatMessage();
return (
<div>
{t({ id: 'label' })}
{intl.formatNumber(1000)}
</div>
);
}
Позволяет разделять ответственность внутри компонента.