Хук useTranslation с namespace

Работа с пространствами имён (namespaces) в i18next является ключевым механизмом организации переводов в крупных приложениях. Хук useTranslation в связке с namespaces позволяет структурировать словарь, изолировать доменные области интерфейса и минимизировать избыточную загрузку переводов.


Пространства имён как структура организации переводов

Namespaces в i18next представляют собой логические контейнеры для ключей локализации. Вместо единого плоского JSON-файла используется набор файлов или объектов, разделённых по функциональным областям:

  • auth — авторизация и регистрация
  • common — общие строки интерфейса
  • dashboard — панель управления
  • errors — сообщения об ошибках

Такой подход снижает связность и упрощает поддержку больших приложений.

Пример структуры:

locales/
  en/
    common.json
    auth.json
    dashboard.json
  ru/
    common.json
    auth.json
    dashboard.json

Базовое использование useTranslation

В экосистеме react-i18next хук useTranslation является основным инструментом доступа к переводам внутри компонентов.

Базовый вариант без указания namespace:

import { useTranslation } from "react-i18next";

function Header() {
  const { t } = useTranslation();

  return <h1>{t("title")}</h1>;
}

В этом случае используется namespace по умолчанию (defaultNS, чаще всего translation).


Указание одного namespace

Передача namespace в useTranslation позволяет ограничить область поиска ключей:

const { t } = useTranslation("auth");

Теперь все вызовы t будут искать ключи только в auth.json.

Пример использования:

function LoginForm() {
  const { t } = useTranslation("auth");

  return (
    <form>
      <h2>{t("login.title")}</h2>
      <button>{t("login.submit")}</button>
    </form>
  );
}

Структура auth.json:

{
  "login": {
    "title": "Вход в систему",
    "submit": "Войти"
  }
}

Несколько namespaces одновременно

useTranslation поддерживает массив namespaces. Это позволяет обращаться к нескольким словарям без повторной инициализации хука.

const { t } = useTranslation(["common", "auth"]);

При таком подходе поиск ключей происходит в порядке приоритета: сначала в первом namespace, затем в следующих.

Пример:

function Navbar() {
  const { t } = useTranslation(["common", "auth"]);

  return (
    <nav>
      <span>{t("common:home")}</span>
      <button>{t("auth:logout")}</button>
    </nav>
  );
}

Явное указание namespace в ключах

При работе с несколькими namespaces часто используется явное префиксирование:

namespace:key

Пример:

t("common:cancel");
t("dashboard:stats.title");

Такой подход устраняет неоднозначность при совпадении ключей в разных namespaces.


Динамическая загрузка namespaces

Одной из оптимизационных возможностей является lazy loading переводов. При использовании конфигурации загрузчика (например, HTTP backend) namespaces подгружаются по требованию.

const { t } = useTranslation("dashboard");

При первом вызове компонента происходит загрузка dashboard.json, если он ещё не был загружен.

Это снижает начальный размер бандла и ускоряет первичную загрузку приложения.


preloadNamespaces и поведение загрузки

В конфигурации i18next можно заранее определить namespaces, которые должны быть доступны сразу:

i18next.init({
  ns: ["common", "auth"],
  defaultNS: "common"
});

При использовании useTranslation("dashboard") загрузка произойдёт асинхронно, если namespace не был предзагружен.


Параметры useTranslation

Хук принимает дополнительные настройки:

useTranslation(ns, options);

Основные параметры options:

  • keyPrefix — добавление префикса ко всем ключам
  • useSuspense — управление Suspense-поведением
  • bindI18n / bindI18nStore — подписка на события изменения языка
  • lng — принудительное использование языка

Пример с keyPrefix:

const { t } = useTranslation("auth", {
  keyPrefix: "login"
});

t("title"); // фактически auth:login.title

keyPrefix и организация вложенных структур

keyPrefix позволяет упростить доступ к глубоко вложенным ключам:

{
  "login": {
    "form": {
      "title": "Вход",
      "submit": "Отправить"
    }
  }
}

Без keyPrefix:

t("login.form.title");
t("login.form.submit");

С keyPrefix:

const { t } = useTranslation("auth", {
  keyPrefix: "login.form"
});

t("title");
t("submit");

Поведение при отсутствии namespace

Если namespace не загружен, поведение зависит от конфигурации:

  • fallbackLng — язык-резерв
  • fallbackNS — резервный namespace
  • returnNull — возврат null вместо ключа
  • returnEmptyString — возврат пустой строки

Пример fallback:

i18next.init({
  fallbackLng: "en",
  fallbackNS: "common"
});

Работа с TypeScript и namespace типизацией

В TypeScript-проектах namespaces часто типизируются через декларации ресурсов.

declare module "i18next" {
  interface CustomTypeOptions {
    defaultNS: "common";
    resources: {
      common: typeof common;
      auth: typeof auth;
    };
  }
}

Это позволяет получать автодополнение ключей внутри t.


Suspense и асинхронная загрузка namespaces

При включённом Suspense компонент может ожидать загрузки namespace:

const { t } = useTranslation("dashboard", { useSuspense: true });

В этом режиме компонент не рендерится до завершения загрузки переводов.


Интеграция с рендерингом компонентов

Namespaces особенно важны в компонентной архитектуре: каждый модуль приложения может иметь собственный словарь.

Пример модульной структуры:

  • Header → common
  • LoginForm → auth
  • Analytics → dashboard
  • ErrorBoundary → errors

Такое разделение минимизирует пересечения и упрощает масштабирование локализации.


Переиспользование переводов между namespaces

Иногда требуется доступ к нескольким контекстам одновременно:

function Footer() {
  const { t: tCommon } = useTranslation("common");
  const { t: tAuth } = useTranslation("auth");

  return (
    <footer>
      <span>{tCommon("copyright")}</span>
      <button>{tAuth("logout")}</button>
    </footer>
  );
}

Разделение вызовов улучшает читаемость при сложных интерфейсах.


Namespace resolution и приоритет ключей

При использовании массива namespaces порядок имеет значение:

useTranslation(["common", "auth"]);

Алгоритм поиска:

  1. common
  2. auth
  3. fallbackNS (если задан)

При совпадении ключей используется первое найденное значение.


Оптимизация структуры namespaces

Эффективная организация namespaces влияет на производительность:

  • уменьшение размера JSON-файлов
  • параллельная загрузка модулей
  • кэширование по namespace
  • снижение количества конфликтов ключей

Разделение должно соответствовать границам бизнес-доменов, а не UI-структуре.


Особенности поведения при смене языка

При изменении языка происходит перезагрузка активных namespaces:

i18next.changeLanguage("ru");

Компоненты, использующие useTranslation, автоматически обновляют значения t без ручного обновления состояния.