Markdown-bestanden vertalen zonder code, links of front matter te breken
Wat je wel en niet vertaalt in een Markdown- of MDX-bestand, en hoe je het resultaat controleert. Met een voorbeeldbestand, een gratis checker en een lokale LLM-test met 9 runs.

Om een Markdown-bestand te vertalen, vertaal je de lopende tekst en laat je de techniek met rust: front matter-sleutels, code, URL's, linklabels, componenttags en voetnootlabels moeten byte voor byte terugkomen. Controleer daarna drie dingen die een zorgvuldige vertaling alsnog breekt: links naar koppen, codecommentaar en, in het Chinees, Japans of Koreaans, de spatiëring rond vetgedrukte tekst en getalbereiken.
We hebben een MDX-pagina van 73 regels negen keer naar Vereenvoudigd Chinees vertaald met een lokaal model, met drie verschillende prompts, en elk resultaat met een script gecontroleerd. De onderdelen waar mensen zich meestal zorgen over maken, overleefden alle negen runs: code, inline code, URL's, de tabel, de JSX-component en de takenlijst. Drie andere dingen gingen mis. De link naar een kop brak in alle negen runs. Het codecommentaar werd vertaald in alle zes runs die het hele bestand verstuurden, waaronder drie runs waarin de prompt zei dat code niet aangeraakt mocht worden. En de prompt die de syntaxis achter placeholders verborg, wat als de veiligste optie klinkt, brak de front matter in alle drie de runs.
Snel antwoord: wat je vertaalt en wat je met rust laat
| Deel van het bestand | Voorbeeld uit ons voorbeeldbestand | Vertalen? |
|---|---|---|
| Front matter-sleutels | slug:, sidebar_position:, tags: | Nee |
| Front matter-waarden | title: "Export Your Library" | Alleen de waarden die de lezer ziet, zoals title en description |
| Imports en exports (MDX) | import Callout from '@site/src/components/Callout'; | Nee |
| Codeblokken | shelfmark export --format epub | Nee. Beslis apart over commentaar en strings die de gebruiker ziet. |
| Inline code | library.json, --covers | Nee |
| Link- en afbeeldingsdoelen | (./export-options.md), (https://www.w3.org/TR/epub-33/ "EPUB 3.3") | Nee, behalve de optionele titel tussen aanhalingstekens |
| Linktekst en alt-tekst van afbeeldingen | [glossary section], ![Folder layout after an export] | Ja |
| Referentielabels en -definities | [project glossary][glossary], [glossary]: ./glossary.md#terms | Houd het label [glossary] en de URL; vertaal de zichtbare tekst |
| Koppen | ## Keep one glossary for the whole book | Ja, maar geef ze eerst vaste ID's (zie hieronder) |
| JSX-componenten | <Callout type="warning" title="Back up first"> | Behoud tag- en attribuutnamen; vertaal attribuutwaarden die lezers zien, zoals title |
| Admonition-markeringen | :::tip en ::: | Nee |
| Voetnootlabels | [^sync] | Nee |
| MDX-opmerkingen | {/* Translator note: ... */} | Optioneel. Lezers zien ze nooit. |
Al het overige is gewone tekst: alinea's, lijstitems, tabelcellen en blockquotes.
Wat we hebben getest
We schreven sample-source.mdx, een documentatiepagina voor een fictieve leesapp genaamd Shelfmark. Het is geschreven in de MDX-stijl die Docusaurus en vergelijkbare documentatiesites gebruiken, met één voorbeeld van elk construct uit de bovenstaande tabel, plus een harde regelafbreking met twee spaties, een vette link, een vette zin die eindigt op een haakje, twee getalbereiken met en-dashes, en een link binnen de pagina naar de kop "Houd één woordenlijst voor het hele boek aan."
Daarna vroegen we een lokaal model om het op drie manieren naar Vereenvoudigd Chinees te vertalen:
- Heel bestand. Plak het hele bestand en vraag om het vertaalde bestand terug.
- Met instructies. Hetzelfde, plus zes regels: behoud de front matter-sleutels, wijzig niets binnen code, behoud URL's en referentiedefinities, behoud imports, tags en opmerkingen, behoud voetnootlabels en admonition-markeringen, en vertaal koppen, linktekst, alt-tekst en het
title-attribuut. - Beschermd. Vervang code, inline code, URL's, tags, opmerkingen, voetnootlabels, admonition-markeringen en front matter-regels door genummerde placeholders zoals
⟦12⟧, vertaal de rest en zet daarna de originelen terug. De waarden vantitleendescriptionbleven zichtbaar voor vertaling, en zoals bleek ook de----regels van de front matter en de afsluitende aanhalingstekens.
Het model was Qwen 3.6 27B (Q4_K_M) in LM Studio, met thinking uitgeschakeld en temperatuur 0,3, op een Apple M4 Max met 64 GB geheugen. We voerden elke conditie drie keer uit, negen runs in totaal, op 25 oktober 2026. Het script is run_llm_markdown_test.py, en alle negen uitvoer is ongewijzigd gepubliceerd; de README vermeldt elk bestand. Als je nog nooit een lokaal model hebt opgezet, behandelt onze handleiding voor lokaal LLM-vertalen de instellingen.
Dit was een kleine test met één model, één talenpaar en één pagina. Het laat zien welke problemen optreden en hoe je ze kunt opsporen. Het rangschikt geen modellen of prompts.
Resultaat: de syntaxis overleefde; de links en beslissingen niet
We controleerden elke uitvoer met check_markdown_translation.py en renderden elk bestand met remark en de MDX-compiler. De volledige uitvoer van de checker staat in check-results.txt, en results.csv bevat één rij per run.
| Controle | Heel bestand | Geïnstrueerd | Beschermd |
|---|---|---|---|
| Compileert als MDX | 3 van 3 | 3 van 3 | 3 van 3 |
| Code, inline code, URL's, tabel, tags, takenlijst ongewijzigd | 3 van 3 | 3 van 3 | 3 van 3 |
| Vet en cursief worden nog steeds weergegeven | 3 van 3 | 3 van 3 | 3 van 3 |
| Front matter intact | 3 van 3 | 3 van 3 | 0 van 3 |
| Link op de pagina wijst nog steeds naar de juiste kop | 0 van 3 | 0 van 3 | 0 van 3 |
| Codecommentaar ongewijzigd gelaten | 0 van 3 | 0 van 3 | 3 van 3 |
Callout-title vertaald | 3 van 3 | 3 van 3 | 0 van 3 |
De eerste rijen zijn het goede nieuws. Dit model gaf de Markdown-syntaxis intact terug toen we het hele bestand plakten; we vonden niets om te repareren in code, URL's of tabellen. De laatste vier rijen zijn waar het werk zit, en geen ervan verschijnt als een fout wanneer je de site bouwt.
1. Vertaalde koppen breken links ernaar
Het voorbeeld linkt naar zijn glossarium-sectie met [glossary section](#keep-one-glossary-for-the-whole-book). Elke run vertaalde de kop, zoals het hoort, en elke run behield het linkdoel, zoals het hoort. Het resultaat is een link naar een ID dat niet meer bestaat.
De meeste Markdown-tools bouwen kop-ID's op basis van de koptekst. Pandoc's documentatie beschrijft de identifier als "gebaseerd op de koptekst", en Docusaurus waarschuwt dat je een kop wilt wijzigen of vertalen "zonder de bestaande ID bij te werken om links niet te breken". Zodra de kop 为整本书保留一个术语表 luidt, is de gegenereerde ID Chinees, en #keep-one-glossary-for-the-whole-book scrollt nergens heen. De pagina bouwt nog steeds, dus niets vertelt je het.
Je kunt dit ook niet oplossen door de link na vertaling te bewerken. Over negen runs schreef het model dezelfde kop op vier verschillende manieren, dus de gegenereerde ID zou bij elke hervertaling opnieuw veranderen. De oplossing hoort vóór de vertaling: geef elke kop waarnaar gelinkt wordt een vaste ID.
- Gebruik in Docusaurus MDX
## Keep one glossary for the whole book {/* #keep-one-glossary */}. Docusaurus merkt op dat de oudere{#id}-vorm "niet langer geldige MDX-syntaxis" is, en zijnwrite-heading-ids-commando voegt automatisch ID's toe aan elk document. - Gebruik in Pandoc en in Markdown-processors die PHP Markdown Extra volgen
{#keep-one-glossary}aan het einde van de kop.
De ID blijft dan hetzelfde in elke taal, en de checker behandelt het als het linkdoel.
2. Codecommentaar wordt vertaald, en de zichtbare string niet
Het voorbeeld heeft een shell-commentaar en een YAML-commentaar:
library:
name: "My books" # shown in the sidebar
sort: title
Alle zes runs die het hele bestand stuurden, vertaalden beide commentaren, inclusief de drie waarin de prompt zei: "Verander niets binnen afgebakende codeblokken." De code zelf bleef in alle negen runs onaangeroerd. Ondertussen bleef "My books", waarvan het commentaar zegt dat het in de zijbalk wordt getoond, in alle negen runs in het Engels. Het model deed het tegenovergestelde van wat een gelokaliseerde pagina nodig heeft: het vertaalde de notitie voor ontwikkelaars en liet het label staan dat lezers zullen zien.
Geen van beide keuzes is in elk geval verkeerd. Voor een tutorial waarvan lezers de code in hun eigen project kopiëren, helpen vertaalde commentaren. Voor referentiedocumentatie waarvan de code moet overeenkomen met een repository, zorgen ze ervoor dat de pagina niet meer overeenkomt met de bron. Neem de beslissing één keer voor het project, en bekijk stringwaarden in configuratievoorbeelden handmatig, want geen enkele tool kan een weergavelabel van een identifier onderscheiden. De checker meldt wijzigingen die alleen commentaar betreffen daarom als waarschuwingen.
3. De veilig lijkende methode brak de front matter
De beschermde conditie deed wat ze beloofde: alle 32 placeholders kwamen terug in alle drie runs, dus code, URL's en tags werden perfect hersteld. Maar ons script liet twee kleine dingen buiten de placeholders: de ----regel die de front matter opent, en het afsluitende aanhalingsteken na de vertaalde titel en beschrijving. Het model liet ze allemaal vallen in alle drie runs. Het bestand begon zo:
title: "导出您的书库
description: "在更换设备之前,请备份您的笔记和书籍。
slug: export-library
Zonder de openings---- ziet een Markdown-parser geen front matter meer. Het leest de zes YAML-regels plus de afsluitende --- als een kop, dus de pagina zou openen met een grote kop die de YAML bevat. Het compileerde nog steeds als MDX. De --- terugzetten is ook niet genoeg: de YAML-parser verwerpt de twee niet-afgesloten aanhalingstekens.
De les is niet om placeholders te vermijden. Het is dat wat je blootstelt, gewijzigd kan terugkomen, en dat front matter helemaal niet als onderdeel van de pagina naar het model moet. Parseer het, stuur alleen de lezersgerichte waarden (title, description) als afzonderlijke strings, en schrijf de vertalingen terug in de oorspronkelijke structuur. Dat is een paar regels code en verwijdert de hele klasse van problemen.
Vetgedrukte tekst en bereiken in het Chinees, Japans en Koreaans
Twee andere problemen verschenen nooit in onze negen runs, maar ze zijn het controleren waard omdat ze pagina's stilzwijgend breken, en beide hebben BookTranslator's eigen blog getroffen. De blog is geschreven in MDX en machinaal vertaald naar 27 talen, en in één geplande vertaalrun faalden twee Koreaanse artikelen onze structuurcheck drie herpogingen op rij. De oorzaken waren de twee onderstaande patronen.
Vetgedrukte tekst die eindigt met leesteken. CommonMark bepaalt of ** vetgedrukte tekst kan openen of sluiten door naar de tekens aan weerszijden te kijken. Een afsluitende ** die direct na een leesteken komt, moet worden gevolgd door een spatie, een leesteken of het einde van de regel; dit is de right-flanking rule. In het Engels staat daar altijd een spatie. In het Chinees, Japans en Koreaans vaak niet. Dus 打开**设置 → 导出(测试版)**并选择 toont letterlijke asterisken, omdat de vetgedrukte tekst eindigt met een volledige breedte haakje en direct wordt gevolgd door 并. Dezelfde regel zonder het haakje wordt wel vet weergegeven, en dat geldt ook voor de regel met een spatie na de **. Een vetgedrukte link heeft hetzelfde probleem, omdat een link eindigt met ): 点击**[导出](./export-options.md)**打开 mislukt, en het Koreaanse **[API](./api.md)**는 ook.
Ons model zette toevallig een spatie aan beide zijden van elke vetgedrukte frase, dus de uitvoer werd correct weergegeven. Een redacteur die die spaties later verwijdert om Chinese typografische conventies te volgen, haalt de bug terug. Je kunt alle zeven varianten uitproberen in render-cases.md.
Getalbereiken met een tilde. Chinese en Japanse tekst schrijft bereiken vaak als 3~5. GitHub Flavored Markdown-sites die op remark zijn gebouwd, zetten enkele tildes standaard om in doorhalen: de remark-gfm-optie singleTilde staat op true tenzij je dat wijzigt. Twee bereiken in één alinea, zoals 需要 3~5 分钟,生成 10~20 MB 的文件夹, worden weergegeven met de tekst ertussen doorgestreept. Ons voorbeeld gebruikte en-dashes, en acht runs behielden die terwijl de negende 3 到 5 schreef. Vraag om en-dashes of woorden in bereiken, of zet singleTilde: false in je remark-configuratie.
De structuurcontrole markeert beide patronen. Om te bevestigen wat er werkelijk wordt weergegeven, telt render_check.mjs vetgedrukte tekst, cursief, doorhalen en overgebleven asterisken in de bron en de vertaling, en probeert een MDX-compilatie:
npm install @mdx-js/mdx@3 unified@11 remark-parse@11 remark-gfm@4
node render_check.mjs source.mdx translated.mdx
Minder vetgedrukte nodes of meer letterlijke asterisken in de vertaling betekent dat sommige nadruk niet meer sluit.
Een werkwijze die standhoudt
-
Los eerst de heading-ID's op. Voeg expliciete ID's toe aan elke heading waarnaar iets linkt, in de syntaxis die je sitegenerator ondersteunt. Doe dit in de brontaal, één keer, en commit het voordat er iets wordt vertaald.
-
Haal front matter van de pagina af. Vertaal alleen waarden die voor de lezer bedoeld zijn, zoals
titleendescription, als afzonderlijke strings, en schrijf ze terug in de oorspronkelijke YAML. -
Bepaal het codebeleid. Commentaar vertaald of niet; weergaveteksten in configuratievoorbeelden vertaald of niet. Leg het vast in je vertaalwoordenlijst naast de productnamen die niet mogen veranderen, zoals Shelfmark in ons voorbeeld.
-
Vertaal de body. Gebruik een tool die Markdown parseert, of stuur de hele pagina met expliciete regels. In onze test bleef de syntaxis intact bij het versturen van de hele pagina; als je placeholders gebruikt, bescherm dan volledige constructies en laat niets half open.
-
Voer de structuurcontrole uit.
python3 check_markdown_translation.py source.mdx translated.mdx --keep ShelfmarkHet vergelijkt front matter-sleutels en -waarden, imports, codeblokken, inline code, linkdoelen, referentiedefinities, headingniveaus, linkdoelen binnen de pagina, JSX-tags en -attributen, MDX-commentaar, admonition-markeringen, voetnootlabels, tabelvorm, taaklijstvakjes, harde regeleinden, nadruk die niet kan sluiten, tilde-bereiken en termen die je wilt behouden. Het beoordeelt de vertaalkwaliteit niet.
-
Controleer de weergave voor CJK-doelen met
render_check.mjs, en voeg een spatie toe na elke afsluitende**die op een leesteken volgt. -
Bouw de site en klik op de links. Open de pagina in elke taal, klik op elke link binnen de pagina en lees de configuratievoorbeelden. Een geslaagde build bewijst alleen dat het bestand compileert.
Voor documentatie waar nauwkeurigheid belangrijk is, gelden de terminologie- en reviewstappen uit onze technische vertaalworkflow bovenop dit alles.
Waar BookTranslator past
BookTranslator's TXT-vertaler accepteert .txt-, .md- en .mdx-bestanden. Volgens de productpagina vertaalt hij ze met behoud van alinea's, regeleinden, speciale tekens en tekststructuur, en splitst hij grote bestanden in segmenten voor contextbewuste vertaling, zodat je een hele handleiding of een boek in Markdown kunt uploaden in plaats van het in stukjes te plakken.
De productpagina beschrijft geen speciale behandeling voor front matter, codeblokken of MDX-componenten, en we hebben dit voorbeeld voor dit artikel niet door BookTranslator gehaald. Welke tool je ook gebruikt, doe stap 1 tot en met 3 vóór het vertalen en stap 5 tot en met 7 erna. Een heading zonder vaste ID verliest nog steeds zijn links, en een bereik met tildes wordt nog steeds doorgestreept. Als je een boek in meerdere talen uitgeeft, behandelt onze gids voor self-publishing in meerdere talen de rest van die klus.
Download de testbestanden
Alles uit deze test is vrij te hergebruiken:
- sample-source.mdx: het Engelse voorbeeld van 73 regels;
- check_markdown_translation.py: de structuurcontrole (alleen Python-standaardbibliotheek);
- render_check.mjs en render-cases.md: de weergavecontrole en de zeven CJK-testgevallen;
- run_llm_markdown_test.py: de drie promptcondities voor elke OpenAI-compatibele lokale server;
- de negen uitvoerbestanden in de map met uitvoerbestanden, met check-results.txt en results.csv.
Gerelateerde berichten





