Outils d'aide à la traduction "traduitjdm"

J’ai commencé à travailler sur un outils d’aide à la traduction des plugins.

Une première version (v0.1.0) recherche les textes à traduire dans le fichiers *js et *php d’un plugin et génère un fichier .json dans le répertoire core.i18n.

Cette première version est très limitée:

  • Le fichier généré contient une traduction français => français
  • Il faut éditer le fichier à la main pour y mettre les traductions dans la langue cible
  • Le fichier précédent est écrasé et son contenu perdu lors de chaque exécution (une option de la ligne de commande permet toutefois de renommer les 6 versions précédentes

Le but de cette première version était surtout ce vérifier le concept.

Les prochaines étapes probables

  1. refonte du code pour permettre une meilleure évolutivité.
  2. Si une version du fichier existe, les traduction qu’ils contient seront conservées et les nouveaux texte à traduire seront ajoutés
  3. Une option permettra de supprimer les texte traduit qui ne sont plus dans le code du plugin.
  4. L’utilitaire devra détecter si un même texte se trouvant dans des fichiers différents à des traductions différente.
    1.Pour chaque texte non traduit. l’utilitaire cherchera s’il y a une traduction pour un texte identique dans le core et reprendra cette traduction dans le plugin
  5. Si tout va bien, Peut-être que le plugin pourra aller chercher des proposition de traction sur des sites comme translate.google.com

La doc est disponible là ==> https://ktn001.github.io/traduitjdm/ Vous y trouverez un lien vers la page `release notes avec les liens de téléchargement.

3 « J'aime »

Hello,

Je suis pas sur de comprendre, car dans le core jeedom c’est pas comme sa qu’il faut faire :
image.

Normalement pour que les traduction soit prise en compte, il faut mettre {{ text }}.
Je sait pas si c’est possible, mais plutôt que d’écraser le fichier, tu pourrais crée un fichier générique.

Pareil, je sait pas si sa te complique les chose, mais possible aussi d’avoir une traduction automatique via le system de traduction de Microsoft. (J’ai des licenses pro chez eux, donc sa m’intéresse).

Cordialement
Thibaut

La syntaxe {{...}} est à utiliser dans les code « js » et « php » pour les « desktop » et « mobile ». Par contre,dans le code « php » des classes, il faut utiliser __(...,__FILE__).

Je n’ai pas saisi tout les détails mais, il me semble que ce qui est envoyé aux navigateurs est d’abord mis en cache sur le serveur puis passé dans une moulinette qui remplace les « {{…}} » par le texte traduit.

Par contre, le code dans le « core » du plugin doit utiliser la syntaxe __(...,__FILE__)

Le but final sera de créer des fichiers traduits qui conservent ce qui était déjà traduit dans la version précédente. La génération d’un fichier générique ne me semble pas idéale dans cette optique mais peut-être qu’une option de la ligne de commande pourra permettre de la faire. Ce n’est pas ma priorité pour le moment.

Ceci dit, l’option -b permet de ne pas écraser les 6 versions précédentes. Il est toujours possible de créer un alias dans le fichier .bashrc si on crains d’oublier cette option lors d’une exécution.

La version v0.2.0 est disponible.

Cette version conserve les traductions existantes et y ajoute les nouveaux textes trouvés dans le code.

Cette version est donc la première qui soit utilisable pour maintenir la liste des textes à traduire sans perdre les traductions déjà effectuées en éditant le fichier dans plugin/<plugin_name>/core/i18n

Version 0.3.0 disponible.

Cette version reprend les traductions du core. Si différentes traductions sont définies dans le core pour un même texte, c’est la dernière trouvée qui sera reprise.

Bonjour.

J’ai essayé sur un de mes plugins, mais sans succès.
Il y a des pré-requis ? Avoir des fichiers de base, vide, aucun ?

Commande saisie
python3 traduitjdm -l fr_FR -v id_du_plugin
Sans fichier fr_FR.json
Lecture des versions précédantes...
    Langue: fr_FR...
        Pas de version précédente à lire!
Recherche des traductions dansle core...
    Langue: fr_FR...
Ecriture du/des fichier(s) de traduction(s)...
    Langue: fr_FR...
Traceback (most recent call last):
  File "traduitjdm", line 217, in <module>
    write_traduction();
  File "traduitjdm", line 203, in write_traduction
    trad = fs.get_traduction(langue)
  File "/home/Flobul/traduitjdm-0.3.0/bin/fichierSource.py", line 128, in get_traduction
    traduction = texte.get_traduction(langue)
AttributeError: 'NoneType' object has no attribute 'get_traduction'
Avec fichier fr_FR.json
Lecture des versions précédantes...
    Langue: fr_FR...
        Lecture de la version précédente...
Recherche des traductions dansle core...
    Langue: fr_FR...
Ecriture du/des fichier(s) de traduction(s)...
    Langue: fr_FR...
Traceback (most recent call last):
  File "traduitjdm", line 217, in <module>
    write_traduction();
  File "traduitjdm", line 203, in write_traduction
    trad = fs.get_traduction(langue)
  File "/home/Flobul/traduitjdm-0.3.0/bin/fichierSource.py", line 128, in get_traduction
    traduction = texte.get_traduction(langue)
AttributeError: 'NoneType' object has no attribute 'get_traduction'

Non, traduitjdm n’a pas besoin d’avoir des fichiers de traduction préexistants.

Je vérifie mon code et reviens ici dès que j’ai trouvé quelque chose. En attendant, peux-tu me confirmer que tu utilises la version 0.3.0?

Celle-là : https://github.com/ktn001/traduitjdm/archive/refs/tags/v0.3.0.zip

Mais dans le fichier :

Flobul@jeedom:~/traduitjdm-0.3.0/bin$ cat traduitjdm 
#!/usr/bin/python3

version = "0.2.1"
1 « J'aime »

Désolé, oublié de mettre la version à jour dans le code.

Je n’arrive pas à reproduire le problème…

On poursuit en mp pour ne pas polluer le forum.

Je mettrai la résolution ici

@Flobul a identifié le problème.

Son code contenait un texte vide à traduire.

Je vais faire évoluer traduitjdm pour résister à ce cas de figure.

Version 0.3.1 publiée!

Cette version ignore les textes le longueur égale à zéro.

Version 0.4.0 publiée.

Les évolutions

  1. Permet de choisir un proposition lorsqu’il y a plusieurs traductions dans le core pour un même texte.
  2. Affichage des messages en couleur selon de type de message
  3. Utilisation d’un fichiers de configuration

bonjour @ktn merci pour ce formidable outil ! c’est redoutable d’efficacité :slight_smile:

Quelques remarques en passant:

  1. possible de créer le répertoire i18n s’il n’existe pas à la 1ere utilisation ? J’ai eu une erreur e type « file not found » je suppose au moment d’enregistrer le fichier json généré. Après avoir créé ce répertoire c’est ok
  2. Pour une raison étrange, le script me pose cette question:
La source <core> propose plusieurs traductionsi en <en_US> pour : "401 - Accès non autorisé"

1 : 401 - Unauthorized access
2 : 401 - Unauthorized Access

En l’écrivant ici, je remarque qu’il est sensible à la casse, c’est peut-être utile… ou pas ? Possible d’ajouter une option en ligne de commande pour ignorer la casse ? :smiley:

  1. enfin pour terminer, certaines traductions reviennent plusieurs fois (je suppose, pour plusieurs fichiers). Typiquement celle ci, 401 accès non autorisé. C’est possible de conserver la 1ère réponse en cache?

Bonjour @pifou
Merci pour ce retour.

  1. Excellente proposition que je vais m’empresser d’implémenter

  2. Le problème, si on ignore la case sera de décidé laquelle des deux propositions choisir. Le programme pourrait éventuellement le faire en se basant sur la casse du texte original mais ça me semble inutilement compliqué et ça risque de resté plus ou moins aléatoire.

  3. Proposition d’amélioration judicieuse. Je vais l’implémenter après avoir fait le point 1. Ça allégera le soucis du point 2. car la question ne sera posée qu’une seule fois.

ho, rien de compliqué pour le 2e, juste prendre la 1ère option qui vient du moment qu’il est identique à la 2nd ça n’a aucune importance en fait :slight_smile: je ne sais pas comment tu fais tes comparaisons de texte, mais toutes les fonctions ont leur équivalent insensible à la casse, en général une option -i pour les regex, ou bien les fonctions php stri* : du moment qu’on choisit d’ignorer la casse des traductions, n’importe quelle solution est valable.

Hello,

Point 1. implémenté et publié dans la release v0.5.0.

Documentation
Realease notes et téléchargement

Hello,

Je viens de tester l’outils. C’est vraiment pas mal.
Quelques remarques :

La recherche retourne des choses anormales. Je suppose que ta regex est trop large pour mon cas.

Cas 1:

J’utilise un JSON pour stocker toutes mes commandes. Donc je boucle dans mon JSON pour les ajouter dans Jeedom.
Je fais donc ceci :
$cmd->setName(__($command['name'], __FILE__));
Et naturellement c’est retrouvé:

"$command['name']": "$command['name']",

Correction possible : Regarder si il y un $ suivi directement par un mot ?

Cas 2:

Le fichier de traduction contient ca :
".*)\/', $cmd->getLogicalId(), $splitCmd)) {\n if (isset($informations[$splitCmd[1]][$splitCmd[2]])) {\n $this->checkAndUpdateCmd($cmd->getLogicalId(), $informations[$splitCmd[1]][$splitCmd[2]], $measuredAt->setTimezone($timezone)->format('Y-m-d H:i:s'));\n log::add(__CLASS__, 'debug', __FUNCTION__ . '::' . __('Mise à jour de la commande'": ".*)\/', $cmd->getLogicalId(), $splitCmd)) {\n if (isset($informations[$splitCmd[1]][$splitCmd[2]])) {\n $this->checkAndUpdateCmd($cmd->getLogicalId(), $informations[$splitCmd[1]][$splitCmd[2]], $measuredAt->setTimezone($timezone)->format('Y-m-d H:i:s'));\n log::add(__CLASS__, 'debug', __FUNCTION__ . '::' . __('Mise à jour de la commande'",

Qui correspond a cette partie de mon code :

foreach ($cmdsInfos as $cmd) {
                    if (preg_match('/(.*)__(.*)/', $cmd->getLogicalId(), $splitCmd)) {
                        if (isset($informations[$splitCmd[1]][$splitCmd[2]])) {
                            $this->checkAndUpdateCmd($cmd->getLogicalId(), $informations[$splitCmd[1]][$splitCmd[2]], $measuredAt->setTimezone($timezone)->format('Y-m-d H:i:s'));
                            log::add(__CLASS__, 'debug', __FUNCTION__ . '::' . __('Mise à jour de la commande', __FILE__) . ' ' . $cmd->getLogicalId() . ' ' . __('avec la valeur', __FILE__) . ' ' . $informations[$splitCmd[1]][$splitCmd[2]] . ' ' . __('collectée à', __FILE__) . ' ' . $measuredAt->format('Y-m-d H:i:s'));
                        }
                    } else {
                        if (isset($informations[$cmd->getLogicalId()])) {
                            $this->checkAndUpdateCmd($cmd->getLogicalId(), $informations[$cmd->getLogicalId()], $measuredAt->setTimezone($timezone)->format('Y-m-d H:i:s'));
                            log::add(__CLASS__, 'debug', __FUNCTION__ . '::' . __('Mise à jour de la commande', __FILE__) . ' ' . $cmd->getLogicalId() . ' ' . __('avec la valeur', __FILE__) . ' ' . $informations[$cmd->getLogicalId()] . ' ' . __('collectée à', __FILE__) . ' ' . $measuredAt->format('Y-m-d H:i:s'));
                        }
                    }
                }

Cette fois si je pense qu’il match mes 2 underscores du preg_match (qui me servent de séparateur) mais je suis pas dans le format __(‹ xxxxx ›, FILE) mais en effet, il trouve les 2 underscores et parenthese ouvrante puis plus loin dans le code plus loin (sur une autre ligne meme) FILE

Pas de recherche dans les templates dashboard et mobile

L’outil ne me retourne aucune des {{}} qui sont dans mon template dashboard.


Voila mes 2 cents…
En tout cas bravo pour ton tools, c’est genial et je pense que rare sont ceux qui tomberons sur le meme probleme que moi mais je pense que cela peut etre résolu par l’optimisation de ta regex de recherche

Merci d’avance

Hello,
Merci pour l’info, Je vais voir si j’arrive corriger ça ce weekend…

Je mettrai une réponse ici lorsque se sera fait.

1 « J'aime »

Hello,
Une nouvelle version (0.6.0) est publiée.
@mguyard, peux-tu vérifier si tes deux problèmes sont résolus?

Le soucis est que je n’avais pas encore la maîtrise de l’utilisation des regex en python lorsque j’ai écris ce script (je trouve Perl bien plus efficace sur ce point). Je cherchai donc les textes à traduire avec mon propre code.

Ma maîtrise de l’utilisation des regex en Python ayant évolué depuis, j’ai réécris cette partie du code en les utilisants.