Les fichiers JSON de traduction

La version 5.4 de Laravel nous permet d’utiliser des fichiers JSON pour les traductions et c’est bien pratique. Mais subsiste toutefois un souci pour créer ces fichiers et les actualiser parce qu’aucun automatisme n’a été prévu. Je me suis donc fait quelques commandes Artisan pour mes propres besoins et finalement je les partage dans un package.


Edit le 31/05/2017 :

Une application récente, extérieure à Laravel, permet de gérer les fichiers JSON :

Il suffit de l’installer sur sa machine, d’ouvrir le dossier d’une application Laravel et tout est géré parfaitement ! Vous avez donc maintenant le choix entre mon package qui comporte des commandes Artisan ou cette application, ou pourquoi pas les deux ?


Etat des lieux

Avant la version 5.4 de Laravel on n’avait pas le choix, il fallait définir une clé pour chaque item linguistique et créer autant de fichiers de langue qu’on avait de langages prévus dans une application.

Cette stratégie est efficace et permet surtout de repérer facilement les traductions manquantes puisqu’elles sont toutes rassemblées dans un même dossier.

Mais lorsqu’on a beaucoup de traductions à prévoir ça devient laborieux et d’autre part les clés qu’on choisit ne sont pas forcément toujours assez explicites pour une traduction efficace.

L’arrivée de la possibilité de ne plus utiliser de clé mais directement la version linguistique par défaut dans le code est une belle avancée parce qu’on génère directement les textes en même temps que le code.

Ensuite il suffit de créer des fichiers JSON pour les locales en prenant comme clé le texte par défaut. Le principe est simple et efficace. Et rien n’empêche de conserver l’ancien système pour tout ce qui est déjà par défaut dans l’installation de Laravel (auth, pagination, passwords et validation).

Sauf que la première fois que j’ai procédé ainsi je me suis retrouvé avec tout mon code avec les textes anglais par défaut et il me fallait alors créer le fichier JSON pour le français. Et là je me suis dit voyons voir un bon package pour me créer ça facilement. Mais après une bonne recherche je n’ai pas trouvé ce que je cherchais. Il y a bien des packages pour gérer des fichiers JSON existants mais rien en amont.

La package

Alors je me suis retroussé les manches pour créer quelques commandes Artisan :

  • language:strings pour afficher touts les textes extraits du code (la recherche se fait dans les dossiers app et resource/views)
  • language:make pour créer automatiquement un fichier JSON pour une locale à partir des textes extraits du code
  • language:diff pour voir les différences (en plus et en moins) pour une locale par rapport aux textes extraits du code
  • language:sync pour synchroniser automatiquement le fichier JSON d’une locale avec les textes extraits du code

Je les ai rassemblées dans ce package. L’installation est toute simple et est décrite sur la page du package.

language:strings

Cette commande est toute simple, elle permet de lister tous les textes dans le code. J’ai limité la recherche dans les dossiers app et resources/views. Elle collecte tout ce qui correspond à trans, trans_choice, __ et @lang.

La lecture de cet article m’a donné à réfléchir quant à la manière d’écrire du code et je m’y suis un peu essayé dans ce package. Ainsi voici la fonction chargée d’extraire les textes :

/**
 * Get strings collection
 *
 * @return Collection
 */
protected function getStrings()
{
    return collect([
        $this->filesystem->allFiles(app_path()),
        $this->filesystem->allFiles(resource_path('views'))
    ])
        ->collapse()
        ->map(function (SplFileInfo $item) {
            preg_match_all(
                '/(@lang|trans|__|trans_choice)\s*(\(\s*[\'"])([^$]*)([\'"]\s*\))/U',
                $item->getContents(),
                $out,
                PREG_PATTERN_ORDER);
            return $out[3];
        })
        ->collapse()
        ->unique()
        ->filter(function ($value) {
            return !$this->translator->has($value);
        })
        ->sort(function ($a, $b) {
            return strtolower($a) > strtolower($b);
        });
}

Par rapport à une approche impérative ce codage déclaratif est effectivement plus lisible. On voit facilement les actions effectuées :

  • on collecte (collect) les fichiers dans une collection (merci à la puissante méthode allFiles du système de fichier !)
  • on rassemble (collapse) les deux paquets récupérés
  • on parcourt (map) la collection pour aller chercher (avec une expression régulière) tous les textes
  • on rassemble à nouveau (collapse) tout ça
  • on garde une seule version (unique) des textes pour éliminer les doublons
  • on filtre (filter) les clés classiques
  • pour finir on trie (sort) les textes

Je ne suis pas convaincu par contre qu’on y gagne en performance mais ici ce n’est pas important.

La commande affiche donc la liste des textes :

php artisan language:strings

About Our Site
About us
Active
Administration
Administrator
All
Author
author
Blog
...

language:make

Cette commande est la plus intéressante parce qu’elle permet de créer un JSON pour une locale à partir des textes par défaut :

php artisan language:make fr
File successfully created

Le fichier est donc créé avec les textes comme clés :

{
    "About Our Site": "",
    "About us": "",
    "Active": "",
    "Administration": "",
    "Administrator": "",
    "All": "",
    "Author": "",
    "author": "",
    "Blog": "",
    ...
}

Il ne reste plus qu’à ajouter les traductions ! Il serait possible d’automatiser aussi cette tâche à partir du service de Microsoft mais je pense qu’il y aurait tellement de retouches à faire que ça ne m’est pas paru pas judicieux.

Si le fichier existe déjà on est alerté et on invite à utiliser l’option –force pour écraser le fichier existant :

php artisan language:make fr
File already exists. Use --force option to replace it

language:diff

C’est bien de créer un fichier à partir des textes existants mais que se passe-t-il si on en ajoute ou si on en retire ? On se retrouve alors avec des différences entre le (ou les) fichier JSON et les textes dans le code. Cette commande permet de faire le point en listant ce qui manque et ce qui est en plus :

php artisan language:diff fr
-----------------------------------
Missing strings for this locale
-----------------------------------
Body
Creation
Destroy
Login
Logout
New
Password
Social
-----------------------------------
Further strings for this locale
-----------------------------------
Newer
Passwords
Socials

language:sync

Le package ne se contente pas de lister les différences, avec cette commande on peut synchroniser le fichier avec les textes par défaut existants. Donc ajouter ce qui manque et enlever ce qui est en trop :

php artisan language:sync fr
File successfully synchronised for missing strings
File successfully synchronised for further strings

php artisan language:diff fr
-----------------------------------
No Missing strings for this locale
-----------------------------------
-----------------------------------
No Further strings for this locale
-----------------------------------

On dispose de deux options :

  • –nomissing : pour ne pas synchroniser ce qui manque
  • –nofurther : pour ne pas synchroniser ce qui est en trop

Conclusion

J’espère que ce package rendra service, et si vous trouvez des bugs ou pensez à des améliorations…

4 réflexions sur “Les fichiers JSON de traduction

  1. scud167 dit :

    Salut Bestmomo!
    Merci beaucoup pour ce package =)
    J’ai essayé de l’utiliser mais cela ne fonctionne pas. J’ai essayé de changer les paths mais cela ne change rien. Le language:strings ne me retourne que du vide :/

    j’essaie de trouver l’origine du problème.

Laisser un commentaire