La traduction de chaines dans WPML
Dans un ancien article, dont le principe de base n’a toujours pas changé, j’expliquais quels étaient les différents contenus d’un site ( WordPress ), et comment on les traduisaient :
- les chaines contenues dans les fichiers php doivent être traduites via les fonctions gettext et une utilisation du fichier .po / .mo
- les chaines contenus dans les fichiers .js sont traduites via les fichiers .js
- les contenus (c’est à dire tout ce qui va dans la table wp_post et sa petite copine wp_postmeta, ainsi que dans les taxonomies) est traduit par un plugin, inutile de vous dire que je vous recommande chaudement WPML ^^
- et tout le reste… la question se pose ! Le reste étant le contenu de la table wp_options, donc les widgets, les options du thème, le nom du site, le slogan et pas mal d’options de plugins (par exemple, la traduction des balises titles et meta de WordPress SEO)
WPML a donc une solution spécifique pour cela, la traduction de chaine, disponible via un plugin supplémentaire, WPML String Translation, disponible pour ceux qui ont acheté la licence CMS à 79 USD.
Comment fonctionne la traduction de chaîne ?
Le principe de base de WPML est d’utiliser les tables standard de WordPress pour stocker les traductions, en rajoutant des tables spécifiques, qui commencent par le préfixe icl_ pour stocker toutes les informations spécifiques au plugin, et notamment les relations entre les éléments traduits.
Les quatre tables utilisées pour la traduction des chaines sont :
- wp_icl_strings où sont stockées les chaines à traduire
- wp_icl_translations où sont stockées les traductions des chaines précédentes
- wp_icl_string_positions qui indique la position dans la page des chaines
- wp_icl_string_status qui est utile uniquement en cas de sous-traitance de la traduction via ICL
C’est donc la seule fois où WPML va stocker à nouveau des chaînes qui se trouvent déjà ailleurs dans WordPress, dans la table wp_icl_strings .
Pourquoi ? Parce que le format d’origine de ces chaînes est très varié :
- options dans la table WordPress, comme le nom et le slogan du blog
- options sérialisées dans la table, donc “en gros” stockées comme des éléments d’une sous table, dont il va falloir extraire une chaîne ou plusieurs, au milieu d’autres qu’on n’utilise pas (eg, un widget “commentaires récents” a un titre, qui doit être traduit), et d’autres éléments qui sont des options, comme le nombre de commentaires, qu’on ne traduit pas. Si on veut afficher 5 commentaires, ça ne change pas du français à l’anglais…
- chaines des fichiers .php, normalement traduites via les fichiers .po / .mo et pour lesquelles on peut, si on veut, utiliser la traduction de chaîne (mais c’est une très mauvaise idée)
Les stocker dans une table à part permet donc de les mettre toutes dans le même format, avec un identifiant numérique, une langue d’origine, un contexte qui permet de les rattacher à un élément précis et un nom. Ainsi, la même chaîne peut être traduite de deux façons différentes selon le contexte.
En gros, WPML se reconstitue sont fichier .po / .mo dans les tables, il y a d’ailleurs la possibilité d’exporter ou d’importer des chaines au format .po / .mo
La table wp_icl_string_translations va stocker les traductions d’une chaîne dans les différentes langues du site. Quand on utilise la gestion de la traduction, le traducteur auquel la tâche est assignée est stocké, et la table wp_icl_status est utilisée pour suivre “le statut” de la traduction (ce qui a un impact sur la facturation, en cas de traducteur externe).
Comment l’utiliser pour traduire son site ?
Les chaines se traduisent donc dans l’admin, menu WPML, sous-menu “Traduction de chaines”.
La notion de la langue de base
Le message d’avertissement en haut est important et il faut bien le comprendre :
la table icl_strings, où sont stockées les chaines “de base” ne peut pas comprendre des chaines en plusieurs langues. Si vous utilisez la traduction de chaine pour traduire un thème, au lieu des fichiers .po / .mo , alors toutes vos chaines originales, celles que vous saisissez dans l’admin du blog, y compris le titre de votre blog et son slogan, et tous vos widgets doivent être en anglais, puis traduits via WPML.
Sinon WPML n’arrive pas à retrouver ses petits.…
Concrètement, cela veut dire que vous ne pouvez pas utiliser WPML pour “découvrir” des chaines codées en dur dans les fichiers des thèmes et des plugins, et les traduire via WPML, au lieu des fonctions WordPress.
Ma conclusion : ça ne me fait ni chaud ni froid, un thème qui ferait ça est affreusement mal codé…. en revanche, impossible de faire peser sur un utilisateur francophone la contrainte de rédiger son site “en anglais”.…
Si vous limitez les chaines que vous traduisez aux contenus de la table wp_options, par contre, vous pouvez oublier ce message, vous n’aurez aucun problème.
Traduire les chaines dans l’admin
La traduction elle-même est simplissime, bien qu’un peu ennuyeuse…
On clique sur traduction, ce qui affiche dans des boites les messages dans les autres langues (WPML y copie par défaut la chaine d’origine, ce qui est bien pratique pour des options comme celles de WordPress SEO … comme %%title%%), on coche “traduction terminée” pour chaque langue, ce qui met le statut de la traduction à 1 dans la table wp_icl_string_translations. Quand toutes les langues du sites sont traduites, le statut de la chaîne dans la table wp_icl_strings passe à 1 (terminé).
Suivre les positions … ou pas
Le suivi des positions permet théoriquement de faire s’afficher l’emplacement des chaînes sur le site. En cliquant sur l’option “afficher la position”, la chaîne traduite s’affiche surlignée en jaune. Je ne vois vraiment pas l’intérêt de cette option, qui est très consommatrice de ressources : il y a d’autres moyens d’identifier les chaines, si il faut vraiment….
Découvrir automatiquement les chaines … ou pas
De la même façon, la découverte automatique des chaines n’a pas, à mon avis, d’intérêt avec un thème et des plugins correctement codés. Mieux vaut corriger les erreurs de marquage que l’utiliser (surtout si on est dans la configuration où la langue de base n’est pas l’anglais).
Comment rendre ses thèmes et ses plugins WPML compatibles ?
Parce que rien n’est plus désagréable que de se retrouver face à un thème qui fait intensivement appel à des widgets et des options, et qui n’a pas prévu de les rendre identifiables par WPML. …
Pour l’identification des chaines à traduire,il y a deux façons de faire, qui vont traiter des chaînes différentes.
Les chaines “uniques” : le fichier de configuration de WPML
C’est à dire celles qui correspondent à une option unique, même si elle est sérialisée. C’est ce que WPML appelle les “admin_texts”.
C’est une section particulière du fichier de configuration WPML, qui se présente sous la forme d’un fichier wpml-config.wpml à la racine du répertoire du thème ou du plugin. Le fichier se présente de façon assez simple :
<wpml-config> <admin-texts> <key name="serial_option1"> <key name="suboption1" /> <key name="suboption2" /> </key> <key name="single_option1" /> </admin-texts> </wpml-config>
Avec cela, WPML peut désérialiser serial_option1 et en extraire les deux chaines suboption1 et suboption2. Ces deux chaines vont apparaitre dans l’admin, avec single_option1
Le contexte sera admin_texts_type_name , avec “type” pouvant prendre les valeurs “plugin” ou “theme” et “name” étant le nom système (celui qui correspond au dossier).
Le nom de la chaine sera [serial_option1]suboption1 ou single_option1.
Les chaînes “multiples” : l’API WPML
Cette méthode est impossible à appliquer pour les widgets : en effet, un widget peut être présent de multiples fois, on ne peut donc pas à l’avance connaître la structure de l’option sérialisée qui va le stocker dans la table wp_options. Il peut aussi y avoir des options dont le nombre n’est pas connu a priori.
Il faut donc, au moment de l’envoi de la chaîne à la table wp_options, lors de l’enregistrement du widget ( function update( $new_instance, $old_instance ) dans la classe de votre widget), utiliser la fonction icl_register_string ( $context, $name , $value )
Ce qui donne ceci, pour enregistrer une chaine “legend” :
$instance[ 'legend' ] = $new_instance[ 'legend' ]; if (function_exists('icl_register_string')) { icl_register_string('MyWidget', 'widget_legend' . $this->id, $instance['legend']); }
Et hop…. la chaîne apparaît miraculeusement dans l’admin.
La traduction de la chaîne : l’API WPML ou get_option
Une fois les chaînes enregistrées et traduites, l’utilisation de get_option renvoie la valeur traduite de la chaîne.
Quand on n’utilise pas get_option, par exemple dans les widgets, il y a à nouveau une fonction de l’API WPML, qui est un peu l’équivalent de __( pour l’utilisation de fichiers .po : icl_t ( $context, $name , $value )
Donc, pour afficher notre “legend”, dans la fonction widget( $args, $instance ) de notre classe, on va utiliser :
if ( function_exists ('icl_t') ) { $legend = icl_t('MyWidget', 'widget_legend' . $this->id, $instance['legend']) ; } else { $legend = $instance['legend '] ; }
Dans le cas de Spacious (qui vous permet de voir concrètement comment on fait avec le fichier du thème téléchargeable à la fin de l’article), au lieu d’utiliser get_option, l’auteur utilisation of_get_option (une fonction du plugin “option framework), le hook de WPML ne fonctionnait pas et il fallait donc utiliser icl_t , ce qui est beaucoup plus lourd.
Donc, pour coder légèrement… récupérer la valeur qui vous intéresse via get_option, puis traitez la.
Comment faire quand on a des widgets non compatibles WPML et qu’on ne veut pas reprogrammer ?
Il reste une solution de secours, qui n’est pas très “jolie” mais qui peut dépanner pour un ou deux widgets récalcitrants : l’utilisation de WidgetLogic et de l’identification de la langue.
WidgetLogic pour afficher des widgets selon des conditions
Le plugin Widget Logic fait partie de mes best of. Il ajoute, à l’intérieur de la boite du widget une case où rentrer un test, en fonction duquel le widget va être affiché ou pas.
Par exemple, si vous voulez afficher un widget uniquement si vous n’êtes pas sur la page d’accueil du blog, vous mettrez
!is_front_page()
La constante WPML pour la langue
ICL_LANGUAGE_CODE permet de déterminer le code sur deux lettres de la langue affichée. Sur une page en français, ICL_LANGUAGE_CODE sera égal à fr, qu’il s’agisse d’un fr_FR, fr_BE ou fr_CA
“Traduire” un widget grâce à WidgetLogic
Il suffira donc de mettre deux fois le même widget, une fois avec
ICL_LANGUAGE_CODE = 'fr'
et la seconde fois avec
ICL_LANGUAGE_CODE = 'en'
Cela reste une solution de dépannage.
(En revanche, elle est parfaite si vous avez besoin de gérer un contenu vraiment différent de votre sidebar entre deux langues).
La meilleure façon de faire pour traduire les chaines
En conclusion, la meilleure façon de traduire des chaines est quand même de passer par le fichier .po / .mo à chaque fois que cela est possible. En tant qu’utilisateur, si votre site n’est pas en anglais à la base, il est totalement déconseillé d’utiliser WPML pour traduire ces chaines à la place du fichier .po
WPML permet de traduire les autres chaînes, pour que cela soit simple à gérer, il vaut mieux :
- éviter de mettre ce qui devrait être du contenu dans des widgets (construire une page d’accueil uniquement à partir de widgets n’est pas une bonne idée)
- éviter d’utiliser des fonctions de framework pour appeler les options
WPML permet d’identifier les chaines à traduire dans le fichier wpml-config.xml (que chacun peut créer assez facilement) ou directement dans le code avec icl_string_register() et icl_t()
En tant qu’utilisateur, vous pouvez bidouiller avec WidgetLogic et ICL_LANGUAGE_CODE facilement.
En tant que développeur, ICL_LANGUAGE_CODE vous permet de faire des choses assez complexes, comme charger un fichier css différent pour une langue… extrêmement utile quand vous gérez un site français – arabe ! (oui, tuto à venir !! )