BookTranslator
BookTranslator

Cum să traduci fișiere Markdown fără a strica codul, linkurile sau front matter

Ce să traduci într-un fișier Markdown sau MDX, ce să lași neatins și cum să verifici rezultatul. Cu un fișier exemplu, un verificator gratuit și un test local cu LLM în 9 rulări.

BookTranslator

BookTranslator Team

14 min read

Pentru a traduce un fișier Markdown, traduce textul și lasă mecanismul neatins: cheile din front matter, codul, URL-urile, etichetele linkurilor, tag-urile componentelor și etichetele notelor de subsol trebuie să rămână identice byte cu byte. Apoi verifică trei lucruri pe care o traducere atentă tot le strică: linkurile către titluri, comentariile din cod și, în chineză, japoneză sau coreeană, spațierea din jurul textului aldine și a intervalelor numerice.

Am tradus o pagină MDX de 73 de linii în chineză simplificată de nouă ori cu un model local, folosind trei prompturi diferite, și am verificat fiecare rezultat cu un script. Părțile care de obicei îngrijorează au supraviețuit în toate cele nouă rulări: codul, codul inline, URL-urile, tabelul, componenta JSX și lista de sarcini. Alte trei lucruri au mers prost. Linkul către un titlu s-a stricat în toate cele nouă rulări. Comentariile din cod au fost traduse în toate cele șase rulări care au trimis întregul fișier, inclusiv în trei rulări în care promptul spunea să nu se atingă codul. Iar promptul care ascundea sintaxa în spatele unor substituenți, ceea ce sună ca opțiunea cea mai sigură, a stricat front matter în toate cele trei rulări ale sale.

Răspuns rapid: ce să traduci și ce să lași neatins

Parte a fișieruluiExemplu din fișierul nostruSe traduce?
Cheile din front matterslug:, sidebar_position:, tags:Nu
Valorile din front mattertitle: "Export Your Library"Doar cele vizibile pentru cititor, cum ar fi title și description
Importuri și exporturi (MDX)import Callout from '@site/src/components/Callout';Nu
Blocuri de codshelfmark export --format epubNu. Decide separat despre comentarii și șirurile vizibile pentru utilizator.
Cod inlinelibrary.json, --coversNu
Țintele linkurilor și imaginilor(./export-options.md), (https://www.w3.org/TR/epub-33/ "EPUB 3.3")Nu, cu excepția titlului opțional dintre ghilimele
Textul linkurilor și textul alternativ al imaginilor[glossary section], ![Folder layout after an export]Da
Etichete și definiții de referință[project glossary][glossary], [glossary]: ./glossary.md#termsPăstrează eticheta [glossary] și URL-ul; traduce textul vizibil
Titluri## Keep one glossary for the whole bookDa, dar mai întâi atribuiți-le ID-uri fixe (consultați mai jos)
Componente JSX<Callout type="warning" title="Back up first">Păstrați numele etichetelor și al atributelor; traduceți valorile atributelor vizibile pentru cititor, cum ar fi title
Marcatori de admonestare:::tip și :::Nu
Etichete de note de subsol[^sync]Nu
Comentarii MDX{/* Translator note: ... */}Opțional. Cititorii nu le văd niciodată.

Tot restul este proză obișnuită: paragrafe, elemente de listă, celule de tabel și citate de bloc.

Ce am testat

Am scris sample-source.mdx, o pagină de documentație pentru o aplicație fictivă de lectură numită Shelfmark. Este scrisă în stilul MDX folosit de Docusaurus și de site-uri similare de documentație, cu câte un exemplu pentru fiecare construct din tabelul de mai sus, plus un salt de linie forțat cu două spații, un link îngroșat, o expresie îngroșată care se termină cu o paranteză, două intervale numerice scrise cu linii de pauză și un link în pagină către titlul „Păstrați un singur glosar pentru întreaga carte”.

Apoi am rugat un model local să îl traducă în chineză simplificată în trei moduri:

  1. Fișier complet. Lipiți întregul fișier și cereți fișierul tradus înapoi.
  2. Cu instrucțiuni. La fel, plus șase reguli: păstrați cheile din front matter, nu modificați nimic din interiorul codului, păstrați URL-urile și definițiile de referință, păstrați importurile, etichetele și comentariile, păstrați etichetele notelor de subsol și marcatorii de admonestare și traduceți titlurile, textul linkurilor, textul alternativ și atributul title.
  3. Protejat. Înlocuiți codul, codul inline, URL-urile, etichetele, comentariile, etichetele notelor de subsol, marcatorii de admonestare și liniile din front matter cu substituenți numerotați precum ⟦12⟧, traduceți restul, apoi puneți originalele la loc. Valorile title și description au fost lăsate expuse pentru traducere și, după cum s-a dovedit, la fel au fost liniile --- din front matter și ghilimelele de închidere.

Modelul a fost Qwen 3.6 27B (Q4_K_M) în LM Studio, cu gândirea dezactivată și temperatura 0,3, pe un Apple M4 Max cu 64 GB de memorie. Am rulat fiecare condiție de trei ori, nouă rulări în total, pe 25 octombrie 2026. Scriptul este run_llm_markdown_test.py, iar toate cele nouă rezultate sunt publicate needitate; README listează fiecare fișier. Dacă nu ați configurat niciodată un model local, ghidul nostru de traducere cu LLM local acoperă setările.

Acesta a fost un test mic cu un singur model, o singură pereche de limbi și o singură pagină. Arată ce probleme apar și cum să le depistați. Nu clasează modelele sau prompturile.

Rezultat: Sintaxa a supraviețuit; linkurile și deciziile, nu

Am verificat fiecare rezultat cu check_markdown_translation.py și am randat fiecare rezultat cu remark și compilatorul MDX. Rezultatul complet al verificatorului este în check-results.txt, iar results.csv are câte un rând pentru fiecare rulare.

VerificareFișier completInstructatProtejat
Se compilează ca MDX3 din 33 din 33 din 3
Cod, cod inline, URL-uri, tabel, etichete, listă de sarcini neschimbate3 din 33 din 33 din 3
Aldinul și cursivele încă se afișează3 din 33 din 33 din 3
Front matter intact3 din 33 din 30 din 3
Linkul din pagină indică în continuare către titlul său0 din 30 din 30 din 3
Comentariile din cod lăsate ca în original0 din 30 din 33 din 3
Callout-ul title tradus3 din 33 din 30 din 3

Primele rânduri sunt veștile bune. Acest model a returnat sintaxa Markdown intactă când am lipit întregul fișier; nu am găsit nimic de corectat în cod, URL-uri sau tabele. Ultimele patru rânduri arată unde este de lucru, și niciunul dintre ele nu apare ca eroare când construiești site-ul.

1. Titlurile traduse rup linkurile către ele

Eșantionul face legătura către secțiunea sa de glosar cu [glossary section](#keep-one-glossary-for-the-whole-book). Fiecare rulare a tradus titlul, cum ar trebui, și fiecare rulare a păstrat ținta linkului, cum ar trebui. Rezultatul este un link către un ID care nu mai există.

Majoritatea instrumentelor Markdown construiesc ID-uri de titlu din textul titlului. Documentația Pandoc descrie identificatorul ca fiind „bazat pe textul titlului”, iar Docusaurus avertizează că s-ar putea să vrei să modifici sau să traduci un titlu „fără a actualiza ID-ul existent pentru a evita ruperea linkurilor”. Odată ce titlul devine 为整本书保留一个术语表, ID-ul generat este în chineză, iar #keep-one-glossary-for-the-whole-book nu duce nicăieri. Pagina încă se construiește, așa că nimic nu te anunță.

Nu poți remedia acest lucru nici editând linkul după traducere. În nouă rulări, modelul a scris același titlu în patru moduri diferite, așa că ID-ul generat s-ar schimba din nou la fiecare retraducere. Soluția aparține înainte de traducere: acordă fiecărui titlu către care se face legătură un ID fix.

  • În Docusaurus MDX, folosește ## Keep one glossary for the whole book {/* #keep-one-glossary */}. Docusaurus notează că forma mai veche {#id} „nu mai este sintaxă MDX validă”, iar comanda sa write-heading-ids adaugă ID-uri fiecărui document pentru tine.
  • În Pandoc și în procesoarele Markdown care urmează PHP Markdown Extra, folosește {#keep-one-glossary} la sfârșitul titlului.

ID-ul rămâne astfel același în fiecare limbă, iar verificatorul îl tratează ca țintă a linkului.

2. Comentariile din cod sunt traduse, iar șirul vizibil nu

Eșantionul are un comentariu shell și un comentariu YAML:

library:
  name: "My books"   # shown in the sidebar
  sort: title

Toate cele șase rulări care au trimis întregul fișier au tradus ambele comentarii, inclusiv cele trei în care promptul spunea „Nu modifica nimic din interiorul blocurilor de cod delimitate.” Codul în sine a rămas neatins în toate cele nouă rulări. Între timp, "My books", despre care comentariul spune că este afișat în bara laterală, a rămas în engleză în toate cele nouă rulări. Modelul a făcut opusul a ceea ce are nevoie o pagină localizată: a tradus nota pentru dezvoltatori și a lăsat eticheta pe care o vor vedea cititorii.

Nicio alegere nu este greșită în toate cazurile. Pentru un tutorial ai cărui cititori vor copia codul în propriul proiect, comentariile traduse ajută. Pentru documentația de referință al cărei cod trebuie să corespundă unui depozit, ele fac pagina să nu mai fie de acord cu sursa. Ia decizia o dată pentru proiect și verifică manual valorile șirurilor din exemplele de configurare, pentru că niciun instrument nu poate distinge o etichetă de afișare de un identificator. Verificatorul raportează modificările doar în comentarii ca avertismente din acest motiv.

3. Metoda aparent sigură a stricat front matter-ul

Condiția protejată și-a făcut treaba promisă: toate cele 32 de substituenți au revenit în toate cele trei rulări, așa că codul, URL-urile și etichetele au fost restaurate perfect. Dar scriptul nostru a lăsat două lucruri mici în afara substituenților: linia --- care deschide front matter-ul și ghilimeaua de închidere după titlul și descrierea traduse. Modelul le-a eliminat pe toate în toate cele trei rulări. Fișierul începea astfel:

title: "导出您的书库
description: "在更换设备之前,请备份您的笔记和书籍。
slug: export-library

Fără --- de deschidere, un parser Markdown nu mai vede front matter. Citește cele șase linii YAML plus --- de închidere ca pe un titlu, așa că pagina s-ar deschide cu un titlu mare care conține YAML-ul. Totuși a compilat ca MDX. Nici punerea la loc a --- nu este suficientă: parserul YAML respinge cele două ghilimele neînchise.

Lecția nu este să eviți substituenții. Ci că orice lași expus poate reveni modificat și că front matter-ul nu ar trebui trimis modelului ca parte a paginii deloc. Analizează-l, trimite doar valorile vizibile pentru cititor (title, description) ca șiruri separate și scrie traducerile înapoi în structura originală. Sunt câteva linii de cod și elimină întreaga clasă de probleme.

Text aldine și intervale în chineză, japoneză și coreeană

Încă două probleme nu au apărut niciodată în cele nouă rulări ale noastre, dar merită verificate pentru că rup paginile în tăcere, și ambele au afectat blogul propriu al BookTranslator. Blogul este scris în MDX și tradus automat în 27 de limbi, iar într-o rulare de traducere programată două articole coreene au eșuat verificarea structurii noastre de trei ori la rând. Cauzele au fost cele două modele de mai jos.

Aldin care se termină cu punctuație. CommonMark decide dacă ** poate deschide sau închide aldina uitându-se la caracterele din jurul său. Un ** de închidere care vine imediat după punctuație trebuie urmat de un spațiu, de punctuație sau de sfârșitul liniei; aceasta este regula flancării drepte. Engleza are întotdeauna un spațiu acolo. Chineza, japoneza și coreeana adesea nu au. Astfel, 打开**设置 → 导出(测试版)**并选择 afișează asteriscuri literale, deoarece aldina se termină cu o paranteză full-width și este urmată direct de 并. Aceeași linie fără paranteză se afișează cu aldina, la fel și linia cu un spațiu după **. Un link aldina are aceeași problemă, deoarece un link se termină cu ): 点击**[导出](./export-options.md)**打开 eșuează, la fel și coreeana **[API](./api.md)**는.

Modelul nostru a plasat din întâmplare un spațiu pe ambele părți ale fiecărei expresii aldine, astfel încât rezultatul său s-a afișat corect. Un editor care elimină ulterior acele spații pentru a respecta convențiile de tipărire chinezești readuce eroarea. Puteți încerca toate cele șapte variante în render-cases.md.

Intervale numerice cu tilde. Textul chinezesc și japonez scrie adesea intervalele ca 3~5. Site-urile GitHub Flavored Markdown construite pe remark transformă tildurile simple în tăiere implicit: opțiunea remark-gfm singleTilde este true dacă nu o modificați. Două intervale într-un paragraf, cum ar fi 需要 3~5 分钟,生成 10~20 MB 的文件夹, se afișează cu textul dintre ele tăiat. Eșantionul nostru a folosit cratime en, iar opt rulări le-au păstrat, în timp ce a noua a scris 3 到 5. Cereți cratime en sau cuvinte în intervale, sau setați singleTilde: false în configurația remark.

Verificatorul structural semnalează ambele modele. Pentru a confirma ce se afișează efectiv, render_check.mjs numără aldinele, italicele, tăierile și asteriscurile rămase în sursă și traducere și încearcă o compilare MDX:

npm install @mdx-js/mdx@3 unified@11 remark-parse@11 remark-gfm@4
node render_check.mjs source.mdx translated.mdx

Mai puține noduri aldine sau mai multe asteriscuri literale în traducere înseamnă că o parte din accent a încetat să se închidă.

Un flux de lucru care rezistă

  1. Remediați mai întâi ID-urile titlurilor. Adăugați ID-uri explicite la fiecare titlu către care se face legătura, în sintaxa suportată de generatorul site-ului. Faceți-o în limba sursă, o dată, și comiteți înainte de a traduce ceva.

  2. Scoateți front matter din pagină. Traduceți doar valorile vizibile pentru cititor, cum ar fi title și description, ca șiruri separate, și scrieți-le înapoi în YAML-ul original.

  3. Decideți politica pentru cod. Comentariile se traduc sau nu; șirurile afișate în exemplele de configurare se traduc sau nu. Notați-o în glosarul de traducere lângă numele produselor care nu trebuie modificate, cum ar fi Shelfmark în eșantionul nostru.

  4. Traduceți corpul. Folosiți un instrument care analizează Markdown sau trimiteți întreaga pagină cu reguli explicite. În testul nostru, trimiterea întregii pagini a păstrat sintaxa intactă; dacă folosiți substituenți, protejați constructele complete și nu lăsați nimic pe jumătate expus.

  5. Rulați verificarea structurală.

    python3 check_markdown_translation.py source.mdx translated.mdx --keep Shelfmark
    

    Compară cheile și valorile front matter, importurile, blocurile de cod, codul inline, țintele linkurilor, definițiile de referință, nivelurile titlurilor, țintele linkurilor din pagină, etichetele și atributele JSX, comentariile MDX, marcatorii de admonestare, etichetele notelor de subsol, forma tabelului, casetele listelor de sarcini, întreruperile de linie forțate, accentele care nu se pot închide, intervalele cu tilde și termenii pe care îi cereți să fie păstrați. Nu judecă calitatea traducerii.

  6. Verificați afișarea pentru ținte CJK cu render_check.mjs și adăugați un spațiu după orice ** de închidere care urmează după punctuație.

  7. Construiți site-ul și faceți clic pe linkuri. Deschideți pagina în fiecare limbă, faceți clic pe fiecare link din pagină și citiți exemplele de configurare. O construcție reușită dovedește doar că fișierul se compilează.

Pentru documentația în care acuratețea contează, pașii de terminologie și revizuire din fluxul nostru de traducere tehnică se aplică peste acestea.

Unde se potrivește BookTranslator

Traducătorul TXT al BookTranslator acceptă fișiere .txt, .md și .mdx. Conform paginii produsului, le traduce păstrând paragrafele, întreruperile de linie, caracterele speciale și structura textului și împarte fișierele mari în segmente pentru traducere conștientă de context, astfel încât puteți încărca un manual întreg sau o carte scrisă în Markdown în loc să o lipiți bucată cu bucată.

Pagina produsului nu descrie o gestionare specială pentru front matter, blocuri de cod sau componente MDX și nu am rulat acest eșantion prin BookTranslator pentru acest articol. Indiferent de instrumentul folosit, faceți pașii 1–3 înainte de traducere și pașii 5–7 după. Un titlu fără ID fix încă își pierde linkurile, iar un interval scris cu tilde încă se transformă în tăiere. Dacă publicați o carte în mai multe limbi, ghidul nostru pentru auto-publicare în mai multe limbi acoperă restul acestei sarcini.

Obțineți fișierele de test

Totul din acest test poate fi reutilizat gratuit:

Articole asociate