Как сделать локализацию нескольких языков в приложении при получении с Backend актуальных данных в нужной локации

Ответ

Для локализации с динамическими данными с бекенда можно использовать библиотеку i18next вместе с react-i18next.

  1. Настройка i18next:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

i18n.use(initReactI18next).init({
  resources: {
    en: { translations: {} },
    ru: { translations: {} },
  },
  lng: 'en',
  fallbackLng: 'en',
  interpolation: { escapeValue: false },
});
  1. Загрузка переводов с бекенда:
const loadTranslations = async (lang) => {
  const response = await fetch(`/api/translations?lang=${lang}`);
  const data = await response.json();
  i18n.addResourceBundle(lang, 'translations', data);
  i18n.changeLanguage(lang);
};
  1. Использование в компоненте:
import { useTranslation } from 'react-i18next';

const Component = () => {
  const { t } = useTranslation();
  return <div>{t('key_from_backend')}</div>;
};

Нюансы:

  • Кешируйте переводы, чтобы избежать лишних запросов.
  • Учитывайте асинхронность загрузки (можно добавить лоадер).
  • Для SSR (Next.js) используйте getServerSideProps для предзагрузки.

Ответ 18+ 🔞

А, ну это же про локализацию, когда переводы с бекенда прилетают! Классика, блядь. Сейчас разжуем, как это с i18next запилить, чтобы не вышло пиздеца.

Смотри, первым делом надо эту библиотеку инициализировать, как полагается. Заводишь себе файлик i18n.js и пишешь там стандартную хуйню:

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

i18n.use(initReactI18next).init({
  resources: {
    en: { translations: {} },
    ru: { translations: {} },
  },
  lng: 'en',
  fallbackLng: 'en',
  interpolation: { escapeValue: false },
});

Видишь? Сначала ресурсы пустые, как твои карманы после зарплаты. Потому что мы их будем тянуть с сервака, а не хранить статично, как дурачки.

Дальше — самое интересное, ёпта. Надо эти переводы загрузить. Пишем функцию, которая дергает бекенд и суёт ответ прямо в i18next. Смотри, не обосрись:

const loadTranslations = async (lang) => {
  const response = await fetch(`/api/translations?lang=${lang}`);
  const data = await response.json();
  i18n.addResourceBundle(lang, 'translations', data);
  i18n.changeLanguage(lang);
};

Вот это уже дело! Прилетел JSON с ключами-переводами — и бац, добавляем его в ресурсы. Главное, не забудь это вызвать где надо, например, при смене языка юзером или при первоначальной загрузке приложения.

Ну и финальный аккорд — использование в компонентах. Тут всё просто, как три копейки:

import { useTranslation } from 'react-i18next';

const Component = () => {
  const { t } = useTranslation();
  return <div>{t('key_from_backend')}</div>;
};

Вызываешь t('some_key'), а библиотека уже сама находит нужный перевод в тех данных, что мы с бекенда притащили. Красота, в рот меня чих-пых!

А теперь, блядь, нюансы, на которых все погорают:

  • Кеширование, ёбаный насос! Не гоняй запросы на бекенд каждый раз, когда юзер ткнул в переключатель языка. Сохрани переводы куда-нибудь, хоть в localStorage, хоть в стейт-менеджер. А то сервер тебе ебальник отломает.
  • Асинхронность, сука! Пока переводы грузятся, покажи какой-нибудь лоадер или заглушку. Не оставляй пользователя смотреть на пустые ключи типа common.loading.... Выглядит пиздецово.
  • Если на SSR (типа Next.js) сидишь — там свои пляски с бубном. Переводы надо грузить в getServerSideProps или getStaticProps, чтобы на сервере уже всё было готово и в браузер прилетала готовая, локализованная страница, а не кусок говна.

Вот, в принципе, и вся магия. Ничего сложного, главное — не накосячить с асинхронной загрузкой и всё протестить, а то будет не "Hello World", а "хуюло ворлд", понимаешь?