Como traduzir arquivos Markdown sem quebrar código, links ou front matter
O que traduzir em um arquivo Markdown ou MDX, o que deixar intacto e como verificar o resultado. Com um arquivo de exemplo, um verificador gratuito e um teste com 9 execuções de LLM local.

Para traduzir um arquivo Markdown, traduza a prosa e deixe a mecânica intacta: chaves de front matter, código, URLs, rótulos de link, tags de componente e rótulos de nota de rodapé devem voltar byte a byte. Depois, verifique três coisas que uma tradução cuidadosa ainda quebra: links para títulos, comentários de código e, em chinês, japonês ou coreano, o espaçamento ao redor de texto em negrito e intervalos numéricos.
Traduzimos uma página MDX de 73 linhas para chinês simplificado nove vezes com um modelo local, usando três prompts diferentes, e verificamos cada resultado com um script. As partes com que as pessoas costumam se preocupar sobreviveram em todas as nove execuções: código, código embutido, URLs, a tabela, o componente JSX e a lista de tarefas. Três outras coisas deram errado. O link para um título quebrou em todas as nove execuções. Os comentários de código foram traduzidos em todas as seis execuções que enviaram o arquivo inteiro, incluindo três execuções em que o prompt dizia para não mexer no código. E o prompt que escondia a sintaxe atrás de placeholders, que parece a opção mais segura, quebrou o front matter em todas as suas três execuções.
Resposta rápida: o que traduzir e o que deixar intacto
| Parte do arquivo | Exemplo do nosso arquivo de exemplo | Traduzir? |
|---|---|---|
| Chaves de front matter | slug:, sidebar_position:, tags: | Não |
| Valores de front matter | title: "Export Your Library" | Apenas os voltados ao leitor, como title e description |
| Imports e exports (MDX) | import Callout from '@site/src/components/Callout'; | Não |
| Blocos de código | shelfmark export --format epub | Não. Decida separadamente sobre comentários e strings voltadas ao usuário. |
| Código embutido | library.json, --covers | Não |
| Destinos de links e imagens | (./export-options.md), (https://www.w3.org/TR/epub-33/ "EPUB 3.3") | Não, exceto o título opcional entre aspas |
| Texto de link e texto alternativo de imagem | [glossary section], ![Folder layout after an export] | Sim |
| Rótulos e definições de referência | [project glossary][glossary], [glossary]: ./glossary.md#terms | Mantenha o rótulo [glossary] e a URL; traduza o texto visível |
| Títulos | ## Keep one glossary for the whole book | Sim, mas primeiro atribua a eles IDs fixos (veja abaixo) |
| Componentes JSX | <Callout type="warning" title="Back up first"> | Mantenha os nomes das tags e dos atributos; traduza os valores de atributos voltados ao leitor, como title |
| Marcadores de admonição | :::tip e ::: | Não |
| Rótulos de notas de rodapé | [^sync] | Não |
| Comentários MDX | {/* Translator note: ... */} | Opcional. Os leitores nunca os veem. |
Todo o resto é prosa comum: parágrafos, itens de lista, células de tabela e citações em bloco.
O que testamos
Escrevemos o sample-source.mdx, uma página de documentação para um aplicativo de leitura fictício chamado Shelfmark. Ela está escrita no estilo MDX usado pelo Docusaurus e por sites de documentação semelhantes, com um exemplo de cada construção da tabela acima, além de uma quebra de linha rígida de dois espaços, um link em negrito, uma frase em negrito terminando em parêntese, dois intervalos numéricos escritos com travessões e um link interno para o título "Mantenha um glossário para o livro inteiro."
Em seguida, pedimos a um modelo local que a traduzisse para chinês simplificado de três maneiras:
- Arquivo inteiro. Cole o arquivo completo e peça o arquivo traduzido de volta.
- Com instruções. O mesmo, mais seis regras: mantenha as chaves do front matter, não altere nada dentro de código, mantenha URLs e definições de referência, mantenha imports, tags e comentários, mantenha rótulos de notas de rodapé e marcadores de admonição, e traduza títulos, texto de link, texto alternativo e o atributo
title. - Protegido. Substitua código, código embutido, URLs, tags, comentários, rótulos de notas de rodapé, marcadores de admonição e linhas do front matter por placeholders numerados como
⟦12⟧, traduza o restante e depois recoloque os originais. Os valores detitleedescriptionforam deixados expostos para tradução e, como se viu, também as linhas---do front matter e as aspas de fechamento.
O modelo foi o Qwen 3.6 27B (Q4_K_M) no LM Studio, com o modo de raciocínio desativado e temperatura 0,3, em um Apple M4 Max com 64 GB de memória. Executamos cada condição três vezes, nove execuções no total, em 25 de outubro de 2026. O script é o run_llm_markdown_test.py, e todas as nove saídas são publicadas sem edição; o README lista cada arquivo. Se você nunca configurou um modelo local, nosso guia de tradução com LLM local cobre as configurações.
Este foi um teste pequeno, com um modelo, um par de idiomas e uma página. Ele mostra quais problemas acontecem e como detectá-los. Não classifica modelos nem prompts.
Resultado: a sintaxe sobreviveu; os links e as decisões, não
Verificamos cada saída com o check_markdown_translation.py e renderizamos cada uma com remark e o compilador MDX. A saída completa do verificador está em check-results.txt, e o results.csv tem uma linha por execução.
| Verificação | Arquivo inteiro | Instruído | Protegido |
|---|---|---|---|
| Compila como MDX | 3 de 3 | 3 de 3 | 3 de 3 |
| Código, código inline, URLs, tabela, tags e lista de tarefas inalterados | 3 de 3 | 3 de 3 | 3 de 3 |
| Negrito e itálico ainda renderizam | 3 de 3 | 3 de 3 | 3 de 3 |
| Front matter intacto | 3 de 3 | 3 de 3 | 0 de 3 |
| Link interno ainda aponta para seu título | 0 de 3 | 0 de 3 | 0 de 3 |
| Comentários de código mantidos como escritos | 0 de 3 | 0 de 3 | 3 de 3 |
Callout title traduzido | 3 de 3 | 3 de 3 | 0 de 3 |
As primeiras linhas são a boa notícia. Este modelo devolveu a sintaxe Markdown intacta quando colamos o arquivo inteiro; não encontramos nada para corrigir em código, URLs ou tabelas. As últimas quatro linhas são onde está o trabalho, e nenhuma delas aparece como erro quando você compila o site.
1. Títulos traduzidos quebram links para eles
O exemplo tem um link para sua seção de glossário com [glossary section](#keep-one-glossary-for-the-whole-book). Toda execução traduziu o título, como deveria, e toda execução manteve o destino do link, como deveria. O resultado é um link para um ID que não existe mais.
A maioria das ferramentas Markdown cria IDs de título a partir do texto do título. A documentação do Pandoc descreve o identificador como "baseado no texto do título", e o Docusaurus avisa que você pode querer alterar ou traduzir um título "sem atualizar o ID existente para evitar quebrar links". Quando o título passa a ser 为整本书保留一个术语表, seu ID gerado fica em chinês, e #keep-one-glossary-for-the-whole-book não rola para lugar nenhum. A página ainda compila, então nada te avisa.
Também não dá para corrigir isso editando o link depois da tradução. Em nove execuções, o modelo escreveu o mesmo título de quatro maneiras diferentes, então o ID gerado mudaria de novo a cada retradução. A correção pertence ao momento anterior à tradução: dê a cada título que é alvo de link um ID fixo.
- No MDX do Docusaurus, use
## Keep one glossary for the whole book {/* #keep-one-glossary */}. O Docusaurus observa que a forma mais antiga{#id}"não é mais sintaxe MDX válida", e seu comandowrite-heading-idsadiciona IDs a todos os documentos para você. - No Pandoc e em processadores Markdown que seguem o PHP Markdown Extra, use
{#keep-one-glossary}no final do título.
O ID então permanece o mesmo em todos os idiomas, e o verificador o trata como o destino do link.
2. Comentários de código são traduzidos, e a string visível não
O exemplo tem um comentário de shell e um comentário YAML:
library:
name: "My books" # shown in the sidebar
sort: title
Todas as seis execuções que enviaram o arquivo inteiro traduziram ambos os comentários, incluindo as três em que o prompt dizia "Não altere nada dentro de blocos de código cercados". O código em si ficou intocado nas nove execuções. Enquanto isso, "My books", que o comentário diz ser exibido na barra lateral, permaneceu em inglês nas nove execuções. O modelo fez o oposto do que uma página localizada precisa: traduziu a nota para desenvolvedores e deixou o rótulo que os leitores verão.
Nenhuma das escolhas está errada em todos os casos. Para um tutorial cujos leitores copiarão o código para o próprio projeto, comentários traduzidos ajudam. Para documentação de referência cujo código deve corresponder a um repositório, eles fazem a página discordar da fonte. Tome a decisão uma vez para o projeto e revise manualmente os valores de string em exemplos de configuração, porque nenhuma ferramenta consegue distinguir um rótulo de exibição de um identificador. O verificador relata alterações apenas em comentários como avisos por esse motivo.
3. O método aparentemente seguro quebrou o front matter
A condição protegida fez o que prometeu: todos os 32 placeholders voltaram nas três execuções, então código, URLs e tags foram restaurados perfeitamente. Mas nosso script deixou duas pequenas coisas fora dos placeholders: a linha --- que abre o front matter e a aspa de fechamento após o título e a descrição traduzidos. O modelo descartou todas elas nas três execuções. O arquivo começou assim:
title: "导出您的书库
description: "在更换设备之前,请备份您的笔记和书籍。
slug: export-library
Sem o --- de abertura, um analisador Markdown não vê mais o front matter. Ele lê as seis linhas YAML mais o --- de fechamento como um título, então a página abriria com um título grande contendo o YAML. Ainda compilou como MDX. Colocar o --- de volta também não basta: o analisador YAML rejeita as duas aspas não fechadas.
A lição não é evitar placeholders. É que tudo o que você deixa exposto pode voltar alterado, e que o front matter não deveria ir para o modelo como parte da página. Faça o parse dele, envie apenas os valores voltados ao leitor (title, description) como strings separadas e grave as traduções de volta na estrutura original. São algumas linhas de código e eliminam toda essa classe de problemas.
Texto em negrito e intervalos em chinês, japonês e coreano
Mais dois problemas nunca apareceram nas nossas nove execuções, mas vale verificá-los porque quebram páginas silenciosamente, e ambos já atingiram o próprio blog do BookTranslator. O blog é escrito em MDX e traduzido automaticamente para 27 idiomas, e em uma execução agendada de tradução dois artigos em coreano falharam nossa verificação de estrutura três vezes seguidas. As causas foram os dois padrões abaixo.
Negrito que termina em pontuação. O CommonMark decide se ** pode abrir ou fechar negrito observando os caracteres dos dois lados dele. Um ** de fechamento que vem logo após pontuação precisa ser seguido por um espaço, pontuação ou o fim da linha; esta é a regra de flanco direito. O inglês sempre tem um espaço ali. O chinês, o japonês e o coreano frequentemente não têm. Assim, 打开**设置 → 导出(测试版)**并选择 mostra asteriscos literais, porque o negrito termina em um parêntese de largura total e é seguido diretamente por 并. A mesma linha sem o parêntese renderiza em negrito, e a linha com um espaço após o ** também. Um link em negrito tem o mesmo problema, porque um link termina em ): 点击**[导出](./export-options.md)**打开 falha, e o coreano **[API](./api.md)**는 também.
Nosso modelo acabou colocando um espaço dos dois lados de cada frase em negrito, então sua saída renderizou corretamente. Um editor que depois remove esses espaços para seguir as convenções de tipografia chinesa traz o bug de volta. Você pode testar todas as sete variantes em render-cases.md.
Intervalos numéricos com til. Textos em chinês e japonês frequentemente escrevem intervalos como 3~5. Sites GitHub Flavored Markdown construídos sobre remark transformam tis únicos em riscado por padrão: a opção singleTilde do remark-gfm é true a menos que você a altere. Dois intervalos em um parágrafo, como 需要 3~5 分钟,生成 10~20 MB 的文件夹, renderizam com o texto entre eles riscado. Nossa amostra usou travessões, e oito execuções os mantiveram enquanto a nona escreveu 3 到 5. Peça travessões ou palavras nos intervalos, ou defina singleTilde: false na sua configuração do remark.
O verificador estrutural sinaliza ambos os padrões. Para confirmar o que realmente renderiza, render_check.mjs conta negrito, itálico, riscado e asteriscos remanescentes no original e na tradução, e tenta uma compilação MDX:
npm install @mdx-js/mdx@3 unified@11 remark-parse@11 remark-gfm@4
node render_check.mjs source.mdx translated.mdx
Menos nós de negrito ou mais asteriscos literais na tradução significa que alguma ênfase parou de fechar.
Um Fluxo de Trabalho que se Sustenta
-
Corrija os IDs dos títulos primeiro. Adicione IDs explícitos a cada título para o qual algo aponta, na sintaxe que o gerador do seu site suporta. Faça isso no idioma de origem, uma vez, e faça commit antes de qualquer coisa ser traduzida.
-
Tire o front matter da página. Traduza apenas valores voltados ao leitor, como
titleedescription, como strings separadas, e escreva-os de volta no YAML original. -
Decida a política de código. Comentários traduzidos ou não; strings de exibição em exemplos de configuração traduzidas ou não. Registre isso no seu glossário de tradução junto aos nomes de produtos que não devem mudar, como Shelfmark na nossa amostra.
-
Traduza o corpo. Use uma ferramenta que analise Markdown, ou envie a página inteira com regras explícitas. No nosso teste, enviar a página inteira manteve a sintaxe intacta; se você usar placeholders, proteja construções completas e não deixe nada meio exposto.
-
Execute a verificação estrutural.
python3 check_markdown_translation.py source.mdx translated.mdx --keep ShelfmarkEla compara chaves e valores do front matter, imports, blocos de código, código inline, destinos de links, definições de referência, níveis de título, destinos de links na página, tags e atributos JSX, comentários MDX, marcadores de admonição, rótulos de notas de rodapé, formato de tabela, caixas de lista de tarefas, quebras de linha forçadas, ênfase que não consegue fechar, intervalos com til, e termos que você pede para manter. Ela não julga a qualidade da tradução.
-
Verifique a renderização para alvos CJK com
render_check.mjs, e adicione um espaço após qualquer**de fechamento que venha depois de pontuação. -
Construa o site e clique nos links. Abra a página em cada idioma, clique em todos os links na página e leia os exemplos de configuração. Uma build que passa prova apenas que o arquivo compila.
Para documentação onde a precisão importa, as etapas de terminologia e revisão do nosso fluxo de trabalho de tradução técnica se aplicam por cima disso.
Onde o BookTranslator se Encaixa
O tradutor de TXT do BookTranslator aceita arquivos .txt, .md e .mdx. De acordo com a página do produto, ele os traduz mantendo parágrafos, quebras de linha, caracteres especiais e estrutura do texto, e divide arquivos grandes em segmentos para tradução com contexto, então você pode enviar um manual inteiro ou um livro escrito em Markdown em vez de colar em pedaços.
A página do produto não descreve tratamento especial para front matter, blocos de código ou componentes MDX, e não executamos esta amostra pelo BookTranslator para este artigo. Qualquer que seja a ferramenta que você use, faça as etapas 1 a 3 antes de traduzir e as etapas 5 a 7 depois. Um título sem ID fixo ainda perde seus links, e um intervalo escrito com tis ainda vira riscado. Se você está publicando um livro em vários idiomas, nosso guia para autopublicação em vários idiomas cobre o resto desse trabalho.
Obtenha os Arquivos de Teste
Tudo deste teste é livre para reutilização:
- sample-source.mdx: a amostra em inglês de 73 linhas;
- check_markdown_translation.py: o verificador estrutural (apenas biblioteca padrão do Python);
- render_check.mjs e render-cases.md: a verificação de renderização e os sete casos de teste CJK;
- run_llm_markdown_test.py: as três condições de prompt para qualquer servidor local compatível com OpenAI;
- as nove saídas na pasta de saídas, com check-results.txt e results.csv.
Posts Relacionados





