Retour sur transformation TMX à TBX

This commit is contained in:
Philippe Tourigny 2023-04-17 23:51:47 +09:00
parent 8de68d89df
commit 86b8406c18
2 changed files with 340 additions and 0 deletions

View File

@ -0,0 +1,278 @@
# Convertir un fichier TMX en TBX avec une transformation XSLT
Ce document est une tentative pour créer une transformation XSL (XSLT) simple entre un fichier TMX (mémoire de traduction) et un fichier TBX (glossaire).
Il permet dutiliser la TMX créée à partir de la traduction dun fichier des chaînes de linterface utilisateur dun logiciel et dutiliser le contenu en tant que glossaire pour vérifier que les chaînes de lIU sont bien traduites dans les documents qui la décrivent (manuels, etc.)
## Utilisation
Il est possible d'utiliser ce document en l'enregistrant dans un fichier texte, et en l'associant à une liste de documents dans Rainbow ou avec un processeur XSLT tel que xsltproc, à la ligne de commande:
```
xsltproc -o monFuturFichierTBX.tbx cetteTransformationXSLT.xsl monFichierTMX.tmx
```
La transformation a été écrite par Sirine Ben Hadj Khalifa et moi-même lors du stage de fin détudes de M2 de madame Ben Hadj Khalifa.
Les explications sont écrites par moi et correspondent à mon niveau de compréhension des standards à la date de leur écriture.
### Références:
- TMX = [Translation Memory eXchange](https://www.gala-global.org/tmx-14b)
(format déchange de mémoire de traduction)
- Rappel sur la structure dune mémoire TMX: une TMX est constituée de
balises `<tu>`translation unit») qui contiennent des `<tuv>`
translation unit variant»). Chaque `<tuv>` a un attribut `<xml-lang>`
qui spécifie la langue de son contenu, et contient, quand elle contient
quelque chose, une balise `<seg>`segment») qui elle contiendra le
texte.
```xml
<tu>
<note>UI</note>
<tuv xml:lang="en">
<seg>OmegaT options :</seg>
</tuv>
<tuv xml:lang="fr" creationid="OmegaT Aligner" creationdate="20230401T121435Z">
<seg>Options OmegaT:</seg>
</tuv>
</tu>
```
- TBX = [TermBase eXchange](https://www.iso.org/schema/isosts/v0.6/doc/tbx/) (format déchange de base terminologique)
- Rappel sur la structure dun glossaire TBX (simple): un TBX est constitué
de balises `<termEntry>` qui contiennent des `<langSet>` dans lesquels on
trouve des `<tig>`term information group») qui à leur tour
contiennent les `<term>`.
```xml
<termEntry id="OmegaT options:">
<note xml:lang="en">UI</note>
<langSet xml:lang="en">
<tig>
<term>OmegaT options :</term>
</tig>
</langSet>
<langSet xml:lang="fr">
<tig>
<term>Options OmegaT:</term>
</tig>
</langSet>
</termEntry>
```
On remarque que les deux hiérarchies ont une structure extrêmement similaire.
- [Rainbow](https://www.okapiframework.org)
- [xsltproc](https://gitlab.gnome.org/GNOME/libxslt/-/wikis/home) (disponible sur Linux, macOS, Cygwin pour Windows)
- [Qu'est-ce que le logiciel libre](https://www.gnu.org/philosophy/free-sw.fr.html)
- La [licence GPL 3.0](https://www.gnu.org/licenses/quick-guide-gplv3.fr.html)
## Syntaxe XML
```xml
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:local="http://www.w3.org/2005/xquery-local-functions">
```
La syntaxe dun document XML est très claire, mais les ajouts de crochets et autres décorations rendent sa lecture difficile à un être humain. Cest pour ceci que lorsquon publie des documents XML il est préférable dutiliser des fonctions automatiques de mise en retrait des lignes en fonction de leur niveau demboîtement, et donc dutiliser correctement lemboîtement (les sauts de ligne) pour correctement identifier les rapports entre balises (pour lesquelles on utilise la métaphore familiale : parent, enfant, ancêtre, descendant, etc.) et leurs attributs.
On peut diviser la structure dune balise en 3 éléments, et ce sont ces éléments sur lesquels notre attention doit porter pour comprendre la structure, et dans le cas dune feuille XSL le fonctionnement, du document.
Une balise dans une langue conforme à la norme XML est en général composée ainsi:
- le nom de la balise
- les attributs de la balise (avec pour chaque attribut son nom et sa valeur)
- le contenu de la balise
La plupart des langues XML autorisent des balises au contenu vide, et des valeurs dattributs par défaut, etc.
Certaines langues autorisent le mélange à lintérieur du document de balises provenant de langues externes. Pour sassurer que la distinction est faite entre leurs propres balises et les balises «externes», elles vont systématiquement ajouter un préfixe à leurs propres balises. Ainsi, la lectrice saura toujours que les balises préfixées sont à interpréter dans le cadre de la langue du document alors que les balises non préfixées sont externes et à interpréter, éventuellement, dans le cadre de la langue externe.
Cest le cas de XSLT qui va décrire la manière dont la transformation doit sopérer avec ses propres balises et qui va utiliser les balises externes (ici les balises TBX) pour créer le fichier TBX. Les balises XSLT vont toutes être préfixées avec `<xsl:>` pour indiquer que seules ces balises sont à interpréter dans le cadre de la langue XSLT.
### Références:
- [Stylesheet element](https://www.w3.org/TR/1999/REC-xslt-19991116#stylesheet-element)
- [XML = eXtensible Markup Language](https://www.w3.org/TR/REC-xml/), donc «langue extensible de balisage»
XML est un ensemble de règles qui permet de définir des langues de balisage de document
- [XSL = eXtensible Stylesheet Language](https://www.w3.org/Style/XSL/), donc «langue extensible de feuille de style»
XSL est un ensemble de recommandations pour définir des transformations et des présentations pour documents XML
- XSL est composé de:
- XSLT = XSL Transformations, qui est utilisée pour définir les règles de transformation dun document XML
- XPATH = XML Path Language, qui est utilisé pour trouver son chemin dans un document XML et éventuellement identifier les éléments qui seront la cible dune transformation
- XSL-FO = XSL Formatting Objects, qui est utilisé principalement pour produire des documents PDF
Il faut noter que la complexité de XSL-FO et lévolution des technologies du Web font que [XSL-FO a tendance à être remplacé par CSS](https://www.w3.org/TR/NOTE-XSL-and-CSS) pour produire des documents lisibles dans un navigateur.
- [CSS = Cascading Stylesheet Language](https://www.w3.org/TR/CSS/) (langue de feuilles de style en cascade)
## Préparer de document de sortie
```xml
<xsl:output
method="xml"
encoding="UTF-8"
indent="yes"
doctype-public="ISO 12200:1999A//DTD MARTIF core (DXFcdV04)//EN"
doctype-system="TBXcdv04.dtd"
/>
```
Ici, on va produire («output») un fichier qui sera
- du XML, de version 1.0 par défaut
- en encodage UTF-8, déclaré dans le document.
- Ses lignes de la sortie seront mises en retrait en fonction de leur emboîtement
- Son `doctype` public et le `doctype` local sont également définis ici, et ils spécifient que le document sera un document TBX.
### Références:
- [Output](https://www.w3.org/TR/1999/REC-xslt-19991116#output)
## Définir la feuille de transformation
```xml
<xsl:template match="/">
<martif type="TBX" xml:lang="en">
<martifHeader>
<fileDesc>
<sourceDesc>
<p>tmx2tbx</p>
</sourceDesc>
</fileDesc>
</martifHeader>
<text>
<body>
<xsl:apply-templates select="tmx/body/tu"/>
</body>
</text>
</martif>
</xsl:template>
```
Une feuille de transformation fonctionne en gros de la manière suivante:
- on définit une «template» (un modèle) qui sapplique à certains éléments du fichier dorigine (ici, des parties du fichier TMX que nous cherchons à transformer en fichier TBX)
- on définit dans ce «modèle» les manières de transformer ces éléments (pour produire ici des parties du fichier TBX final).
Notre premier modèle va sappliquer à la totalité du document dorigine (TMX) car le symbole `</>` dans le contexte dune arborescence de document XML correspond à lorigine du document. Pour en savoir plus, il est nécessaire de consulter des tutoriels XPATH.
Puis on inscrit à lintérieur de la définition du modèle la manière de modifier ce contenu auquel il sapplique.
Tout ce qui se trouve entre le `<xsl:template match="/">` et le `</xsl:template>` de notre premier modèle est le contenu qui va être mis à la place de la totalité du document dorigine. Toutes les balises qui ny sont pas préfixées par `<xsl:>` sont des éléments qui seront reproduits tels quels dans le document final. En ce qui nous concerne, ces parties sont donc des éléments du fichier TBX final.
Toutes les balises préfixées par `<xsl:>` sont des directives de transformation qui ne se retrouveront pas telles quelles dans le document final. Seulement le résultat de ces directives sy retrouvera.
À lintérieur des balises TBX de notre premier modèle, on trouve une nouvelle directive XSL :
```xml
<xsl:apply-templates select="tmx/body/tu"/>
```
Cette nouvelle directive nous indique quici on va maintenant faire autre chose que dajouter des balises prédéfinies et quon va aller chercher des données à lintérieur des `<tu>` du fichier TMX dorigine, qui se trouvent à lintérieur de `tmx/body`. Cette notation avec des `</>` indique la hiérarchie entre les éléments:
`/` est lorigine du document
`tmx` est la balise racine du document (tout document XML a une balise racine, pour un fichier TMX cest la balise `<tmx>`, pour un fichier TBX cest la balise `<martif>`).
`tmx/body` est une balise body qui est directement incluse dans la balise `<tmx>`
`tmx/body/tu` est une balise tu qui est directement incluse dans la balise `<body>`, etc.
La directive nous demande donc dappliquer un autre modèle, à lintérieur du modèle principal, celle qui correspond aux éléments `<tu>` de la TMX.
### Références:
- [Defining Template Rules](https://www.w3.org/TR/1999/REC-xslt-19991116#section-Defining-Template-Rules)
- [Applying Template Rules](https://www.w3.org/TR/1999/REC-xslt-19991116#section-Applying-Template-Rules)
## Transformer les `<tu>`
```xml
<xsl:template match="tmx/body/tu">
<termEntry>
<xsl:attribute name="id">
<xsl:value-of select="tuv[1]/seg"/>
</xsl:attribute>
<note xml:lang="en">UI</note>
<xsl:apply-templates select="tuv"/>
</termEntry>
</xsl:template>
```
On retrouve ici la même structure que le premier modèle : on cherche des éléments auxquels on va appliquer une transformation.
Ici, les éléments sont les `<tu>` du document TMX dorigine.
De la même manière que le premier modèle remplaçait la totalité du document dorigine avec des balises de type TBX, ici on va remplacer les `<tu>` de la TMX dorigine par la balise TBX `<termEntry>`.
On va ajouter un attribut à cette balise. Le nom de lattribut sera `<id>` et sa valeur est définie de la manière suivante :
`<xsl:value-of select="tuv[1]/seg"/>` qui nous indique quon doit prendre la valeur de lélément sélectionné à droite: `tuv[1]/seg`
Nous nous trouvons dans le contexte dune `<tu>` puisque cest ce à quoi le modèle que nous considérons sapplique (`match="tmx/body/tu"`) et dans ce contexte, `<tuv[1]/seg>` veut dire la balise `<seg>` qui se trouve dans la première balise `<tuv>` de la balise `<tu>` considérée. Sachant que la transformation va sappliquer à toutes les balises qui correspondent à la spécification `match`.
La directive `select` nous indique que nous allons prendre le contenu (ici textuel) qui se trouve entre la balise ouvrante `<seg>` et la balise fermante `</seg>` qui constituent les éléments de base dune TMX (cf. le rappel plus haut).
Ce que nous avons défini ici cest une balise `<termEntry>` dont lattribut `id` aura pour contenu, le texte de la balise `<seg>` de la première `<tuv>` de notre `<tu>`. Vous pouvez trouver le résultat dans lexemple donné dans le rappel plus haut.
À lintérieur dune `<tu>` on a potentiellement une `<tuv>` au minimum, et parfois plus. Ici, je décide que la valeur que doit prendre le nouvel attribut `id` dun `<termEntry>` est le contenu de la balise `<seg>` qui est elle-même contenue dans le premier TUV (dans notre TMX nous en avons 2 par `<tu>`).
La syntaxe est le contenu de la balise `<seg>` à lintérieur du premier `<tuv>` : `tuv[1]/seg`.
Une fois lattribut `id` de `<termEntry>` défini, la directive `<xsl:attribute name="id">` se ferme avec
`</xsl:attribute>` et on passe à lajout dun contenu écrit en toutes lettres, qui est:
```xml
<note xml:lang="en">UI</note>
```
Cette note sera la même pour tous les `<termEntry>` de notre TBX, mais on pourrait imaginer un modèle qui y mettrait un contenu qui dépend dun élément présent dans la TMX.
Après cette note, on trouve un autre appel à un modèle, qui va cette fois travailler sur le contenu des `<tuv>` de notre TMX.
### Références:
- [Creating Attributes with xsl:attribute](https://www.w3.org/TR/1999/REC-xslt-19991116#creating-attributes)
- [Generating Text with xsl:value-of](https://www.w3.org/TR/1999/REC-xslt-19991116#value-of)
## Préciser la langue naturelle
```xml
<xsl:template match="tuv">
<langSet>
<xsl:attribute name="xml:lang">
<xsl:value-of select="@xml:lang"/>
</xsl:attribute>
<xsl:apply-templates select="seg"/>
</langSet>
</xsl:template>
```
Comme on la vu plus haut avec `<termEntry>`, on ajoute ici une balise TBX `<langSet>` à laquelle on va associer un attribut.
Cette fois-ci, la définition de lattribut utilise une autre syntaxe, mais elle va toujours sélectionner le contenu textuel dun élément.
Cet élément est spécifié avec la notation `@` ce qui signifie quil sagit non pas dune balise descendante de `<tuv>` mais dun attribut de `<tuv>`, dont le nom est `<xml-lang>`, cest-à-dire le code qui identifie la langue naturelle du contenu du segment. Cest le même code langue qui sera utilisé dans lattribut `<xml-lang>` qui, par un heureux hasard, a exactement le même nom dans TMX et dans TBX, mais ça nest pas exactement un hasard, puisque cest la méthode recommandée dans la [norme XML pour identifier des langages](https://www.w3.org/TR/REC-xml/#sec-lang-tag):
Une fois lattribut créé, on trouve un nouvel appel à un modèle, cette fois-ci pour traiter les balises `<seg>`, probablement pour associer leur contenu au contenu dun `<term>` dans le fichier TBX final.
## Récuperer et insérer le contenu du segment
```xml
<xsl:template match="seg">
<tig>
<term>
<xsl:value-of select="."/>
</term>
</tig>
</xsl:template>
```
Ce dernier modèle va mettre entre les balises <term> et </term> la valeur textuelle du contenu de `.` qui est, dans la syntaxe dun cheminement XML le lieu même du contexte, ici notre balise `<seg>`.
Nous allons donc aller chercher le contenu textuel de nos segments et les copier (sans conserver déventuelles balises XML puisque `<value-of>` ne conserve que le contenu textuel) à lintérieur des balises `<term>` de notre TBX, et avec ce dernier modèle nous avons fini notre transformation.
Il faut remarquer que tous les modèles sappliquent à tous les éléments correspondants à la spécification `match`, il nest donc pas nécessaire dans notre transformation dutiliser de boucles de traitement ([`xsl:for-each`](https://www.w3.org/TR/1999/REC-xslt-19991116#for-each)) quon utiliserait dans un langage de programmation.

62
xslt/tmx2tbx/tmx2tbx.xsl Normal file
View File

@ -0,0 +1,62 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
Ce document est une tentative pour créer une transformation XSL (XSLT) simple entre un fichier TMX (mémoire de traduction) et un fichier TBX (glossaire).
Vous trouverez des explications détaillées ici:
https://mac4translators.blogspot.com/2023/04/convertir-un-fichier-tmx-en-tbx-avec.html
Le document est un logiciel libre qui est utilisable et modifiable selon les termes de la licence GPL 3.0 (ou plus).
Copyright Sirine Ben Hadj Khalifa, Jean-Christophe Helary
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:local="http://www.w3.org/2005/xquery-local-functions">
<xsl:output method="xml" encoding="UTF-8" indent="yes" doctype-public="ISO 12200:1999A//DTD MARTIF core (DXFcdV04)//EN" doctype-system="TBXcdv04.dtd" />
<xsl:template match="/">
<martif type="TBX" xml:lang="en">
<martifHeader>
<fileDesc>
<sourceDesc>
<p>tmx2tbx</p>
</sourceDesc>
</fileDesc>
</martifHeader>
<text>
<body>
<xsl:apply-templates select="tmx/body/tu"/>
</body>
</text>
</martif>
</xsl:template>
<xsl:template match="tmx/body/tu">
<termEntry>
<xsl:attribute name="id">
<xsl:value-of select="tuv[1]/seg"/>
</xsl:attribute>
<note xml:lang="en">UI</note>
<xsl:apply-templates select="tuv"/>
</termEntry>
</xsl:template>
<xsl:template match="tuv">
<langSet>
<xsl:attribute name="xml:lang">
<xsl:value-of select="@xml:lang"/>
</xsl:attribute>
<xsl:apply-templates select="seg"/>
</langSet>
</xsl:template>
<xsl:template match="seg">
<tig>
<term>
<xsl:value-of select="."/>
</term>
</tig>
</xsl:template>
</xsl:stylesheet>