meta données pour cette page
  •  

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
envrac:bash-international [2012/03/03 08:10]
ztrulphcs [Il ne peut y en avoir qu'un]
envrac:bash-international [2022/10/30 06:55] (Version actuelle)
ztrulphcs [Il ne peut y en avoir qu'un]
Ligne 1: Ligne 1:
 ====== Script bash internationalisé ====== ====== Script bash internationalisé ======
 +
 +Ou comment traduire un script bash.
 +------------------
  
 Bash possède un mécanisme interne d'internationalisation. C'est pas bien difficile à trouver. Par exemple y'a [[http://www.pclinuxos.com/forum/index.php?topic=59145.0|ce how-to]], mais il est en anglais, et puis après le forum part en quenouille sur une sombre histoire de locale par défaut... Bash possède un mécanisme interne d'internationalisation. C'est pas bien difficile à trouver. Par exemple y'a [[http://www.pclinuxos.com/forum/index.php?topic=59145.0|ce how-to]], mais il est en anglais, et puis après le forum part en quenouille sur une sombre histoire de locale par défaut...
Ligne 5: Ligne 8:
 En fait, la base est simple; Les chaines entre ''%%$"%%'' et ''%%"%%'' seront candidates à la traduction. On peut donc écrire des choses comme ça : En fait, la base est simple; Les chaines entre ''%%$"%%'' et ''%%"%%'' seront candidates à la traduction. On peut donc écrire des choses comme ça :
  
-<code bash>+<code bash essai-001>
 echo $"Hello World !" echo $"Hello World !"
 </code> </code>
Ligne 41: Ligne 44:
  
  
-Notez au passage que bash se donne vraiment beaucoup de mal pour trouver le catalogue de chaines traduites. Si on fait exprès de le taquiner un peu et qu'on regarde avec ''[[http://linuxmanpages.com/man1/strace.1.php|strace]]'' ce qu'il essaie de faire, on peut voir ceci :+Notez au passage que bash se donne vraiment beaucoup de mal pour trouver le catalogue de chaines traduites. Si on fait exprès de le taquiner un peu et qu'on regarde avec ''[[http://man7.org/linux/man-pages/man1/strace.1.html|strace]]'' ce qu'il essaie de faire, on peut voir ceci :
 <code txt> <code txt>
 open(".../locale/fr_FR.UTF-8/LC_MESSAGES/multilingue.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open(".../locale/fr_FR.UTF-8/LC_MESSAGES/multilingue.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
Ligne 113: Ligne 116:
 ==== Traduire plus sérieusement ==== ==== Traduire plus sérieusement ====
  
-Ben pourquoi c'était pas sérieux ? Disons que c'était maladroit. D'abord, un fichier ''.po'' peut contenir plus d'informations que les seules chaines traduites, le nom et l'adresse de courriel du traducteur pour ne citer qu'eux. Ensuite, remarquons que notre procédure n'est pas adaptée aux changements qui peuvent intervenir dans le script. Si on rajoute une chaine dans le script, ou si on en change une, il faudrait tout retraduire puisque la méthode ''%%bash --dump... >toto.po%%'' va écrabouiller le précédent travail de traduction. Voilà, ces réponses suffisent ? pas tout a fait ? Allez, cerise sur la gâteau, si les modifications dans le script sont suffisamment légères, alors on peut conserver automatiquement l'ancienne traduction dans le fichier ''.po'' --celui qu'on édite pour y inclure les traductions-- tout en ayant un commentaire qui indique qu'il y a eu un léger changement. Ça allège le travail de traduction. +Ben pourquoic'était pas sérieux ? Disons que c'était maladroit. D'abord, un fichier ''.po'' peut contenir plus d'informations que les seules chaines traduites, le nom et l'adresse de courriel du traducteur pour ne citer qu'eux. Ensuite, remarquons que notre procédure n'est pas adaptée aux changements qui peuvent intervenir dans le script. Si on rajoute une chaine dans le script, ou si on en change une, il faudrait tout retraduire puisque la méthode ''%%bash --dump... >toto.po%%'' va écrabouiller le précédent travail de traduction. Notons encore que si une chaine apparait plusieurs fois dans le script, elle se trouvera aussi plusieurs fois dans le fichier à traduire, et ce sera alors à vous d'éliminer les doublons de ce fichier, sinon la génération du catalogue échouera. Voilà, ces réponses suffisent ? pas tout a fait ? Allez, cerise sur la gâteau, si les modifications dans le script sont suffisamment légères, alors on peut conserver automatiquement l'ancienne traduction dans le fichier ''.po'' --celui qu'on édite pour y inclure les traductions-- tout en ayant un commentaire qui indique qu'il y a eu un léger changement. Ça allège le travail de traduction. 
  
 La meilleure méthode est donc  La meilleure méthode est donc 
Ligne 152: Ligne 155:
 Ok, voilà un exemple. La chaine contient des variables mais ne cela n'a pas d'importance, et ça fonctionne on l'a déjà vu. Ok, voilà un exemple. La chaine contient des variables mais ne cela n'a pas d'importance, et ça fonctionne on l'a déjà vu.
  
-<code bash>+<code bash essai-002>
 firstname=toto firstname=toto
 secondname='le heros' secondname='le heros'
Ligne 160: Ligne 163:
 Maintenant, un peu plus compliqué, on a plein de chaines de résultats dans un tableau, et on veut afficher le statut en fonction d'une autre valeur. Maintenant, un peu plus compliqué, on a plein de chaines de résultats dans un tableau, et on veut afficher le statut en fonction d'une autre valeur.
  
-<code bash>+<code bash essai-003>
 status=( status=(
   $"Perfect",   $"Perfect",
Ligne 176: Ligne 179:
 Imaginons maintenant qu'on veuille faire rentrer ''$name'' dans les chaines du tableau, ce qui permettra aux traducteurs de choisir la place que doit occuper le nom dans la phrase. Peut être au début dans une langue (''%%"$name blablabla"%%''), et à la fin dans une autre langue (''%%"gnak gnak gnik $name"%%''). Emporté par notre élan, on écrit le script naïf suivant : Imaginons maintenant qu'on veuille faire rentrer ''$name'' dans les chaines du tableau, ce qui permettra aux traducteurs de choisir la place que doit occuper le nom dans la phrase. Peut être au début dans une langue (''%%"$name blablabla"%%''), et à la fin dans une autre langue (''%%"gnak gnak gnik $name"%%''). Emporté par notre élan, on écrit le script naïf suivant :
  
-<code bash>+<code bash essai-004>
 status=( status=(
   $"$name Perfect",   $"$name Perfect",
Ligne 192: Ligne 195:
 Ben oui, mais normal quoi. Si on prend pas à pas ce qui se passe lors de l'affichage, voilà ce qu'on obtient : Ben oui, mais normal quoi. Si on prend pas à pas ce qui se passe lors de l'affichage, voilà ce qu'on obtient :
  
-  * bash voit une chaine ''%%"${status[$result]}"%%'', +  * bash voit une chaine ''%%"${status[$result]}"%%'' qui n'est pas une chaine à traduire
-  * procède à l'expansion des variables, effectue le remplacement par la valeur qui est une traduction **déjà** réalisée +  * procède à l'expansion normale des variables et remplace ''%%"${status[$result]}"%%'' par la valeur idoine du tableau ''status''; cette valeur est une traduction **déjà** réalisée, 
-  * et s'arrête là, content de lui.+  * et il s'arrête là, content de lui.
  
 ''$name'' dans l'histoire ? il n'en est pas question **au moment où on le souhaiterai**. En fait, ''%%$name%%'' a été évalué bien avant, lors de la **définition** du tableau:  ''$name'' dans l'histoire ? il n'en est pas question **au moment où on le souhaiterai**. En fait, ''%%$name%%'' a été évalué bien avant, lors de la **définition** du tableau: 
Ligne 202: Ligne 205:
   * recherche un équivalent dans le catalogue,   * recherche un équivalent dans le catalogue,
   * il trouve des chaines du genre ''%%"parfait $name", "presque bien $name", "$name : tu peux faire mieux", "tout faux $name"%%'',   * il trouve des chaines du genre ''%%"parfait $name", "presque bien $name", "$name : tu peux faire mieux", "tout faux $name"%%'',
-  * fait le remplacement de variable ''%%$name%%'' => ''%%''%%'' car **à ce moment** ''%%$name%%'' n'est pas encore définie... +  * remplace les chaines d'origine par leur traduction, 
-  * range ce résultat dans la tableau et passe à la suite+  * puis, au moment où il exécute la commande, c'est à dire l'affectation au tableau,\\ fait le remplacement de variable ''%%$name%%'' => ''%%''%%'' car **à ce moment** ''%%$name%%'' n'est pas encore définie... 
 +  * range ce résultat dans la tableau et passe à la suite
 Si on essaie frénétiquement ceci : Si on essaie frénétiquement ceci :
  
Ligne 213: Ligne 218:
  
 Si on essaie alors ceci : Si on essaie alors ceci :
-<code bash>+<code bash essai-005>
 status=( status=(
   "$name Perfect",   "$name Perfect",
Ligne 227: Ligne 232:
 C'est pas mieux. Voir l'explication ci dessus, mais en plus, les chaines du tableau sont même pas traduites... C'est pas mieux. Voir l'explication ci dessus, mais en plus, les chaines du tableau sont même pas traduites...
  
-Il n'y a pas de solution alors ? ben si. Y'a [[http://linuxmanpages.com/man1/printf.1.php|printf]]. Au passageil se trouve, que ''printf'' est une commande [[http://linuxmanpages.com/man1/bash.1.php#lbCZ|interne de bash]] (et aussi de dash et ash) et donc peu coûteuse -- même si le lien donné pointe vers la page de manuel de la commande externe du même nom. Un exemple correct pour ce script est :+Il n'y a pas de solution alors ? ben si. Y'a [[https://www.gnu.org/software/bash/manual/bash.html#index-printf|printf]], une commande interne de bash. Cette fonction interne reprend et étend la **commande externe** [[http://linuxmanpages.com/man1/printf.1.php|printf]]. Cette commande étant un interne de bast (et aussi de dash et ash) est donc peu coûteuse. Un exemple correct pour ce script est : 
 + 
 +<code bash essai-006> 
 +#! /bin/bash 
 + 
 +TEXTDOMAIN=${0##*/
 +TEXTDOMAINDIR="$PWD/locale"
  
-<code bash> 
 status=( status=(
  $"%s Perfect\\n",  $"%s Perfect\\n",
Ligne 237: Ligne 247:
 ) )
 name=toto name=toto
-result=3+result=$(( $RANDOM % 4 ))
 printf "${status[$result]}" "$name" printf "${status[$result]}" "$name"
 +read -p $"press the return key"
 # ou alors, si on fait des boites de dialogue, on peut utiliser ceci : # ou alors, si on fait des boites de dialogue, on peut utiliser ceci :
 +result=$(( $RANDOM % 4 ))
 dialog --msgbox "$( printf "${status[$result]}" "$name" )" 0 0 dialog --msgbox "$( printf "${status[$result]}" "$name" )" 0 0
 +result=$(( $RANDOM % 4 ))
 zenity --info --text="$( printf "${status[$result]}" "$name" )" zenity --info --text="$( printf "${status[$result]}" "$name" )"
 </code> </code>
Ligne 246: Ligne 259:
 Les traducteurs pourront mettre les noms aux endroits où ils le veulent. Sauf qu'ils peuvent éventuellement ne même pas vraiment savoir à quoi correspond le ''%s'' dans la chaine à traduire. Les traducteurs pourront mettre les noms aux endroits où ils le veulent. Sauf qu'ils peuvent éventuellement ne même pas vraiment savoir à quoi correspond le ''%s'' dans la chaine à traduire.
  
 +Notez l'emploi de ''TEXTDOMAIN=${0##*/}''. ''${0##*/}'' est **toujours** égal au nom du script, quelque soit ce nom.
 +
 +Voilà le fichier .po pour ceux qui voudraient essayer :
 +<code po essai-006.po>
 +#: essai-007:7
 +msgid "%s Perfect\\\\n"
 +msgstr "%s, C'est parfait !\\\\n"
 +#: essai-006:8
 +msgid "%s almost correct\\\\n"
 +msgstr "Presque correcte %s\\\\n"
 +#: essai-006:9
 +msgid "%s could be better\\\\n"
 +msgstr "%s : Peut mieux faire\\\\n"
 +#: essai-006:10
 +msgid "%s all wrong\\\\n"
 +msgstr "%s a tout faux !\\\\n"
 +#: essai-006:15
 +msgid "press the return key"
 +msgstr "Appuyez sur la touche « entrée »"
 +</code>
 +
 +et voilà aussi les commandes à passer :
 +<code bash>
 +langue=fr_FR
 +mkdir -p locale/$langue/LC_MESSAGES/
 +msgfmt -o locale/$langue/LC_MESSAGES/essai-006.mo essai-006.po
 +bash essai-006
 +</code>
  
 ===== Téléchargement bonus ===== ===== Téléchargement bonus =====