Jak tłumaczyć pliki Markdown bez psucia kodu, linków i front matter
Co tłumaczyć w pliku Markdown lub MDX, czego nie ruszać i jak sprawdzić wynik. Z przykładowym plikiem, darmowym checkerem i testem lokalnego LLM w 9 przebiegach.

Aby przetłumaczyć plik Markdown, tłumacz prozę, a maszynerię zostaw w spokoju: klucze front matter, kod, adresy URL, etykiety linków, tagi komponentów i etykiety przypisów muszą wrócić bajt w bajt. Następnie sprawdź trzy rzeczy, które psuje nawet staranne tłumaczenie: linki do nagłówków, komentarze w kodzie oraz — w języku chińskim, japońskim i koreańskim — odstępy wokół pogrubionego tekstu i zakresów liczbowych.
Przetłumaczyliśmy 73-wierszową stronę MDX na uproszczony chiński dziewięć razy za pomocą lokalnego modelu, używając trzech różnych promptów, i sprawdziliśmy każdy wynik skryptem. Elementy, o które ludzie zwykle się martwią, przetrwały we wszystkich dziewięciu przebiegach: kod, kod w linii, adresy URL, tabela, komponent JSX i lista zadań. Trzy inne rzeczy poszły nie tak. Link do nagłówka zepsuł się we wszystkich dziewięciu przebiegach. Komentarze w kodzie zostały przetłumaczone we wszystkich sześciu przebiegach, w których wysłano cały plik, w tym w trzech, gdzie prompt mówił, żeby nie ruszać kodu. A prompt, który ukrywał składnię za placeholderami — co brzmi jak najbezpieczniejsza opcja — zepsuł front matter we wszystkich trzech swoich przebiegach.
Szybka odpowiedź: co tłumaczyć, a czego nie ruszać
| Część pliku | Przykład z naszego pliku | Tłumaczyć? |
|---|---|---|
| Klucze front matter | slug:, sidebar_position:, tags: | Nie |
| Wartości front matter | title: "Export Your Library" | Tylko te skierowane do czytelnika, takie jak title i description |
| Importy i eksporty (MDX) | import Callout from '@site/src/components/Callout'; | Nie |
| Bloki kodu | shelfmark export --format epub | Nie. Osobno zdecyduj o komentarzach i ciągach znaków widocznych dla użytkownika. |
| Kod w linii | library.json, --covers | Nie |
| Cele linków i obrazów | (./export-options.md), (https://www.w3.org/TR/epub-33/ "EPUB 3.3") | Nie, z wyjątkiem opcjonalnego tytułu w cudzysłowie |
| Tekst linku i tekst alternatywny obrazu | [glossary section], ![Folder layout after an export] | Tak |
| Etykiety i definicje referencji | [project glossary][glossary], [glossary]: ./glossary.md#terms | Zachowaj etykietę [glossary] i adres URL; przetłumacz widoczny tekst |
| Nagłówki | ## Keep one glossary for the whole book | Tak, ale najpierw nadaj im stałe identyfikatory (patrz poniżej) |
| Komponenty JSX | <Callout type="warning" title="Back up first"> | Zachowaj nazwy tagów i atrybutów; przetłumacz wartości atrybutów widoczne dla czytelnika, takie jak title |
| Znaczniki admonicji | :::tip i ::: | Nie |
| Etykiety przypisów | [^sync] | Nie |
| Komentarze MDX | {/* Translator note: ... */} | Opcjonalnie. Czytelnicy ich nie widzą. |
Wszystko inne to zwykła proza: akapity, elementy listy, komórki tabeli i cytaty blokowe.
Co testowaliśmy
Napisaliśmy sample-source.mdx, stronę dokumentacji fikcyjnej aplikacji do czytania o nazwie Shelfmark. Jest napisana w stylu MDX używanym przez Docusaurus i podobne strony dokumentacji, z jednym przykładem każdej konstrukcji z powyższej tabeli, a do tego twardym łamaniem wiersza za pomocą dwóch spacji, pogrubionym linkiem, pogrubioną frazą kończącą się nawiasem, dwoma zakresami liczb zapisanymi z półpauzami oraz linkiem wewnątrz strony do nagłówka „Zachowaj jeden słownik dla całej książki”.
Następnie poprosiliśmy lokalny model o przetłumaczenie go na uproszczony chiński na trzy sposoby:
- Cały plik. Wklej cały plik i poproś o przetłumaczony plik z powrotem.
- Z instrukcjami. To samo plus sześć reguł: zachowaj klucze front matter, nie zmieniaj niczego w kodzie, zachowaj adresy URL i definicje referencji, zachowaj importy, tagi i komentarze, zachowaj etykiety przypisów i znaczniki admonicji oraz przetłumacz nagłówki, tekst linków, tekst alternatywny i atrybut
title. - Z ochroną. Zastąp kod, kod w linii, adresy URL, tagi, komentarze, etykiety przypisów, znaczniki admonicji i wiersze front matter numerowanymi symbolami zastępczymi, takimi jak
⟦12⟧, przetłumacz resztę, a następnie przywróć oryginały. Wartoścititleidescriptionpozostawiono odsłonięte do tłumaczenia, podobnie jak — jak się okazało — linie---front matter i zamykające cudzysłowy.
Modelem był Qwen 3.6 27B (Q4_K_M) w LM Studio, z wyłączonym myśleniem i temperaturą 0,3, na Apple M4 Max z 64 GB pamięci. Każdy warunek uruchomiliśmy trzy razy, łącznie dziewięć uruchomień, 25 października 2026 r. Skrypt to run_llm_markdown_test.py, a wszystkie dziewięć wyników opublikowano bez edycji; README wymienia każdy plik. Jeśli nigdy nie konfigurowałeś lokalnego modelu, nasz przewodnik po tłumaczeniu z lokalnym LLM omawia ustawienia.
To był mały test jednego modelu, jednej pary językowej i jednej strony. Pokazuje, jakie problemy się zdarzają i jak je wychwycić. Nie szereguje modeli ani promptów.
Wynik: Składnia przetrwała; linki i decyzje już nie
Sprawdziliśmy każdy wynik za pomocą check_markdown_translation.py i wyrenderowaliśmy każdy z nich za pomocą remark i kompilatora MDX. Pełne wyjście sprawdzania znajduje się w check-results.txt, a results.csv zawiera jeden wiersz na uruchomienie.
| Sprawdzenie | Cały plik | Zgodnie z instrukcją | Zabezpieczone |
|---|---|---|---|
| Kompiluje się jako MDX | 3 z 3 | 3 z 3 | 3 z 3 |
| Kod, kod w linii, adresy URL, tabela, znaczniki, lista zadań bez zmian | 3 z 3 | 3 z 3 | 3 z 3 |
| Pogrubienie i kursywa nadal się renderują | 3 z 3 | 3 z 3 | 3 z 3 |
| Front matter nienaruszony | 3 z 3 | 3 z 3 | 0 z 3 |
| Link w obrębie strony nadal wskazuje swój nagłówek | 0 z 3 | 0 z 3 | 0 z 3 |
| Komentarze w kodzie pozostawione bez zmian | 0 z 3 | 0 z 3 | 3 z 3 |
Przetłumaczono title w Callout | 3 z 3 | 3 z 3 | 0 z 3 |
Pierwsze wiersze to dobra wiadomość. Ten model zwrócił składnię Markdown w nienaruszonym stanie, gdy wkleiliśmy cały plik; nie znaleźliśmy nic do poprawienia w kodzie, adresach URL ani tabelach. Ostatnie cztery wiersze to miejsce, w którym jest praca, i żaden z nich nie pojawia się jako błąd podczas budowania strony.
1. Przetłumaczone nagłówki psują linki do nich
Przykład linkuje do swojej sekcji słowniczka za pomocą [glossary section](#keep-one-glossary-for-the-whole-book). Każde uruchomienie tłumaczyło nagłówek, jak powinno, i każde uruchomienie zachowywało cel linku, jak powinno. Wynikiem jest link do identyfikatora, który już nie istnieje.
Większość narzędzi Markdown tworzy identyfikatory nagłówków na podstawie tekstu nagłówka. Dokumentacja Pandoca opisuje identyfikator jako „oparty na tekście nagłówka”, a Docusaurus ostrzega, że możesz chcieć zmienić lub przetłumaczyć nagłówek „bez aktualizowania istniejącego identyfikatora, aby uniknąć psucia linków”. Gdy nagłówek brzmi 为整本书保留一个术语表, jego wygenerowany identyfikator jest chiński, a #keep-one-glossary-for-the-whole-book nie przewija nigdzie. Strona nadal się buduje, więc nic cię nie ostrzega.
Nie można tego naprawić, edytując link po tłumaczeniu. W dziewięciu uruchomieniach model zapisał ten sam nagłówek na cztery różne sposoby, więc wygenerowany identyfikator zmieniałby się przy każdym ponownym tłumaczeniu. Poprawka należy przed tłumaczeniem: nadaj każdemu nagłówkowi, do którego prowadzą linki, stały identyfikator.
- W Docusaurus MDX użyj
## Keep one glossary for the whole book {/* #keep-one-glossary */}. Docusaurus zauważa, że starsza forma{#id}„nie jest już poprawną składnią MDX”, a jego poleceniewrite-heading-idsdodaje identyfikatory do każdego dokumentu za ciebie. - W Pandocu i w procesorach Markdown zgodnych z PHP Markdown Extra użyj
{#keep-one-glossary}na końcu nagłówka.
Identyfikator pozostaje wtedy taki sam w każdym języku, a checker traktuje go jako cel linku.
2. Komentarze w kodzie są tłumaczone, a widoczny ciąg nie
Przykład zawiera komentarz powłoki i komentarz YAML:
library:
name: "My books" # shown in the sidebar
sort: title
Wszystkie sześć uruchomień, które wysłały cały plik, przetłumaczyły oba komentarze, w tym trzy, w których prompt mówił „Nie zmieniaj niczego wewnątrz bloków kodu ogrodzonego”. Sam kod pozostał nietknięty we wszystkich dziewięciu uruchomieniach. Tymczasem "My books", które według komentarza jest wyświetlane na pasku bocznym, pozostało po angielsku we wszystkich dziewięciu uruchomieniach. Model zrobił odwrotność tego, czego potrzebuje zlokalizowana strona: przetłumaczył notatkę dla programistów, a zostawił etykietę, którą zobaczą czytelnicy.
Żaden wybór nie jest błędny w każdym przypadku. W samouczku, którego czytelnicy skopiują kod do własnego projektu, przetłumaczone komentarze pomagają. W dokumentacji referencyjnej, której kod musi być zgodny z repozytorium, sprawiają, że strona nie zgadza się ze źródłem. Podejmij decyzję raz dla projektu i ręcznie sprawdź wartości ciągów w przykładach konfiguracji, ponieważ żadne narzędzie nie odróżni etykiety wyświetlanej od identyfikatora. Z tego powodu checker zgłasza zmiany tylko w komentarzach jako ostrzeżenia.
3. Metoda wyglądająca na bezpieczną zepsuła front matter
Warunek chroniony zrobił to, co obiecał: wszystkie 32 placeholdery wróciły we wszystkich trzech uruchomieniach, więc kod, adresy URL i tagi zostały przywrócone idealnie. Ale nasz skrypt pozostawił dwie małe rzeczy poza placeholderami: linię ---, która otwiera front matter, oraz zamykający cudzysłów po przetłumaczonym tytule i opisie. Model porzucił je wszystkie w trzech uruchomieniach. Plik zaczynał się tak:
title: "导出您的书库
description: "在更换设备之前,请备份您的笔记和书籍。
slug: export-library
Bez otwierającego --- parser Markdown nie widzi już front matter. Czyta sześć linii YAML plus zamykające --- jako nagłówek, więc strona otwierałaby się dużym nagłówkiem zawierającym YAML. Nadal kompilowało się jako MDX. Przywrócenie --- też nie wystarczy: parser YAML odrzuca dwa niezamknięte cudzysłowy.
Lekcja nie polega na unikaniu placeholderów. Polega na tym, że cokolwiek pozostawisz odsłonięte, może wrócić zmienione, a front matter w ogóle nie powinien trafiać do modelu jako część strony. Przeanalizuj go, wyślij tylko wartości przeznaczone dla czytelnika (title, description) jako osobne ciągi i zapisz tłumaczenia z powrotem do oryginalnej struktury. To kilka linii kodu i usuwa całą klasę problemów.
Pogrubiony tekst i zakresy w języku chińskim, japońskim i koreańskim
Dwa kolejne problemy nigdy nie pojawiły się w naszych dziewięciu uruchomieniach, ale warto ich sprawdzać, ponieważ po cichu psują strony, a oba dotknęły własnego bloga BookTranslator. Blog jest napisany w MDX i tłumaczony maszynowo na 27 języków, a w jednym zaplanowanym uruchomieniu tłumaczenia dwa koreańskie artykuły nie przeszły naszego sprawdzania struktury trzy razy z rzędu. Przyczynami były dwa poniższe wzorce.
Pogrubienie kończące się znakiem interpunkcyjnym. CommonMark decyduje, czy ** może otworzyć lub zamknąć pogrubienie, patrząc na znaki po obu jego stronach. Zamykające **, które występuje bezpośrednio po znaku interpunkcyjnym, musi być poprzedzone spacją, znakiem interpunkcyjnym lub końcem linii; to jest reguła prawostronnego ogranicznika. W języku angielskim zawsze jest tam spacja. W języku chińskim, japońskim i koreańskim często jej nie ma. Dlatego 打开**设置 → 导出(测试版)**并选择 pokazuje dosłowne gwiazdki, ponieważ pogrubienie kończy się pełnoszerokim nawiasem i jest bezpośrednio poprzedzone znakiem 并. Ta sama linia bez nawiasu renderuje się jako pogrubiona, podobnie jak linia ze spacją po **. Pogrubiony link ma ten sam problem, ponieważ link kończy się znakiem ): 点击**[导出](./export-options.md)**打开 zawodzi, podobnie jak koreańskie **[API](./api.md)**는.
Nasz model przypadkowo wstawił spację po obu stronach każdej pogrubionej frazy, więc jego wynik renderował się poprawnie. Redaktor, który później usunie te spacje, aby zastosować się do chińskich konwencji typograficznych, przywróci błąd. Możesz wypróbować wszystkie siedem wariantów w render-cases.md.
Zakresy liczbowe z tyldą. Tekst chiński i japoński często zapisuje zakresy jako 3~5. Witryny GitHub Flavored Markdown zbudowane na remark domyślnie zamieniają pojedyncze tyldy na przekreślenie: opcja singleTilde w remark-gfm ma wartość true, chyba że ją zmienisz. Dwa zakresy w jednym akapicie, takie jak 需要 3~5 分钟,生成 10~20 MB 的文件夹, renderują się z przekreślonym tekstem pomiędzy nimi. Nasz przykład używał półpauz, a osiem uruchomień je zachowało, podczas gdy dziewiąte zapisało 3 到 5. Proś o półpauzy lub słowa w zakresach albo ustaw singleTilde: false w konfiguracji remark.
Narzędzie do sprawdzania struktury oznacza oba wzorce. Aby potwierdzić, co faktycznie się renderuje, render_check.mjs zlicza pogrubienia, kursywę, przekreślenia i pozostałe gwiazdki w źródle i tłumaczeniu oraz próbuje skompilować MDX:
npm install @mdx-js/mdx@3 unified@11 remark-parse@11 remark-gfm@4
node render_check.mjs source.mdx translated.mdx
Mniejsza liczba węzłów pogrubienia lub więcej dosłownych gwiazdek w tłumaczeniu oznacza, że niektóre wyróżnienia przestały się zamykać.
Proces, który się sprawdza
-
Najpierw popraw identyfikatory nagłówków. Dodaj jawne identyfikatory do każdego nagłówka, do którego coś linkuje, w składni obsługiwanej przez generator witryny. Zrób to w języku źródłowym, raz, i zatwierdź przed tłumaczeniem czegokolwiek.
-
Usuń metadane z treści strony. Tłumacz tylko wartości widoczne dla czytelnika, takie jak
titleidescription, jako osobne ciągi znaków, i zapisz je z powrotem do oryginalnego YAML. -
Ustal politykę dotyczącą kodu. Komentarze tłumaczone lub nie; ciągi wyświetlane w przykładach konfiguracji tłumaczone lub nie. Zapisz to w swoim słowniku tłumaczeń obok nazw produktów, których nie wolno zmieniać, takich jak Shelfmark w naszym przykładzie.
-
Przetłumacz treść. Użyj narzędzia, które parsuje Markdown, lub wyślij całą stronę z jawnymi regułami. W naszym teście wysłanie całej strony zachowało składnię nienaruszoną; jeśli używasz symboli zastępczych, chroń kompletne konstrukcje i nie pozostawiaj niczego na wpół odsłoniętego.
-
Uruchom sprawdzanie struktury.
python3 check_markdown_translation.py source.mdx translated.mdx --keep ShelfmarkPorównuje klucze i wartości metadanych, importy, bloki kodu, kod w linii, cele linków, definicje referencji, poziomy nagłówków, cele linków w obrębie strony, znaczniki JSX i atrybuty, komentarze MDX, znaczniki adnotacji, etykiety przypisów, kształt tabeli, pola listy zadań, twarde podziały wierszy, wyróżnienia, które nie mogą się zamknąć, zakresy z tyldą oraz terminy, o których zachowanie prosisz. Nie ocenia jakości tłumaczenia.
-
Sprawdź renderowanie dla celów CJK za pomocą
render_check.mjsi dodaj spację po każdym zamykającym**, które następuje po znaku interpunkcyjnym. -
Zbuduj witrynę i kliknij linki. Otwórz stronę w każdym języku, kliknij każdy link w obrębie strony i przeczytaj przykłady konfiguracji. Udana kompilacja dowodzi tylko, że plik się kompiluje.
W przypadku dokumentacji, w której liczy się dokładność, kroki dotyczące terminologii i przeglądu z naszego procesu tłumaczenia technicznego mają zastosowanie dodatkowo.
Gdzie pasuje BookTranslator
Tłumacz TXT BookTranslatora akceptuje pliki .txt, .md i .mdx. Według strony produktu tłumaczy je, zachowując akapity, podziały wierszy, znaki specjalne i strukturę tekstu, a duże pliki dzieli na segmenty w celu tłumaczenia z uwzględnieniem kontekstu, dzięki czemu możesz przesłać cały podręcznik lub książkę napisaną w Markdown zamiast wklejać ją fragmentami.
Strona produktu nie opisuje specjalnej obsługi metadanych, bloków kodu ani komponentów MDX, a my nie przetestowaliśmy tego przykładu przez BookTranslator na potrzeby tego artykułu. Niezależnie od użytego narzędzia, wykonaj kroki od 1 do 3 przed tłumaczeniem i kroki od 5 do 7 po nim. Nagłówek bez ustalonego identyfikatora nadal traci swoje linki, a zakres zapisany z tyldami nadal zamienia się w przekreślenie. Jeśli publikujesz książkę w kilku językach, nasz przewodnik po samodzielnym publikowaniu w wielu językach obejmuje resztę tego zadania.
Pobierz pliki testowe
Wszystko z tego testu można swobodnie wykorzystywać:
- sample-source.mdx: 73-liniowy angielski przykład;
- check_markdown_translation.py: narzędzie do sprawdzania struktury (tylko biblioteka standardowa Pythona);
- render_check.mjs i render-cases.md: sprawdzanie renderowania i siedem przypadków testowych CJK;
- run_llm_markdown_test.py: trzy warunki promptu dla dowolnego lokalnego serwera zgodnego z OpenAI;
- dziewięć wyników w folderze wyników, wraz z check-results.txt i results.csv.
Powiązane wpisy





