top of page
  • lilianfaedi

Traduction et programmation, commencer par quelque chose d’utile



Introduction (par Jean-Christophe Helary)


Quand Ismaël et Lilian m’ont proposé dans leur projet de stage l’écriture de programmes à utiliser avec OmegaT, j’étais perplexe. Je ne suis pas un professionnel de la programmation, et même si j’ai commencé à écrire des programmes sur un ZX81 pendant mes années collège au début des années 80, je suis resté dans l’amateurisme pour me consacrer ces 20 dernières années à la traduction.


Je leur ai donc proposé un défi pour leur dernier mois de stage : nous partirions tous les trois à partir de zéro avec un langage de programmation inconnu mais réputé facile à apprendre et nous écririons un programme minimaliste mais réellement utile dans le cadre de nos activités. À ce stade, la seule différence qui existe entre eux et moi est le fait que mon expérience de l’écriture de petits programmes et ma connaissance des concepts fait que je sais un peu mieux où chercher des informations et comment interpréter les erreurs qui jalonneront notre chemin.


J’ai proposé le langage Python car je ne le connaissais pas et également parce qu’il est utilisé dans de nombreux outils de localisation, à la tête desquels on trouve le Translate-Toolkit.


Comme “programme minimaliste” j’ai proposé la chose suivante :

  • Le programme utilise les données trouvées dans deux fichiers texte pour créer un fichier TMX.

Avec les contraintes de simplification suivantes qui nous permettent de nous concentrer sur le cœur de la fonction sans avoir à faire d’inutiles conversions, tests et autres interfaces :


  • Le nom des fichiers est modifiable dans le code ;

  • Les deux fichiers sont de longueur égale ;

  • Leur contenu est encodé en UTF-8 ;

  • Le nom des langues source et cible sont modifiables dans le code ;

  • Le programme n’a pas d’interface graphique et est utilisable à l’invite de la ligne de commande ;

  • Le fichier résultant a une syntaxe conforme à la dernière version du standard TMX.


Après quelques heures passées indépendamment à s’initier à Python (essentiellement créer des variables, imprimer des contenus à l’écran …), nous nous sommes retrouvés pour une session d’écriture de code avec pour objectif de ne pas s’arrêter avant d’avoir obtenu un programme fonctionnel.


La session a duré 4h. Et au bout de 4h nous sommes arrivés à un petit programme d’une soixantaine de lignes (sans les commentaires) extrêmement performant puisqu’il transforme presque instantanément deux fichiers courts en une vingtaine de secondes pour transformer les contenus de deux fichiers de 50 Mo (avec chacun autour de 400 000 segments) en une TMX de 175 Mo…


La méthode d’écriture adoptée est la suivante :

  1. Trouver sur internet un exemple de code trivial ;

  2. Le tester et s’assurer que le résultat est conforme à la sortie attendue du code ;

  3. Modifier une partie élémentaire du code ;

  4. Tester le code de nouveau et s’assurer que le résultat est conforme à la sortie que nous envisagions.

Et ainsi de suite.


Je savais que les étapes essentielles du processus pouvaient se résumer de la manière suivante :

  1. Lire le contenu de deux fichiers ;

  2. Combiner ces contenus ;

  3. Convertir ce résultat en TMX ;

  4. Écrire le résultat de la conversion dans un fichier.

Les étapes de l’écriture, de la recherche et de l’adaptation du code trouvé ont correspondu aux “concepts” et tâches suivantes et ont porté essentiellement sur la “syntaxe” de notre écriture :

  • Imprimer un contenu arbitraire à l’écran (avec print) ;

  • Effectuer la déclaration d’une variable et l’assignation d’un contenu à cette variable (avec =) ;

  • Imprimer le contenu d’un fichier à l’écran (avec open) ;

  • Imprimer un contenu arbitraire dans un fichier (avec write) ;

  • Charger le contenu de deux fichiers dans un tableau avec une ligne par “cellule” (avec une boucle for … in) ;

  • Imprimer un contenu XML trivial (avec le module minidom et import) ;

  • Modifier manuellement ce contenu trivial pour en faire une TMX avec une <tu> seulement ;

  • Combiner une boucle for … in avec la génération de TMX pour faire une TMX plus “réelle”.


Seule la boucle de conversion en TMX a demandé un petit effort logique et une réflexion sur l’utilisation du module minidom.


J’ai une petite expérience en création de XML, mais avec AppleScript, le langage d’automatisation d’Apple, et j’imaginais que cette partie allait être la plus complexe. Cette inquiétude s’est révélée fondée, mais il nous a seulement fallu 2h pour aboutir à quelque chose de fonctionnel, alors que le code que j’avais écrit seul avec AppleScript avait nécessité plusieurs jours de recherche et de travail (ce code et les explications qui sont en commentaire sont cependant considérés dans la communauté AppleScript comme un tutoriel auquel on peut se référer).


Une fois le code écrit, il est important de laisser des commentaires à destination de nous même, mais un “nous-même” qui vivra dans une semaine, ou dans un mois, quand nous aurons oublié toutes ces réflexions, ce qui fait la différence entre un apprenant et une personne multilingue …


Ce code qu’Ismaël et Lilian vont tenter d’expliquer ci-dessous est le résultat de ce processus, il est testé, utilisable, performant, et vous êtes invité•e à l’essayer, le modifier et l’utiliser. Pour respecter l’esprit qui l’a fait naître, il est mis à disposition, dans toute sa modestie, sous la licence d’utilisation GPL 3 qui permet son utilisation et sa modification en toute liberté.


Les documents qui ont servi de référence à nos “copier-coller-adapter” sont les suivants :



Description du code (expliqué par Ismaël et moi-même)


Les explications



Python est un langage de programmation, détaillé sur la page suivante : https://fr.wikipedia.org/wiki/Python_(langage)).


IDLE est une application, en général fournie avec le langage, qui permet d’écrire des petits programmes en Python et de les tester immédiatement.


Python va nous servir aujourd’hui à écrire un petit programme qui résout un problème fréquent : comment transformer deux fichiers de même longueur qui contiennent l’un la traduction de l’autre pour créer une mémoire de traduction au format TMX qui nous servira de mémoire de référence dans notre traduction.


Notez que les lignes qui commencent par dièse (“#”) sont des commentaires pour mieux comprendre le script, et n’ont aucun impact sur le résultat final.


Il s’agira donc de détailler pas à pas les étapes qui ont servi à le définir.


1) Importation de l’outil


Avant de commencer l’écriture, il faut importer une interface dédiée utilisée par le script au tout début. Cela permet au programme d’exécuter des commandes spécifiques, seulement possible avec cet équipement. Ainsi, il faut marquer au début :


from xml.dom import minidom

import os


minidom” (cf. https://docs.python.org/3/library/xml.dom.minidom.html pour savoir précisément de quoi il s’agit) permet d’effectuer des tâches présentes dans le script. A un moment de notre écriture, nous avons tenté d’utiliser “etree” (cf. https://docs.python.org/3/library/xml.etree.elementtree.html), un autre outil, mais nous n’avons pas réussi à atteindre le résultat escompté avec celui-ci. Nous sommes alors retournés sur minidom.


2) Définir les variables élémentaires


Il faut maintenant que chaque ligne d’un document soit considérée comme la langue source et la langue cible à importer dans la mémoire de traduction. Pour ce faire, nous allons définir des variables à utiliser plus tard, avec “=” :


langsrc = "en"

langcbl = "fr"


Une fois ceci fait, il faut définir les fichiers qui vont être pris en compte dans l’alignement. Nous les avons nommé ici “en.txt” et “fr.txt” et les avons défini sous la variable “nomDesFichiers” :


nomDesFichiers = ('en.txt', 'fr.txt')


Enfin, il faut définir le format de base dans lequel sera rédigé notre mémoire de traduction (le format TMX) dans une variable nommé “maTMX” :


maTMX = "maTMX.tmx"


Maintenant que les éléments ont été posés, le code peut réellement commencer.


3) Créer une boucle au moyen d’un tableau


Nous devons faire en sorte de faire passer ces deux fichiers pour un tableau dans l’interface de Python, qui va mettre chaque segment du document source en face de chaque segment du document cible. Ainsi, cela va lui permettre de considérer chaque segment correspondant à chaque langue, et donc de créer la mémoire de traduction. Pour ce faire, on va devoir créer une boucle en utilisant la variable “nomDesFichiers” définie au préalable. La fonction précise de cette boucle est de ne pas écrire mille lignes de code, et surtout de l’adapter à tout fichier donné. Il faut alors ouvrir chaque fichier et prendre en compte leurs lignes :


nombreDeLignes = len([ligne.strip() for ligne in open(nomDesFichiers[0])])

DONNEES = ["",""]


La variable “nombreDeLignes” est définie pour permettre la définition de colonnes du tableau plus tard et ainsi de l’adapter au nombre de lignes des deux fichiers texte. Vous notez l’utilisation de “len”, qui va prendre en compte la longueur de la ligne source pour l’adapter à la ligne cible (puisqu’une langue peut être plus courte ou plus longue selon sa nature).


for i in range(0, len(nomDesFichiers)):

DONNEES[i] = [ligne.strip() for ligne in open(nomDesFichiers[i])]


/!\ Attention à l’espace de tabulation/d'indentation, sinon la boucle va être inopérante ! /!\

Ici, nous créons ce fameux tableau de données que nous avons pour rappel défini comme ci : les colonnes sont “nombreDeLignes”. Il faut désormais que la longueur des lignes soit égale à deux, donc “len(nomDesFichiers) = 2”. Le tableau “DONNEES” (dont “i” correspond à l'occurrence de la boucle) vient alors d’être défini. Reste à coder le fichier TMX (au format XML en lui-même).


4) Format d’un document XML


Un document XML est écrit d’une certaine manière pour que son code soit interprété par des applications adaptées. Il se découpe de la manière suivante :

  • Le format du document, en l’occurence ici “tmx”;

  • La version du XML, en l’occurence ici “1.4” ;

  • L’en-tête (ou header) en anglais, qui contient :

    • La version de l’outil de création (ici “0.1”) ;

    • Le type de découpage des éléments (ici “segtype” et “paragraph”) ;

    • La date de création sous un format comprise par le code (ici “20220524T211111Z”, soit le 24 mai 2022 à 21:11) ;

    • Le type de données (ici elle est inconnue, donc “unknown”) ;

    • La langue source (ici “en”) ;

    • Le nom de l’outil de création (ici, “monScriptPython”) ;

    • La prise en charge par des logiciels (ici “tmf” et “Emacs").

Nous devons définir ces éléments avec ce code :


tmx = minidom.Document()

xml = tmx.createElement('tmx')

xml.setAttribute('version', '1.4' )


header = tmx.createElement('header')

header.setAttribute('creationtoolversion', '0.1' )

header.setAttribute('segtype', 'paragraph')

header.setAttribute('creationdate', '20220524T211111Z')

header.setAttribute('datatype', 'unknown')

header.setAttribute('srclang', 'en')

header.setAttribute('creationtool', 'monScriptPython')

header.setAttribute('o-tmf', 'Emacs')


Bien sûr, il y a sûrement un moyen de faire plus simple et plus efficace, mais cette méthode permet de définir TOUS les attributs du header.


5) Format d’un document TMX


En-dessous de ce code, nous devons définir les éléments appartenant au format TMX, à savoir :


  • Le corps (ou “<body>”), qui constitue l’ensemble du format TMX ;

  • Les segments (ou “<seg>”) de la mémoire ;

  • Les unités de traduction (ou “translations units”, “<tu>”), divisés en deux : langue source (“en”), et la langue cible (“fr”) ;

  • La version des unités de traduction (ou “translations units version”, “<tuv>”).


Chaque élément est organisé de façon à ce qu’ils soient contenus à l’intérieur du précédent élément : <tuv> appartient à <tu>, qui lui-même appartient à <seg>, qui lui-même appartient à <body>, qui lui-même appartient à <xml>.


6) Installer les éléments parents et enfants dans le script


Pour démarrer, installons les éléments xml, header et body :


body = tmx.createElement('body')


tmx.appendChild(xml)

xml.appendChild(header)

xml.appendChild(body)


“createElement” et “appendChild” sont deux fonctions propres à minidom. On crée d’abord l’élément de tmx “body”, puis on installe “l’enfant” de chaque élément en cascade (comme par exemple, dans des répertoires pour des fichiers, avec des dossiers parents et enfants). xml devient l’enfant de tmx, et header et body sont tous les deux enfants de xml.


Avant de conclure, il faut créer une boucle qui définit une fois de plus les éléments parents et enfants tout en incorporant cette fois le tableau “DONNEES”, avec “nombreDeLignes” entre autres. On crée tous les éléments et on utilise encore “appendChild” pour chacun. On va alors utiliser deux nouvelles variables : “text_en” et “text_fr”, puis créer le tableau avec “createTextNote” à l’intérieur de “tmx”. Cette boucle donne alors :


for i in range(0, nombreDeLignes):

tu = tmx.createElement('tu')

body.appendChild(tu)


tuv = tmx.createElement('tuv')

tuv.setAttribute('xml:lang', langsrc)

tu.appendChild(tuv)


seg = tmx.createElement('seg')

tuv.appendChild(seg)


text_en = tmx.createTextNode(DONNEES[0][i])

seg.appendChild(text_en)


tuv = tmx.createElement('tuv')

tuv.setAttribute('xml:lang', langcbl)

tu.appendChild(tuv)


seg = tmx.createElement('seg')

tuv.appendChild(seg)


text_fr = tmx.createTextNode(DONNEES[1][i])

seg.appendChild(text_fr)


/!\ Attention encore une fois aux espaces de tabulation/d'indentation ! /!\

“DONNEES[0]” correspond au premier segment (puisque “0” signifie la première valeur dans le cadre d’une boucle), et “DONNEES[1]” au deuxième.


7) Finalisation et importation


Ce contenu doit désormais être organisé de façon présentable, avec l’indentation “\t”. Il s’agit alors de demander au programme de le faire avec :


xml_str = tmx.toprettyxml(indent ="\t")


Enfin, nous allons importer et enregistrer le résultat dans une TMX appelée “maTMX” avec “w” pour signifier qu’elle sera modifiée en écriture :


with open(maTMX, "w") as f:

f.write(xml_str)


8) Exécuter le script


Mettez ce script avec vos deux autres fichiers (nommés respectivement “en” et “fr”), puis exécutez-le avec “F5” ou “Run Module” sur IDLE. Normalement, votre TMX a été créée.


Conclusion


Nous avons vu dans cet article comment créer un script pour aligner deux documents avec Python. Cette démarche permet une grande flexibilité, dans le sens où l’ajout ou le retrait d’éléments vous permet de l’adapter à l’utilisation requise.


Si vous avez des questions, n’hésitez pas à poster un commentaire.


85 vues0 commentaire

Posts récents

Voir tout
bottom of page