Table des matières

Traductions

Documentation i18next
Documentation react-i18next
Documenation Intl

Vous souhaitez développer une application traduites en plusieures langues. Aucun problème, react-i18next met à dispoistion un système qui gére des fichiers de traduction. Il permet de traduire directement du texte dans vos composants et de gérer dans des cas plus complexes des formats (date, nombre, …).

Nous vous invitons à consulter également l'objet natif Intl de JavaScript pour gérer tout type de formats .

Stocker un fichier de traduction

Les fichiers de traductions sont des fichiers JSON. Il y a deux moyens de les stocker selon la façon des les charger:

Nous ne traiterons ici la méthode “dynamique”. Pour la méthode “statique”, veuillez référer à la documentation de l'astuce Fichiers de traductions statiques.

Faire un fichier de traduction

Encore une fois, il y a deux méthodes pour organiser ses fichiers de traductions:

Nous ne traiterons ici la première méthode. Pour la seconde, veuillez vous référer la documentation de l'astuce Faire des fichiers de traductions “namespace”.

Comme nous avons un fichier par langue qui doit potentiellement gérer plusieures pages, plusieurs composants, il s'agirait de bien s'organiser. Essayons avec notre page Login.

// public/locales/en.json

{
    "loginPage": {
        "emailInput": {
            "label": "Email address",
            "placeholder": "Write your email address here ..."
        },
        "passwordInput": {
            "label": "Password",
            "placeholder": "●●●●●●●●" 
        },
        "button": "Login"
    }
}
// public/locales/fr.json

{
    "loginPage": {
        "emailInput": {
            "label": "Adresse email",
            "placeholder": "Tapez votre adresse email ici..."
        },
        "passwordInput": {
            "label": "Mot de passe",
            "placeholder": "●●●●●●●●" 
        },
        "button": "Connexion"
    }
}

Configurer i18next

Pour cela, nous devons:

// src/i18n/index.js

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import HttpBackend from "i18next-http-backend";

i18n
  .use(HttpBackend)
  .use(initReactI18next)
  .init({
    interpolation: {
      escapeValue: false,
    },
    backend: {
      loadPath: "/locales/{{lng}}.json",
    },
  });

export { i18n };
// src/components/app/I18nextProvider/index.jsx

import { I18nextProvider as Provider } from "react-i18next";
import { useEffect } from "react";
import { i18n } from "../../../i18n";
import { useSelector } from "react-redux";

export const I18nextProvider = (props) => {
    const { children } = props;

    const settings = useSelector(state => state.settings.data) ?? {};
    const { lng } = settings;  

    useEffect(() => {
        i18n.changeLanguage(lng);
    }, [lng]);

    return (
        <Provider i18n={i18n}>
            {children}
        </Provider>
    );
};

Comme nous sommes au sein du ReduxProvider, nous pouvons utiliser l'état global pour stocker des paramètres et notamment la langue. On doit alors créer un slice pour les paramètres, définir un état initial et des actions pour pouvoir les modifier. A vous de jouer !

// src/App.jsx

import { Router } from "./components/app/Router";
import { ReduxProvider } from "./components/app/ReduxProvider";
import { I18nextProvider } from "./components/app/I18nextProvider";

export const App = () => {
    return (
        <ReduxProvider>
            <I18nextProvider>
                <Router />
            </I18nextProvider>
        </ReduxProvider>
    );
};

Désormais les traductions sont accessibles dans n'importe quel fichier utilisé au sein du I18nextProvider. .

Utiliser les traductions

Pour traduire directement dans un composant, nous pouvons utiliser le hook useTranslation.

// src/components/pages/Login/index.jsx

import { Input } from "../form/Input";
import { useDispatch } from "react-redux";
import { setSession } from "../../../redux";
import { API_URL } from "../../../utils/constants/vite";
import { useTranslation } from "react-i18next"; 

export const Login = () => {
    const { t } = useTranslation();

    const dispatch = useDispatch();
    
    const handleFormOnSubmit = (e) => {
        // request
    };
    
    return (
        <div className="fixed inset-0 bg-white flex justify-center items-center p-10">
            <form
                onSubmit={handleFormOnSubmit}
                className="flex flex-col gap-6"
            >
                <Input
                    id="email"
                    name="email"
                    label={t("LoginPage.emailInput.label")}
                    type="email"
                    placeholder={t("LoginPage.emailInput.placeholder")}
                />
                <Input
                    id="password"
                    name="password"
                    label={t("LoginPage.passwordInput.label")}
                    type="password"
                    placeholder={t("LoginPage.emailInput.placeholder")}
                />
                <button className="shadow-md bg-blue-500 text-white font-semibold text-xl uppercase tracking-wide rounded-full px-8 py-4 active:brightness-90 duration-100">
                    {t("LoginPage.button")}
                </button>
            </form>
        </div>
    );
};

Pour ne pas à réécrire à chaque fois loginPage, vous pouvez utiliser le système de prefix. Pour cela, veuillez vous référer à la documentaton de l'astuce Utiliser les prefix avec useTranslation