15 septembre 2015 · 6 min de lecture
Traduire un site, ou un logiciel, est un travail fastidieux. Heureusement, un programme existe pour vous aider, il s’appelle gettext
. Il n’est pas nouveau, c’est même un dinosaure. Mais comprendre son fonctionnement et le mettre en place peut être un peu déroutant au début.
Voyons pas à pas comment traduire un site en PHP.
Cas concret : vous avez la page internet index.php
suivante dans votre site :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Titre de page</title>
</head>
<body>
<p>
<strong>Premier paragraphe</strong>
</p>
<p>
Cool, demain j'ai piscine.
</p>
</body>
</html>
Modifiez-la comme ceci :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><?php echo _("Titre de page"); ?></title>
</head>
<body>
<p>
<strong><?php echo _("Premier paragraphe"); ?></strong>
</p>
<p>
<?php echo _("Cool, demain j'ai piscine."); ?>
</p>
</body>
</html>
Dans le navigateur vous ne verrez aucune différence. On a juste isolé le texte traductible. Pour info “_
” est un alias de la fonction gettext.
Comme vous l’avez remarqué, en l’absence de traduction, le texte par défaut est affiché (“Titre de page”, etc.). Il servira d’index.
Dans l’arborescence du site, créez un dossier locale
et un sous-dossier pour chaque langue que vous souhaitez. Vous devez respecter obligatoirement la structure suivante :
monsite/locale
/en_US
/LC_MESSAGES
/es_ES
/LC_MESSAGES
...
Pour avoir un aperçu des pays existants, sous Linux, saisissez la commande :
cat /usr/share/i18n/SUPPORTED
On va parcourir le code source, en extraire les textes, et générer un fichier qui servira de base pour toutes les traductions. Celui-ci pourra être écrasé au besoin, pour suivre les mises à jour de votre code.
En ligne de commande, tapez (mais pas trop fort) :
cd monsite
find . -iname "*.php" | xargs xgettext -o locale/traductions.pot
C’est quoi ce charabia ?
cd monsite
: on se place à la racine du dossier contenant le code source.find . -iname "*.php"
: on recherche de façon récursive dans le dossier courant (et sous-dossiers), les fichiers se terminant par php
, quelque soit la casse.xgettext
: la commande magique qui extrait les textes à traduire depuis chaque fichier PHP.-o locale/traductions.pot
: on crée le fichier modèle traductions.pot
dans le dossier locale
.Pour l’anecdote .pot
signifie Portable Object Template
.
On va traduire en anglais. Copiez le fichier modèle pot
dans le dossier LC_MESSAGES
de la langue. Changez l’extension en po
:
cd monsite/locale
cp traductions.pot en_US/LC_MESSAGES/traductions.po
Alternativement, on peut utiliser la commande msginit
qui tiendra compte de vos variables d’environnement pour y ajouter vos informations :
msginit --locale=en -i locale/traductions.pot -o locale/en_US/LC_MESSAGES/traductions.po
Ouvrez ce fichier en_US/LC_MESSAGES/traductions.po
dans votre éditeur de texte préféré :
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: MonSite\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-09-14 23:23+0200\n"
"PO-Revision-Date: 2015-09-14 23:24+0100\n"
"Last-Translator: Jean-François GAZET <theboss@jeffprod.com>\n"
"Language-Team: JeffProd <thedreamteam@jeffprod.com>\n"
"Language: English\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: index.php:5
msgid "Titre de page"
msgstr ""
#: index.php:9
msgid "Premier paragraphe"
msgstr ""
#: index.php:12
msgid "Cool, demain j'ai piscine."
msgstr ""
msgid
.Il ne vous reste qu’à inscrire les traductions dans les msgstr
comme ceci :
#: index.php:5
msgid "Titre de page"
msgstr "Page title"
#: index.php:9
msgid "Premier paragraphe"
msgstr "First paragraph"
#: index.php:12
msgid "Cool, demain j'ai piscine."
msgstr "Yes, swimming pool tomorrow."
Maintenant, on génère à partir de ce fichier texte, un catalogue binaire de messages (fichier mo
). C’est ce dernier qui sera utilisé par le site :
cd locale/en_US/LC_MESSAGES
msgfmt traductions.po -o traductions.mo
Voilà. La traduction anglaise est prête.
Revenons à notre page PHP. Le texte est toujours affiché en français. Ajoutons un peu de code en haut de page :
<?php
// Choix de la langue : de_DE, fr_(FR,BE,CA,CH,LU) en_(US,GB)...
$locale='en_US.utf8';
// Domaine : nom du fichier 'mo', car vous pouvez en gérer plusieurs.
// La traduction sera cherchée dans :
// ./locale/en_US/LC_MESSAGES/traductions.mo
$domaine = 'traductions';
putenv('LC_ALL='.$locale); // Fixe la valeur d'une variable d'environnement
setlocale(LC_ALL, $locale); // Modifie les informations de localisation
bindtextdomain($domaine, 'locale'); // Fixe le chemin (relatif ou absolu) d'un domaine
textdomain($domaine); // choix du domaine par défaut
?><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><?php echo _("Titre de page"); ?></title>
</head>
<body>
<p>
<strong><?php echo _("Premier paragraphe"); ?></strong>
</p>
<p>
<?php echo _("Cool, demain j'ai piscine."); ?>
</p>
</body>
</html>
La page est affichée maintenant en anglais. Vous pouvez adapter ce code pour prendre en compte par exemple une variable de session ou un paramètre dans l’URL pour le choix de la langue. Vous pouvez également placer ce code dans un fichier séparé (et l’inclure avec include
).
Le plus dur est fait. Pour la suite, c’est la même chose.
Le code évolue. J’ajoute du texte, j’en modifie, et j’en supprime :
<?php
// Choix de la langue : de_DE, fr_(FR,BE,CA,CH,LU) en_(US,GB)...
$locale='en_US.utf8';
// Domaine : nom du fichier 'mo', car vous pouvez en gérer plusieurs.
// La traduction sera cherchée dans :
// ./locale/en_US/LC_MESSAGES/traductions.mo
$domaine = 'traductions';
putenv('LC_ALL='.$locale); // Fixe la valeur d'une variable d'environnement
setlocale(LC_ALL, $locale); // Modifie les informations de localisation
bindtextdomain($domaine, 'locale'); // Fixe le chemin (relatif ou absolu) d'un domaine
textdomain($domaine); // choix du domaine par défaut
?><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><?php echo _("Titre"); ?></title>
</head>
<body>
<p>
<?php echo _("Cool, demain j'ai piscine."); ?><br>
<?php echo _("ou course à pied."); ?><br>
</p>
</body>
</html>
La méthode est la même. On regénère le fichier modèle pot
en écrasant l’ancien (même commande que précédemment) :
cd monsite
find . -iname "*.php" | xargs xgettext -o locale/traductions.pot
Info : si vous obtenez l’erreur “Commentaire non-ASCII”, ajoutez --from-code=UTF-8
à la fin de la ligne de commande.
On fait un remix du nouveau modèle avec le fichier po
de langue anglaise existant :
msgmerge locale/en_US/LC_MESSAGES/traductions.po locale/traductions.pot --output-file=locale/en_US/LC_MESSAGES/traductions.po
Ouvrez le fichier locale/en_US/LC_MESSAGES/traductions.po
. Vous constatez que les traductions supprimées ont été placées en commentaire. Celles qui sont toujours d’actualité sont inchangées. Et il y a des nouvelles lignes à traduire. Yapluka.
On génère ensuite le fichier binaire mo
(comme précédemment) :
cd locale/en_US/LC_MESSAGES
msgfmt traductions.po -o traductions.mo
Et la traduction est à jour.
Pour ceux qui redoutent les lignes de commande il existe des logiciels “user-friendly” :
On peut gérer les traductions au pluriel comme “j’ai %d bonbon” ou “j’ai %d bonbons” selon la valeur du nombre : pour cela voir ngettext.
gettext sur Wikipedia
Site officiel de gettext et manuel en ligne