JeuWeb - Crée ton jeu par navigateur

Version complète : Multilingue - les solutions
Vous consultez actuellement la version basse qualité d'un document. Voir la version complète avec le bon formatage.
Bonsoir,

Je me pose actuellement la question sur les possibilités offertes par le php pour faire des sites multilingues.
Vous me direz, tout est prévu à la base et ça s'appelle gettext. Cependant, je vois un défaut majeur à cette possibilité, c'est l'impossibilité d'avoir une interface permettant de traduire "en live".
D'où ma question, quelles solutions pour le multilingue avec php tout en se gardant la possibilité d'une traduction directe?
Utilisation de constantes? Table SQL dédiée 66? Autres?
Pour dev mes site avec plusieurs langue, j'utilise un petite système,

Les arrays.

J'ai un dossier language, qui contient des sous dossier ( fr, en ect )
Dedan j'ai,
Code PHP :
$lang['home'] = 'Accueil';
$lang['stats'] = 'Statistiques';
$lang['faq'] = 'FAQ';
$lang['contact'] = 'Contact'

Je recupère la langue du navigateur, si le gars n'a pas de SESSION de langue. et j'inclu le sous dossier correspondant.

Recuperation du language :
Code PHP :
function BrowserLanguage()
{
    
$language explode(",",$_SERVER['HTTP_ACCEPT_LANGUAGE']);
    
$language strtolower(substr(chop($language[0]),0,2));
    return 
$language;
}

function 
LanguageRecuperation()
{
    
$result = (isset($_SESSION['lang'])) ? $_SESSION['lang'] :  BrowserLanguage();
    
    return 
$result;


et inclusion
Code PHP :
$_SESSION['lang'] = LanguageRecuperation();
include(
'languages/'.$_SESSION['lang'].'/index.php'); 

Biensur, l'exemple de tout a l'heure peut etre mis dans un sous dossier en, avec dedans :

Code PHP :
$lang['home'] = 'Homel'//Par exemple 

Cordialement,
J'avais ouvert un sujet sur la question qui s'était révélé très intéressant (car apportant plein de réponses de divers intervenant). Il serait intéressant d'en faire la synthèse.

El[u]ox t'as donné une piste pour le contenu statique. Je vais t'en donner une pour le contenu dynamique.

Imaginons que tu travailles sur un jeu de rôle où es joueurs peuvent avoir des objets. Tu as donc une table objets avec les champs suivants :
  • Id (clé primaire)
  • Nom

Il faudra donc traduire le champ Nom.

Pour cela, il faudra une table d'internationalisation : nommons-la objets_i18n qui contiendra les champs :
  • Id
  • Nom
  • Langue

Admettons ensuite que tu ai 2 objets dans ta table objets :
  • 1, Heaume de bataille de porteguerre
  • 2, Lames d'épaules de destructeur

Ta table de localisation contiendra alors quelque chose comme cela :
  • 1, Warbringer Battle-Helm, en
  • 1, Yelmo de batalla belisario, es
  • 2, Destroyer Shoulderblades, en

Chaque objet peut donc avoir plusieurs traduction, différenciée par une locale (fr pour le français, es pour l'espagnol, en pour l'anglais, etc. Tu peux avoir autant de langue que tu le souhaites.

Code :
SELECT O.id,
IF(O2.nom IS NULL, O.nom, O2.nom) AS nom
FROM objets O
LEFT JOIN objets_i18n O2 ON O2.id = O.id AND O2.langue = 'en';

Ainsi, la traduction est transparente (le champ garde le même nom : nom). La locale (en) est donnée par une variable de session par exemple (que tu auras déterminé précédemment).

S'il n'y a pas de traduction pour cet objet ou pour cette langue, alors le nom par défaut (celui indiqué dans la table objets sera utilisé, le jeu reste ainsi utilisable même si tout n'est pas traduit.


Sephi-Chan
Bonne mémoire Sephi 16
Merci de vos réponses.
Je ne vais pas être très crédibles mais j'avais fait une recherche avant d'ouvrir ce sujet et avait été étonné qu'il n'est pas encore été traité. Avant le multilingue, il va peut-être falloir que je m'occupe de l'utilisation de la fonction recherche 6

Edit: la recherche avec i18n est un peu plus fructueuse
Le sujet de Sephi-Chan: C'est ici
Et un autre avec un très bon lien de naholyr vers le site phpfrance: C'est par là
naholyr a écrit :Bonne mémoire Sephi 16
Hey ! Ça m'a beaucoup servi et j'ai beaucoup aimé utiliser cette technique. Ce serait ne pas jouer le jeu que de la garder pour moi. 2

Pour ma part, le problème vient surtout du contenu statique. Le défaut de l'array, c'est que les vues PHP (ou templates) perdent en clarté… Gettext l'est un peu plus mais il pose d'autres problèmes.


Sephi-Chan
Problème ardu 34
Pour ma part j'ai opté pour un fichier xml par langue, interprété par une classe qui va bien.
Il est à noté qu'au delà des débats sur la rapidité fichiers/array/sql, il est surtout très important de lier la localisation avec un cache robuste pour éviter les appels dans tout les sens 34
Je peut poster la classe en question avec des xml d'exemple si jamais ça intéresse.
Pareil pour moi, j'utilise le XML mais couplé au XSL pour l'interprétation
J'en avais déjà parlé ici pour ceux que ça intéresse.
Je suis intéressé par la classe dont tu parles, Gamboo. 2
Ça me permettra de la comparer avec la méthode XSLT.


Sephi-Chan
Alors je vais essayer de faire assez simple, donc voici un xml de langue, exemple d'un xml nommé fr.xml :
Code PHP :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE language SYSTEM "lang.dtd" >

<language>
    <key id="language">Français</key>
      <key id="chaine1">Chaine avec variable dynamique qui vaut %s, voila !</key>
</language> 
Maintenant voici la classe en question (qui est elle même intégrée à mon framework, si vous avez des soucis de compréhension jsuis la 34)
Code PHP :
<?
class Lang
{
    public 
$lang;
    private static 
$_instance;
    private 
$_list = array();
    private 
$_file = array();

    
// --------------------------------------------------------------
    
public static function getInstance() { 
    
// --------------------------------------------------------------
        
if(empty(self::$_instance)) 
        {
            
self::$_instance = new Lang();
        }
        return 
self::$_instance;
    }

    
// --------------------------------------------------------------
    
private function __construct() { 
    
// --------------------------------------------------------------
        
$this->_list Core::$_core->config['language_list'];
        if(!isset(
$_SESSION['lang'])) 
        { 
            
$AcceptedLangage explode(",",$_SERVER["HTTP_ACCEPT_LANGUAGE"]); 
            if(
in_array($AcceptedLangage[0],$this->_list)) $_SESSION['lang'] = $AcceptedLangage[0];
            else 
$_SESSION['lang'] = 'en'
        }
        
$this->lang $_SESSION['lang'];
        if(
file_exists(Core::$_core->config['base_path']."public/lang/".$this->lang.".xml")) array_push($this->_file,$this->lang);
    }

    
// --------------------------------------------------------------
    
public function setLang($lang) { 
    
// --------------------------------------------------------------
        
if(file_exists(Core::$_core->config['base_path']."public/lang/".$this->lang.".xml")) 
        {
            
$_SESSION['lang'] = $lang;
            
$this->lang $lang;
            
$this->_file = array();
            
$this->_xml = array();
            
array_push($this->_file,$this->lang);
        }
        else return 
false;
    }

    
// --------------------------------------------------------------
    
public function init() { 
    
// --------------------------------------------------------------
        
if(!empty($this->_file))
            
$this->_xml simplexml_load_file(Core::$_core->config['base_path']."public/lang/".$this->_file[0].".xml");
        else 
            
$this->_xml simplexml_load_string("<language></language>");
    }

    
// --------------------------------------------------------------
    
public function _() { 
    
// --------------------------------------------------------------
        
$Aarguments func_get_args();
        if(
$sChain Cache::get(md5(serialize($Aarguments).$this->lang))) return $sChain;
        else
        {
            if(empty(
$this->_xml)) $this->init();
            if(
$sChain $this->_xml->xpath("//key[@id='".$Aarguments[0]."']")) 
            {
                if(
count($Aarguments)>1
                {
                    
$var $Aarguments;
                    
$var[0] = (string)$sChain[0];
                    
$sChain call_user_func_array('sprintf',$var);
                }
                else 
$sChain = (string)$sChain[0];
                
Cache::set(md5(serialize($Aarguments).$this->lang),$sChain,86400);
                return 
$sChain;    
            } 
            else return 
"[".$Aarguments[0].":empty]";
        }
    }
       
}
?>
Et maintenant voici donc son utilisation plus en détails :
Code PHP :
<?
$this
->lang Lang::getInstance(); // on récupere l'instance de la classe lang. La langue du navigateur est déterminée par la classe.
echo $this->lang->_('language'); // Affichera "Français"
?>
Mais il y à également une fonction qui permet d'insérer des variables dynamique assez facilement, exemple :
Code PHP :
<?
$this
->lang->_('chaine1','36'); // affichera "Chaine avec variable dynamique qui vaut 36, voila !"
?>
Chaque chaine affichée est ensuite mise en cache (dans APC mais d'autres système peuvent être utilisés) et donc le fichier xml n'est chargée qu'a partir du moment ou une chaine non cachée est rencontrée.
Voila si vous avez des questions, ou des remarques (je n'en doute pas) à vous les micro 2
URLs de référence