Mise en place du multilingue de contenus (AMS)
Un article de DocAstairs.
Sommaire |
[modifier] Introduction
Auparavant, l'ensemble des contenus pédagogique d'Astairs était en une seule langue. Les éléments textuels (chaines de charactères, textes,... ) et les images les constituant n'étaient pas associées à une langue.
La création de contenus pédagogiques de formations, c'est à dire les évaluations, exercices, parcours, étapes,.... se faisait donc dans une langue unique, et pour traduire intégralement une telle formation, il fallait recréer à l'identique l'ensemble des contenus pédagogiques.
Les contenus de formations étaient donc totalements distincts, sans liens, alors qu'elles étaient identiques en tout point, langue excepté bien sur.
La mise en place du multilingue de contenu répond à cette problématique:
- Lors de la création d'une formation et de ses contenus pédagogiques, les éléments textuels (chaines de charactères, textes,... ) et les images les constituant deviennent associés à une langue.
- Chacune des ressources pédagogiques "contient" ses différentes langues, le contenu est alors multilingue.
Pour ce faire, il convient de distinguer 2 choses:
- les chaines de charactères et textes
- les médias
Après une présentation du principe de fonctionnement, nous expliquerons la mise en place générale du système puis ces 2 éléments séparéments.
[modifier] Principe
Le système repose sur un élément principal, les ams. Une ams (Astairs Mutilingual String), est le format de chaine de caractère pour le système multilingue.
Une AMS est caractérisé par: -Une langue -Un texte (String)
Là ou auparavent nous avions une chaine simple, nous manipulerons à l'avenir une chaine contenant une ou plusieurs AMS.
Prenons l'exemple d'un QCM, en considérant qu'un QCM est composé d'une question et de plusieurs réponses.
En v1, un QCM est non multilingue. La question est donc stockée en base de données sous la forme d'une chaine (string). Exemple:
"Comment allez vous?"
En v2, on stockera la chaine sous la forme d'une ams:
##AMS1##{"Comment allez vous?"}
Notez que l'ams contient l'identifiant de la langue de la question , qui est ici 1 (Français) Ce format intègre donc la langue du contenu.
Si l'on souhaite proposer notre question en 2 langues, français anglais, on stokera la traduction anglaise dans le meme champs de base de données. Pour ce faire, on ajoutera une 2eme ams dans le champs. Dans notre exemple, celui-ci contiendra:
##AMS1##{"Comment allez vous?"},##AMS2##{"How are you?"}
Notez que la seconde ams contient l'identifiant de la langue de la question en anglais , qui est ici 2 (Anglais), et que le séparateur pour les ams est la virgule.
[modifier] Mise en place générale
Afin de mettre en place le plus facilement possible ce système, un ensemble de classe et de fonctions ont été écrites.
Les fonctions AMS sont actuellement régroupées dans le fichier fonctions_langue_.inc du répertoire /lib/langue. Les classes AMS sont actuellement dans le repertoire /lib_graphique/objets/langue.
Vous trouverez les indications concernant leurs utilisations ci-desous. Ces indications sont regroupées par problématiques.
[modifier] Selection de la langue AMS
La langue AMS définit la langue dans laquelle on affiche et saisi les libéllés, Elle doit donc etre définie dans toutes les parties du Back-Office ou des AMS sont crées, c'est à dire sur l'ensemble des Ressources Pédagogiques. A cet effet, cette partie du Back-Office dispose d'une entete spéciale, incluant un composant permettant la séléction de cette langue.
Cette langue est stockée en session dans la variable $ams_langue. Si un composant en à besoin et que celle-ci n'est pas valuée, un message s'affiche automatiquement pour indiquer à l'utilisateur de séléctionner cette langue.
Bien que celà soit déjà mis en place, il convient d'indiquer que la classe concernée est guiAmsLangues et qu'elle dispose d'un helper: p_gui_ams_langues();
Vous ne devriez pas avoir à utiliser ces éléments, celà ayant déjà été fait pour vous, dans l'entete RH.
[modifier] Insertion d'une AMS
Pour inserer une AMS, il suffit d'appeller une fonction particuliere sur le libéllé lors de l'appel à une fonction PHP d'insertion (set_...) au lieu du classique string2Sql().
Voici un exemple, $question1 valant "Comment allez-vous?":
- sans AMS:
$numquest = set_question_qcm(string2Sql($question1), bool2Sql($inter), int2Sql($theme)); La fonction insert donc en base de données : "Comment allez-vous?" dans le champ correspondant.
- avec AMS:
$numquest = set_question_qcm(set_ams_libelle($question1), bool2Sql($inter), int2Sql($theme)); La fonction insert donc en base de données : ##AMS1##{"Comment allez vous?"} dans le champ correspondand.
[modifier] Affichage d'une AMS (BO)
Pour afficher une AMS, il convient de la formater afin que celle-ci produise l'affichage attendu, soit le texte que l'on a saisi ("Comment allez-vous?" dans notre exemple), correspondant à la langue que l'on souhaite afficher (la langue AMS). Il convient par ailleurs d'indiquer à l'utilisateur qu'il est entrain de saisir un contenu multilingue et de lui afficher les informations lui permettant la traduction eventuelle.
Pour celà, plusieurs classes et fonctions sont disponibles en fonction de l'affichage à faire (texte, champ imput, text aréa, ....):
[modifier] Texte (Class guiAmsLibelle )
Un guiAmsLibelle affiche un DIV composé de l'ams correspondant à la langue_ams de la session, ainsi que le code de pays de la langue en question. Cet élément graphique provoque l'affichage d'une bulle lorsqu'il est survolé par le curseur de la souris, qui indique les autres traductions disponibles pour l'ams.
2 fonctions (helpers) Permettent de récupére cet objet facilement:
- get_gui_libelle($string_libelles,$intefonctrpretationHTML=false) : retourne le DIV sour forme d'une chaine, pour utilisation directe dans la chaine d'un print ou un echo.
- p_gui_libelle($string_libelles,$interpretationHTML=false) : affiche le DIV sour forme d'une chaine, pour utilisation directe dans un script PHP.
[modifier] Input (type=text) (Class guiAmsLibelleInput )
Un guiAmsLibelleInput affiche un DIV pour la saisie d'une ams, à partir d'une chaine SQL brute contenant une, plusieurs ou aucune ams. Un guiAmsLibelleInput affiche un champ imput initalisé avec l'ams correspondant à la langue_ams de la session, ainsi que le code de pays de la langue en question. Cet élément graphique provoque l'affichage d'une bulle lorsqu'il est survolé par le curseur de la souris, qui indique les autres traductions disponibles pour l'ams
2 fonctions (helpers) Permettent de récupére cet objet facilement:
- get_gui_libelle_input($input_name,$string_libelles,$disabled=false,$taille=80,$onKeyUp=)
- p_gui_libelle_input($input_name,$string_libelles,$disabled=false,$taille=80,$onKeyUp=)
[modifier] TextArea (Class guiAmsLibelleTextarea )
Un guiAmsLibelleTextarea affiche un DIV contenant un guiAmsLibelleTextarea pour la saisie d'une ams, à partir d'une chaine SQL brute contenant une, plusieurs ou aucune ams. Un guiAmsLibelleTextarea affiche un champ textearea initalisé avec l'ams correspondant à la langue_ams de la session, ainsi que le code de pays de la langue en question. Cet élément graphique provoque l'affichage d'une bulle lorsqu'il est survolé par le curseur de la souris, qui indique les autres traductions disponibles pour l'ams
2 fonctions (helpers) Permettent de récupére cet objet facilement:
- function get_gui_libelle_textearea($input_name,$string_libelles)
- function p_gui_libelle_textearea($input_name,$string_libelles)
[modifier] Select (Pas de Class)
Pour la selection d'éléménts dont les libéllés sont des AMS, il n'y a pas actuellement de classe ou de fonction adaptée. Voici un exemple de code permettant la transformation d'une AMS pour l'utiliser en tant que libéllé pour les balises <option>.
$tmp_reponse=get_fo_libelle($rowrep[1]); $reponse=substr($tmp_reponse[1],0,30); // SI le libellé de la réponse est trop long, on tronque if(strlen($reponse)>28){ $reponse.="..."; } if(!empty($reponse[0])){ $res_langue=get_langue($tmp_reponse[0]); $reponse.="(".get_country_code_primary(pg_fetch_result($res_langue,0,3)).")"; }else{ $reponse.="(X)"; }
Ici, nous pourront donc utiliser la variable $reponse dans notre option de select. Celle ci affichera, pour notre exemple:
<option value="6756">Comment allez-vo...(fr)</option>
[modifier] Affichage d'une AMS (FO)
Pour afficher une AMS en Front Office, il convient de la formater afin que celle-ci produise l'affichage attendu, soit le texte que l'on a saisi ("Comment allez-vous?" dans notre exemple), dans la langue que l'utilisateur à choisi pour son front office. Aucune information sur la langue n'est ici utile.
A cet effet, une seule fonction est nécessaire:
- get_fo_libelle($string_libelles)
Celle-ci retourne la chaine attendue uniquement ("Comment allez-vous?")
Compte tenu que le fornt office utilise essentiellement des Classes et Objets, il faut ici placer l'appel à cette fonction dans les GETTERs:
Exemple:
- Sans AMS
class Element{ ... function getLibelle(){ return $this->libelle; } ... }
- Avec AMS
class Element{ ... function getLibelle(){ return get_fo_libelle($this->libelle); } ... }
Comme il s'agit ici de la méthode qui est appelée pour toute les étapes, évaluation, et autres classes héritant de Element, cette méthode est très efficace!
[modifier] Mise à jour d'une AMS
Il s'agit ici de la partie la plus pénible de la mise en place des AMS: il faut modifier l'ensemble des fonctions PLPGSQL de mise à jour (af_maj_...) concernées par les AMS.
En effet, sans cet ajout, chaque mise à jour d'AMS efface la précédente.
Pour simplifier celà au mieux, une fonction PLPGSQL est à utiliser:
contraintes.fw_get_ams_libelle('nom_table','nom_colonne','condition_sql_pour_selection', 'nouvelle_ams')
Cette fonction retourne la valeur du champs à mettre à jour, soit:
- L'ancienne valeur + la nouvelle AMS si les ams_langues sont différentes .
- L'ancienne valeur mis à jour avec la nouvelle AMS si la nouvelle ams_langue est déjà présente.
- La nouvelle AMS si le champs contenait une chaine non AMS ou si elle était vide.(soit 1 AMS).
- etc...
Il s'agit donc de passer le paramettre contenant l'AMS à cette fonction et de faire l'UPDATE avec la valeur qu'elle retourne.
Voici un exemple:
- Sans AMS
CREATE OR REPLACE FUNCTION contraintes.af_maj_exotlc_plate_forme(int4, "varchar", "varchar", "varchar", "varchar", "varchar", "varchar") RETURNS bool AS $BODY$ -- $1 : numero exotlc -- $2 : titre exotlc -- $3 : commentaire -- $4 : texte -- $5 : enonce -- $6 : remarque -- $7 : fichier rendu declare modif1 bool:=false; modif2 bool:=false; v_commentaire text; v_texte text; v_enonce text; v_remarque text; ams text; begin -- mise à jour du titre UPDATE contraintes.etape SET libelle=$2 WHERE id=$1; modif1:=found; -- mise à jour exotlc update contraintes.exotlc set commentaire=$3,texte=$4,enonce=$5,remarque=$6 where id=$1; modif2:=found; -- mise à jour fichier rendu update contraintes.exotlc_plate_forme set fichier_rendu=$7 where id=$1; return modif1 or modif2 or found; end;$BODY$ LANGUAGE 'plpgsql' VOLATILE;
- Avec AMS
CREATE OR REPLACE FUNCTION contraintes.af_maj_exotlc_plate_forme(int4, "varchar", "varchar", "varchar", "varchar", "varchar", "varchar") RETURNS bool AS $BODY$ -- $1 : numero exotlc -- $2 : titre exotlc -- $3 : commentaire -- $4 : texte -- $5 : enonce -- $6 : remarque -- $7 : fichier rendu declare modif1 bool:=false; modif2 bool:=false; v_commentaire text; v_texte text; v_enonce text; v_remarque text; ams text; begin -- mise à jour du titre SELECT INTO ams contraintes.fw_get_ams_libelle('etape','libelle','id='||$1,$2); UPDATE contraintes.etape SET libelle=ams WHERE id=$1; modif1:=found; -- mise à jour exotlc SELECT INTO v_commentaire contraintes.fw_get_ams_libelle('exotlc','commentaire','id='||$1,$3); SELECT INTO v_texte contraintes.fw_get_ams_libelle('exotlc','texte','id='||$1,$4); SELECT INTO v_enonce contraintes.fw_get_ams_libelle('exotlc','enonce','id='||$1,$5); SELECT INTO v_remarque contraintes.fw_get_ams_libelle('exotlc','remarque','id='||$1,$6); update contraintes.exotlc set commentaire=v_commentaire,texte=v_texte,enonce=v_enonce,remarque=v_remarque where id=$1; modif2:=found; -- mise à jour fichier rendu update contraintes.exotlc_plate_forme set fichier_rendu=$7 where id=$1; return modif1 or modif2 or found; end;$BODY$ LANGUAGE 'plpgsql' VOLATILE;
Comme vous l'avez certainement remarqué, les UPDATES pourrait etre certainement optimisés. Ce n'est actuellement pas une problématique importante, la problématique étant de passer un minimum de temps sur ces modifications.
[modifier] Précisions IMPORTANTES
Lorsqu'il s'agit de manipuler les AMS, il convient de ne pas faire de traitement particulier sur les chaines: Soit:
- aucun addslashes
- aucun htmlentities
- aucun stripsashes
- etc...
Il faut donc bien penser à supprimer toutes les utilisation de ces fonctions sur les AMS
Si des problèmes de cet ordre venaient à etre détectés, il faut ajouter ces traitements dans les fonctions AMS, afin que celà s'applique PARTOUT. Ne pas hésiter à faire remonter ses éventuels besoins s'ils venaient à survenir.
[modifier] NB
Au 6 juin 2008, afin de fournir l'exemple le plus complet, les AMS ont été mises en place:
- en BackOffice : QCM, SONDAGES, EXOTLC (création/édition uniquement)
- en BackOffice : PARCOURS, mais sans les modification pour les af_maj...
- en FrontOffice : EXOTLC