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

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

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

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

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Настройка i18n-фреймворка (i18next) для веб-приложения
Средняя
от 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-фреймворка (i18next) для веб-приложения

i18next — наиболее распространённый i18n-фреймворк для JavaScript-экосистемы. Работает с React, Vue, Angular, Svelte, Node.js и vanilla JS. Огромная экосистема плагинов: бэкенды для загрузки переводов, детекторы языка, форматтеры. В отличие от react-intl, не привязан к одному фреймворку.

Установка

# Базовый пакет
npm install i18next

# React-интеграция
npm install react-i18next

# Загрузка переводов через HTTP
npm install i18next-http-backend

# Определение языка браузера
npm install i18next-browser-languagedetector

# Кеширование в localStorage
npm install i18next-localstorage-backend

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

// src/i18n/config.ts
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import HttpBackend from 'i18next-http-backend'
import LanguageDetector from 'i18next-browser-languagedetector'

i18n
  .use(HttpBackend)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    // Языки приложения
    supportedLngs: ['ru', 'en', 'de', 'uk'],
    fallbackLng: 'ru',
    defaultNS: 'common',

    // Неймспейсы — разбивка переводов по доменам
    ns: ['common', 'catalog', 'checkout', 'account'],

    // Загрузка с сервера
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json',
      addPath: '/locales/add/{{lng}}/{{ns}}', // для i18next-parser
    },

    // Определение языка
    detection: {
      order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag'],
      lookupQuerystring: 'lng',
      lookupCookie: 'locale',
      lookupLocalStorage: 'i18nextLng',
      caches: ['localStorage', 'cookie'],
    },

    interpolation: {
      escapeValue: false,
      // Форматтеры для дат, чисел, валюты
      format(value, format, lng) {
        if (format === 'date') {
          return new Intl.DateTimeFormat(lng, { dateStyle: 'medium' }).format(value)
        }
        if (format === 'currency') {
          const currency = lng === 'ru' ? 'RUB' : lng === 'uk' ? 'UAH' : 'USD'
          return new Intl.NumberFormat(lng, { style: 'currency', currency, maximumFractionDigits: 0 }).format(value)
        }
        return value
      },
    },

    // Не выводить предупреждения при отсутствии ключа в dev
    saveMissing: process.env.NODE_ENV === 'development',
    missingKeyHandler(lngs, ns, key) {
      console.warn(`[i18next] Missing key: ${ns}:${key} for ${lngs.join(',')}`)
    },
  })

export default i18n
// src/main.tsx
import './i18n/config'  // импорт до App
import { Suspense } from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <Suspense fallback={<div>Загрузка...</div>}>
    <App />
  </Suspense>
)

Файлы переводов

public/locales/
  ru/
    common.json
    catalog.json
    checkout.json
  en/
    common.json
    catalog.json
    checkout.json
// public/locales/ru/catalog.json
{
  "title": "Каталог",
  "filter": {
    "title": "Фильтры",
    "reset": "Сбросить",
    "apply": "Применить",
    "price_from": "Цена от",
    "price_to": "до"
  },
  "sort": {
    "label": "Сортировка",
    "price_asc": "Дешевле",
    "price_desc": "Дороже",
    "popular": "Популярные",
    "new": "Новинки"
  },
  "items_count_one": "{{count}} товар",
  "items_count_few": "{{count}} товара",
  "items_count_many": "{{count}} товаров",
  "items_count_other": "{{count}} товаров",
  "empty": "По вашему запросу ничего не найдено",
  "price": "{{price, currency}}"
}

Использование в React

import { useTranslation, Trans } from 'react-i18next'

function CatalogPage({ count, price }: { count: number; price: number }) {
  // Загрузка конкретного неймспейса
  const { t, i18n } = useTranslation('catalog')

  return (
    <main>
      <h1>{t('title')}</h1>

      {/* Плюрализация */}
      <p>{t('items_count', { count })}</p>
      {/* ru, count=3: "3 товара" */}

      {/* Форматирование через интерполяцию */}
      <p>{t('price', { price })}</p>
      {/* ru: "14 990 ₽" */}

      {/* Несколько неймспейсов */}
      <FilterPanel />
    </main>
  )
}

// Trans компонент для текста с HTML/компонентами внутри
function PrivacyNote() {
  const { t } = useTranslation('common')

  return (
    <Trans
      i18nKey="privacy_note"
      components={{
        link: <a href="/privacy" className="underline" />,
      }}
    />
    // JSON: "Нажимая кнопку, вы принимаете <link>политику конфиденциальности</link>"
  )
}

Переключение языка

function LanguageSwitcher() {
  const { i18n } = useTranslation()

  const changeLanguage = async (lng: string) => {
    await i18n.changeLanguage(lng)
    // i18next автоматически:
    // 1. Загрузит нужные JSON файлы если ещё не загружены
    // 2. Сохранит в localStorage/cookie
    // 3. Обновит все компоненты через React context
    document.documentElement.lang = lng
  }

  return (
    <div>
      {['ru', 'en', 'de', 'uk'].map(lng => (
        <button
          key={lng}
          onClick={() => changeLanguage(lng)}
          disabled={i18n.resolvedLanguage === lng}
        >
          {lng.toUpperCase()}
        </button>
      ))}
    </div>
  )
}

SSR: i18next с Node.js

// server/i18n.ts — отдельный инстанс для SSR
import i18next from 'i18next'
import Backend from 'i18next-fs-backend'

const serverI18n = i18next.createInstance()

await serverI18n
  .use(Backend)
  .init({
    lng: 'ru',
    fallbackLng: 'ru',
    ns: ['common', 'catalog'],
    backend: {
      loadPath: './public/locales/{{lng}}/{{ns}}.json',
    },
    interpolation: { escapeValue: false },
  })

export function createI18nForRequest(locale: string) {
  return serverI18n.cloneInstance({ lng: locale })
}

Автоматическое извлечение ключей

npm install --save-dev i18next-parser

# i18next-parser.config.js
module.exports = {
  locales: ['ru', 'en', 'de'],
  output: 'public/locales/$LOCALE/$NAMESPACE.json',
  input: ['src/**/*.{ts,tsx}'],
  keepRemoved: false,
  sort: true,
}

npx i18next-parser

Парсер найдёт все вызовы t('key'), useTranslation('ns'), <Trans i18nKey="..."> и обновит JSON-файлы: добавит новые ключи, оставит имеющиеся, удалит неиспользуемые.

Неймспейсы по маршрутам

// Загрузка неймспейса только для нужной страницы
export async function loader() {
  // React Router v6 loader
  await i18n.loadNamespaces('checkout')
  return null
}

function CheckoutPage() {
  const { t } = useTranslation('checkout')
  // Неймспейс гарантированно загружен
}

Сроки

Установка и базовая конфигурация с 2 языками — 1 день. С несколькими неймспейсами, ленивой загрузкой по маршрутам, i18next-parser и CI-проверкой — 2–3 дня.