next-i18n-auth

i18n Architecture and Implementation

Overview

The i18n system in this project is designed for internationalization (i18n) with type-safety and efficient handling of translations. The system integrates i18next with React and Next.js, while leveraging TypeScript for strict typing and Gulp for automated tasks.

This documentation covers the file structure, translation functions, and key components of the i18n system, including how translation keys are handled, how translations are loaded, and how server-side translation functions are utilized.

Note: src/i18n/ folder is used by automated scripts. See Automation for more details.

File Structure

Here is the layout of the i18n system files:

src/
├── i18n/
│   ├── generated/          // Generated files for namespaces and translation types
│   │   ├── namespaces.     // Client-side i18next initialization
│   │   └── types.d.ts      // Type-safe wrapper for translation functions
│   ├── lib/
│   │   ├── client.ts       // Client-side i18next initialization
│   │   ├── config.ts       // Configuration file for languages and fallback
│   │   ├── safety.ts       // Type-safe wrapper for translation functions
│   │   └── server.ts       // Server-side i18next initialization
│   ├── locales/            // Translation files per language (JSON)
│   ├── types/
│   │   └── i18n.d.ts       // Type definitions for translation functions
│   └── index.ts            // Exports i18n utilities for the project

Key Components

1. /src/i18n/index.ts

This file serves as the centralized entry point for accessing translation functionality throughout the project. It exports the following:

export { useTranslation, default as i18n } from "./lib/client";
export { getTranslation } from "./lib/server";
export { languages, FALLBACK_LANGUAGE, type TLanguage } from "./lib/config";
export { NAMESPACES } from "./generated/namespaces";

2. Client-Side: /src/i18n/lib/client.ts

This file is responsible for initializing i18next on the client-side. It:

Key Code Example:

i18next
    .use(initReactI18next)
    .use(LanguageDetector)
    .use(
        resourcesToBackend((language: string, namespace: string) => {
            return import(`@/i18n/locales/${language}/${namespace}.json`);
        })
    )
    .init(baseInitOptions);

The useTranslation function is typed to ensure that developers can only access the correct translation keys for the given namespace, avoiding errors from invalid keys.


3. Server-Side: /src/i18n/lib/server.ts

This file is responsible for initializing i18next on the server-side. It:

Key Code Example:

const i18nextInstance = await initI18nextOnce(language, ns);
const rawT = i18nextInstance.getFixedT(language, ns);
const t = safeT(rawT);

This ensures that the server-side code can retrieve translations in a type-safe manner, using the TNamespace types to guarantee the correctness of the keys.


4. Translation Function Wrapping (safeT)

The safeT function is used to create a type-safe translation function. It ensures that when calling t() inside components or server-side code, the translation keys are validated and suggestions are available in your IDE.

Key Code Example:

export function safeT<T extends TNamespace>(rawT: any, namespace: T) {
    return (key: TNamespaceTranslationKeys[T], options?: Record<string, unknown>) => {
        return rawT(key, options); // Ensure strict typing on key
    };
}

This adds strict typing for the translation function, improving developer experience by providing autocompletion for translation keys and namespaces in the IDE.


5. i18n/lib/config.ts

This file contains basic configuration related to languages and fallback language. It defines:

export const languages = ["kk", "ru", "en"] as const;
export type TLanguage = (typeof languages)[number];
export const FALLBACK_LANGUAGE: TLanguage = "en"; // Переименовали переменную
export const COOKIE_NAME = "NEXT_LANGUAGE";
export const defaultNS = "translation";

Translation Key Management

Static Keys with Placeholders

As part of the i18n system design, we follow a philosophy inspired by Django gettext, where translation keys are static and placeholders are used for variables (e.g., ``).

Example:

{t("Welcome, ", { username: data?.firstname ?? "" })}

This approach ensures that:


Generated Types for Translation Keys

The translation keys and namespaces are generated using Gulp scripts. The types.d.ts file ensures that the translation keys are strictly typed and prevents errors in accessing the wrong keys.

export type TFunction<N extends TNamespace> = <
    K extends TNamespaceTranslationKeys[N]
>(key: K, options?: Record<string, unknown>) => string;

This ensures that developers only use valid translation keys and namespaces, further improving the development experience and reducing potential bugs.


Conclusion

The i18n system in this project is designed to be scalable, maintainable, and type-safe. With i18next, TypeScript, and custom utilities like createStrictT, the system provides a powerful and developer-friendly environment for managing translations. The modular approach, with a dedicated focus on static translation keys and placeholders, ensures that translations remain consistent across languages and easy to maintain as the project grows. See types for more details about how generated types are used in the project.