IV. Les langues▲
Dans cette partie, je vais vous présenter la méthode que j'utilise pour traduire un site Web.
IV-A. Le texte "hard-coded"▲
Dans l'exemple de Pierre-Baptiste, il y a plusieurs messages inclus directement dans le code. Nous allons créer des fichiers de langue pour les contenir :
<?php
define("L_YOURE_HERE"
,
"Vous êtes ici : "
);
define("L_FOOTER"
,
"Ceci est le pied de page..."
);
define("L_DIE"
,
"Mauvaise requête : %s<br />
\n
Veuillez envoyer ce message à un administrateur"
);
?>
<?php
define("L_YOURE_HERE"
,
"You are here: "
);
define("L_FOOTER"
,
"This is the footer..."
);
define("L_DIE"
,
"Wrong query: %s<br />
\n
Please send this message to the webmaster"
);
?>
Vous remarquerez l'utilisation du préfixe "L_" : cela permet de s'assurer que les constantes que nous définissons ici n'entreront pas en conflit avec d'autres constantes. Cela permet également d'utiliser les fonctionnalités d'autocomplétion de code de votre éditeur favori.
Il faut évidemment inclure ce fichier dans notre script :
include_once("
./includes/mes-fonctions.php
"
);
include_once("
./includes/template.php
"
);
include_once("
./language/fr.php
"
);
L'intérêt de cette méthode est de permetre de changer la langue simplement en incluant tel fichier (de langue) ou tel autre. Vous pourriez par exemple conserver l'infrmation de langue dans une session ou dans un profil utilisateur.
Il faut maintenant utiliser les nouvelles variables :
<div id
=
"chemin_fer"
>
{L_YOURE_HERE}
<hr />
{L_FOOTER}
// Envoi des variables 'globales' au gabarit
$template
->
assign_vars(array(
"
THEMES_FOLDER
"
=>
THEMES_FOLDER,
"
HEAD_MOTS_CLES
"
=>
$_ENV
[
"
mots_cles
"
],
"
HEAD_DESCRIPTION
"
=>
$_ENV
[
"
description
"
],
"
HEAD_TITRE
"
=>
$_ENV
[
"
titre
"
],
"
PAGE_CONTENU
"
=>
$_ENV
[
"
contenu
"
],
"
L_YOURE_HERE
"
=>
L_YOURE_HERE,
"
L_FOOTER
"
=>
L_FOOTER
));
function exception_handler($exception
) {
if(defined("
L_DIE
"
))
{
die(sprintf(L_DIE,
$exception
->
getMessage()));
}
else
{
die($exception
->
getMessage());
}
}
À ce stade, le code du site proposé par Pierre-Baptiste est complètement réécrit. L'objectif que je m'étais proposé en début d'article est atteint. Ce qui vient ensuite est un bonus, une réflexion plus poussée.
Voici le code complet de Pierre-Baptiste converti jusqu'à cette étape : [ FTP ] ou [ HTTP ].
IV-B. La base de données▲
"Oui, mais là il reste encore plein de mots en français !"
Ahhh, en effet. Nous n'avons pas traduit la base de données...
Traduire la base de données implique une charge de travail importante en permanence. En effet, il faut enregistrer chaque message dans chaque langue. Imaginez un site d'annonces dans cinq langues : vos utilisateurs devraient envoyer chaque annonce (titre + contenu) dans ces cinq langues, sans quoi elles ne seraient pas affichées par tous les visiteurs. Quelle galère !
Je vous conseille fortement de bien réfléchir à ce que cela implique.
Anecdote : j'ai développé un site qu'un client voulait en plusieurs langues. Résultat : les produits sont ok dans sa langue maternelle mais cela fait plusieurs mois que les traductions sont vides. Il est parfois préférable de revoir ses ambitions à la baisse...
Bref.
Voici comment je m'y prends : je définis une table "language" dans la base de données. Ensuite, je sépare les champs de type texte de chaque table pour laquelle je souhaite proposer une traduction. Il vous faudra des notions de bases de données relationnelles pour aborder cette partie, notamment ce qui touche aux clefs étrangères.
Exemple de modification
Nous souhaitons traduire la page "Accueil" (Id_page=1, Id_parent=0) en français (Id_langue=1) et en anglais (Id_langue=2).
Il nous faut utiliser la nouvelle table pages_lang pour effectuer la jointure entre la page et la langue. Nous y introduisons donc les identifiants des tuples à relier (il y a deux langues donc deux étapes) : Id_page=1 et Id_langue=1 avec Titre="Accueil", puis Id_page=1 et Id_langue=2 avec Titre="Home".
Voici maintenant la totalité des modifications
CREATE
TABLE
`langues`
(
`Id_langue`
int
(
11
)
NOT
NULL
auto_increment
,
`Nom`
varchar
(
255
)
NOT
NULL
,
`Diminutif`
varchar
(
5
)
NOT
NULL
,
PRIMARY
KEY
(
`Id`
)
)
;
CREATE
TABLE
`pages`
(
`Id_page`
int
(
11
)
NOT
NULL
auto_increment
,
`Id_parent`
int
(
11
)
NOT
NULL
default
'1'
,
PRIMARY
KEY
(
`Id_page`
)
)
;
CREATE
TABLE
`pages_lang`
(
`Id_page`
int
(
11
)
NOT
NULL
,
`Id_langue`
int
(
11
)
NOT
NULL
default
'1'
,
`Titre`
varchar
(
255
)
NOT
NULL
,
`Mots_cles`
varchar
(
255
)
NOT
NULL
,
`Description`
varchar
(
255
)
NOT
NULL
,
`Contenu`
TEXT
NOT
NULL
,
PRIMARY
KEY
(
`Id_page`
,`Id_langue`
)
)
;
INSERT
INTO
`langues`
(
`Id_langue`
, `Nom`
, `Diminutif`
)
VALUES
(
1
, 'Français'
, 'fr'
)
,
(
2
, 'English'
, 'en'
)
;
INSERT
INTO
`pages`
(
`Id_page`
, `Id_parent`
)
VALUES
(
1
, 0
)
,
(
2
, 1
)
,
(
3
, 1
)
,
(
4
, 1
)
,
(
5
, 1
)
,
(
6
, 2
)
,
(
7
, 2
)
,
(
8
, 2
)
,
(
9
, 3
)
,
(
10
, 3
)
,
(
11
, 10
)
,
(
12
, 10
)
;
INSERT
INTO
`pages_lang`
(
`Id_page`
, `Id_langue`
, `Titre`
, `Mots_cles`
, `Description`
, `Contenu`
)
VALUES
(
1
, 1
, 'Accueil'
, 'Accueil'
, 'Accueil'
, 0x4163637565696c)
,
(
1
, 2
, 'Home'
, 'Home'
, 'Home'
, 0x486f6d65)
,
(
2
, 1
, 'Mon corps de rêve'
, 'Mon corps de rêve'
, 'Mon corps de rêve'
, 0x4d6f6e20636f7270732064652072c3aa7665)
,
(
2
, 2
, 'My heavenly body'
, 'My heavenly body'
, 'My heavenly body'
, 0x4d792068656176656e6c7920626f6479)
,
(
3
, 1
, 'Mes vacances'
, 'Mes vacances'
, 'Mes vacances'
, 0x4d657320766163616e636573)
,
(
3
, 2
, 'My holidays'
, 'My holidays'
, 'My holidays'
, 0x4d7920686f6c6964617973)
,
(
4
, 1
, 'Mes loisirs'
, 'Mes loisirs'
, 'Mes loisirs'
, 0x4d6573206c6f6973697273)
,
(
4
, 2
, 'My hobbies'
, 'My hobbies'
, 'My hobbies'
, 0x4d7920686f6262696573)
,
(
5
, 1
, 'Me contacter'
, 'Me contacter'
, 'Me contacter'
, 0x4d6520636f6e746163746572)
,
(
5
, 2
, 'Contact me'
, 'Contact me'
, 'Contact me'
, 0x436f6e74616374206d65)
,
(
6
, 1
, 'Mes abdos Kro'
, 'Mes abdos Kro'
, 'Mes abdos Kro'
, 0x4d6573206162646f73204b726f)
,
(
6
, 2
, 'My Kro muscles'
, 'My Kro muscles'
, 'My Kro muscles'
, 0x4d79204b726f206d7573636c6573)
,
(
7
, 1
, 'Mes mains'
, 'Mes mains'
, 'Mes mains'
, 0x4d6573206d61696e73)
,
(
7
, 2
, 'My hands'
, 'My hands'
, 'My hands'
, 0x4d792068616e6473)
,
(
8
, 1
, 'Mon profil Grec'
, 'Mon profil Grec'
, 'Mon profil Grec'
, 0x4d6f6e2070726f66696c2047726563)
,
(
8
, 2
, 'My greek profile'
, 'My greek profile'
, 'My greek profile'
, 0x4d7920677265656b2070726f66696c65)
,
(
9
, 1
, 'Au ski'
, 'Au ski'
, 'Au ski'
, 0x417520736b69)
,
(
9
, 2
, 'Skying'
, 'Skying'
, 'Skying'
, 0x536b79696e67)
,
(
10
, 1
, 'A la mer'
, 'A la mer'
, 'A la mer'
, 0x41206c61206d6572)
,
(
10
, 2
, 'At the beach'
, 'At the beach'
, 'At the beach'
, 0x417420746865206265616368)
,
(
11
, 1
, 'Mer du Nord'
, 'Mer du Nord'
, 'Mer du Nord'
, 0x4d6572206475204e6f7264)
,
(
11
, 2
, 'North Sea'
, 'North Sea'
, 'North Sea'
, 0x4e6f72746820536561)
,
(
12
, 1
, 'Mer Morte'
, 'Mer Morte'
, 'Mer Morte'
, 0x4d6572204d6f727465)
,
(
12
, 2
, 'Dead Sea'
, 'Dead Sea'
, 'Dead Sea'
, 0x4465616420536561)
;
Alors oui, évidemment, cela fait des chiffres partout, ce n'est pas lisible.
Vous savez quoi ? Une base de données n'est pas faite pour être lisible à l'oeil nu. Elle doit contenir des données aussi segmentées que possible. C'est aux requêtes d'assembler les données de manière à leur donner du sens
C'est ici qu'il devient particulièrement intéressant de conserver dans une session les informations sur la langue en cours.
Voici le code complet de Pierre-Baptiste converti à cette étape : [ FTP ] ou [ HTTP ].