Налаштування 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 автодоповнення та 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 дні.