BookTranslator
BookTranslator

Как да превеждате Markdown файлове, без да чупите код, връзки или front matter

Какво да превеждате в Markdown или MDX файл, какво да оставите непокътнато и как да проверите резултата. С примерен файл, безплатен инструмент за проверка и тест с локален LLM в 9 пускания.

За да преведете Markdown файл, преведете текста и оставете техническата част непокътната: ключовете във front matter, кода, URL адресите, етикетите на връзките, таговете на компонентите и етикетите на бележките под линия трябва да се върнат байт по байт. След това проверете три неща, които дори внимателният превод все още чупи: връзките към заглавия, коментарите в кода и, при китайски, японски или корейски, разстоянието около удебелен текст и диапазони от числа.

Преведохме 73-редова MDX страница на опростен китайски девет пъти с локален модел, използвайки три различни подсказки, и проверихме всеки резултат със скрипт. Частите, за които хората обикновено се притесняват, оцеляха във всичките девет пускания: кодът, вграденият код, URL адресите, таблицата, JSX компонентът и списъкът със задачи. Три други неща се объркаха. Връзката към заглавие се счупи във всичките девет пускания. Коментарите в кода бяха преведени във всичките шест пускания, които изпратиха целия файл, включително три пускания, в които подсказката казваше да не се пипа кодът. А подсказката, която скри синтаксиса зад заместители, което звучи като най-сигурния вариант, счупи front matter във всичките си три пускания.

Бърз отговор: какво да превеждате и какво да оставите непокътнато

Част от файлаПример от нашия образецДа се преведе ли?
Ключове във front matterslug:, sidebar_position:, tags:Не
Стойности във front mattertitle: "Export Your Library"Само тези, предназначени за читателя, като title и description
Импорти и експорти (MDX)import Callout from '@site/src/components/Callout';Не
Блокове с кодshelfmark export --format epubНе. Решете отделно за коментарите и низовете, предназначени за потребителя.
Вграден кодlibrary.json, --coversНе
Цели на връзки и изображения(./export-options.md), (https://www.w3.org/TR/epub-33/ "EPUB 3.3")Не, с изключение на незадължителното заглавие в кавички
Текст на връзката и алтернативен текст на изображението[glossary section], ![Folder layout after an export]Да
Етикети и дефиниции за препратки[project glossary][glossary], [glossary]: ./glossary.md#termsЗапазете етикета [glossary] и URL адреса; преведете видимия текст
Заглавия## Keep one glossary for the whole bookДа, но първо им задайте фиксирани ID (вижте по-долу)
JSX компоненти<Callout type="warning" title="Back up first">Запазете имената на таговете и атрибутите; преведете стойностите на атрибутите, видими за читателя, като например title
Маркери за предупреждения:::tip и :::Не
Етикети на бележки под линия[^sync]Не
MDX коментари{/* Translator note: ... */}По избор. Читателите никога не ги виждат.

Всичко останало е обикновен текст: параграфи, елементи от списъци, клетки от таблици и блокови цитати.

Какво тествахме

Създадохме sample-source.mdx – документационна страница за измислено приложение за четене, наречено Shelfmark. Тя е написана в MDX стила, използван от Docusaurus и подобни документационни сайтове, с по един пример за всяка конструкция от таблицата по-горе, плюс принудително прекъсване на ред с два интервала, удебелена връзка, удебелена фраза, завършваща със скоба, два диапазона от числа, написани с тирета, и връзка в страницата към заглавието „Keep one glossary for the whole book.“

След това помолихме локален модел да го преведе на опростен китайски по три начина:

  1. Цял файл. Поставете целия файл и поискайте обратно преведения файл.
  2. С инструкции. Същото, плюс шест правила: запазете ключовете на front matter, не променяйте нищо в кодовите блокове, запазете URL адресите и референтните дефиниции, запазете импортите, таговете и коментарите, запазете етикетите на бележките под линия и маркерите за предупреждения и преведете заглавията, текста на връзките, алтернативния текст и атрибута title.
  3. С протекции. Заменете кодовите блокове, вградените кодови фрагменти, URL адресите, таговете, коментарите, етикетите на бележките под линия, маркерите за предупреждения и редовете на front matter с номерирани заместители като ⟦12⟧, преведете останалото и след това върнете оригиналите. Стойностите на title и description бяха оставени открити за превод и, както се оказа, също и редовете --- на front matter и затварящите кавички.

Моделът беше Qwen 3.6 27B (Q4_K_M) в LM Studio, с изключено мислене и температура 0.3, на Apple M4 Max с 64 GB памет. Проведохме всяко условие три пъти, общо девет пускания, на 25 октомври 2026 г. Скриптът е run_llm_markdown_test.py, а всичките девет резултата са публикувани без редакция; README изброява всеки файл. Ако никога не сте настройвали локален модел, нашето ръководство за превод с локален LLM обхваща настройките.

Това беше малък тест на един модел, една езикова двойка и една страница. Той показва какви проблеми се случват и как да ги хванете. Той не класира модели или подсказки.

Резултат: Синтаксисът оцеля; връзките и решенията – не

Проверихме всеки резултат с check_markdown_translation.py и изобразихме всеки един с remark и MDX компилатора. Пълният изход на проверката е в check-results.txt, а results.csv има по един ред за всяко пускане.

ПроверкаЦял файлИнструктираноЗащитено
Компилира се като MDX3 от 33 от 33 от 3
Код, вграден код, URL адреси, таблица, тагове, списък със задачи – без промяна3 от 33 от 33 от 3
Удебелен и курсивен текст все още се визуализират3 от 33 от 33 от 3
Front matter е непокътнат3 от 33 от 30 от 3
Връзката в страницата все още сочи към своето заглавие0 от 30 от 30 от 3
Коментарите в кода са оставени както са написани0 от 30 от 33 от 3
Превод на title в Callout3 от 33 от 30 от 3

Първите редове са добрата новина. Този модел върна Markdown синтаксиса непокътнат, когато поставихме целия файл; не открихме нищо за поправяне в код, URL адреси или таблици. Последните четири реда са там, където е работата, и нито един от тях не се показва като грешка при изграждането на сайта.

1. Преведените заглавия чупят връзките към тях

Примерът съдържа връзка към своята секция с речник с [glossary section](#keep-one-glossary-for-the-whole-book). Всяко изпълнение преведе заглавието, както трябва, и всяко изпълнение запази целта на връзката, както трябва. Резултатът е връзка към ID, което вече не съществува.

Повечето Markdown инструменти създават ID на заглавията от текста на заглавието. Документацията на Pandoc описва идентификатора като „базиран на текста на заглавието“, а Docusaurus предупреждава, че може да искате да промените или преведете заглавие „без да актуализирате съществуващото ID, за да избегнете счупване на връзки“. След като заглавието гласи 为整本书保留一个术语表, генерираното му ID е на китайски и #keep-one-glossary-for-the-whole-book не води до никъде. Страницата все още се изгражда, така че нищо не ви уведомява.

Не можете да поправите това и чрез редактиране на връзката след превод. В девет изпълнения моделът написа същото заглавие по четири различни начина, така че генерираното ID ще се променя отново при всеки повторен превод. Поправката е преди превода: дайте на всяко заглавие, към което има връзка, фиксирано ID.

  • В Docusaurus MDX използвайте ## Keep one glossary for the whole book {/* #keep-one-glossary */}. Docusaurus отбелязва, че по-старият формат {#id} „вече не е валиден MDX синтаксис“, а командата му write-heading-ids добавя ID към всеки документ вместо вас.
  • В Pandoc и в Markdown процесори, които следват PHP Markdown Extra, използвайте {#keep-one-glossary} в края на заглавието.

Тогава ID остава същото на всеки език и проверяващият го третира като цел на връзката.

2. Коментарите в кода се превеждат, а видимият низ не

Примерът има shell коментар и YAML коментар:

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

Всичките шест изпълнения, които изпратиха целия файл, преведоха и двата коментара, включително трите, в които подсказката казваше „Не променяйте нищо вътре в оградените блокове с код“. Самият код беше недокоснат във всичките девет изпълнения. Междувременно "My books", за което коментарът казва, че се показва в страничната лента, остана на английски във всичките девет изпълнения. Моделът направи обратното на това, което е нужно на локализирана страница: преведе бележката за разработчици и остави етикета, който читателите ще видят.

Нито един от двата избора не е грешен във всеки случай. За урок, чиито читатели ще копират кода в собствения си проект, преведените коментари помагат. За справочна документация, чийто код трябва да съвпада с хранилище, те карат страницата да не съответства на източника. Вземете решението веднъж за проекта и прегледайте ръчно стойностите на низовете в примерите за конфигурация, защото никой инструмент не може да различи етикет за показване от идентификатор. Проверяващият отчита промените само в коментари като предупреждения поради тази причина.

3. Методът, който изглеждаше безопасен, счупи front matter

Защитеното условие изпълни обещаното: всичките 32 заместителя се върнаха и в трите изпълнения, така че кодът, URL адресите и таговете бяха възстановени перфектно. Но нашият скрипт остави две малки неща извън заместителите: реда ---, който отваря front matter, и затварящата кавичка след преведения title и description. Моделът ги изпусна и в трите изпълнения. Файлът започваше така:

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

Без отварящия ---, Markdown парсерът вече не вижда front matter. Той чете шестте YAML реда плюс затварящия --- като заглавие, така че страницата щеше да се отвори с голямо заглавие, съдържащо YAML. Все още се компилираше като MDX. Връщането на --- също не е достатъчно: YAML парсерът отхвърля двете незатворени кавички.

Поуката не е да избягвате заместители. А че каквото оставите открито, може да се върне променено, и че front matter изобщо не трябва да отива при модела като част от страницата. Парснете го, изпращайте само стойностите, обърнати към читателя (title, description), като отделни низове и записвайте преводите обратно в оригиналната структура. Това е няколко реда код и премахва целия клас проблеми.

Удебелен текст и диапазони на китайски, японски и корейски

Още два проблема никога не се появиха в нашите девет изпълнения, но си струва да ги проверявате, защото чупят страници безшумно, и двата са засегнали собствения блог на BookTranslator. Блогът е написан на MDX и машинно преведен на 27 езика, а при едно планирано изпълнение за превод две корейски статии не преминаха нашата структурна проверка три повторни опита подред. Причините бяха двата модела по-долу.

Удебелен текст, който завършва с пунктуация. CommonMark решава дали ** може да отваря или затваря удебеляване, като гледа символите от двете му страни. Затварящ **, който идва непосредствено след пунктуация, трябва да бъде последван от интервал, пунктуация или края на реда; това е правилото за десен фланг. В английския винаги има интервал там. В китайския, японския и корейския често няма. Така 打开**设置 → 导出(测试版)**并选择 показва буквални звездички, защото удебеляването завършва с широка скоба и е последвано директно от 并. Същият ред без скобата се визуализира удебелен, както и редът с интервал след **. Удебелената връзка има същия проблем, защото връзката завършва с ): 点击**[导出](./export-options.md)**打开 се проваля, както и корейското **[API](./api.md)**는.

Нашият модел случайно постави интервал от двете страни на всяка удебелена фраза, така че резултатът му се визуализира правилно. Редактор, който по-късно премахне тези интервали, за да следва китайските типографски конвенции, връща грешката. Можете да изпробвате всичките седем варианта в render-cases.md.

Диапазони от числа с тилда. Китайският и японският текст често записват диапазони като 3~5. Сайтовете с GitHub Flavored Markdown, изградени върху remark, превръщат единичните тилди в зачертаване по подразбиране: опцията singleTilde на remark-gfm е true, освен ако не я промените. Два диапазона в един параграф, като 需要 3~5 分钟,生成 10~20 MB 的文件夹, се визуализират с зачертан текст между тях. Нашата извадка използва дълги тирета и осем изпълнения ги запазиха, докато деветото написа 3 到 5. Поискайте дълги тирета или думи в диапазоните, или задайте singleTilde: false в конфигурацията на remark.

Структурната проверка открива и двата модела. За да потвърдите какво всъщност се визуализира, render_check.mjs брои удебелявания, курсив, зачертаване и останали звездички в източника и превода и опитва MDX компилация:

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

По-малко удебелени възли или повече буквални звездички в превода означава, че някое акцентиране е спряло да се затваря.

Работен процес, който издържа

  1. Първо коригирайте ID на заглавията. Добавете явни ID към всяко заглавие, към което нещо води, в синтаксиса, който вашият генератор на сайтове поддържа. Направете го на изходния език, веднъж, и го ангажирайте, преди нещо да бъде преведено.

  2. Извадете front matter от страницата. Превеждайте само стойности, насочени към читателя, като title и description, като отделни низове, и ги записвайте обратно в оригиналния YAML.

  3. Решете политиката за код. Коментарите превеждат ли се или не; показваните низове в примерите за конфигурация превеждат ли се или не. Запишете го в своя речник за превод до имената на продукти, които не трябва да се променят, като Shelfmark в нашата извадка.

  4. Преведете тялото. Използвайте инструмент, който анализира Markdown, или изпратете цялата страница с явни правила. В нашия тест изпращането на цялата страница запази синтаксиса непокътнат; ако използвате заместители, защитете цели конструкции и не оставяйте нищо полуразкрито.

  5. Стартирайте структурната проверка.

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

    Тя сравнява ключове и стойности на front matter, импорти, кодови блокове, вграден код, цели на връзки, референтни дефиниции, нива на заглавия, цели на връзки в страницата, JSX тагове и атрибути, MDX коментари, маркери за предупреждения, етикети на бележки под линия, форма на таблица, квадратчета за задачи, твърди прекъсвания на редове, акцентиране, което не може да се затвори, тилда диапазони и термини, които искате да запази. Тя не оценява качеството на превода.

  6. Проверете визуализацията за CJK цели с render_check.mjs и добавете интервал след всеки затварящ **, който следва пунктуация.

  7. Изградете сайта и щракнете върху връзките. Отворете страницата на всеки език, щракнете върху всяка връзка в страницата и прочетете примерите за конфигурация. Успешната компилация доказва само, че файлът се компилира.

За документация, където точността е важна, стъпките за терминология и преглед в нашия работен процес за технически превод се прилагат върху това.

Къде се вписва BookTranslator

TXT преводачът на BookTranslator приема файлове .txt, .md и .mdx. Според продуктовата страница той ги превежда, като запазва параграфи, прекъсвания на редове, специални символи и текстова структура, и разделя големи файлове на сегменти за контекстно-зависим превод, така че можете да качите цяло ръководство или книга, написана в Markdown, вместо да я поставяте на части.

Продуктовата страница не описва специална обработка за front matter, кодови блокове или MDX компоненти и не сме прекарали тази извадка през BookTranslator за тази статия. Какъвто и инструмент да използвате, направете стъпки 1 до 3 преди превод и стъпки 5 до 7 след това. Заглавие без фиксиран ID все още губи връзките си, а диапазон, написан с тилди, все още се превръща в зачертаване. Ако публикувате книга на няколко езика, нашето ръководство за самостоятелно публикуване на няколко езика покрива останалата част от тази задача.

Вземете тестовите файлове

Всичко от този тест е свободно за повторна употреба:

Свързани публикации