Internationalisation
L'API WebExtensions dispose d'un module pour l'internationalisation des extensions : i18n
. Dans cet article, nous allons explorer ses fonctionnalités et illustrer son utilisation par un exemple pratique. L'API i18n
pour les extensions web est similaire aux bibliothèques JavaScript tierces d'internationalisation.
Note : L'exemple d'extension présenté dans cet article, notify-link-clicks-i18n
, est disponible sur GitHub. Suivez le code source pendant que vous parcourez cette page.
Anatomie d'une extension internationalisée
Une extension internationalisée peut contenir les mêmes fonctionnalités que n'importe quelle autre extension (scripts d'arrière-plan, scripts de contenu, etc.), mais avec du contenu supplémentaire lui permettant de basculer entre différentes locales. Les éléments ajoutés pour l'internationalisation sont résumés dans l'arborescence suivante :
répertoire-racine-de-l'extension/
_locales
en
messages.json
: un fichier qui contiendra les chaines de caractères en anglais
fr_FR
messages.json
: un fichier qui contiendra les chaines de caractères en français
de
messages.json
: un fichier qui contiendra les chaines de caractères en allemand
- etc.
manifest.json
: des métadonnées relatives aux locales sont ajoutées au manifestefichierJavaScript.js
: de la logique pour récupérer la locale du navigateur, récupérer les messages spécifiques à la locale courante, etc.mesStyles.css
: les règles CSS peuvent changer de comportement suivant la locale
Examinons chacune de ces fonctionnalités supplémentaires. Chacune des sections qui suit représente une étape à suivre pour l'internationalisation de votre extension.
Fournir des chaines localisées dans _locales
L'internationalisation nécessite de fournir des chaines traduites pour les différentes locales qu'on souhaite prendre en charge. Pour les extensions, le répertoire _locales
, présent à la racine de l'extension, contient un sous-répertoire pour chaque locale, nommé grâce à l'étiquette de langue correspondante et ce dernier contient un fichier messages.json
avec les chaines de caractères traduites pour la locale correspondante.
Attention : Contrairement à la convention qui consiste à séparer la sous-étiquette de base et celle de la variante régionale par un tiret (par exemple en-US
ou fr-CA
), il faudra utiliser un tiret bas pour le nom du répertoire sous _locales
(par exemple en_US
ou fr_CA
).
Note : Vous pouvez rechercher des étiquettes de langue à l'aide de cet outil en ligne (en anglais). Notez que vous devez rechercher le nom anglais de la langue.
Dans le répertoire _locales
de notre exemple d'extension, nous avons des répertoires pour l'anglais (en
), l'allemand (de
), le français tel que parlé en France (fr_FR
), le japonais (ja
), le norvégien tel que parlé en Norvège (nb_NO
), le néerlandais (nl
), et le portugais brésilien (pt_BR
). Chacun de ces répertoires contient un fichier messages.json
.
Regardons maintenant la structure de l'un de ces fichiers (_locales/en/messages.json
):
{
"extensionName": {
"message": "Notify link clicks i18n",
"description": "Name of the extension."
},
"extensionDescription": {
"message": "Shows a notification when the user clicks on links.",
"description": "Description of the extension."
},
"notificationTitle": {
"message": "Click notification",
"description": "Title of the click notification."
},
"notificationContent": {
"message": "You clicked $URL$.",
"description": "Tells the user which link they clicked.",
"placeholders": {
"url": {
"content": "$1",
"example": "https://developer.mozilla.org"
}
}
}
}
Ce fichier est du JSON standard, chaque propriété est un objet avec un nom, qui contient une propriété message
et une propriété description
. Tous ces éléments sont des chaines de caractères et $URL$
est un emplacement de substitution qui sera remplacé par une sous-chaine lorsque la propriété notificationContent
sera manipulée par l'extension. Nous verrons comment faire dans la section Récupération des messages localisés dans le code JavaScript.
Note : Pour plus d'informations sur le contenu des fichiers messages.json
, voir la référence des formats de messages localisés.
Internationalisation du manifeste
Plusieurs actions sont nécessaires pour internationaliser le manifeste (manifest.json
) de l'extension.
Récupérer les chaines localisées dans le manifeste
Le manifeste de l'extension contient des chaines de caractères qui seront visibles de l'utilisatrice et de l'utilisateur, comme le nom et la description de l'extension. Si vous internationalisez ces propriétés et placez les traductions appropriées dans les fichiers messages.json
, la traduction appropriée sera affichée en fonction des paramètres de locale du navigateur.
Pour internationaliser ces propriétés, renseignez le manifeste ainsi :
"name": "__MSG_extensionName__",
"description": "__MSG_extensionDescription__",
Ces valeurs spéciales indiqueront au navigateur de rechercher la chaine localisée correspondante, plutôt que d'utiliser la même valeur statique pour toutes les locales.
Pour faire référence à un message localisé, composez la chaine de caractères en concaténant :
- Deux tirets bas (
__
) - La chaine
MSG
- Un tiret bas (
_
) - Le nom du message visé, tel qu'il est défini dans
messages.json
- Deux tirets bas (
__
)
__MSG_ + messageName + __
Par exemple, si on souhaite utiliser le message localisé identifié par la clé toto
, on écrira ainsi la propriété dans le manifeste :
"champ_de_manifeste": "__MSG_toto__"
Indiquer une locale par défaut
Dans le manifeste, il est conseillé de renseigner la propriété default_locale
.
"default_locale": "en"
Si un message n'est pas disponible dans la locale courante du navigateur, ce dernier cherchera le message dans la locale default_locale
. Nous verrons ci-après des informations supplémentaires importantes sur la façon dont le navigateur sélectionne les messages effectivement utilisés.
Utiliser du code CSS variant selon la locale
Il est aussi possible d'utiliser des chaines localisées au sein des fichiers CSS de l'extension. Par exemple, on pourra ainsi construire une règle CSS qui varie selon la locale :
header {
background-image: url(../images/__MSG_extensionName__/header.png);
}
Voir aussi comment utiliser des messages prédéfinis ci-après qui permet une meilleure gestion dans certains cas.
Récupérer des messages localisés en JavaScript
Après avoir mis en place les fichiers contenant les messages et paramétré le manifeste, voyons comment utiliser les messages localisés depuis le code JavaScript afin que l'extension utilise la bonne locale autant que possible. L'API i18n
dispose de quatre méthodes :
i18n.getMessage()
-
Il s'agit de la méthode que vous utiliserez le plus souvent. Elle récupère un message localisé à partir de son identifiant. Nous verrons des exemples d'utilisation après.
i18n.getAcceptLanguages()
eti18n.getUILanguage()
-
Ces méthodes peuvent être utilisées pour personnaliser l'interface utilisateur en fonction de la locale (par exemple pour réordonner une liste d'options en mettant les options spécifiques aux langues préférées de l'utilisateur en premier, ou afficher des informations culturelles pertinentes uniquement pour une certaine locale, ou formater les dates affichées en respectant la locale courante du navigateur).
i18n.detectLanguage()
-
Cette méthode peut être utilisée pour détecter la langue de contenus utilisateurs afin de le formater correctement.
Dans l'exemple notify-link-clicks-i18n
, le script d'arrière-plan contient ces lignes :
let title = browser.i18n.getMessage("notificationTitle");
let content = browser.i18n.getMessage("notificationContent", message.url);
La première ligne récupère le message avec l'identifiant notificationTitle
depuis le fichier messages.json
le plus pertinent pour la locale courante du navigateur. La seconde ligne est similaire, mais fournit en plus une URL comme deuxième paramètre. Cette valeur sera utilisée pour remplacer l'emplacement de substitution $URL$
dans le champ message
du champ notificationContent
:
"notificationContent": {
"message": "You clicked $URL$.",
"description": "Tells the user which link they clicked.",
"placeholders": {
"url" : {
"content" : "$1",
"example" : "https://developer.mozilla.org"
}
}
}
La propriété "placeholders"
définit tous les emplacements de substitution ainsi que leur origine pour le remplacement. Pour "url"
, l'origine du contenu est $1
, ce qui correspond à la première valeur passée dans le second paramètre de getMessage()
. Puisque l'emplacement de substitution est appelé "url"
, nous utilisons $URL$
pour l'appeler dans la chaine de message (pour "nomdemplacement"
vous utiliserez $NOMDEMPLACEMENT$
, etc.). Si un message possède plusieurs emplacements de substitution, les valeurs à remplacer pourront être fournies sous la forme d'un tableau, passé en deuxième paramètre à i18n.getMessage()
. Ainsi, fournir le tableau [a, b, c]
permettra de fournir des valeurs pour les emplacements de substitution dont les origines respectives sont $1
, $2
, et $3
.
Par exemple, dans le fichier en/messages.json
, la chaine originale du message notificationContent
est
You clicked $URL$.
Si le lien sur lequel on a cliqué pointe vers https://developer.mozilla.org
, après l'appel à i18n.getMessage()
, le contenu du deuxième paramètre sera mis à disposition via l'origine $1
, et remplacera la sous-chaine $URL$
tel que défini dans "url"
. La chaine de caractères finalement obtenue sera donc :
You clicked https://developer.mozilla.org.
Utilisation directe d'un emplacement de substitution
Il est possible d'insérer vos variables ($1
, $2
, $3
, etc.) directement dans les chaines de message. Par exemple nous pourrions réécrire la propriété "notificationContent"
comme ceci :
"notificationContent": {
"message": "You clicked $1.",
"description": "Tells the user which link they clicked."
}
Cela peut sembler plus rapide et moins complexe, mais l'utilisation de "placeholders"
est considérée comme une meilleure pratique. En effet, le nom de l'emplacement réservé (par exemple "url"
) et l'exemple vous aideront à vous souvenir du rôle de cet emplacement. Au contraire, si vous utilisez uniquement $1
…$8
, après une semaine, vous aurez plus de difficultés à retrouver les correspondances.
Substitution codée en dur
Il est également possible d'inclure des chaines statiques dans des emplacements de substitution, de sorte que la même valeur soit utilisée à chaque fois plutôt que d'obtenir la valeur d'une variable dans le code. Par exemple :
"mdn_banner": {
"message": "For more information on web technologies, go to $MDN$.",
"description": "Tell the user about MDN",
"placeholders": {
"mdn": {
"content": "https://developer.mozilla.org/"
}
}
}
Dans ce cas, nous plaçons une chaine statique pour la substitution plutôt que de l'obtenir à partir d'une variable comme $1
. Cette technique peut s'avérer utile lorsque le fichier de messages est très complexe et qu'il devient nécessaire de séparer différentes valeurs afin de rendre le fichier plus lisible. De plus, ces valeurs sont alors accessibles en JavaScript.
En outre, vous pouvez utiliser ces substitutions pour spécifier les parties de la chaine que vous ne souhaitez pas traduire, telles que les noms de personne ou d'entreprise.
Algorithme de sélection de la chaine de caractères localisée
Les locales peuvent être indiquées à l'aide d'une simple étiquette de langue comme fr
ou en
, ou avec en plus une sous-étiquette de région comme en_US
ou en_GB
. Lorsqu'on utilise l'API i18n
afin de récupérer une chaine de caractères localisée, le navigateur utilise l'algorithme suivant :
- S'il existe un fichier
messages.json
pour exactement la locale courante, et si ce fichier contient la chaine demandée, c'est celle-ci qui est renvoyée. - Sinon, si la locale courante est fournie avec une sous-étiquette de région (par exemple
en_US
) et qu'il existe un fichiermessages.json
pour l'étiquette de langue correspondante sans région (par exempleen
), et si ce fichier contient la chaine, c'est celle-ci qui est renvoyée. - Sinon, s'il existe un fichier
messages.json
pour la locale par défaut (fournie via la propriété du manifestedefault_locale
), et que ce fichier contient la chaine, c'est celle-ci qui est renvoyée. - Sinon, c'est la chaine de caractères vide qui est renvoyée.
Prenons la structure d'exemple suivante :
répertoire-racine-de-l'extension/
_locales
en_GB
messages.json
avec le contenu suivant{ "colorLocalized": { "message": "colour", "description": "Color." }, /* … */ }
en
messages.json
avec le contenu suivant{ "colorLocalized": { "message": "color", "description": "Color." }, /* … */ }
fr
messages.json
avec le contenu suivant{ "colorLocalized": { "message": "couleur", "description": "Color." }, /* … */}
Supposons que default_locale
vaille fr
, et que la locale courante du navigateur soit en_GB
:
- Si l'extension appelle
getMessage("colorLocalised")
, c'est la chaine"colour"
qui sera renvoyée - Si
colorLocalised
n'était pas présent dans le fichier pouren_GB
,getMessage("colorLocalised")
renverrait alors"color"
(caren
est l'étiquette de langue sans région correspondante àen_GB
), et pas"couleur"
.
Messages prédéfinis
L'API i18n
permet d'utiliser des messages prédéfinis, de la même façon que pour récupérer les chaines localisées dans le manifeste ou depuis le code CSS. Par exemple :
__MSG_extensionName__
Les messages prédéfinis utilisent exactement la même syntaxe, mais avec @@
avant le nom du message. Par exemple :
__MSG_@@ui_locale__
Le tableau suivant indique les différents messages prédéfinis disponibles :
Nom du message | Description |
---|---|
@@extension_id |
L'UUID généré en interne pour l'extension. Vous pouvez utiliser cette chaine pour créer des URL pour les ressources à l'intérieur de l'extension. Même les extensions non localisées peuvent utiliser ce message. Vous ne pouvez pas utiliser ce message dans un fichier de manifeste.
Notez également que cet identifiant ne correspond pas à l'identifiant renvoyé par |
@@ui_locale |
La locale courante. Cette chaine peut être utilisée afin de construire des URL variant en fonction de la locale. |
@@bidi_dir |
La direction du texte pour la locale courante. Cette chaine vaut "ltr" pour les langues écrites de gauche à droite telles que le français ou "rtl" pour les langues écrites de droite à gauche telles que l'arabe. |
@@bidi_reversed_dir |
Si @@bidi_dir vaut "ltr" , alors cette chaine vaudra "rtl" , sinon elle vaudra "ltr" . |
@@bidi_start_edge |
Si @@bidi_dir vaut "ltr" , alors cette chaine vaudra "left" , sinon elle vaudra "right" . |
@@bidi_end_edge |
Si @@bidi_dir vaut "ltr" , alors cette chaine vaudra "right" , sinon elle vaudra "left" . |
Ainsi, si nous revenons à l'exemple que nous avions pris pour le code CSS, il serait plus pertinent de l'écrire ainsi :
header {
background-image: url(../images/__MSG_@@ui_locale__/header.png);
}
Grâce à cette écriture, nous pouvons stocker nos images localisées dans des répertoires qui correspondent aux différentes locales prises en charge (en
, de
, etc.).
Prenons un autre exemple où nous utilisons les messages prédéfinis @@bidi_*
dans un fichier CSS :
body {
direction: __MSG_@@bidi_dir__;
}
div#header {
margin-bottom: 1.05em;
overflow: hidden;
padding-bottom: 1.5em;
padding-__MSG_@@bidi_start_edge__: 0;
padding-__MSG_@@bidi_end_edge__: 1.5em;
position: relative;
}
Pour les langues écrites de gauche à droite telles que le français, les déclarations CSS avec les messages prédéfinis ci-dessus se comportent ainsi :
direction: ltr;
padding-left: 0;
padding-right: 1.5em;
Dans le cas d'une langue écrite de droite à gauche comme l'arabe, le résultat obtenu aurait été :
direction: rtl;
padding-right: 0;
padding-left: 1.5em;
Tester votre extension
Pour tester la localisation de votre extension, utilisez Firefox ou Firefox Beta, car ils permettent d'installer des packs de langue.
Ensuite, pour chaque locale que vous prenez en charge et que vous voulez tester, suivez les instructions de la page Utiliser Firefox dans une autre langue afin de changer la locale utilisée pour l'interface utilisateur de Firefox (si vous connaissez les paramètres, allez dans la section Langue et utilisez Choisir des alternatives).
Lorsque Firefox utilise la locale à tester, installez l'extension temporairement. Après avoir installé votre extension, vérifiez dans la page about:debugging
que votre extension est bien mise en place et que l'icône, le nom et la description apparaissent avec la bonne locale. Vous pouvez également vérifier les métadonnées localisées via la page about:addons
. Finalement, utilisez les fonctionnalités de l'extension pour vérifier que les chaines localisées sont bien présentes.
Si vous souhaitez vous faire la main sur ce processus de test, vous pouvez utiliser l'exemple d'extension notify-link-clicks-i18n
. Paramétrez Firefox pour qu'il s'affiche dans l'une des locales prise en charge (l'allemand, le néerlandais ou le japonais), chargez l'extension et allez sur un site web. Cliquez sur un lien pour voir la notification localisée indiquer le lien de l'URL.