Class lang avec cookie + http_accept_language

Soyez le premier à donner votre avis sur cette source.

Snippet vu 4 205 fois - Téléchargée 17 fois

Contenu du snippet

Cette classe permet de gérer plusieurs langues pour votre site web.
Celle-ci utilise un fichier class.lang.php, plusieurs fichiers .lng contenant la liste des variables (fr.lng) ainsi que des images .png pour les drapeaux.

La langue de l’utilisateur visitant votre site web est automatiquement récupérée grâce à la variable serveur $_SERVER['HTTP_ACCEPT_LANGUAGE']. Celle-ci est ensuite enregistrée dans un cookie.

Mais l’utilisateur peut très bien choisir la langue souhaitée qui sera passée en $_GET puis à nouveau enregistrée dans un cookie.

Source / Exemple :


/**

  • @author Cr@zy
  • @version 1.0
  • @copyright 2009 @ crazyws.fr
  • /
class Lang { var $lang; var $load = array(); var $listLangs = array(); var $subdir = ''; private $path = "lang/"; private $ext = ".lng"; private $default = "fr"; public function __construct() { $this->GetLangs(); if( !isset($_COOKIE['lang']) ){ $_COOKIE['lang'] = substr( $_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2 ); } if( isset($_GET['lang']) ){ $this->CheckLang($_GET['lang']); } else if( isset($_COOKIE['lang']) ){ $this->CheckLang($_COOKIE['lang']); } setcookie("lang", $this->lang, time() + 365 * 24 * 3600); $this->LoadLang(); } private function CheckLang($lang) { if( in_array($lang . $this->ext, $this->listLangs) ){ $this->lang = $lang; } else { $this->lang = $this->default; } } private function LoadLang() { $file = $this->subdir . $this->path . $this->lang . $this->ext; $handle = fopen($file, "r"); if( $handle ){ while( !feof($handle) ){ $buffer = fgets($handle, 4096); if( (substr($buffer,0,1) == "\n") || (!substr($buffer,0,1)) ){ continue; } if( substr($buffer,0,1) == '[' ){ $prefix = substr($buffer,1,-3); } else { $buffer = trim($buffer); if( !empty($buffer) ){ list($key,$value) = preg_split("/ = /", trim($buffer)); $this->load[$prefix][$key] = substr($value,0); } } } } } private function GetLangs() { if( $handle = opendir($this->subdir . $this->path) ){ while( false !== ($file = readdir($handle)) ){ if( $file != "." && $file != ".." && preg_match("/.lng$/",$file) ){ $this->listLangs[] = $file; } } closedir($handle); } } public function SetParams($string, $params=array()){ foreach($params as $k => $v){ $string = str_replace("{" . $k . "}", $v, $string); } return $string; } }

Conclusion :


J'espère que cette classe aura sû vous aider.
J'attends vos commentaires ou plutôt vos appréciations bonnes ou mauvaises ^^

Pour plus d'infos et télécharger un exemple : http://www.crazyws.fr/blog/?p=1196

A voir également

Ajouter un commentaire

Commentaires

Messages postés
1
Date d'inscription
mercredi 15 avril 2009
Statut
Membre
Dernière intervention
7 février 2010

bonjour CrazyShooter,

je voudrais savoir si tu pense améliorer ta class lang après les commentaires de neigedhiver.

Merci en tout cas pour ta class que je vais mettre deja sur mon site et si mise a jour constructive je la mettrais aussitot.

Merci en tout cas de ton partage.
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
15
Salut,

Je viens de survoler ton code et à première vue : ça me plaît énormément. C'est propre, clair et, cerise sur le gâteau, tu utilises correctement readdir() (c'est peut-être un détail pour vous, mais pour moi ça veut dire beaucoup lol plus sérieusement, c'est un peu un de mes chevaux de bataille...)

Quelques remarques :

else if (avec un espace) est un peu moins performant que elseif (sans espace). La raison : PHP interprète le else, puis le if et crée alors une seconde boucle if. Alors que sans espace, PHP sait qu'il s'agit de la même boucle. Oui, c'est vraiment du pinaillage (mais bon, comme mes remarques ne concernent que des détails, je les relève quand même ^^)

La lecture du tableau de langue me paraît... comment dire... trop compliquée pour ce que c'est. Visiblement, tu utilises une syntaxe type fichier INI. Pourquoi ne pas utiliser la fonction native de PHP parse_ini_file() ? C'est quand même plus simple et... BEAUCOUP plus performant, puisque natif à PHP (donc codé en C). Par ailleurs, comme tu utilises une PCRE pour parser chaque ligne, c'est très gourmand en ressources.

Pourquoi ne pas utiliser un itérateur pour parcourir le répertoire, plutôt que readdir() ? Même si tu l'utilises correctement, contrairement à 95% des auteurs des codes qu'on trouve sur phpcs, c'est quand même plus "pratique", plus lisible, plus facile à maintenir et peut-être même plus performant (mais je n'ai aucune conviction pour ce dernier point). Ça donnerait un truc du genre :

private function GetLangs() {
foreach ($it = new DirectoryIterator($this->subdir . $this->path) as $file) {
if ($file -> isFile() && '.lng' == substr($file->getFilename(), -4)) {
$this -> listLangs[] = $file -> getFilename();
}
}
}

Ici, l'utilisation de substr() est plus rapide qu'une PCRE, qui n'est par ailleurs pas nécessaire pour un test aussi simple.

La syntaxe :
var $lang;
est une syntaxe PHP4. Même si ça fonctionne encore en PHP5 (pour des raisons de compatibilité) et que c'est rigoureusement à la syntaxe PHP5 (par défaut, une propriété dont la visibilité n'est pas définie, comme c'est le cas avec var, celle-ci est publique), il convient d'écrire :
public $lang;
C'est encore un détail, mais c'est juste pour être rigoureux.

Enfin, je trouve dommage d'utiliser des tableaux pour accéder à une variable de langue. Même si c'est certainement très performant, je préfère la facilité d'écriture pour une perte de performance franchement dérisoire. Personnellement, j'utiliserais une classe supplémentaire, LangCat dont les propriétés (virtuelles, accessibles grâce à la méthode magique __get() ) seraient les variables de langue, dans la catégorie en question. On pourrait alors avoir une syntaxe comme celle-ci :

$lang = new Lang();
echo $lang -> cat -> var;

Autre chose : tu ne gères pas les erreurs. Que se passe-t-il si une langue n'existe pas ? A priori, d'après ce que je comprends du code, aucune clé de langue ne sera disponible.
Que se passe-t-il si la clé de langue n'existe pas ? Comme tu utilises des tableaux auxquels on accède directement depuis le code, on obtient une erreur. Il serait peut-être bon de retourner une valeur par défaut (au moins la clé demandée). Ceci serait possible avec une classe LangCat (qui contrôlerait l'accès aux variables de langue), mais ne l'est pas avec un accès direct au tableau.
Que se passe-t-il si dans le fichier de langue, une phrase contient un signe égal = ? La partie après le signe égal n'est pas prise en compte à cause de preg_split(). D'où l'intérêt de l'utilisation de la fonction parse_ini_file()

Une dernière chose (pour le moment ^^) cette classe est sympa, mais oblige à utiliser une syntaxe de type INI. Ce n'est pas dramatique, mais il pourrait être sympa de permettre l'utilisation de différents modes de stockage : INI, tableau PHP, XML, base de données, etc.
Pour cela, une classe générique qui gère la langue, le format de fichier (une factory), et des classes spécialisées pour chaque type. La factory aurait en charge d'ouvrir le fichier, d'en vérifier le format s'il n'est pas spécifié manuellement, et d'instancier la classe adéquate en fonction du type et de la retourner.
$lang = Lang::open('fichier.xml', LANG::XML);
$lang = Lang::open('autre_fichier.php);
Ce n'est qu'une suggestion.
Et pourquoi pas, proposer des fichiers gettext ?

Autre proposition : permettre la création de fichiers de langue, permettant ainsi de développer aisément une interface d'admin pour traduire dans le back-office ou convertir des fichiers d'un format à l'autre. Là, ça devient plus élaboré. Dans la même veine, proposer une conversion depuis un fichier Excel et/ou CSV (j'ai été confronté à ce problème récemment : le client voulait pouvoir traduire dans un tableur : je récupère le fichier XLS, je l'exporte en CSV et je le passe dans moulinette pour en faire un fichier avec un tableau PHP).

Sinon, je le répète : la classe est bien structurée et le code clair et facile à comprendre. Ca fait plaisir de voir un code comme ça ^^

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.