Accueil Blog ⇉ Un site multilingue en PHP ? C'est simple !

PHP

SMARTY

illustration_article

Cet article ne traite que de l'aspect "technique" d'un site multilingue en PHP ; il ne traitera donc pas des différentes options concernant la traduction, le SEO ou autre débat entre deux plugins géniaux pour tel ou tel CMS encore plus génial.
Et attention : ce n'est PAS un routeur.


Le préambule



Le (futur) client vient de partir en laissant son cahier des charges pour un proto de gestion multilingue pour son site à venir :
- Système monsite.com/ => fr - monsite.com/en/ =>en, etc...
- Pas d'usine à gaz, un truc simple, facilement compréhensible et surtout, qui marche.
- Pouvoir rajouter ou enlever des langues sans être obligé de tout démonter.
- Correspondance systématique de page en page : monsite.com/page1.php switche vers la page monsite.com/en/page1.php et non vers monsite.com/en/
- Aucun PHP dans le html (son webdesigner doit être fâché avec...)

Et nous avons immédiatement promis une démo grandeur nature dans 3 heures...

Les écueils et la stratégie



Il va nous falloir gérer principalement 4 questions (dans le désordre) :
1/ Récupérer la langue courante à la connexion utilisateur
2/ Offrir la possibilité de basculer vers une langue à chaque page.
3/ Proposer des URLs propres et "SEO-friendly".
4/ Gérer le changement de contenu en fonction de la langue

help “La seule chose requise est un accès au fichier htaccess, le reste c'est du pur standard.”


Pour ce faire, l'option retenue va être ultra-classique :
- pour le 1 et le 3, un RewriteRule dans le fichier .htaccess fera très bien l'affaire.
- Pour le 2, nous allons créer un petit switcher qui assurera le changement de langue et la récupe de la langue courante à la volée (par exemple, quand un visiteur arrive directement sur monsite.com/es/page1.php elle lui sera servie en espagnol.
- Et pour le 4, nous allons faire intervenir Smarty, qui en plus de ne pas traumatiser son webdesigner (qui est de fait notre nouveau meilleur ami), va permettre de stocker tout le texte statique.

Débutons...

Le htaccess


Nous allons régler de suite la question de la détection et des url, ce sera fait.
Notre URL finie sera (e.g.) : monsite.com/es/page1.php, et pour faire comprendre ceci facilement au serveur, nous allons partir sur un bête passage de paramètres :
monsite.com/page1.php?lang=es, ce qui est clair certes, mais horriblement moche. pour transformer ceci, rajoutons une ligne dans notre fichier htaccess :
RewriteRule ^(en|es|de)/(.*)$ $2?lang=$1 [L,QSA], qui signifie que lorsque le serveur va récupérer notre url contenant le 1er groupe ($1) soit "en/, es/, de/" il va aller rajouter derrière l'url (après $2, soit.*) lang=le 1er groupe ($1); donc par exemple, "de". Bête comme chou.
En l'état en fait, avec le "fr" ça va donner "Undefined index: lang", normal puisqu'on ne la définit pas comme les autres (vu qu'elle ne doit pas apparaître dans l'url réécrite suivant les directives de notre bien-aimé client).
Pour remédier à ce phénomène, rajoutons RewriteRule ^(.*)$ $1?lang=fr [L,QSA] qui dit au serveur, "s'il n'y a rien, tu dis que lang=fr"

Voilà la question "structurelle" des adresses réglée en deux lignes (c'est un simple rewrite en fait) ; passons maintenant à l'exploitation du code.

le PHP


De façon basique, notre système va être constitué d'une classe mère qui fera le sale boulot et qu'on étendra à la demande.

help “Possibilité 1 : On récupère tout simplement une URL”


Vous avez remarqué dans l'exemple au-dessus qu'on récupère déjà la langue d'une URL avec une facilité déconcertante, commençons donc par la fin...
De façon à exploiter le langage courant récupéré, on va le transformer en variables ou en sessions (comme on veut) pour le répercuter dans le site, et ceci d'une façon toute simple :


session_start(); //on démarre les sessions

class LS {

public function index()
{
[...] //la gestion du if{} else{} arrive juste après
$_SESSION['lg'] = $_GET['lang'];// on récupère 'lang' et on la colle dans une session
$this->arrayLang = array(
'lang' => $_GET['lang'] . '/',
'langTool' => str_replace('/', '', $_GET['lang']) //on créé deux variables, lang, genre /es, et langTool : es ; ce sera utile à maints égards.
);
return $this->arrayLang; //on les retourne
}
}
$ls = new LS;
$ls->index($_GET);


Comme dit, on se borne à concrétiser ce qu'on faisait au-dessus déjà, en rendant des variables exploitables dans le cas d'une url qui déboule de nulle part, rien de spécial.

Le côté un peu "sensible" va être de changer de langue une fois dans le site :
Quand notre classe voit qu'elle récupère un ?lang=qqch, elle sait qu'elle n'a rien à faire d'autre que d'extraire la valeur de la langue.
Pour lui dire qu'on veut en plus une redirection (vers la même page mais avec la nouvelle langue), on va donc lui passer un paramètre différent, par exemple ?lg=qqch.


help “Possibilité 2 : le changement de langue”



Il va se déclencher par un lien ou un select/options qui lui enverra par exemple une url sous cette forme :
http://monsite.com/ls.php?lg=en ou sous celle-ci http://monsite.com/en/ls.php?lg=fr

Regardons les étapes de ce qui va lui arriver :
Quand nous récupérons un param en "lg" :
- nous récupérons l'url du script JS grâce à HTTP_REFERER
- Avant toute chose nous la nettoyons des /lg/ qui seraient dans l'array possible (ici "/en/") en les remplaçant par un "/"
- une fois "propre" nous la parsons (avec parse_url($url) pour la récupérer en morceaux
Si lg=en :
- elle est retournée sous cette forme : $url['scheme'] . '://' . $url['host'] . '/' . $_GET['lg'] . $url['path'];
Et si lg=fr, c'est :
$url['scheme'] . '://' . $url['host'] . $url['path'];
Avec le code, ça donne ça :


if ((isset($_GET['lg'])) && ($_GET['lg'] != '')) //donc, si on récupère "lg" (et pas "lang")
{
$newLang = $_GET['lg']; // par commodité
$url_lang = array('/en/'); //l'array des choix possibles (certes, ici c'est léger)
$url = str_replace($url_lang, '/', $_SERVER['HTTP_REFERER']); //on nettoie l'url reçue des langues déjà dedans potentiellement
$url = parse_url($url); // on la parse pour pouvoir la modifier
if ($newLang != "fr") // si la langue demandée est l'anglais :
{
$newUrl = $url['scheme'] . '://' . $url['host'] . '/' . $newLang . $url['path']; //on rajoute $newlang entre les segment 'host' et 'path'
} else
{
$newUrl = $url['scheme'] . '://' . $url['host'] . $url['path']; // sinon, on ne rajoute rien (cf la 2è ligne du htaccess
}
$_SESSION['lg'] = $newLang; // on passe la nouvelle langue en session (si on veut)

header("location:" . $newUrl); // on redirige vers la nouvelle page
} else //sinon, c'est "lang", cf au-dessus
{ [...]



Vous pouvez rentrer des url de votre choix et voir comment se passe la manipulation ; c'est le point "délicat" à surveiller (la gestion des "/") :


Cet exemple renvoie la modife sur l'url, elle ne fait pas de redirection ; avec la redirection normale, ça donne ça :



Voilà l'idée ; à ce stade, la gestion des langues et des changements est finie ; j'ai évidemment puissamment triché en mettant en dur (et dans la classe beurk..!) les deux textes (notre ami webdesigner va en tomber tout raide) aussi, on ne va pas rester comme ça, et c'est là que va intervenir Smarty.

NB : ce système marcherait exactement de la même façon avec des urls sous la forme https://de.monsite.com/page1.php

La finition avec Smarty


On le trouve ici https://www.smarty.net/
L'installation est très simple, et une fois les répertoires et fichiers en ordre de route, je vous recommande d'aller jusqu'au chapitre "extended setup", c'est mieux pour obtenir une fois pour toute les chemins requis.
(Je me borne ici à ce dont j'ai besoin, Smarty est assez fourni, la doc est très simple à comprendre et il y a vraiment peu de pièges)
Pour impressionner définitivement notre client, nous allons faire deux pages : un index et une autre page qui contiendra un appel ajax qui renverra, lui, des variables de langues (dont une avec un petit sprintf associé à un strftime chopées chez Smarty, juste pour le fun :)

Vérifions vite fait que ça marche :
fichier php:


include ('LS3.php');
require_once('smarty/setup.php');

class Ind4 extends LS3
{
public function index()
{
$smarty = new Smarty_GBNet(); // l'instance dans le fichier setup
parent::index();
$data['bjr'] = "Bonjour"; //on créé un index "bjr" dans l'array "data"
$data['lang'] = $this->arrayLang['lang']; //idem avec "lang"

$smarty->assign($data); //on passe tout ça à la template
$smarty->display('smarty/templates/index.tpl'); //on affiche la template
}
}
$ind = new Ind4;
$ind->index();


et le fichier tpl :


<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html" />
<meta name="author" content="gbnet" />
<link href="19.css" rel="stylesheet" type="text/css" />
<title>Untitled 5</title>
</head>
<body>
<span class="text12">{$bjr}, ma langue est "{$lang}"</span> {* affichage des valeurs passées par le fichier php *}


Si vous obtenez ça, c'est que ça marche :


(* Notez que si vous incrustez "en" entre gb-net.fr/ et /blog tout là-haut, vous allez modifier le résultat à la volée :-) valable pour tout l'article d'ailleurs)
et que donc on peut foncer pour la dernière ligne droite..!

help “Gooooooo...!”



Créons un répertoire "lang" et dedans, mettons deux fichiers, "en.conf", et "fr.conf". Ce sont les fichiers où l'on va stocker les textes statiques (je n'ai pas précisé mais il va de soi que les textes dynamiques viennent d'ailleurs, genre bdd) ; stockage qui se fait de cette façon:
fr.conf:
fle = Je suis une jolie fleur
en.conf:
fle = I am a beautiful flower
Ces fichiers vont se récupérer dans la classe via configLoad("path/to/*.conf") par exemple (ce qui donnera :

configLoad('smarty/lang/'.$this->arrayLang['langTool'].'.conf');

-- on peut également les récupérer dans la template -- et les y intégrer comme ceci : {#fle#}
Il est également possible de segmenter les fichiers conf afin de gagner un peu de poids. Par exemple, j'ai créé une section 'ajax' de cette façon:

[ajax]
var = ma var


et le fichier php qui reçoit l'appel ajax ne charge que cette section, comme ceci :

configLoad('smarty/lang/'.$this->arrayLang['langTool'].'.conf', 'ajax');

ce qui est particulièrement utile lors de gros fichiers.
Et pour récupérer juste des variables directement (par exemple, pour un retour ajax comme dans l'exemple ci-dessous), il suffit de le faire dans le fichier php :

$this->fleur = $smarty->getConfigVars('fle');



En résumé, en quelques lignes de code, nous voici avec un exemple de deux pages qui remplit parfaitement les conditions basiques pour un site multilingue. Il suffit de rajouter une langue dans le fichier htaccess, dans le tableau de la classe mère et de créer un fichier .conf avec son texte, pour obtenir une nouvelle version du site, sans toucher en rien au code.
Et pour le bidule que l'utilisateur va avoir pour choisir sa langue, voir ici : Insérer des images dans un champ select (auto-promo)
De plus, Smarty nous a permis une séparation complète du PHP et du HTML, produisant ainsi un code source parfaitement clair.

help “Attention toutefois...”


D'après moi, (à mon humble avis), la gestion des sections est "mal foutue" dans la mesure où quand on définit une ou plusieurs sections, on DOIT les préciser en les chargeant sous peine de ne PAS les charger.
Il aurait été, je pense, bien plus souhaitable de tout charger par défaut (en n'en précisant aucune), et de ne charger QUE celles qui sont précisées le cas échéant.

Un dernier point : "Pourquoi, me direz-vous, ne pas faire toute cette petite tambouille en JS côté client sans toucher au htaccess" ? Tout simplement parce que ça suppose de faire côté client ce qu'on a vu côté serveur, ce que je n'aime pas faire, que ce n'est pas l'objet de l'article ;-) et surtout, que ça fusille les chemins relatifs, car du coup, "/en/" ou "/es/" etc.. deviennent des segments supplémentaires, pas avec htaccess.

A propos de clarté donc, j'ai essayé de l'être mais si un ou plusieurs points demeurent obscurs, n'hésitez pas à me contacter, ou dessous, ou via mon mail ou le formulaire de la page d'accueil gb-net.fr !



Modifié le 27-07-2020
Article précédent


HTML : Aligner le dernier élément d'une liste

Commentaires

Pas encore de commentaire

Publier un commentaire :



capcha   



Raccourcis : php css html sql js img

Prévisualiser
GB-Net.fr 2020



fleche haut
Résultats de votre recherche pour :
reduce close