BookTranslator
BookTranslator

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.

BookTranslator

BookTranslator Team

13 min read

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ęść plikuPrzykład z naszego plikuTłumaczyć?
Klucze front matterslug:, sidebar_position:, tags:Nie
Wartości front mattertitle: "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 kodushelfmark export --format epubNie. Osobno zdecyduj o komentarzach i ciągach znaków widocznych dla użytkownika.
Kod w liniilibrary.json, --coversNie
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#termsZachowaj etykietę [glossary] i adres URL; przetłumacz widoczny tekst
Nagłówki## Keep one glossary for the whole bookTak, 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:

  1. Cały plik. Wklej cały plik i poproś o przetłumaczony plik z powrotem.
  2. 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.
  3. 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ści title i description pozostawiono 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.

SprawdzenieCały plikZgodnie z instrukcjąZabezpieczone
Kompiluje się jako MDX3 z 33 z 33 z 3
Kod, kod w linii, adresy URL, tabela, znaczniki, lista zadań bez zmian3 z 33 z 33 z 3
Pogrubienie i kursywa nadal się renderują3 z 33 z 33 z 3
Front matter nienaruszony3 z 33 z 30 z 3
Link w obrębie strony nadal wskazuje swój nagłówek0 z 30 z 30 z 3
Komentarze w kodzie pozostawione bez zmian0 z 30 z 33 z 3
Przetłumaczono title w Callout3 z 33 z 30 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 polecenie write-heading-ids dodaje 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

  1. 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.

  2. Usuń metadane z treści strony. Tłumacz tylko wartości widoczne dla czytelnika, takie jak title i description, jako osobne ciągi znaków, i zapisz je z powrotem do oryginalnego YAML.

  3. 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.

  4. 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.

  5. Uruchom sprawdzanie struktury.

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

    Poró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.

  6. Sprawdź renderowanie dla celów CJK za pomocą render_check.mjs i dodaj spację po każdym zamykającym **, które następuje po znaku interpunkcyjnym.

  7. 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ć:

Powiązane wpisy