Настройка i18n-фреймворка (react-intl) для веб-приложения

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

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Настройка i18n-фреймворка (react-intl) для веб-приложения
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Настройка i18n-фреймворка (react-intl) для веб-приложения

React Intl — часть проекта FormatJS. Отличие от i18next: react-intl строго следует стандарту ICU Message Format, что даёт мощный синтаксис для сложных случаев: плюрализация, выбор по значению, форматирование дат/чисел/валюты — всё через единый стандарт без кастомных хелперов.

Установка

npm install react-intl

Для TypeScript — типы включены в пакет.

Инициализация

// i18n/messages/ru.ts
export const ru = {
  'nav.catalog':     'Каталог',
  'nav.cart':        '{count, plural, one {Корзина ({count} товар)} few {Корзина ({count} товара)} many {Корзина ({count} товаров)} other {Корзина ({count} товаров)}}',
  'product.price':   '{price, number, ::currency/RUB}',
  'product.added':   'Товар добавлен {date, date, medium}',
  'order.status':    '{status, select, pending {Ожидает} paid {Оплачен} cancelled {Отменён} other {Неизвестно}}',
  'welcome':         'Добро пожаловать, {name}!',
}
// i18n/messages/en.ts
export const en = {
  'nav.catalog':     'Catalog',
  'nav.cart':        '{count, plural, one {Cart ({count} item)} other {Cart ({count} items)}}',
  'product.price':   '{price, number, ::currency/USD}',
  'product.added':   'Product added {date, date, medium}',
  'order.status':    '{status, select, pending {Pending} paid {Paid} cancelled {Cancelled} other {Unknown}}',
  'welcome':         'Welcome, {name}!',
}
// App.tsx
import { IntlProvider } from 'react-intl'
import { ru } from '@/i18n/messages/ru'
import { en } from '@/i18n/messages/en'

const messages = { ru, en }

function App({ locale = 'ru' }: { locale: string }) {
  return (
    <IntlProvider
      locale={locale}
      messages={messages[locale as keyof typeof messages]}
      defaultLocale="ru"
      onError={(err) => {
        // Не падать при отсутствующих ключах в разработке
        if (err.code !== 'MISSING_TRANSLATION') throw err
      }}
    >
      <Router />
    </IntlProvider>
  )
}

Использование в компонентах

import { FormattedMessage, FormattedNumber, FormattedDate, useIntl } from 'react-intl'

// Простой текст
function Greeting({ name }: { name: string }) {
  return <FormattedMessage id="welcome" values={{ name }} />
}

// Плюрализация
function CartIcon({ count }: { count: number }) {
  return (
    <span>
      <FormattedMessage id="nav.cart" values={{ count }} />
    </span>
  )
  // count=1: "Корзина (1 товар)"
  // count=5: "Корзина (5 товаров)"
}

// Числа и валюта
function Price({ value }: { value: number }) {
  return (
    <FormattedNumber
      value={value}
      style="currency"
      currency="RUB"
      maximumFractionDigits={0}
    />
  )
  // ru: "14 990 ₽"
}

// Дата
function ProductDate({ date }: { date: Date }) {
  return <FormattedDate value={date} year="numeric" month="long" day="numeric" />
  // ru: "28 марта 2026 г."
}

// select — статусы, роли, категории
function OrderStatus({ status }: { status: string }) {
  return <FormattedMessage id="order.status" values={{ status }} />
}

useIntl хук для императивного использования

function SearchInput() {
  const intl = useIntl()

  return (
    <input
      type="search"
      placeholder={intl.formatMessage({ id: 'search.placeholder' })}
      aria-label={intl.formatMessage({ id: 'search.label' })}
    />
  )
}

defineMessages: безопасная типизация

import { defineMessages, useIntl } from 'react-intl'

// Объявляем сообщения как константы — IDE autocomplete и TypeScript найдут ошибки
const messages = defineMessages({
  title: {
    id: 'catalog.title',
    defaultMessage: 'Каталог товаров',
    description: 'Заголовок страницы каталога',
  },
  empty: {
    id: 'catalog.empty',
    defaultMessage: 'Товары не найдены',
  },
})

function CatalogPage() {
  const intl = useIntl()
  return <h1>{intl.formatMessage(messages.title)}</h1>
}

Загрузка переводов асинхронно

// Переводы — отдельные чанки для каждого языка
async function loadMessages(locale: string): Promise<Record<string, string>> {
  switch (locale) {
    case 'ru': return (await import('@/i18n/messages/ru')).ru
    case 'en': return (await import('@/i18n/messages/en')).en
    case 'de': return (await import('@/i18n/messages/de')).de
    default:   return (await import('@/i18n/messages/ru')).ru
  }
}

// В компоненте
function LocalizedApp({ locale }: { locale: string }) {
  const [messages, setMessages] = useState<Record<string, string> | null>(null)

  useEffect(() => {
    loadMessages(locale).then(setMessages)
  }, [locale])

  if (!messages) return <PageLoader />

  return (
    <IntlProvider locale={locale} messages={messages}>
      <App />
    </IntlProvider>
  )
}

Извлечение сообщений для переводчиков

FormatJS предоставляет CLI для автоматического сбора всех id из кода:

npx @formatjs/cli-lib extract \
  'src/**/*.{ts,tsx}' \
  --out-file src/i18n/extracted.json \
  --id-interpolation-pattern '[sha512:contenthash:base64:6]'

Полученный JSON отдаём переводчику или загружаем в Crowdin / Phrase.

Относительное время

import { FormattedRelativeTime } from 'react-intl'

function TimeAgo({ timestamp }: { timestamp: number }) {
  const diff = Math.round((timestamp - Date.now()) / 1000) // секунды

  return (
    <FormattedRelativeTime
      value={diff}
      unit="second"
      updateIntervalInSeconds={30} // автообновление
    />
  )
  // "-5 минут назад", "вчера", "3 дня назад"
}

Сроки

Установка, настройка IntlProvider, перевод базового интерфейса (100–200 строк) на 2 языка — 1–2 дня. С асинхронной загрузкой переводов, настройкой CLI-экстракции и CI-проверкой полноты переводов — 3 дня.