Cet article est une version légèrement remaniée de l’article que j’avais publié en avril 2023 sur mon blog Mac For Translators : Convertir un fichier TMX en TBX avec une transformation XSLT.
<?xml version='1.0' encoding="UTF-8"?>
<!--
Comment utiliser ce document
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 d’utiliser la TMX créée à partir de la traduction d’un fichier des chaines de l’interface utilisateur d’un logiciel et d’utiliser le contenu en tant que glossaire pour vérifier que les chaines de l’IU sont bien traduites dans les documents qui la décrivent (manuels, etc.)
La transformation a été écrite par madame 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.
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
Le document peut être utilisé en l’état, car les explications sont toutes à l’intérieur de commentaires XML et ne gênent en aucun cas le traitement du document.
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.
Références générales
Les sections qui suivent donnent les éléments de base pour comprendre la discussion. Il est cependant utile d’avoir une expérience de la manipulation des types de fichiers dont nous parlons ici pour éviter les erreurs et devenir capable d’étendre soi-même le code présenté ici.
TMX = Translation Memory eXchange
TMX est un format d’échange de mémoire de traduction.
https://www.gala-global.org/tmx-14b
Rappel sur la structure d’une 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.
Voici un élément de TMX qui s’inspire de la traduction d’OmegaT :
<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
TBX est un format d’échange de base terminologique
https://www.iso.org/schema/isosts/v0.6/doc/tbx/
Rappel sur la structure d’un 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.
Voici l’élément de TBX qui a été créé à partir de l’élément TMX ci-dessus. On remarque que les hiérarchies TMX et TBX ont une structure extrêmement similaire :
<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>
XML
-
XML = eXtensible Markup Language (langue extensible de balisage)
XML est un ensemble de règles qui permet de définir des langues de balisage de document.
TMX, TBX, les recommandations qui font partie de XSL (voir ci-dessous), mais également XLIFF, SRX, etc., sont des langues de balisage définies par les règles de la norme XML.
XSL
-
XSL = eXtensible Stylesheet Language (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 d’un document XML
https://www.w3.org/TR/xslt-10/
- XPATH = XML Path Language, qui est utilisé pour trouver son chemin dans un document XML et également identifier les éléments qui seront la cible d’une transformation
https://www.w3.org/TR/xpath-10/
- 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 pour produire des documents lisibles dans un navigateur.
-
CSS = Cascading Stylesheet Language (langue de feuilles de style en cascade)
Logiciels permettant le traitement de XSLT
-
Rainbow
-
xsltproc
xsltproc est un utilitaire qui fonctionne sur la ligne de commande. Il est disponible sur Linux, macOS et 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
-->
<!--
L’élément stylesheet
https://www.w3.org/TR/1999/REC-xslt-19991116#stylesheet-element
-->
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:local="http://www.w3.org/2005/xquery-local-functions">
<!--
Syntaxe d’un document xml
La syntaxe d’un document XML est très claire, mais les ajouts de crochets et autres décorations rendent sa lecture difficile à un être humain.
C’est pour ceci que lorsque l’on publie des documents XML, en plus de la colorisation automatique des contenus, il est préférable d’utiliser des fonctions automatiques de mise en retrait des lignes en fonction de leur niveau d’emboitement, et donc d’utiliser correctement l’emboitement et 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 d’une 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 d’une 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 (ici
stylesheet) - les attributs de la balise, avec pour chaque attribut son nom et sa valeur (ici
versionqui a pour valeur1.0, ainsi que deux autres attributs :xmlns:xsletxmlns:local, avec leurs valeurs respectives) - le contenu de la balise : ici la totalité du document, jusqu’au </xsl:stylesheet> qui clôt le document, y compris ces commentaires explicatifs.
La plupart des langues XML autorisent des balises au contenu vide, et des valeurs d’attributs par défaut, etc.
Certaines langues autorisent le mélange à l’intérieur du document de balises provenant de langues externes. Pour s’assurer que la distinction est faite entre leurs propres balises et les balises « externes », ces langues vont systématiquement ajouter un préfixe à leurs propres balises.
C’est le cas de XSLT qui décrit une transformation à l’aide de ses propres balises et qui va utiliser des données composées de balises externes (ici des balises TMX) pour créer des données de sortie (un fichier TBX dans notre cas). Les balises XSLT seront donc toutes être préfixées avec xsl:, comme on le voit ici avec xsl:stylesheet, pour indiquer que seules ces balises sont à interpréter dans le cadre de la langue XSLT, alors que les balises non préfixées ne seront à considérer que comme des « données » sur lesquelles travailler.
-->
<!--
L’élément output
https://www.w3.org/TR/1999/REC-xslt-19991116#output
-->
<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 emboitement.
- Son
doctypepublic et ledoctypelocal sont également définis ici, et ils spécifient que le document sera un document TBX.
-->
<!--
Définir et appliquer les règles de notre modèle
- Définir les règles du modèle avec
xsl:template
https://www.w3.org/TR/1999/REC-xslt-19991116#section-Defining-Template-Rules
- Appliquer les règles du modèle avec
xsl:apply-templates
https://www.w3.org/TR/1999/REC-xslt-19991116#section-Applying-Template-Rules
Une feuille de transformation fonctionne en gros de la manière suivante :
- on définit une « template » (un modèle) qui s’applique à certains éléments du fichier d’origine (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 définir des règles pour la totalité du document d’origine (TMX), et va inclure à l’intérieur de la définition du modèle la manière de modifier ce contenu auquel il s’applique.
-->
<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>
<!--
Ce modèle définit des règles pour la totalité du document d’origine (TMX), car il est défini comme s’appliquant au contenu du symbole /. Dans le contexte d’une arborescence de document XML, le symbole / en tête de « chemin » correspond à l’origine du document (si vous souhaitez en savoir plus, il est nécessaire de consulter des tutoriels XPATH).
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 « sorti » pour créer un document TBX : toutes les balises qui ne sont pas préfixées par xsl: sont des éléments TBX qui seront reproduits tels quels dans le document 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 leur résultat s’y retrouvera.
À l’intérieur des balises TBX de notre premier modèle, on trouve ainsi une nouvelle directive XSL : <xsl:apply-templates select="tmx/body/tu"/>
Cette nouvelle directive nous indique qu’ici on va maintenant faire autre chose que d’ajouter des balises prédéfinies et qu’on va appliquer une transformation aux données à l’intérieur des tu du fichier TMX d’origine, qui se trouvent à l’intérieur de tmx/body. Cette notation avec des / qui séparent les éléments indique la hiérarchie entre ces éléments :
-
tmxest la balise racine du document.Tout document XML a une balise racine située « sous » l’origine du document qui est
/, pour un fichier TMX c’est la balisetmx, pour un fichier TBX c’est la balisemartif. Il n’est pas nécessaire de reproduire/ici, puisque nous sommes déjà dans le contexte défini par la première ligne de la directive : <xsl:template match="/"> . -
tmx/bodyest la balisebodyqui est directement « sous » la balisetmx.C’est-à-dire que la directive ne s’appliquera pas à un éventuel
bodyqui serait « sous » un autre élément, lui-même « sous »tmx. La spécification du standard TMX (cf. plus haut) fait que ceci est par définition impossible, mais c’est une notation qui simplifie la suite. -
tmx/body/tuest une balisetuqui est directement « sous » la balisebody, etc.
La directive nous demande donc d’appliquer un autre modèle, à l’intérieur du modèle principal, et cette directive s’appliquera à tous les éléments tu de la TMX qui sont directement « sous » l’élément body.
-->
<!--
Créer des attributs et du texte
- Créer des attributs avec
xsl:attribute
https://www.w3.org/TR/1999/REC-xslt-19991116#creating-attributes
- Créer du texte avec
xsl:value-of
https://www.w3.org/TR/1999/REC-xslt-19991116#value-of
Maintenant que la structure de base du fichier TBX a été créé, il nous faut remplir les éléments du glossaire avec des éléments de la TMX.
-->
<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 d’origine.
De la même manière que le premier modèle remplaçait la totalité du document d’origine avec des balises de type TBX, ici on va remplacer les tu de la TMX d’origine par la balise TBX termEntry.
On va ajouter un attribut à cette balise. Le nom de l’attribut sera id et sa valeur est définie grâce à
<xsl:value-of select="tuv[1]/seg"/>
qui nous indique qu’on doit prendre la valeur de (value-of) l’élément sélectionné à droite : tuv[1]/seg.
Nous nous trouvons dans le contexte d’une tu puisque c’est ce à quoi le modèle que nous considérons s’applique (
match="tmx/body/tu"
) et dans ce contexte,
tuv[1]/seg
veut dire la balise seg qui se trouve dans la première ([1]) balise tuv de la balise tu considérée, en n’oubliant pas que la transformation va s’appliquer de manière séquentielle à toutes les balises tu qui correspondent à la spécification match :
<xsl:template match="tmx/body/tu">
.
À l’intérieur d’une 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 d’un 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 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 d’une TMX (cf. le rappel plus haut).
Ce que nous avons défini ici, c’est une balise termEntry dont l’attribut id aura pour contenu le texte de la balise seg de la première tuv de la tu sur laquelle la transformation s’applique. Vous pouvez trouver le résultat dans l’exemple donné dans le rappel situé plus haut.
Une fois l’attribut id de termEntry défini, la directive
<xsl:attribute name="id">
se ferme avec
</xsl:attribute>
et on passe à l’ajout d’un contenu écrit en toutes lettres, qui est :
<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 d’un é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.
-->
<!--
Sélectionner des attributs avec @
Définir la langue en XML avec xml:lang
Comme on l’a fait plus haut avec termEntry, on ajoute ici une balise TBX langSet dont l’attribut principal contiendra le code langue de l’élément auquel elle se réfère.
La norme XML recommande que l’attribut xml:lang soit utilisé pour toutes les langues de balises qui utilisent sa syntaxe. C’est donc le contenu de l’attribut xml:lang des tuv de la TMX qui servira à alimenter l’attribut xml:lang des langSet du TBX.
https://www.w3.org/TR/REC-xml/#sec-lang-tag
-->
<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>
<!--
Une fois l’attribut créé, on trouve un nouvel appel à un modèle, cette fois-ci pour traiter les balises seg, pour associer leur contenu au contenu d’un term dans le fichier TBX final.
-->
<xsl:template match="seg">
<tig>
<term>
<xsl:value-of select="."/>
</term>
</tig>
</xsl:template>
</xsl:stylesheet>
<!--
Ce dernier modèle va mettre entre les balises
<term>
et
</term>
la valeur textuelle du contenu de . qui est, dans la syntaxe d’un 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) à l’intérieur des balises term de notre TBX, et avec ce dernier modèle, nous avons fini notre transformation.
-->