Dans mes articles précédents, j'ai abordé les différents aspects d'Elixir, un langage de programmation fonctionnel moderne. Aujourd'hui, cependant, j'aimerais m'éloigner du langage lui-même et discuter d'un framework MVC très rapide et fiable appelé Phoenix, écrit en Elixir..
Ce cadre est apparu il y a près de cinq ans et a reçu une certaine traction depuis. Bien sûr, il n’est pas encore aussi populaire que Rails ou Django, mais il a un grand potentiel et j’aime vraiment beaucoup.
Dans cet article, nous allons voir comment introduire I18n dans les applications Phoenix. Quel est I18n, tu demandes? Eh bien, il s’agit d’un numéronyme qui signifie "internationalisation", car il y a exactement 18 caractères entre la première lettre "i" et le dernier "n". Vous avez probablement aussi rencontré un L10n numonyme qui signifie "localisation". Les développeurs de nos jours sont tellement paresseux qu'ils ne peuvent même pas écrire quelques caractères supplémentaires, hein?
L'internationalisation est un processus très important, surtout si vous prévoyez que l'application sera utilisée par des utilisateurs du monde entier. Après tout, tout le monde ne connaît pas bien l'anglais et la traduction de l'application dans la langue maternelle de l'utilisateur donne une bonne impression..
Il semble que le processus de traduction des applications Phoenix diffère quelque peu de la traduction des applications Rails, par exemple (mais il est assez similaire au même processus dans Django). Pour traduire les applications Phoenix, nous utilisons une solution assez populaire appelée Gettext, qui existe déjà depuis plus de 25 ans. Gettext fonctionne avec des types spéciaux de fichiers, à savoir PO et POT, et prend en charge des fonctionnalités telles que la portée, la pluralisation et d'autres avantages..
Dans cet article, je vais donc vous expliquer ce qu'est Gettext, en quoi PO diffère de POT, comment localiser les messages dans Phoenix et où stocker les traductions. Nous allons également voir comment changer les paramètres régionaux de l'application et comment utiliser les règles de pluralisation et les domaines.
Allons-nous commencer?
Gettext est un outil d’internationalisation à code source ouvert et testé sur le terrain, introduit pour la première fois par Sun Microsystems en 1990. En 1995, GNU publiait sa propre version de Gettext, qui est maintenant considérée comme la plus populaire (la dernière version datant de 0.19.8 à au moment de la rédaction de cet article). Gettext peut être utilisé pour créer des systèmes multilingues de toutes tailles et de tous types, des applications Web aux systèmes opérationnels. Cette solution est assez complexe et nous ne discuterons pas de toutes ses fonctionnalités, bien sûr. La documentation complète de Gettext est disponible sur gnu.org.
Gettext vous fournit tous les outils nécessaires pour effectuer la localisation et présente certaines exigences concernant la manière dont les fichiers de traduction doivent être nommés et organisés. Deux types de fichiers sont utilisés pour héberger les traductions: PO et MO.
PO (Objet portable) les fichiers stockent les traductions pour les chaînes données, ainsi que les règles de pluralisation et les métadonnées. Ces fichiers ont une structure assez simple et peuvent être facilement édités par un humain. Dans cet article, nous nous en tiendrons à eux. Chaque fichier de commande contient des traductions (ou une partie des traductions) d'une seule langue et doit être stocké dans un répertoire nommé d'après cette langue: en, fr, de, etc.
MO (Objet machine) les fichiers contiennent des données binaires non destinées à être éditées directement par un humain. Il est plus difficile de travailler avec eux, et leur discussion sort du cadre de cet article..
Pour rendre les choses plus complexes, il y a aussi POT (modèle d'objet portable) des dossiers. Ils n'hébergent que des chaînes de données à traduire, mais pas les traductions elles-mêmes. Fondamentalement, les fichiers POT sont utilisés uniquement comme plans pour créer des fichiers PO pour divers environnements locaux.
Bon, maintenant passons à la pratique! Si vous souhaitez suivre, assurez-vous d’avoir installé les éléments suivants:
Créez un exemple d'application sans base de données en exécutant:
mélanger phx.new i18ndemo --no-ecto
--non-ecto
indique que l'application ne doit pas utiliser la base de données (Ecto est un outil pour communiquer avec le DB lui-même). Notez que le générateur peut nécessiter quelques minutes pour tout préparer.
Maintenant utiliser CD
aller à la nouvelle création i18ndemo
dossier et exécutez la commande suivante pour amorcer le serveur:
mélanger phx.server
Ensuite, ouvrez le navigateur et accédez à http: // localhost: 4000
, où vous devriez voir un "Bienvenue à Phoenix!" message.
Ce qui est intéressant à propos de notre application Phoenix et, plus précisément, du message de bienvenue, c'est que Gettext est déjà utilisé par défaut. Allez-y et ouvrez le demo / lib / demo_web / templates / page / index.html.eex
fichier qui agit comme une page de départ par défaut. Supprimer tout sauf ce code:
<%= gettext "Welcome to %name!", name: "Phoenix" %>
Ce message de bienvenue utilise un gettext
fonction qui accepte une chaîne à traduire en tant que premier argument. Cette chaîne peut être considérée comme un clé de traduction, bien qu’il soit quelque peu différent des clés utilisées dans Rails I18n et quelques autres cadres. Dans Rails, nous aurions utilisé une clé comme page.welcome
, alors qu'ici la chaîne traduite est une clé lui-même. Donc, si la traduction est introuvable, nous pouvons afficher cette chaîne directement. Même un utilisateur connaissant mal l'anglais peut au moins avoir une idée de base de ce qui se passe.
Cette approche est très pratique: arrêtez-vous une seconde et réfléchissez-y. Vous avez une application où tous les messages sont en anglais. Si vous souhaitez l'internationaliser, dans le cas le plus simple, tout ce que vous avez à faire est d'envelopper vos messages avec le message gettext
fonctionnent et fournissent des traductions pour ceux-ci (nous verrons plus tard que le processus d'extraction des clés peut être facilement automatisé, ce qui accélère encore davantage).
D'accord, revenons à notre petit extrait de code et jetons un coup d'œil au deuxième argument passé à gettext
: nom: "Phoenix"
. Ceci est un soi-disant contraignant-un paramètre enveloppé avec %
que nous aimerions interpoler dans la traduction donnée. Dans cet exemple, il n'y a qu'un seul paramètre appelé prénom
.
Nous pouvons également ajouter un message supplémentaire à cette page à des fins de démonstration:
<%= gettext "Welcome to %name!", name: "Phoenix" %>
<%= gettext "We are using version %version", version: "1.3" %>
Maintenant que nous avons deux messages sur la page racine, où devrions-nous ajouter des traductions pour eux? Il semble que toutes les traductions sont stockées sous le priv / gettext
dossier, qui a une structure prédéfinie. Prenons un moment pour discuter de la manière dont les fichiers Gettext doivent être organisés (cela ne s'applique pas uniquement à Phoenix, mais à toute application utilisant Gettext)..
Tout d’abord, nous devrions créer un dossier nommé d'après les paramètres régionaux pour lesquels il stockera les traductions. A l'intérieur, il devrait y avoir un dossier appelé LC_MESSAGES
contenant un ou plusieurs .po
fichiers avec les traductions réelles. Dans le cas le plus simple, vous auriez un default.po
fichier par locale. défaut
voici le nom du domaine (ou de la portée). Les domaines sont utilisés pour diviser les traductions en différents groupes: par exemple, vous pouvez avoir des domaines nommés admin
, Wysiwig
, Chariot
, et autre. Ceci est pratique lorsque vous avez une grande application avec des centaines de messages. Pour les petites applications, cependant, avoir une seule défaut
domaine suffit.
Donc, notre structure de fichier pourrait ressembler à ceci:
Pour commencer à créer des fichiers PO, nous avons d’abord besoin du modèle correspondant (POT). Nous pouvons le créer manuellement, mais je suis trop paresseux pour le faire de cette façon. Lançons la commande suivante à la place:
mélanger gettext.extract
C'est un outil très pratique qui analyse les fichiers du projet et vérifie si Gettext est utilisé n'importe où. Une fois le script terminé, une nouvelle priv / gettext / default.pot
le fichier contenant les chaînes à traduire sera créé.
Comme nous l'avons déjà appris, les fichiers POT sont des modèles, ils stockent donc uniquement les clés, pas les traductions. Ne modifiez pas ces fichiers manuellement. Ouvrez un fichier nouvellement créé et examinez son contenu:
## Ce fichier est un fichier de modèle de bon de commande. "msgstr" sont souvent extraits du code source. ## Ajouter de nouvelles traductions manuellement uniquement s'il s'agit de traductions dynamiques ## qui ne peuvent pas être extraites de manière statique. ## ## Exécutez 'mix gettext.extract' pour amener ce fichier à la date ##. Laissez 'msgstr vide car vous ne les changez pas ici comme ## effet: éditez-les plutôt dans des fichiers PO (' .po '). msgstr "Nous utilisons la version% version" msgstr "" #: lib / demo_web / templates / page / index.html "msgstr" "msgstr" "#: lib / demo_web / templates / page / index.html.eex: 3 msgstr "Bienvenue à% name!" msgstr ""
Pratique, n'est ce pas? Tous nos messages ont été insérés automatiquement, et nous pouvons facilement voir exactement où ils se trouvent. msgid
, comme vous l'avez probablement deviné, est la clé, alors que msgstr
va contenir une traduction.
La prochaine étape consiste bien entendu à générer un fichier PO. Courir:
mélanger gettext.merge priv / gettext
Ce script va utiliser le default.pot
modèle et créer un default.po
déposer dans le priv / gettext / en / LC_MESSAGES
dossier. Pour le moment, nous n’avons que des paramètres régionaux anglais, mais la prise en charge d’une autre langue sera également ajoutée dans la section suivante..
En passant, il est possible de créer ou de mettre à jour le modèle POT et tous les fichiers PO en une fois à l’aide de la commande suivante:
mélanger gettext.extract --merge
Maintenant ouvrons le priv / gettext / fr / LC_MESSAGES / default.po
fichier, qui a le contenu suivant:
Les msgids de ce fichier proviennent de fichiers POT (.pot). ## ## Ne pas ajouter, modifier ou supprimer 'msgid' manuellement ici car ## ils sont liés à ceux du fichier POT correspondant ## (avec le même domaine). ## ## Utilisez 'mix gettext.extract --merge' ou 'mix gettext.merge' ## pour fusionner les fichiers POT en fichiers PO. msgstr "Nous utilisons la version% version" msgstr "" #: lib / demo_web / msgstr "Bienvenue dans% name!" msgstr ""
Ceci est le fichier où nous devrions effectuer la traduction proprement dite. Bien sûr, cela n’a aucun sens de le faire car les messages sont déjà en anglais. Passons donc à la section suivante et ajoutons la prise en charge d’une deuxième langue..
Naturellement, les paramètres régionaux par défaut pour les applications Phoenix sont l'anglais, mais ce paramètre peut être facilement modifié en modifiant les paramètres. config / config.exs
fichier. Par exemple, définissons les paramètres régionaux par défaut sur russe (n'hésitez pas à vous en tenir à une autre langue de votre choix):
config: démo, I18ndemoWeb.Gettext, default_locale: "ru"
Il est également judicieux de spécifier la liste complète de tous les paramètres régionaux pris en charge:
config: démo, I18ndemoWeb.Gettext, default_locale: "ru", locales: ~ w (en ru)
Nous devons maintenant générer un nouveau fichier PO contenant les traductions pour les paramètres régionaux russes. Cela peut être fait en exécutant le gettext.merge
script à nouveau, mais avec un --lieu
commutateur:
mélanger gettext.merge priv / gettext --locale ru
Évidemment, un priv / gettext / ru / LC_MESSAGES
dossier avec le .po
les fichiers à l'intérieur seront générés. Notez, en passant, que mis à part le default.po
fichier, nous avons aussi errors.po
. C'est un endroit par défaut pour traduire les messages d'erreur, mais dans cet article, nous allons l'ignorer.
Maintenant, modifiez le priv / gettext / ru / LC_MESSAGES / default.po
en ajoutant quelques traductions:
msgstr "Nous utilisons la version% version" msgstr "Используется версия% version" #: lib / demo_web / templates / page / index.html msgstr "Bienvenue à% name!" msgstr "Добро пожаловать в приложение% name!"
Maintenant, en fonction de la localisation choisie, Phoenix rendra les traductions anglaise ou russe. Mais attendez! Comment pouvons-nous réellement passer d'un lieu à l'autre dans notre application? Passons à la section suivante et découvrons!
Maintenant que certaines traductions sont présentes, nous devons permettre à nos utilisateurs de basculer entre les paramètres régionaux. Il semble qu'il existe un plug-in tiers pour cela appelé set_locale. Cela fonctionne en extrayant les paramètres régionaux choisis de l'URL ou Accepter la langue
En-tête HTTP. Ainsi, pour spécifier un paramètre régional dans l'URL, vous devez taper http: // localhost: 4000 / en / some_path
. Si les paramètres régionaux ne sont pas spécifiés (ou si une langue non prise en charge a été demandée), l'une des deux choses suivantes se produira:
Accepter la langue
En-tête HTTP et cette locale est supportée, l'utilisateur sera redirigé vers une page avec la locale correspondante.Ouvrez le mix.exs
déposer et déposer set_locale
au deps
une fonction:
defp deps [#… : set_locale, "~> 0.2.1"] end
Nous devons également l'ajouter à la application
une fonction:
def application do [mod: Demo.Application, [], extra_applications: [: logger,: runtime_tools,: set_locale]] end
Ensuite, installez tout:
mélanger deps.get
Notre routeur situé à lib / site_de_ demo / router.ex
nécessite quelques modifications aussi. Plus précisément, nous devons ajouter une nouvelle fiche au :navigateur
pipeline:
pipeline: le navigateur fait #… branchez SetLocale, gettext: DemoWeb.Gettext, default_locale: "ru" end
Créez également une nouvelle portée:
scope "/: locale", DemoWeb do pipe_through: navigateur obtenir "/", PageController,: index end
Et c'est tout! Vous pouvez démarrer le serveur et accéder à http: // localhost: 4000 / ru
et http: // localhost: 4000 / en
. Notez que les messages sont traduits correctement, ce qui est exactement ce dont nous avons besoin!
Alternativement, vous pouvez coder vous-même une fonction similaire en utilisant une prise de module. Un petit exemple peut être trouvé dans le guide officiel Phoenix.
Une dernière chose à mentionner est que dans certains cas, vous devrez peut-être appliquer des paramètres régionaux spécifiques. Pour ce faire, utilisez simplement un avec_locale
une fonction:
Gettext.with_locale I18ndemoWeb.Gettext, "en", fn -> MyApp.I18ndemoWeb.gettext ("test") end
Nous avons appris les bases de l'utilisation de Gettext avec Phoenix. Le moment est donc venu de discuter de choses un peu plus complexes.. La pluralisation est l'un d'eux. Fondamentalement, travailler avec des formes plurielles et singulières est une tâche très courante mais potentiellement complexe. Les choses sont plus ou moins évidentes en anglais puisque vous avez "1 pomme", "2 pommes", "9000 pommes", etc. (bien que "1 boeuf", "2 boeufs"!).
Malheureusement, dans d'autres langues comme le russe ou le polonais, les règles sont plus complexes. Par exemple, dans le cas des pommes, vous diriez "1 яблоко", "2 яблока", "9000 яблок". Mais heureusement pour nous, Phoenix a un Gettext.Plural
comportement (vous pouvez voir le comportement en action dans l'un de mes articles précédents) qui prend en charge de nombreuses langues différentes. Par conséquent, tout ce que nous avons à faire est de tirer parti de la ngettext
une fonction.
Cette fonction accepte trois arguments obligatoires: une chaîne au singulier, une chaîne au pluriel et count. Le quatrième argument est facultatif et peut contenir des liaisons qui doivent être interpolées dans la traduction..
Voyons voir ngettext
en action en disant combien d'argent l'utilisateur a en modifiant la demo / lib / demo_web / templates / page / index.html.eex
fichier:
<%= ngettext "You have one buck. Ow :(", "You have %count bucks", 540 %>
%compter
est une interpolation qui sera remplacée par un nombre (540
dans ce cas). N'oubliez pas de mettre à jour le modèle et tous les fichiers PO après avoir ajouté la chaîne ci-dessus:
mélanger gettext.extract --merge
Vous verrez qu'un nouveau bloc a été ajouté à la fois default.po
des dossiers:
msgstr "" "Vous avez% count dollars" msgstr [0] "" msgstr [1] ""
Nous avons non pas une mais deux clés ici à la fois: au singulier et au pluriel. msgstr [0]
va contenir du texte à afficher quand il n'y a qu'un seul message. msgstr [1]
, bien sûr, contient le texte à afficher lorsqu'il y a plusieurs messages. C'est bien pour l'anglais, mais pas assez pour le russe où nous devons introduire un troisième cas:
msgstr_plural "Vous avez% count dollars" msgstr [0] "il y a 1 an." ] "Вас% count долларов"
Cas 0
est utilisé pour 1 dollar, et le cas 1
pour zéro ou quelques dollars. Cas 2
est utilisé autrement.
Un autre sujet que je voulais aborder dans cet article est consacré à domaines. Comme nous le savons déjà, les domaines sont utilisés pour balayer les traductions, principalement dans les grandes applications. Fondamentalement, ils agissent comme espaces de noms.
Après tout, vous pouvez vous retrouver dans une situation où la même clé est utilisée à plusieurs endroits mais doit être traduite un peu différemment. Ou quand vous avez trop de traductions en un seul default.po
déposer et voudrais les séparer d’une manière ou d’une autre. C'est alors que les domaines peuvent être vraiment utiles.
Gettext prend en charge plusieurs domaines immédiatement. Tout ce que vous avez à faire est d'utiliser le dgettext
fonction, qui fonctionne presque le même que gettext
. La seule différence est qu'il accepte le nom de domaine comme premier argument. Par exemple, introduisons un domaine de notification pour afficher des notifications. Ajoutez trois autres lignes de code au demo / lib / demo_web / templates / page / index.html.eex
fichier:
<%= dgettext "notifications", "Heads up: %msg", msg: "something has happened!" %>
Nous devons maintenant créer de nouveaux fichiers POT et PO:
mélanger gettext.extract --merge
Une fois que le script a terminé son travail, notifications.pot
ainsi que deux notifications.po
les fichiers seront créés. Notez encore une fois qu'ils portent le nom du domaine. Tout ce que vous avez à faire maintenant, c’est d’ajouter une traduction en russe en modifiant la priv / ru / LC_MESSAGES / notifications.po
fichier:
msgstr "Heads up:% msg" msgstr "Внимание:% msg"
Que faire si vous souhaitez pluraliser un message stocké dans un domaine donné? C’est aussi simple que d’utiliser un dngettext
une fonction. Ça marche comme ngettext
mais accepte également le nom de domaine comme premier argument:
dgettext "domaine", "Chaîne singulière% msg", "Chaîne plurielle% msg", 10, msg: "démo"
Dans cet article, nous avons vu comment introduire l'internationalisation dans une application Phoenix à l'aide de Gettext. Vous avez appris ce qu'est Gettext et quel type de fichiers il fonctionne. Nous avons cette solution en action, avons travaillé avec des fichiers PO et POT et utilisé diverses fonctions de Gettext..
Nous avons également trouvé un moyen d’ajouter une prise en charge pour plusieurs paramètres régionaux et un moyen de basculer facilement entre eux. Enfin, nous avons vu comment utiliser des règles de pluralisation et comment définir des traductions à l'aide de domaines.
J'espère que cet article vous a été utile! Si vous souhaitez en savoir plus sur Gettext dans le cadre Phoenix, vous pouvez vous reporter au guide officiel, qui fournit des exemples utiles et une référence d'API pour toutes les fonctions disponibles..
Je vous remercie de rester avec moi et à bientôt!