Руководство по архитектуре интернационализации. Включает автоматическую типизацию ключей, проверку полноты перевода и динамическую загрузку ресурсов.
Преимущество: Полная типобезопасность — при отсутствии ключа или несовпадении структуры перевода в разных языках проект не скомпилируется.
Все настройки сосредоточены в shared/config/i18n/. Каждый аспект (типы, инициализация, блоки) вынесен в отдельный файл.
Располагаются в public/locales/[lng]/. Используйте вложенные папки для группировки namespaces (например, booking/order.json).
1export const i18nKey =
2 <Keys extends string>() =>
3 <K extends Keys>(key: K) =>
4 key;TNestedKeyOf для генерации путей к ключам через точку.1export type TDotPrefix<T extends string, P extends string> = P extends ""
2 ? T
3 : `${P}.${T}`;
4
5export type TNestedKeyOf<ObjectType extends object> = {
6 [Key in keyof ObjectType & string]: ObjectType[Key] extends object
7 ? TDotPrefix<TNestedKeyOf<ObjectType[Key]>, Key>
8 : Key;
9}[keyof ObjectType & string];i18n.config.ts импортируем эталонные JSON-файлы и создаем мастер-тип TResources.1import common from "../../../../public/locales/en/common.json";
2import header from "../../../../public/locales/en/header.json";
3
4export type TCommon = typeof common;
5export type THeader = typeof header;
6
7export type TResources = {
8 common: TCommon;
9 header: THeader;
10};
11
12export const NS = ["common", "header"] as const;i18n.blocks.ts.1export const TRANSLATION_BLOCKS = {
2 booking: { folder: "booking", namespaces: ["orders_page"] },
3 shared: { folder: "", namespaces: ["header", "common"] }
4};
5
6export const getNamespacePath = (lng: string, ns: string): string => {
7 // ... логика определения пути к JSON
8 return `/locales/${lng}/${ns}.json`;
9};i18n.init.ts.1import i18n from "i18next";
2import { initReactI18next } from "react-i18next";
3import { NS } from "./i18n.config";
4
5i18n.use(initReactI18next).init({
6 fallbackLng: "en",
7 ns: NS,
8 backend: {
9 loadPath: (lngs, nss) => getNamespacePath(lngs[0], nss[0])
10 }
11});
12export default i18n;i18n.checker.ts. Гарантирует, что все языки имеют идентичную структуру ключей.1import type { TResources } from "./i18n.config";
2import common_ru from "../../../../public/locales/ru/common.json";
3
4// Статическая проверка: если в RU нет ключа из EN - будет ошибка
5export const RU_TRANSLATION_CHECKER: TResources = {
6 common: common_ru,
7};useTranslation и компонент Trans для работы с динамическим контентом.1import { useTranslations } from "next-intl";
2
3export const MyComponent = () => {
4 const t = useTranslations("common");
5
6 return <h1>{t("header.title")}</h1>;
7};1
2import { useTranslations } from "next-intl";
3
4export const MyComponent = () => {
5 const t = useTranslations("common");
6
7 return (
8 <div>
9 <h1>{t("header.title")}</h1>
10 {t.rich("description.text", {
11 0: (chunks) => <strong>{chunks}</strong/>,
12 1: (chunks) => <br>{chunks}</br/>,
13 })}
14 </div>
15 );
16};changeLanguage для синхронного обновления состояния библиотеки и localStorage.1import i18n from "./i18n.init";
2
3export const changeLanguage = (lng: string) => {
4 i18n.changeLanguage(lng);
5 localStorage.setItem("i18nextLng", lng);
6};