Site multilingue : captcha spécifique et menus par catégorie de langue

FrancisFrancis Member
octobre 2012 modifié dans Modifications
Bonjour,

Le captcha de PluXml s'adapte à la langue par défaut du site, c'est super. Mais quand on a un site en plusieurs langues, il faut pouvoir changer la langue du captcha suivant la page affichée.


Pour le site trilingue français-chinois-anglais www.sun-translate.com, j'ai récupéré le captcha de PluXml et j'en ai fait un fichier captcha_lang.php que vous trouverez zippé ici : captcha_lang.zip.


On peut y paramétrer autant de langues que l'on veut.
Ensuite, il suffit de placer ce fichier captcha_lang.php dans le dossier du thème utilisé, et de l'inclure dans le fichier header.php avec l'instruction :
include(dirname(__FILE__) . '/captcha_lang.php');

Dans la page statique qui contient le formulaire dans une langue donnée, on récupère un tableau en appelant la fonction avec le paramètre de cette langue, comme 'fr' pour le français, 'en' pour l'anglais ou 'zh' pour le chinois (zhong wen = la langue chinoise, pour info) :
$tab_captcha = captcha_lang('fr');

On peut alors utiliser dans le formulaire la question $tab_captcha et la réponse $tab_captcha.

J'ai repris la méthode du fichier contact proposé par Stéphane : la réponse est placée dans un champ masqué, pour qu'elle soit transmise en même temps que le formulaire, ce qui permet d'effectuer la comparaison avec la réponse donnée par l'expéditeur du message.


Dans les paramètres du chinois de la fonction captcha_lang, j'ai dû indiquer que le mot à lire (2ème argument) soit en premier et que le n° de la lettre à trouver (1er argument) soit en deuxième.
Mais ne me demandez pas trop de précisions sur la traduction, si j'ai repéré deux ou trois caractères, c'était avant tout du copier-coller !

Réponses

  • Pour répondre à Jerry (voir la question ici), voici comment est organisé le site multilingue www.sun-translate.com


    J'utilise des menus automatiques = liste de tous les articles d'une catégorie, triés par ordre croissant, pour le menu principal de chaque langue.


    Ça donne 3 catégories : Menu principal-FR, Menu principal-EN (anglais) et Menu principal-ZH (ZH = zhong wen = chinois).


    Il y a 3 autres catégories pour les pieds de page : Pied de page-FR, Pied de page-EN, Pied de page-ZH.
    Bien que ce soit possible, il n'y pas de menu automatique dans les footers, simplement des liens en dur vers les pages "Mentions légales", "Copyrights and legal disclaimer" et "版本所有" (à vos dictionnaires !)


    Les petits drapeaux du site pointent chacun vers la page d'accueil de la langue.
    J'utilise 3 modèles avec la langue -xx (-fr, -en, -zh), ce qui me donne 3 fois les fichiers article-xx.php, statique-xx.php, header-xx.php, footer-xx.php et home-xx.php, mais comme il faut bien une page d'accueil du site, celle en français ne s'appelle pas home-fr.php mais home.php


    Le menu automatique s'inspire en droite ligne d'un programme qui liste les articles par catégorie - fourni par Jerry Wham :) - que j'appelle menu-articles.php


    Dans header-fr.php, le menu initialise le n° de catégorie et appelle ce programme :
    <ul id="menu" class="menu">
          <?php
            // Affichage des lignes de menu <li..><a...>...</a></li> : liste des articles triés par ordre de date croissante
            $numcategorie = '001'; // Numéro de la catégorie des pages à lister - 001 = Français
             include 'menu-articles.php';
          ?>
          <!-- Lien "Contact" à la fin  - ATTENTION : A modifier si la page Contact n'est pas la page "static1" -->
          <li class="static1">
            <a href="static1/contact-fr">Contact</a>
          </li>
    </ul>
    


    Enfin, voici ma version de la liste des articles par catégories (fichier menu-articles.php) :
      // Affichage des lignes du menu (SANS LA BALISE <ul>) : noms des pages = noms des articles triés par DATE CROISSANTE
      // => si un article est ajouté (nouvelle page), il se place automatiquement en dernier dans le menu
       
      // Dans le header, renseigner le numéro de la catégorie dont il faut afficher les articles : $numcategorie (sinon, $numcategorie = '001' par défaut)
      if ($numcategorie=='') $numcategorie = '001'; // Numéro de la catégorie dont il faut afficher les articles en tant que menu
    
      // Recherche de la liste des fichiers articles
      $motif = '/^[0-9]{4}.[home|'.$plxMotor->activeCats.',]*.[0-9]{3}.[0-9]{12}.[a-z0-9-]+.xml$/'; 
      // Liste des articles : paramètre 'sort' pour un tri chronologique normal, 'rsort' pour un tri chronologique inverse
      if($aFiles = $plxMotor->plxGlob_arts->query($motif, 'art', 'sort', 0, false, 'before')) { 
    
          $plxRecord_arts = false;
          $tab_nomsdefichiersarticles = array();
          
          foreach ($aFiles as $k=>$v) { # On parcourt tous les fichiers
              $tab_nomsdefichiersarticles[$k] = $plxMotor->parseArticle(PLX_ROOT.$plxMotor->aConf['racine_articles'].$v);
          }
          # On stocke les enregistrements dans un objet plxRecord
          $plxRecord_arts = new plxRecord($tab_nomsdefichiersarticles);
      }
    
    if($plxRecord_arts) {
        # On boucle sur nos articles
        while($plxRecord_arts->loop()) {
            
            if ($plxRecord_arts->f('categorie') == $numcategorie) 
            {
                $num_article = intval($plxRecord_arts->f('numero'));
        				// Si c'est l'article courant (en cours d'affichage), classe "active" pour la ligne, sinon classe "noactive"
        				// => marche pour la page d'accueil (affichage d'un seul article sur la page d'accueil - $plxShow->artId() vaut 1)
                $status = 'noactive';
                if ( ($plxShow->mode()=='article') && ($num_article == $plxShow->artId()) )  $status = 'active'; 
                // Ecriture d'une ligne de menu
                echo '<li class="' . $status . '">
                        <a href="' . $plxMotor->urlRewrite("?article" . $num_article . "/" . plxUtils::strCheck($plxRecord_arts->f('url'))) . '">'
                          . $plxRecord_arts->f('title')
                      .'</a>
                      </li>'."\n";
            }
        } // fin while (écriture de toutes les lignes de menu)
    } // fin du if
    
  • Merci Francis pour ces explications.

    Donc si j'ai bien compris, l'interface d'administration est la même et il faut sélectionner 2 catégories par article en fonction de la langue choisie ("Menu principal-XX" et "Pied de page-XX") et le template de la langue choisie.

    Et il faut penser à rédiger tous les articles dans toutes les langues.
  • FrancisFrancis Member
    octobre 2012 modifié
    C'est bien ça, il y a un seul site, une seule installation de PluXml, une seule interface admin et un seul thème.


    Le changement de langue se fait ici "en dur", par l'appel de la page d'accueil de la langue demandée.


    Les pages du site sont des articles. Les catégories sont associées aux langues, donc il suffit d'avoir un menu qui n'affiche que les articles d'une catégorie donnée pour obtenir le site dans la langue choisie.


    Par contre, il ne faut utiliser qu'une seule catégorie par article (comme Menu principal-FR), car il y a un problème dans PluXml : lorsqu'un article appartient à plusieurs catégories, il n'est listé que dans une seule.


    Le thème doit contenir des fichiers templates pour chaque langue (comme article-fr.php, qui appelle header-fr.php et footer-fr.php + static-fr.php pour les pages statiques).



    Ecrire les pages dans la bonne langue, oui, c'est le minimum ! :) Lorsque d'une langue à l'autre, la structure des pages et les images sont les mêmes, il est pratique est de copier-coller le code source de la page qui est en français et de repasser en mode wysiwyg pour changer le texte.
  • Francis a écrit:
    (...)il y a un problème dans PluXml : lorsqu'un article appartient à plusieurs catégories, il n'est listé que dans une seule.

    Je ne pense pas que cela vienne de Pluxml, mais plutôt de la fonction qui affiche les catégories. Je vais rechercher la modif que j'avais faite pour la fonction et je te la poste. Si tu n'es pas convaincu, vas sur mon site (http://www.ecyseo.net) et regarde dans les catégories Pluxml et Divers : l'article sur Firefox apparait dans les 2.
  • Jerry WhamJerry Wham Member
    octobre 2012 modifié
    La voilà. Je te la livre telle que. Il y a peut-être des modif à apporter.

    A mettre dans un plugin avec plxShowLastCatList comme appel de hook. Comme il y a un return true à la fin, elle remplacera la fonction d'origine, sans modifier les fichiers source de pluxml ni faire d'appel de hook dans le thème.
    	/**
    	 * Méthode qui affiche la liste des catégories actives, avec la liste des articles associés.
    	 * Si la variable $extra est renseignée, un lien vers la
    	 * page d'accueil (nommé $extra) sera mis en place en première
    	 * position.
    	 *
    	 * @param	$extra	string nom du lien vers la page d'accueil
    	 * @param	$format	string format du texte pour chaque catégorie (variable : #cat_id, #cat_status, #cat_url, #cat_name, #art_nb)
    	 *			ou
    	 *			$format array(
    	 *					$format[0] string format du texte pour chaque catégorie (variable : #cat_id, #cat_status, #cat_url, #cat_name, #art_nb)
    	 * 					$format[1] integer nombre d'articles maximum à afficher dans les sous-menu
    	 *			)
         * @param	include string	liste des catégories à afficher séparées par le caractère | (exemple: 001|003)
         * @param	exclude string	liste des catégories à ne pas afficher séparées par le caractère | (exemple: 002|003)
     	 * @return	stdout
    	 * @scope	global
    	 * @author	Anthony GUÉRIN, Florent MONTHEL, Stephane F, Cyril MAGUIRE
    	 */
    	public function plxShowLastCatList(){
    		$string =<<<END
    		if (is_array(\$format)) {
    			\$f = \$format[0];
    			\$nbSousMenu = intval(\$format[1]);
    			\$format = \$f;
    			unset(\$f);
    		} else {
    			\$nbSousMenu = 0;
    		}
    		# Si on a la variable extra, on affiche un lien vers la page d'accueil (avec \$extra comme nom)
    		if(\$extra != '') {
    			\$name = str_replace('#cat_id','cat-home',\$format);
    			\$name = str_replace('#cat_url',\$this->plxMotor->urlRewrite(),\$name);
    			\$name = str_replace('#cat_name',plxUtils::strCheck(\$extra),\$name);
    			\$name = str_replace('#cat_status',((\$this->catId()=='home' && \$this->mode() == 'home')?'active':'noactive'), \$name);
    			\$name = str_replace('#art_nb','',\$name);
    			echo \$name."\n\t\t\t";
    		}
    		if(\$this->plxMotor->aCats) {
    			foreach(\$this->plxMotor->aCats as \$k=>\$v) {
    				\$in = (empty(\$include) OR preg_match('/('.\$include.')/', \$k));
    				\$ex = (!empty(\$exclude) AND preg_match('/('.\$exclude.')/', \$k));
    				if(\$in AND !\$ex) {
    				if((\$v['articles']>0 OR \$this->plxMotor->aConf['display_empty_cat']) AND (\$v['menu']=='oui') AND \$v['active']) { # On a des articles
    					\$k = intval(\$k);
    					if (\$nbSousMenu != 0) :
    					ob_start();
    					\$this->lastArtList('<li class="#art_status"><a href="#art_url"><span>#art_title</span></a></li>',\$nbSousMenu,\$k);
    					\$sousmenu = ob_get_clean();
    					if (strlen(\$sousmenu) != 0):
    			            \$sousmenu = '
    				<ul>
    					'.str_replace('</li><li', '</li>'."\n\t\t\t\t\t".'<li', \$sousmenu).'
    				</ul>
    			</li>';
    					endif;
    					else :
    						\$sousmenu = '</li>';
    					endif;
    
    					# On modifie nos motifs
    						\$name = str_replace('#cat_id','menu_cat-'.\$k,\$format);
    						\$name = str_replace('#cat_url',\$this->plxMotor->urlRewrite('?categorie'.\$k.'/'.\$v['url']),\$name);
    						\$name = str_replace('#cat_name',plxUtils::strCheck(\$v['name']),\$name);
    						if (\$this->mode() == 'article' && in_array(\$k,explode(',',\$this->plxMotor->plxRecord_arts->f('categorie')))) {
    							\$name = str_replace('#cat_status','active', \$name);
    						}else {
    							\$name = str_replace('#cat_status',(\$this->catId()==\$k?'active':'noactive'), \$name);
    						}
    						\$name = str_replace('#art_nb',\$v['articles'],\$name);
    						\$name = str_replace('</li>',\$sousmenu,\$name);
    						echo \$name;
    					}
    				}
    			} 
    		}
    		return true;
    END;
    		echo '<?php '.$string.'?>';
    	}
    
  • Merci bien Jerry, cette version me sera utile.
    Je la regarderai dès que j'aurai un peu de temps.
  • FrancisFrancis Member
    novembre 2012 modifié
    Effectivement, il n'y a pas de problème pour l'affichage des articles par catégorie, même si des articles appartiennent à plusieurs catégories. Il suffit d'utiliser une fonction qui marche ! :)
    Le seul doute que j'ai est sur la fonction $plxShow->artCatId() qui ne renvoie qu'un seul id de catégorie, même si l'article appartient à plusieurs catégories.


    J'ai créé quelques fonctions pour les listes d'articles par catégorie, en ordre chronologique croissant ou décroissant. Les voici les voilà, si ça peut être utile à quelqu'un.


    Comme je préfère appeler mes menus à partir du n° de catégorie (qui reste fixe, le nom de catégorie pouvant être changé par l'utilisateur), voici une fonction pour afficher les articles :
    - d'une catégorie dont l'id est fourni
    - ou de plusieurs catégories dont les id sont fournis dans un tableau comme array(1,2,5), avec suppression des doublons pour les articles appartenant à plusieurs catégories
    /* Fonction liArticles_categorie qui donne la liste des articles d'UNE OU PLUSIEURS CATÉGORIES données par leur id (avec balises <li> et <a> mais pas <ul>)
       
       Les titres des articles sont entourés de balises ligne <li> (avec classe active ou inactive) et lien <a>
       Paramètres facultatifs :
       - $categorie = soit un n° de catégorie, soit un tableau avec plusieurs catégories comme array(1,3,5). Si ce paramètre est absent, il vaut 0 par défaut = "toutes les catégories"
       - $datecroissante = true (valeur par défaut, si absent) => de l'article le plus ancien au plus récent (dates croissantes)   ou   false pour l'inverse (dates décroissantes)
       
       NB : Si plusieurs catégories sont demandées, les articles sont mélangés et triés par date (croissante ou décroissante), et les doublons sont éliminés
       Auteur : Francis D.
    */
    function liArticles_categorie ($categorie=0, $datecroissante=true) {
      $plxShow = plxShow::getInstance();
      
      // Cas où une seule catégorie est fournie comme paramètre
      // ------------------------------------------------------
      if (! is_array($categorie))
      {
          ob_start();
            $plxShow->lastArtList('<li class="#art_status"><a href="#art_url" title="#art_title">#art_title</a></li>','1000',$categorie); //liste les articles de la catégorie
          $txt_lastartlist = ob_get_clean();
          
          preg_match_all('/(<li[^>.]*>.*?<\/li>)/', $txt_lastartlist, $tab); // récupération des lignes de liens => elles sont mémorisées dans les éléments $tab[0][i]
          
          $li_articles = $tab[0]; // simplification : tableau $li_articles à une seule dimension, au lieu de deux pour $tab
          if ($datecroissante) { $li_articles = array_reverse($li_articles); } // si $increasedate est vrai, de l'article le plus ancien au plus récent
        
          return implode($li_articles);
      } 
      
      // Cas où un tableau de catégories est fourni comme paramètre
      // ----------------------------------------------------------
      else
      {
          $li_articles = array(); // tableau des lien des articles de toutes les catégories (provisoirement précédés aaammjjhhmm pour le tri chronologique => date aaaammjj et heure hhmm)
          
          foreach ($categorie as $id_cat) {
            
            ob_start();
              $plxShow->lastArtList('DATE#art_date-HEURE#art_hour-LIEN<li class="#art_status"><a href="#art_url" title="#art_title">#art_title</a></li>','1000',$id_cat); //liste les articles de cette catégorie
            $txt_lastartlist = ob_get_clean();
            // Récupération de $tab[1][i]=jj (jour), $tab[2][i]=mm (mois), $tab[3][i]=aaaa (année), $tab[4][i]=hh (heure), $tab[5][i]=mm (minutes) et $tab[6][i]=lien article :
            preg_match_all('/DATE([0-9]{2})\/([0-9]{2})\/([0-9]{4})-HEURE([0-9]{2}):([0-9]{2})-LIEN(<li[^>.]*>.*?<\/li>)/', $txt_lastartlist, $tab);
            
            // Passage du tableau $tab à deux dimensions au tableau $tab_arts à une dimension, qui contiendra toutes les occurrences pour toutes les catégories
            for ($i=0; $i<count($tab[1]); $i++) {
              $li_articles[] = $tab[3][$i] . $tab[2][$i] . $tab[1][$i] . $tab[4][$i] . $tab[5][$i] . $tab[6][$i]; // titre article précédé de aaaammjjhhmm (année, mois, jour, heure, minutes) pour le tri et pour éliminer les doublons
            }
          
          }
          
          if ($datecroissante) { sort($li_articles); } else { rsort($li_articles); }  // si $increasedate est vrai, de l'article le plus ancien au plus récent, sinon le contraire
          if (count($categorie)>1) $li_articles = array_unique($li_articles); // suppression des doublons (cas où des articles appartiennent à plusieurs des catégories demandées)
          // Sur chaque élément de $li_articles, suppr. des 12 premiers caractères aaaammjjhhmm => par substr, avec un tableau rempli par la valeur 12 et de même longueur que $li_articles
          $li_articles = array_map(substr, $li_articles, array_fill(0,count($li_articles),12));
          
          return implode($li_articles);
      
      }
    } // Fin fonction liArticles_categorie
    


    J'ai eu besoin aussi d'afficher le dernier article d'une catégorie (facile ! :)) et un brin plus compliqué, la liste de tous les articles d'une catégorie sauf le dernier en date. Ça m'a servi pour un site qui gère 4 blogs, avec un menu spécial pour le dernier article de chaque, et les archives par catégorie pour tous les articles sauf le dernier. Voici ces deux fonctions :
    /* Fonction liDernierArticle_categorie qui donne la liste du DERNIER ARTICLE EN DATE d'une catégorie donnée par son id (avec balises <li> et <a> mais pas <ul>)
       
       Le titres de l'article est entouré de balises ligne <li> (avec classe active ou inactive) et lien <a>
       Paramètre facultatif :
       - $numcategorie qui vaut 0 par défaut (si absent), ce qui correspond à "toutes les catégories"
       Auteur : Francis D.
    */
    function liDernierArticle_categorie ($idcategorie=0) {
      $plxShow = plxShow::getInstance();
      ob_start();
        $plxShow->lastArtList('<li class="#art_status"><a href="#art_url" title="#art_title">#art_title</a></li>','1',$idcategorie); //liste les articles de la catégorie
      $txt_lastartlist = ob_get_clean();
    
      return $txt_lastartlist;
    }
    
    
    /* Fonction liArticlesSaufDernier_categorie qui donne la liste des les articles SAUF LE DERNIER, pour une catégorie donnée par son id (avec balises <li> et <a> mais pas <ul>)
       
       Les titres des articles sont entourés de balises ligne <li> (avec classe active ou inactive) et lien <a>
       Paramètres facultatifs :
       - $numcategorie qui vaut 0 par défaut (si absent), ce qui correspond à "toutes les catégories"
       - $datecroissante = true par défaut (si absent) => de l'article le plus ancien au plus récent (dates croissantes)   ou   false pour l'inverse (dates décroissantes)
       Auteur : Francis D.
    */
    function liArticlesSaufDernier_categorie ($idcategorie=0, $datecroissante=true) {
      $plxShow = plxShow::getInstance();
      ob_start();
        $plxShow->lastArtList('<li class="#art_status"><a href="#art_url" title="#art_title">#art_title</a></li>','1000',$idcategorie); //liste les articles de la catégorie
      $txt_lastartlist = ob_get_clean();
      
      preg_match_all('/(<li[^>.]*>.*?<\/li>)/', $txt_lastartlist, $tab); // récupération des lignes de liens => elles sont mémorisées dans les éléments $tab[0][i]
      
      $tablignes = $tab[0]; // simplification : tableau $tablignes à une seule dimension, au lieu de deux pour $tab
      $tablignes = array_slice($tablignes, 1); // Suppression du premier élément = du dernier article en date
      if ($datecroissante) { $tablignes = array_reverse($tablignes); } // si $increasedate est vrai, de l'article le plus ancien au plus récent
    
      return implode($tablignes);
    }
    



    Et puis ça peut être intéressant de donner les noms des catégories au lieu des identifiants, pour les listes d'articles. J'ai donc adapté la technique de Jerry pour obtenir d'abord l'id d'une catégorie à partir de son nom (ou un tableau d'id, à partir d'un tableau de noms de catégories) :
    /* Fonction idcategorie qui renvoie, suivant que le paramètre est un texte simple ou un tableau de textes :
       - l'id d'une catégorie (numéro, sans les 0 du début => 1 au lieu de 001) à partir de son nom (chaîne de caractères fournie en paramètre)
       - ou un tableau d'id de catégories (tableau de numéros) à partir d'un tableau de noms de catégories (tableau de chaînes de caractères fourni comme paramètre)
       
       Lorsque le nom n'est pas trouvé, la fonction renvoie le paramètre $id_si_introuvable, ou la valeur 0 par défaut (dans le cas d'un tableau, idem pour chacune des valeurs du tableau)
       Auteur : Francis D., Jerry Wham
    */
    function idcategorie ($nomcategorie, $id_si_introuvable=0) {
    
      $plxShow = plxShow::getInstance();
        
      if (! is_array($nomcategorie)) 
      { // Cas où $nomcategorie est une chaîne de caractères (une seule catégorie => le paramètre est une simple chaîne, pas un tableau)
          
          $idcat = $id_si_introuvable; // Valeur de $catId ant qu'une catégorie n'a pas été trouvée (valeur 0 par défaut, si le paramètre $id_si_introuvable n'est pas indiqué)
          if ($plxShow->plxMotor->aCats) {
      			
            foreach ($plxShow->plxMotor->aCats  as  $k => $v) { // pour chaque catégorie, avec   $k = n° de catégorie   et   $v["name"] = nom de la catégorie
                if ($nomcategorie==$v['name']) { $idcat = $k;   break; }
            } // Fin foreach sur les catégories
      		} // Fin du if ($plxShow->plxMotor->aCats) sur l'existence de catégories
    
          return intval($idcat); // Renvoi d'un texte lorsque l'argument est un texte
      } // Fin du if (! is_array($nomcategorie))
      else 
      { // Cas où $nomcategorie est un tableau de chaînes de caractères (plusieurs catégories => le paramètre est un tableau)
          $i = 0;
          foreach($nomcategorie as $nomcat) {
            // Appel récursif de la fonction idcategorie pour chacun des noms du tableau (utilisation de la 1ère partie de la fonction, lors de cet appel récursif, car le if est vérifié)
            $tab_idcats[$i] = idcategorie($nomcat);
            $i++;
          }
          return $tab_idcats; // Renvoi d'un tableau lorsque l'argument est un tableau
      }
    
    } // Fin de la fonction idcategorie
    


    En utilisant les fonctions précédentes, ça devient facile d'avoir la liste des articles à partir du nom de leur catégorie (ou d'un tableau contenant plusieurs noms de catégories) :
    /* Fonction liArticles_nomcategorie qui donne la liste des articles (avec balises <li> et <a> mais pas <ul>) :
       - appartenant à une catégorie donnée par SON NOM (texte)
       - ou appartenant à l'une des catégories indiquées par LEUR NOM dans un tableau
       
       Les titres des articles sont entourés de balises ligne <li> (avec classe active ou inactive) et lien <a>
       Paramètres (le 2ème est facultatif) :
       - $nomcategorie = nom de catégorie, ou tableau de noms de catégories comme array("Menu principal", "Pied de page")
       - $datecroissante = true par défaut (si absent) => de l'article le plus ancien au plus récent (dates croissantes)   ou   false pour l'inverse (dates décroissantes)
       Auteur : Francis D.
    */
    function liArticles_nomcategorie ($nomcategorie, $datecroissante=true) {
      $idcat = idcategorie($nomcategorie);
      return liArticles_categorie($idcat, $datecroissante);
    }
    
    Toutes ces fonctions de liste renvoient des chaînes de caractères (listes <li...>...</li>, sans les balises <ul> autour. Il faut les utiliser avec echo pour les afficher.
  • Un debut de réflexion sur un plugin multilingue : http://forum.pluxml.org/viewtopic.php?id=3665
Connectez-vous ou Inscrivez-vous pour répondre.