Comment traduire des fichiers Markdown sans casser le code, les liens ou le front matter
Ce qu'il faut traduire dans un fichier Markdown ou MDX, ce qu'il faut laisser intact, et comment vérifier le résultat. Avec un fichier d'exemple, un vérificateur gratuit et un test local de LLM en 9 exécutions.

Pour traduire un fichier Markdown, traduisez la prose et laissez la mécanique tranquille : les clés du front matter, le code, les URL, les libellés de liens, les balises de composants et les étiquettes de notes de bas de page doivent revenir octet pour octet. Vérifiez ensuite trois choses qu'une traduction soignée casse encore : les liens vers des titres, les commentaires de code et, en chinois, japonais ou coréen, l'espacement autour du texte en gras et des plages numériques.
Nous avons traduit une page MDX de 73 lignes en chinois simplifié neuf fois avec un modèle local, en utilisant trois invites différentes, et avons vérifié chaque résultat avec un script. Les parties qui inquiètent habituellement ont survécu dans les neuf exécutions : le code, le code en ligne, les URL, le tableau, le composant JSX et la liste de tâches. Trois autres choses ont mal tourné. Le lien vers un titre s'est cassé dans les neuf exécutions. Les commentaires de code ont été traduits dans les six exécutions qui envoyaient le fichier entier, y compris trois exécutions où l'invite demandait de ne pas toucher au code. Et l'invite qui masquait la syntaxe derrière des espaces réservés, qui semble être l'option la plus sûre, a cassé le front matter dans ses trois exécutions.
Réponse rapide : ce qu'il faut traduire et ce qu'il faut laisser intact
| Partie du fichier | Exemple de notre échantillon | Faut-il le traduire ? |
|---|---|---|
| Clés du front matter | slug:, sidebar_position:, tags: | Non |
| Valeurs du front matter | title: "Export Your Library" | Uniquement celles destinées au lecteur, comme title et description |
| Imports et exports (MDX) | import Callout from '@site/src/components/Callout'; | Non |
| Blocs de code | shelfmark export --format epub | Non. Décidez séparément pour les commentaires et les chaînes destinées à l'utilisateur. |
| Code en ligne | library.json, --covers | Non |
| Cibles des liens et des images | (./export-options.md), (https://www.w3.org/TR/epub-33/ "EPUB 3.3") | Non, sauf le titre facultatif entre guillemets |
| Texte des liens et texte alternatif des images | [glossary section], ![Folder layout after an export] | Oui |
| Étiquettes et définitions de référence | [project glossary][glossary], [glossary]: ./glossary.md#terms | Conservez l'étiquette [glossary] et l'URL ; traduisez le texte visible |
| Titres | ## Keep one glossary for the whole book | Oui, mais donnez-leur d'abord des ID fixes (voir ci-dessous) |
| Composants JSX | <Callout type="warning" title="Back up first"> | Conservez les noms de balises et d'attributs ; traduisez les valeurs d'attributs destinées au lecteur, comme title |
| Marqueurs d'admonition | :::tip et ::: | Non |
| Étiquettes de notes de bas de page | [^sync] | Non |
| Commentaires MDX | {/* Translator note: ... */} | Facultatif. Les lecteurs ne les voient jamais. |
Tout le reste est de la prose ordinaire : paragraphes, éléments de liste, cellules de tableau et citations.
Ce que nous avons testé
Nous avons rédigé sample-source.mdx, une page de documentation pour une application de lecture fictive appelée Shelfmark. Elle est écrite dans le style MDX utilisé par Docusaurus et les sites de documentation similaires, avec un exemple de chaque construction du tableau ci-dessus, plus un saut de ligne forcé de deux espaces, un lien en gras, une phrase en gras se terminant par une parenthèse, deux plages de nombres écrites avec des tirets demi-cadratin, et un lien interne vers le titre « Conserver un glossaire pour tout le livre ».
Ensuite, nous avons demandé à un modèle local de le traduire en chinois simplifié de trois manières :
- Fichier entier. Collez le fichier complet et demandez le fichier traduit en retour.
- Avec instructions. Idem, plus six règles : conserver les clés du front matter, ne rien modifier à l'intérieur du code, conserver les URL et les définitions de référence, conserver les imports, les balises et les commentaires, conserver les étiquettes de notes de bas de page et les marqueurs d'admonition, et traduire les titres, le texte des liens, le texte alternatif et l'attribut
title. - Protégé. Remplacez le code, le code en ligne, les URL, les balises, les commentaires, les étiquettes de notes de bas de page, les marqueurs d'admonition et les lignes du front matter par des espaces réservés numérotés tels que
⟦12⟧, traduisez le reste, puis remettez les originaux en place. Les valeurstitleetdescriptionont été laissées exposées pour la traduction, et il s'est avéré que les lignes---du front matter et les guillemets fermants l'étaient aussi.
Le modèle était Qwen 3.6 27B (Q4_K_M) dans LM Studio, avec la réflexion désactivée et une température de 0,3, sur un Apple M4 Max avec 64 Go de mémoire. Nous avons exécuté chaque condition trois fois, soit neuf exécutions au total, le 25 octobre 2026. Le script est run_llm_markdown_test.py, et les neuf sorties sont publiées sans modification ; le README liste chaque fichier. Si vous n'avez jamais configuré de modèle local, notre guide de traduction avec un LLM local couvre les réglages.
Il s'agissait d'un petit test portant sur un modèle, une paire de langues et une page. Il montre quels problèmes surviennent et comment les détecter. Il ne classe pas les modèles ni les prompts.
Résultat : la syntaxe a survécu ; les liens et les décisions, non
Nous avons vérifié chaque sortie avec check_markdown_translation.py et rendu chacune avec remark et le compilateur MDX. La sortie complète du vérificateur se trouve dans check-results.txt, et results.csv contient une ligne par exécution.
| Vérification | Fichier entier | Instruit | Protégé |
|---|---|---|---|
| Compile en MDX | 3 sur 3 | 3 sur 3 | 3 sur 3 |
| Code, code en ligne, URL, tableau, balises et liste de tâches inchangés | 3 sur 3 | 3 sur 3 | 3 sur 3 |
| Le gras et l'italique s'affichent toujours | 3 sur 3 | 3 sur 3 | 3 sur 3 |
| Front matter intact | 3 sur 3 | 3 sur 3 | 0 sur 3 |
| Le lien interne pointe toujours vers son titre | 0 sur 3 | 0 sur 3 | 0 sur 3 |
| Commentaires de code laissés tels quels | 0 sur 3 | 0 sur 3 | 3 sur 3 |
Le title de l'encadré traduit | 3 sur 3 | 3 sur 3 | 0 sur 3 |
Les premières lignes sont les bonnes nouvelles. Ce modèle a renvoyé la syntaxe Markdown intacte lorsque nous avons collé le fichier entier ; nous n'avons rien trouvé à corriger dans le code, les URL ou les tableaux. Les quatre dernières lignes sont là où le travail se trouve, et aucune d'elles n'apparaît comme une erreur lors de la compilation du site.
1. Les titres traduits cassent les liens vers eux
L'échantillon renvoie à sa section glossaire avec [glossary section](#keep-one-glossary-for-the-whole-book). Chaque exécution a traduit le titre, comme il se doit, et chaque exécution a conservé la cible du lien, comme il se doit. Le résultat est un lien vers un ID qui n'existe plus.
La plupart des outils Markdown génèrent les ID de titre à partir du texte du titre. La documentation de Pandoc décrit l'identifiant comme « basé sur le texte du titre », et Docusaurus avertit que vous pourriez vouloir modifier ou traduire un titre « sans mettre à jour l'ID existant pour éviter de casser les liens ». Une fois que le titre se lit 为整本书保留一个术语表, son ID généré est en chinois, et #keep-one-glossary-for-the-whole-book ne mène nulle part. La page se compile toujours, donc rien ne vous le signale.
Vous ne pouvez pas non plus corriger cela en modifiant le lien après la traduction. Sur neuf exécutions, le modèle a écrit le même titre de quatre manières différentes, de sorte que l'ID généré changerait à nouveau à chaque retraduction. La correction doit se faire avant la traduction : attribuez à chaque titre lié un ID fixe.
- Dans MDX de Docusaurus, utilisez
## Keep one glossary for the whole book {/* #keep-one-glossary */}. Docusaurus note que l'ancienne forme{#id}n'est « plus une syntaxe MDX valide », et sa commandewrite-heading-idsajoute des ID à chaque document pour vous. - Dans Pandoc et dans les processeurs Markdown qui suivent PHP Markdown Extra, utilisez
{#keep-one-glossary}à la fin du titre.
L'ID reste alors le même dans toutes les langues, et le vérificateur le traite comme la cible du lien.
2. Les commentaires de code sont traduits, et la chaîne visible ne l'est pas
L'échantillon contient un commentaire shell et un commentaire YAML :
library:
name: "My books" # shown in the sidebar
sort: title
Les six exécutions qui ont envoyé le fichier entier ont traduit les deux commentaires, y compris les trois où l'invite disait « Ne changez rien à l'intérieur des blocs de code délimités. » Le code lui-même est resté intact dans les neuf exécutions. Pendant ce temps, "My books", que le commentaire indique comme affiché dans la barre latérale, est resté en anglais dans les neuf exécutions. Le modèle a fait le contraire de ce dont une page localisée a besoin : il a traduit la note pour les développeurs et a laissé l'étiquette que les lecteurs verront.
Aucun des deux choix n'est faux dans tous les cas. Pour un tutoriel dont les lecteurs copieront le code dans leur propre projet, des commentaires traduits aident. Pour une documentation de référence dont le code doit correspondre à un dépôt, ils font que la page ne correspond plus à la source. Prenez la décision une fois pour le projet, et examinez à la main les valeurs de chaîne dans les exemples de configuration, car aucun outil ne peut distinguer une étiquette d'affichage d'un identifiant. C'est pour cette raison que le vérificateur signale les modifications de commentaires uniquement comme des avertissements.
3. La méthode qui semblait sûre a cassé le front matter
La condition protégée a fait ce qu'elle promettait : les 32 espaces réservés sont revenus dans les trois exécutions, donc le code, les URL et les balises ont été restaurés parfaitement. Mais notre script a laissé deux petites choses en dehors des espaces réservés : la ligne --- qui ouvre le front matter, et le guillemet fermant après le titre et la description traduits. Le modèle les a tous supprimés dans les trois exécutions. Le fichier commençait ainsi :
title: "导出您的书库
description: "在更换设备之前,请备份您的笔记和书籍。
slug: export-library
Sans le --- d'ouverture, un analyseur Markdown ne voit plus de front matter. Il lit les six lignes YAML plus le --- de fermeture comme un titre, donc la page s'ouvrirait avec un grand titre contenant le YAML. Elle compilait toujours en MDX. Remettre le --- ne suffit pas non plus : l'analyseur YAML rejette les deux guillemets non fermés.
La leçon n'est pas d'éviter les espaces réservés. C'est que tout ce que vous laissez exposé peut revenir modifié, et que le front matter ne devrait pas du tout être envoyé au modèle dans le cadre de la page. Analysez-le, envoyez uniquement les valeurs destinées au lecteur (title, description) sous forme de chaînes séparées, et réécrivez les traductions dans la structure d'origine. Cela représente quelques lignes de code et élimine toute cette classe de problèmes.
Texte en gras et plages en chinois, japonais et coréen
Deux autres problèmes ne sont jamais apparus dans nos neuf exécutions, mais ils valent la peine d'être vérifiés car ils cassent les pages silencieusement, et tous deux ont touché le blog de BookTranslator lui-même. Le blog est écrit en MDX et traduit automatiquement en 27 langues, et lors d'une exécution de traduction planifiée, deux articles coréens ont échoué à notre vérification de structure trois fois de suite. Les causes étaient les deux motifs ci-dessous.
Gras terminé par une ponctuation. CommonMark décide si ** peut ouvrir ou fermer du gras en examinant les caractères qui l'entourent. Un ** de fermeture qui suit immédiatement une ponctuation doit être suivi d'un espace, d'une ponctuation ou de la fin de la ligne ; c'est la règle du délimiteur à flanc droit. L'anglais a toujours un espace à cet endroit. Le chinois, le japonais et le coréen souvent pas. Ainsi 打开**设置 → 导出(测试版)**并选择 affiche des astérisques littéraux, car le gras se termine par une parenthèse pleine largeur et est suivi directement de 并. La même ligne sans la parenthèse s'affiche en gras, tout comme la ligne avec un espace après le **. Un lien en gras a le même problème, car un lien se termine par ) : 点击**[导出](./export-options.md)**打开 échoue, tout comme le coréen **[API](./api.md)**는.
Notre modèle a mis un espace des deux côtés de chaque expression en gras, donc sa sortie s'affichait correctement. Un éditeur qui retire ensuite ces espaces pour suivre les conventions typographiques chinoises fait réapparaître le bug. Vous pouvez essayer les sept variantes dans render-cases.md.
Plages numériques avec un tilde. Les textes chinois et japonais écrivent souvent les plages sous la forme 3~5. Les sites GitHub Flavored Markdown construits sur remark transforment les tildes simples en barré par défaut : l'option singleTilde de remark-gfm vaut true sauf si vous la modifiez. Deux plages dans un même paragraphe, comme 需要 3~5 分钟,生成 10~20 MB 的文件夹, s'affichent avec le texte entre elles barré. Notre échantillon utilisait des tirets demi-cadratin, et huit exécutions les ont conservés tandis que la neuvième a écrit 3 到 5. Demandez des tirets demi-cadratin ou des mots pour les plages, ou définissez singleTilde: false dans votre configuration remark.
Le vérificateur structurel signale les deux motifs. Pour confirmer ce qui s'affiche réellement, render_check.mjs compte les nœuds gras, italiques, barrés et les astérisques restants dans la source et la traduction, et tente une compilation MDX :
npm install @mdx-js/mdx@3 unified@11 remark-parse@11 remark-gfm@4
node render_check.mjs source.mdx translated.mdx
Moins de nœuds gras ou plus d'astérisques littéraux dans la traduction signifie qu'une emphase a cessé de se fermer.
Un flux de travail qui tient la route
-
Corrigez d'abord les ID de titres. Ajoutez des ID explicites à chaque titre vers lequel quelque chose pointe, dans la syntaxe prise en charge par votre générateur de site. Faites-le dans la langue source, une fois, et validez-le avant toute traduction.
-
Sortez le front matter de la page. Traduisez uniquement les valeurs destinées au lecteur comme
titleetdescription, sous forme de chaînes séparées, et réécrivez-les dans le YAML d'origine. -
Décidez de la politique pour le code. Commentaires traduits ou non ; chaînes affichées dans les exemples de configuration traduites ou non. Notez-le dans votre glossaire de traduction à côté des noms de produits qui ne doivent pas changer, comme Shelfmark dans notre échantillon.
-
Traduisez le corps. Utilisez un outil qui analyse le Markdown, ou envoyez la page entière avec des règles explicites. Dans notre test, envoyer la page entière a préservé la syntaxe ; si vous utilisez des espaces réservés, protégez des constructions complètes et ne laissez rien à moitié exposé.
-
Lancez la vérification structurelle.
python3 check_markdown_translation.py source.mdx translated.mdx --keep ShelfmarkElle compare les clés et valeurs du front matter, les imports, les blocs de code, le code en ligne, les cibles de liens, les définitions de références, les niveaux de titres, les cibles de liens internes, les balises et attributs JSX, les commentaires MDX, les marqueurs d'admonition, les étiquettes de notes de bas de page, la forme des tableaux, les cases de listes de tâches, les sauts de ligne forcés, les emphases qui ne peuvent pas se fermer, les plages avec tilde et les termes que vous demandez de conserver. Elle ne juge pas la qualité de la traduction.
-
Vérifiez le rendu pour les cibles CJK avec
render_check.mjs, et ajoutez un espace après tout**de fermeture qui suit une ponctuation. -
Construisez le site et cliquez sur les liens. Ouvrez la page dans chaque langue, cliquez sur chaque lien interne et lisez les exemples de configuration. Une compilation réussie prouve seulement que le fichier compile.
Pour une documentation où l'exactitude compte, les étapes de terminologie et de relecture de notre flux de traduction technique s'appliquent en plus.
Où BookTranslator intervient
Le traducteur TXT de BookTranslator accepte les fichiers .txt, .md et .mdx. Selon la page produit, il les traduit en conservant les paragraphes, les sauts de ligne, les caractères spéciaux et la structure du texte, et il découpe les gros fichiers en segments pour une traduction contextuelle, ce qui vous permet de téléverser un manuel entier ou un livre écrit en Markdown au lieu de le coller par morceaux.
La page produit ne décrit pas de traitement spécial pour le front matter, les blocs de code ou les composants MDX, et nous n'avons pas fait passer cet échantillon par BookTranslator pour cet article. Quel que soit l'outil utilisé, faites les étapes 1 à 3 avant de traduire et les étapes 5 à 7 après. Un titre sans ID fixe perd toujours ses liens, et une plage écrite avec des tildes se transforme toujours en barré. Si vous publiez un livre en plusieurs langues, notre guide pour l'auto-édition multilingue couvre le reste de ce travail.
Obtenez les fichiers de test
Tout ce qui provient de ce test est librement réutilisable :
- sample-source.mdx : l'échantillon anglais de 73 lignes ;
- check_markdown_translation.py : le vérificateur structurel (bibliothèque standard Python uniquement) ;
- render_check.mjs et render-cases.md : la vérification du rendu et les sept cas de test CJK ;
- run_llm_markdown_test.py : les trois conditions de prompt pour tout serveur local compatible OpenAI ;
- les neuf sorties du dossier outputs, avec check-results.txt et results.csv.
Articles connexes





