Godefroy de Compreignac

Blog de Skreo :: Webdev && Hi-Tech 

  • Connexion
  • Inscription
  • Créer mon blog
  • Index
    • Accueil
    • Contact
    • Rubriques
    • Hi-Tech & Linux
    • Web development
    • Java
    • Flash
    • Maths & Algorithmes
    • Divers
  • Qui suis-je...

    Godefroy de Compreignac, aka Skreo. Je suis actuellement étudiant en prépa PSI à l'ISEP. Passionné d'informatique et plus particulièrement de programmation web depuis 2001, mes principaux sites web sont Murties et EklaBlog. Ce blog est un support pour partager mes astuces, idées, coups de coeurs...
    Vous pouvez me retrouver sur Twitter, et Facebook.

    Flux RSS S'abonner par RSS

    150000 readers on FakeBurner

  • Recherche

  • Twitter
    • Chargement
  • Criteo
    http://widget.criteo.com/
    autoroll
    bi=2136307726
  • MyBlogLog
  • Derniers visiteurs
    SkreoStockholm
    M13yseult-la-blonde
    leongRemV
  • Sites amis
    • EklaWeb - Création de sites web
    • Créer un blog gratuitement
    • Jeux gratuit en ligne
    • Blogroll
    • Clément Delafargue
    • Payda
    • Darklg
    • Symbolique des Fleurs
    • Xipoons
  • Tag Cloud
    eee pc pgp divarvel geekchic php test bac classe hier hecatombe eklablog xml usb skreo soiree reflechir firefox serveur javascript vacances asus p535 programmation cle bibliotheque css blog gmail photos fla site

    Voir tous les tags
Reporter un abus
  • Web development

    Internationalisation d'un site web

    par Skreo, le 9 Juillet 2008 à 02:03

    Je me suis demandé il y a quelques temps quelle serait la meilleure solution pour traduire facilement un site web en plusieurs langues, tout en gardant une facilité de mise à jour, une accessibilité optimale, et des urls correctes pour le référencement. Le sujet a certes beaucoup été traité, mais j'ai trouvé très peu de solutions pratiques, jolies et performantes sur le web.

    Certains webmasters recopient simplement l'intégralité de leur site dans un autre dossier ou sur un autre domaine, puis le traduisent. Oublions tout de suite cette solution... Il faut donc opter pour une solution dynamique, que je traiterai ici en php.

    URL et détection de la langue

    Avant de traduire le site, il faut être capable de détecter la langue du visiteur, de lui proposer de changer de langue, et de mémoriser son choix :

    <?php
    session_start(); // Démarrage de la session pour la sauvegarde du choix de la langue
    $langs = array('en', 'fr', 'it');  // Liste des langues

    // Si la langue a été changée par get ou cookie, on enregistre la modif
    if(isset($_GET['lang']) && in_array($_GET['lang'], $langs) && (!isset($_SESSION['lang']) || $_SESSION['lang']!=$_GET['lang']))
        $_SESSION['lang'] = $_GET['lang'];
    else if(isset($_COOKIE['lang']) && in_array($_COOKIE['lang'], $langs) && (!isset($_SESSION['lang']) || $_SESSION['lang']!=$_COOKIE['lang']))
        $_SESSION['lang'] = $_COOKIE['lang'];

    // Si aucune langue n'est définie, on prend celle du navigateur du visiteur
    if(!isset($_SESSION['lang'])){
        $lang = strtolower(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2));
        $_SESSION['lang'] = in_array($lang, $langs) ? $lang : $langs[0];
    }

    // Si le cookie de la langue n'est pas défini ou est différent de la var de session, on le définit
    if(!isset($_COOKIE['lang']) || $_SESSION['lang']!=$_COOKIE['lang'])
        setcookie('lang', $_SESSION['lang'], time()+60*24*3600, '/');

    // Variable $lang locale que nous utiliserons plus loin
    $lang = $_SESSION['lang'];
    ?>
    [code=php]<?php
    session_start(); // Démarrage de la session pour la sauvegarde du choix de la langue
    $langs = array('en', 'fr', 'it');  // Liste des langues

    // Si la langue a été changée par get ou cookie, on enregistre la modif
    if(isset($_GET['lang']) && in_array($_GET['lang'], $langs) && (!isset($_SESSION['lang']) || $_SESSION['lang']!=$_GET['lang']))
        $_SESSION['lang'] = $_GET['lang'];
    else if(isset($_COOKIE['lang']) && in_array($_COOKIE['lang'], $langs) && (!isset($_SESSION['lang']) || $_SESSION['lang']!=$_COOKIE['lang']))
        $_SESSION['lang'] = $_COOKIE['lang'];

    // Si aucune langue n'est définie, on prend celle du navigateur du visiteur
    if(!isset($_SESSION['lang'])){
        $lang = strtolower(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2));
        $_SESSION['lang'] = in_array($lang, $langs) ? $lang : $langs[0];
    }

    // Si le cookie de la langue n'est pas défini ou est différent de la var de session, on le définit
    if(!isset($_COOKIE['lang']) || $_SESSION['lang']!=$_COOKIE['lang'])
        setcookie('lang', $_SESSION['lang'], time()+60*24*3600, '/');

    // Variable $lang locale que nous utiliserons plus loin
    $lang = $_SESSION['lang'];
    ?>[/code]

    Ce code devra être appelé au tout début de chaque page du site. Nous avons maintenant notre moyen de détection et de mémorisation de la langue.

    Ensuite, nous allons prendre l'exemple d'URLs du type http://www.monsite.com/lang/page.html, ce qui a l'avantage de bien référencer toutes les pages dans toutes les langues traduites. Mais nous pourrions tout aussi bien garder des URLs classiques dans le cas d'un service accessible uniquement aux utilisateurs connectés : par exemple Twitter. La langue serait alors enregistrée dans les paramètres de l'utilisateur.

    Pour cela, mettons en place un .htaccess avec de l'URL Rewriting à la racine :

    RewriteEngine On
    RewriteRule    ^(en|fr|it)/([^\?]+)?(\?(.*))?$    /$2?$4&lang=$1    [QSA,L]
    [code=apache]RewriteEngine On
    RewriteRule    ^(en|fr|it)/([^\?]+)?(\?(.*))?$    /$2?$4&lang=$1    [QSA,L][/code]

    Et voilà, désomais, un accès à la page http://www.monsite.com/fr/page.php appellera la page page.php à la racine du site en lui passant la variable GET lang=fr, ce qui aura pour effet avec le script précédent d'enregistrer "fr" comme langue dans le cookie et la variable de session du visiteur.

    Proposons maintenant au visiteur de choisir sa langue tout en restant sur la même page, au cas où elle aurait été mal détecté (navigateur en anglais pour un français par exemple) :

    <?php
    $URI = $_SERVER['REQUEST_URI'];
    if($URI=='/') $URI = '/'.$lang.'/';
    ?>
    <a href="<?php echo preg_replace('#^/[a-z]{2}#', '/en', $URI); ?>"><img src="/images/en.png" alt="English" /></a> 
     <a href="<?php echo preg_replace('#^/[a-z]{2}#', '/fr', $URI); ?>"><img src="/images/fr.png" alt="Français" /></a> 
    <a href="<?php echo preg_replace('#^/[a-z]{2}#', '/it', $URI); ?>"><img src="/images/it.png" alt="Italiano" /></a>
    [code=php]<?php
    $URI = $_SERVER['REQUEST_URI'];
    if($URI=='/') $URI = '/'.$lang.'/';
    ?>
    <a href="<?php echo preg_replace('#^/[a-z]{2}#', '/en', $URI); ?>"><img src="/images/en.png" alt="English" /></a> 
    <a href="<?php echo preg_replace('#^/[a-z]{2}#', '/fr', $URI); ?>"><img src="/images/fr.png" alt="Français" /></a> 
    <a href="<?php echo preg_replace('#^/[a-z]{2}#', '/it', $URI); ?>"><img src="/images/it.png" alt="Italiano" /></a>[/code]

    Vous trouverez plein de super icônes de drapeaux ici.

    Stockage des traductions

    On peut imaginer deux solutions de stockage pour les textes traduits. J'ai retenu la deuxième :

    1- Première solution : Une fonction getText choisissant entre plusieurs textes proposés. Par exemple

    <?php

    function getText($en, $fr){
        global $lang;
        if($lang=='fr') return $fr;
        else return $en;
    }

    // Affichage d'un texte traduit :
    echo getText('Text in english', 'Texte en français');
    ?>
    [code=php]<?php

    function getText($en, $fr){
        global $lang;
        if($lang=='fr') return $fr;
        else return $en;
    }

    // Affichage d'un texte traduit :
    echo getText('Text in english', 'Texte en français');
    ?>[/code]

    Ce n'est pas très pratique, et pas très lisible dès que les textes deviennent un peu gros et le nombre de langues grand.

    2- Deuxième solution : Le stockage des textes dans divers fichiers : un fichier par langue. L'avantage ici est qu'on peut traduire (ou faire traduire) le site en ajoutant simplement un seul fichier. Nous stockerons les fichiers en.php, fr.php, et it.php dans un dossiers langs. Il suffira d'ajouter cette ligne après la détection de la langue :

    require_once 'langs/'.$lang.'.php';
    [code=php]require_once 'langs/'.$lang.'.php';[/code]

    Ensuite, nous avons encore le choix entre plusieurs méthodes de stockage. Les deux principalement utilisées consistent soit à créer une constante par texte, soit un grand tableau avec une entrée par texte. La méthode des constantes a l'avantage d'être performante mais n'est vraiment pas propre. Celle du tableau n'est pas non plus des plus performantes. Je parle bien sûr ici pour une grande échelle : prévoyons 15 000 entrées pour voir réellement les différences entre les méthodes.

    Je vais vous proposer une autre méthode, une sorte de compromis, mais performante, pratique, et plus lisible. Elle consiste à utiliser une classe pour stocker les textes sous forme de constantes. Ces constantes restent dans la classe, c'est donc propre, l'accès y est très facile, et les performances sont très bonnes (j'avais fait un benchmark il y a quelques mois, mais je ne l'ai plus sous la main...). Nous allons donner un nom très court à cette classe, par exemple "_". Voici un exemple pour le fichier fr.php, il suffit ensuite de copier le fichier et de le traduire pour les autres langues :

    <?php
    // Classe de stockage :
    final class _ {
        const TEXT1 = 'Mon premier texte en français';
        const EXEMPLE = 'Ceci est un exemple';
        const NUM = 'un, deux, trois';
    }
    ?>
    [code=php]<?php
    // Classe de stockage :
    final class _ {
        const TEXT1 = 'Mon premier texte en français';
        const EXEMPLE = 'Ceci est un exemple';
        const NUM = 'un, deux, trois';
    }
    ?>[/code]

    Puis pour afficher le texte :

    <?php
    // Affichage du texte :
    echo _::TEXT1 . '<strong>'. _::EXEMPLE . '</strong><br />'. _::NUM;
    ?>
    [code=php]<?php
    // Affichage du texte :
    echo _::TEXT1 . '<strong>'. _::EXEMPLE . '</strong><br />'. _::NUM;
    ?>[/code]

     

    Et voilà, j'espère que ce tuto pourra servir à quelqu'un. Qu'en pensez-vous ? Quelles solutions utilisez-vous ?


    Partager cet article : Wikio Twitter del.icio.us Facebook Digg Technorati Yahoo! Stumbleupon Google Blogmarks Ask Slashdot
    Tags Tags : internationalisation, traduction, php
    Suivre le flux RSS des commentaires de cet article
    Revenir à la liste des articles

    Haut de page

  • Commentaires

    1
    divarvel Profil de divarvel
    9 Juillet 2008 à 10:29
    divarvel
    C'est clair que c'était galère la solution de la fonction getText... Par contre pour les constantes, va falloir trouver une bonne charte de nommage, car du texte, il y en a plein.... Une fois que le premier fichier est fait, ça va, mais pour le faire...
    2
    Skreo Profil de Skreo
    9 Juillet 2008 à 14:25
    Skreo
    Oui mais en fait ça va. Pour EklaBlog, par exemple pour le lien "Lire la suite" du module "articles", la constante s'appelle mod_articles_LIRE_SUITE. Et après c'est pas dur de s'y retrouver, en mettant des commentaires indiquant les chemins des fichiers correspondants.
    3
    versgui Profil de versgui
    9 Juillet 2008 à 14:50
    Il est clair que ce genre de problème est souvent casse-tête ! J'approuve ta méthode qui est relativement propre, mais ça peut devenir complexe quand tu abordes des langues en dehors de la norme ISO-8859-1 (arabe, mandarin, japonais...).
    Le mieux, c'est d'aussi aborder la problématique de l'encodage avant même de commencer à traduire, je pense. C'est un point trop souvent oublié :)
    4
    Skreo Profil de Skreo
    9 Juillet 2008 à 15:26
    Skreo
    @versgui : En effet, je n'en ai pas parlé. Je fait tout en UTF-8, c'est beaucoup plus pratique. l'UTF-8 supporte toutes les langues, se stocke sans problème (MySQL et fichiers), et passe très bien à l'AJAX


    Ajouter un commentaire
    Nom / Pseudo :

    E-mail (facultatif) :

    Site Web (facultatif) :

    Commentaire :


    Recopiez le code inscrit sur l'image :


    Ce code est un code de sécurité pour empêcher le spam en vérifiant que la personne qui poste est bien un humain et non un robot.

    Haut de page

Godefroy de Compreignac - EklaBlog - Créer un blog gratuit Un site EklaWeb - CGU - Blogs Murties.com - Murties.com
Actions
  • Aller à l'accueil
  • Contact
  • Chercher un article
Connexion Créer mon blog Créer mon compte EklaBlog - Créer un blog gratuit
Vous avez reçu un nouveau message !