Session BRE04 Help

Cours : la gestion des traductions

Gérer le multilinguisme : le principe

Les sites doivent parfois s’adresser à des publics multiples, qui utilisent différents langages. Si sur un petit site statique, on peut se contenter de créer des doublons de page HTML en fonction de la langue, c’est beaucoup plus difficile sur des sites plus gros, avec du contenu dynamique.

On met donc en place différentes stratégies pour permettre de gérer le multilinguisme et de rajouter, au besoin, des nouvelles langues.

Il faut gérer la traduction de deux types de contenus : les contenus statiques (label des formulaires, messages de confirmations, titres des pages…) et les contenus dynamiques (ceux stockés dans la base de données).

Traduire les contenus en BDD

Il existe de multiples stratégies pour la traduction des contenus stockés dans une base de données, je vais vous en présenter une simple. Gardez simplement à l’esprit que ça n’est pas la seule.

Une table monolingue

Imaginons que vous avez une table qui contient les noms et descriptions de catégories de livres :

id

name

description

1

policier

crimes et enquêtes

2

fantastique

elfes, nains et orcs

3

science-fiction

aliens et espace

Et sa version multilingue

Imaginons maintenant que vous souhaitez que votre site soit disponible à la fois en français et en anglais : vous devez traduire tous les champs de la base qui seront affichés sur les vues.

id

name_fr

description_fr

name_en

description_en

1

policier

crimes et enquêtes

thriller

crimes and investigations

2

fantastique

elfes, nains et orcs

heroic-fantasy

elves, dwarves and orcs

3

science-fiction

aliens et espace

science-fiction

aliens and space

Dans l'exemple ci-dessus, on met donc en place des traductions pour le nom et la description, qui seront affichés, mais pas pour l'id qui n'apparait jamais.

Traduire des contenus statiques

Pour vos contenus statiques, la stratégie est un peu différente, vous allez créer des fichiers .json de traduction des textes que vous utilisez.

Un formulaire de login

Voici le code HTML d'un formulaire de connexion qui n'est pour l'instant pas traduit :

<form> <label for="username"> Nom d'utilisateur </label> <input type="text" name="username" id="username" /> <label for="password"> Mot de passe </label> <input type="password" name="password" id="password" /> <button type="submit">Connexion</button> </form>

Nous allons créer, pour chaque langue un fichier de traduction des textes statiques utilisés dans ce formulaire :

Le fichier des textes en français

auth_fr.json:

{ "login_username_label" : "Nom d'utilisateur", "login_password_label" : "Mot de passe", "login_submit_button" : "Connexion" }

Le fichier des textes en anglais :

auth_en.json:

{ "login_username_label" : "Username", "login_password_label" : "Password", "login_submit_button" : "Login" }

Dans ces deux fichiers les clés (par exemple login_username_label) sont les mêmes, ce qui change, c'est bien la valeur de cette clé selon le fichier :

  • en français login_username_label vaut "Nom d'utilisateur"

  • en anglais login_username_label vaut "Username"

Une fois que nous avons créé ces fichiers de traductions nous allons mettre en place du code PHP qui va nous permettre de gérer ces traductions.

La classe de traduction

Nous allons donc créer un Service (une classe qui n'est donc ni un Model, ni un Manager ni un Controller) qui va se charger de gérer les traductions.

class Translator { /* le constructeur reçoit le nom du fichier de traduction, la langue concernée, et initialise sa liste des traductions comme un tableau vide */ public function __construct(private string $file, private string $lang, private array $translations = []) { // il appelle sa méthode privée loadTranslations $this->loadTranslations(); } /* Méthode de chargement des traductions depuis le fichier */ private function loadTranslations() : void { // on génère le chemin du fichier : // translations/nomdufichier_languedufichier.json $filePath = "./translations/{$this->file}_{$this->lang}.json"; // on charge son contenu dans notre $this->translations $this->translations = json_decode(file_get_contents($filePath), true); } /* La méthode publique qui sera appelée lorsque l'on veut traduire un texte */ public function translate(string $key) { // si cette clé de traduction existe, je retourne sa valeur if(isset($this->translations[$key])) { return $this->translations[$key]; } else // sinon je retourne la clé { return $key; } } }

Cette classe va me permettre de charger une liste de traductions dans la langue qui m'intéresse puis d'afficher la traduction de chaque clé de traduction (par exemple login_username_label dans les exemples plus tôt) et d'obtenir sa traduction ("Nom d'utilisateur" ou "Username" selon la langue choisie).

Ajout à l'AbstractController

Comme ce traducteur sera utilisé sur toutes nos pages, et qu’en MVC une route === une méthode de controller, nous allons faire en sorte qu’il soit disponible dans chacun de nos controllers.

abstract class AbstractController { protected Translator $translator; public function __construct(string $file, protected string $currentLang = "fr") { $this->translator = new Translator($file, $this->currentLang); } }

Nos controllers vont ensuite hériter de l' AbstractController:

class AuthController extends AbstractController { public function __construct() { $lang = $_SESSION["lang"]; parent::__construct("auth", $lang); } public function getTranslator() : Translator { return $this->translator; } }

L'utilisation dans vos vues

Une fois que vous avez mis tout ça en place, vous allez utiliser le Translator disponible dans votre Controller :

<form> <label for="username"> <?= $this->getTranslator()->translate("login_username_label") ?> </label> <input type="text" name="username" id="username" /> <label for="password"> <?= $this->getTranslator()->translate("login_password_label") ?> </label> <input type="password" name="password" id="password" /> <button type="submit"> <?= $this->getTranslator()->translate("login_submit_button") ?> </button> </form>

Exercice : Traduction de formulaires

23 July 2025