Налаштування 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
      },
    },

    // Не виводити попередження при відсутніх ключах у розробці
    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 дні.