BookTranslator
BookTranslator

Cómo traducir archivos Markdown sin romper el código, los enlaces ni el front matter

Qué traducir en un archivo Markdown o MDX, qué dejar intacto y cómo comprobar el resultado. Con un archivo de ejemplo, un verificador gratuito y una prueba de 9 ejecuciones con un LLM local.

BookTranslator

BookTranslator Team

15 min read

Para traducir un archivo Markdown, traduce la prosa y deja intacta la maquinaria: las claves del front matter, el código, las URL, las etiquetas de los enlaces, las etiquetas de los componentes y las etiquetas de las notas al pie deben devolverse byte por byte. Después, revisa tres cosas que incluso una traducción cuidadosa puede romper: los enlaces a encabezados, los comentarios del código y, en chino, japonés o coreano, el espaciado alrededor del texto en negrita y de los rangos numéricos.

Tradujimos una página MDX de 73 líneas al chino simplificado nueve veces con un modelo local, usando tres prompts distintos, y comprobamos cada resultado con un script. Las partes que suelen preocupar sobrevivieron en las nueve ejecuciones: el código, el código en línea, las URL, la tabla, el componente JSX y la lista de tareas. Otras tres cosas fallaron. El enlace a un encabezado se rompió en las nueve ejecuciones. Los comentarios del código se tradujeron en las seis ejecuciones que enviaron el archivo completo, incluidas tres en las que el prompt indicaba no tocar el código. Y el prompt que ocultaba la sintaxis detrás de marcadores de posición, que parece la opción más segura, rompió el front matter en sus tres ejecuciones.

Respuesta rápida: qué traducir y qué dejar intacto

Parte del archivoEjemplo de nuestra muestra¿Traducirlo?
Claves del front matterslug:, sidebar_position:, tags:No
Valores del front mattertitle: "Export Your Library"Solo los dirigidos al lector, como title y description
Importaciones y exportaciones (MDX)import Callout from '@site/src/components/Callout';No
Bloques de códigoshelfmark export --format epubNo. Decide por separado sobre los comentarios y las cadenas dirigidas al usuario.
Código en línealibrary.json, --coversNo
Destinos de enlaces e imágenes(./export-options.md), (https://www.w3.org/TR/epub-33/ "EPUB 3.3")No, excepto el título opcional entre comillas
Texto de los enlaces y texto alternativo de las imágenes[glossary section], ![Folder layout after an export]Sí
Etiquetas y definiciones de referencia[project glossary][glossary], [glossary]: ./glossary.md#termsConserva la etiqueta [glossary] y la URL; traduce el texto visible
Encabezados## Keep one glossary for the whole bookSí, pero primero asígnales ID fijos (ver abajo)
Componentes JSX<Callout type="warning" title="Back up first">Conserva los nombres de etiquetas y atributos; traduce los valores de atributos orientados al lector, como title
Marcadores de admonición:::tip y :::No
Etiquetas de notas al pie[^sync]No
Comentarios MDX{/* Translator note: ... */}Opcional. Los lectores nunca los ven.

Todo lo demás es prosa normal: párrafos, elementos de lista, celdas de tabla y citas en bloque.

Qué probamos

Escribimos sample-source.mdx, una página de documentación para una aplicación de lectura ficticia llamada Shelfmark. Está escrita en el estilo MDX que usan Docusaurus y sitios de documentación similares, con un ejemplo de cada construcción de la tabla anterior, además de un salto de línea duro de dos espacios, un enlace en negrita, una frase en negrita que termina en paréntesis, dos rangos numéricos escritos con guiones largos y un enlace interno al encabezado «Keep one glossary for the whole book».

Luego pedimos a un modelo local que lo tradujera al chino simplificado de tres maneras:

  1. Archivo completo. Pegar el archivo entero y pedir de vuelta el archivo traducido.
  2. Con instrucciones. Lo mismo, más seis reglas: conservar las claves del front matter, no cambiar nada dentro del código, conservar las URL y las definiciones de referencia, conservar las importaciones, etiquetas y comentarios, conservar las etiquetas de notas al pie y los marcadores de admonición, y traducir los encabezados, el texto de los enlaces, el texto alternativo y el atributo title.
  3. Protegido. Sustituir el código, el código en línea, las URL, las etiquetas, los comentarios, las etiquetas de notas al pie, los marcadores de admonición y las líneas del front matter por marcadores numerados como ⟦12⟧, traducir el resto y luego devolver los originales a su sitio. Los valores de title y description se dejaron expuestos para su traducción y, como resultó, también lo estuvieron las líneas --- del front matter y las comillas de cierre.

El modelo fue Qwen 3.6 27B (Q4_K_M) en LM Studio, con el razonamiento desactivado y temperatura 0.3, en un Apple M4 Max con 64 GB de memoria. Ejecutamos cada condición tres veces, nueve ejecuciones en total, el 25 de octubre de 2026. El script es run_llm_markdown_test.py, y las nueve salidas se publican sin editar; el README enumera todos los archivos. Si nunca has configurado un modelo local, nuestra guía de traducción con LLM local cubre los ajustes.

Esta fue una prueba pequeña de un modelo, un par de idiomas y una página. Muestra qué problemas ocurren y cómo detectarlos. No clasifica modelos ni prompts.

Resultado: la sintaxis sobrevivió; los enlaces y las decisiones no

Revisamos cada salida con check_markdown_translation.py y renderizamos cada una con remark y el compilador MDX. La salida completa del verificador está en check-results.txt, y results.csv tiene una fila por ejecución.

ComprobaciónArchivo completoIndicadoProtegido
Compila como MDX3 de 33 de 33 de 3
Código, código en línea, URLs, tabla, etiquetas y lista de tareas sin cambios3 de 33 de 33 de 3
La negrita y la cursiva siguen renderizándose3 de 33 de 33 de 3
Front matter intacto3 de 33 de 30 de 3
El enlace interno sigue apuntando a su encabezado0 de 30 de 30 de 3
Los comentarios de código se dejan tal como están escritos0 de 30 de 33 de 3
title del callout traducido3 de 33 de 30 de 3

Las primeras filas son la buena noticia. Este modelo devolvió la sintaxis Markdown intacta cuando pegamos el archivo completo; no encontramos nada que corregir en código, URLs ni tablas. Las últimas cuatro filas son donde está el trabajo, y ninguna de ellas aparece como error al compilar el sitio.

1. Los encabezados traducidos rompen los enlaces a ellos

El ejemplo enlaza a su sección de glosario con [glossary section](#keep-one-glossary-for-the-whole-book). Cada ejecución tradujo el encabezado, como debe ser, y cada ejecución mantuvo el destino del enlace, como debe ser. El resultado es un enlace a un ID que ya no existe.

La mayoría de las herramientas Markdown generan los ID de los encabezados a partir del texto del encabezado. La documentación de Pandoc describe el identificador como "basado en el texto del encabezado", y Docusaurus advierte que quizás quieras cambiar o traducir un encabezado "sin actualizar el ID existente para evitar romper enlaces". Una vez que el encabezado dice 为整本书保留一个术语表, su ID generado es chino, y #keep-one-glossary-for-the-whole-book no lleva a ninguna parte. La página sigue compilando, así que nada te avisa.

Tampoco puedes arreglar esto editando el enlace después de la traducción. En nueve ejecuciones el modelo escribió el mismo encabezado de cuatro maneras distintas, así que el ID generado cambiaría de nuevo con cada retraducción. La solución pertenece antes de la traducción: asigna a cada encabezado que tenga enlaces un ID fijo.

  • En MDX de Docusaurus, usa ## Keep one glossary for the whole book {/* #keep-one-glossary */}. Docusaurus señala que la forma antigua {#id} "ya no es sintaxis MDX válida", y su comando write-heading-ids añade IDs a todos los documentos por ti.
  • En Pandoc y en los procesadores Markdown que siguen PHP Markdown Extra, usa {#keep-one-glossary} al final del encabezado.

Así el ID permanece igual en todos los idiomas, y el verificador lo trata como el destino del enlace.

2. Los comentarios de código se traducen, y la cadena visible no

El ejemplo tiene un comentario de shell y un comentario de YAML:

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

Las seis ejecuciones que enviaron el archivo completo tradujeron ambos comentarios, incluidas las tres en las que el prompt decía "No cambies nada dentro de los bloques de código delimitados". El código en sí quedó intacto en las nueve ejecuciones. Mientras tanto, "My books", que según el comentario se muestra en la barra lateral, permaneció en inglés en las nueve ejecuciones. El modelo hizo lo contrario de lo que necesita una página localizada: tradujo la nota para desarrolladores y dejó la etiqueta que verán los lectores.

Ninguna de las dos opciones es incorrecta en todos los casos. Para un tutorial cuyos lectores copiarán el código en su propio proyecto, los comentarios traducidos ayudan. Para documentación de referencia cuyo código debe coincidir con un repositorio, hacen que la página no concuerde con la fuente. Toma la decisión una vez para el proyecto, y revisa a mano los valores de cadena en los ejemplos de configuración, porque ninguna herramienta puede distinguir una etiqueta de visualización de un identificador. Por esta razón, el verificador informa los cambios solo en comentarios como advertencias.

3. El método que parecía seguro rompió el front matter

La condición protegida cumplió lo que prometía: los 32 marcadores de posición volvieron en las tres ejecuciones, así que el código, las URLs y las etiquetas se restauraron perfectamente. Pero nuestro script dejó dos pequeñas cosas fuera de los marcadores de posición: la línea --- que abre el front matter, y la comilla de cierre después del título y la descripción traducidos. El modelo las eliminó todas en las tres ejecuciones. El archivo comenzaba así:

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

Sin el --- de apertura, un analizador Markdown ya no ve front matter. Lee las seis líneas YAML más el --- de cierre como un encabezado, así que la página se abriría con un encabezado grande que contiene el YAML. Aun así compiló como MDX. Volver a poner el --- tampoco es suficiente: el analizador YAML rechaza las dos comillas sin cerrar.

La lección no es evitar los marcadores de posición. Es que lo que dejes expuesto puede volver cambiado, y que el front matter no debería enviarse al modelo como parte de la página en absoluto. Analízalo, envía solo los valores de cara al lector (title, description) como cadenas separadas, y escribe las traducciones de vuelta en la estructura original. Eso son unas pocas líneas de código y elimina toda la clase de problemas.

Texto en negrita y rangos en chino, japonés y coreano

Otros dos problemas nunca aparecieron en nuestras nueve ejecuciones, pero vale la pena buscarlos porque rompen páginas en silencio, y ambos han afectado al propio blog de BookTranslator. El blog está escrito en MDX y se traduce automáticamente a 27 idiomas, y en una ejecución de traducción programada dos artículos en coreano fallaron nuestra verificación de estructura tres reintentos seguidos. Las causas fueron los dos patrones siguientes.

Negrita que termina en puntuación. CommonMark decide si ** puede abrir o cerrar negrita observando los caracteres a ambos lados. Un ** de cierre que viene justo después de puntuación debe ir seguido de un espacio, puntuación o el final de la línea; esta es la regla de flanqueo derecho. El inglés siempre tiene un espacio ahí. El chino, el japonés y el coreano a menudo no. Así, 打开**设置 → 导出(测试版)**并选择 muestra asteriscos literales, porque la negrita termina en un paréntesis de ancho completo y va seguida directamente de 并. La misma línea sin el paréntesis se renderiza en negrita, y también la línea con un espacio después de **. Un enlace en negrita tiene el mismo problema, porque un enlace termina en ): 点击**[导出](./export-options.md)**打开 falla, y también falla el coreano **[API](./api.md)**는.

Nuestro modelo puso un espacio a ambos lados de cada frase en negrita, así que su salida se renderizó correctamente. Un editor que luego elimine esos espacios para seguir las convenciones tipográficas chinas hace que el error vuelva. Puedes probar las siete variantes en render-cases.md.

Rangos numéricos con tilde. El texto chino y japonés a menudo escribe rangos como 3~5. Los sitios de GitHub Flavored Markdown construidos sobre remark convierten las tildes simples en tachado por defecto: la opción singleTilde de remark-gfm es true a menos que la cambies. Dos rangos en un párrafo, como 需要 3~5 分钟,生成 10~20 MB 的文件夹, se renderizan con el texto entre ellos tachado. Nuestra muestra usó guiones medios, y ocho ejecuciones los mantuvieron mientras que la novena escribió 3 到 5. Pide guiones medios o palabras en los rangos, o establece singleTilde: false en tu configuración de remark.

El verificador estructural marca ambos patrones. Para confirmar qué se renderiza realmente, render_check.mjs cuenta negritas, cursivas, tachados y asteriscos sobrantes en el origen y la traducción, y prueba una compilación MDX:

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

Menos nodos de negrita o más asteriscos literales en la traducción significa que algún énfasis dejó de cerrarse.

Un flujo de trabajo que resiste

  1. Corrige primero los IDs de los encabezados. Añade IDs explícitos a cada encabezado al que algo enlace, con la sintaxis que admita tu generador de sitios. Hazlo en el idioma de origen, una vez, y confírmalo antes de traducir nada.

  2. Saca el front matter de la página. Traduce solo los valores de cara al lector, como title y description, como cadenas separadas, y vuelve a escribirlos en el YAML original.

  3. Decide la política de código. Comentarios traducidos o no; cadenas de visualización en ejemplos de configuración traducidas o no. Anótalo en tu glosario de traducción junto a los nombres de productos que no deben cambiar, como Shelfmark en nuestra muestra.

  4. Traduce el cuerpo. Usa una herramienta que analice Markdown, o envía la página completa con reglas explícitas. En nuestra prueba, enviar la página completa mantuvo la sintaxis intacta; si usas marcadores de posición, protege las construcciones completas y no dejes nada a medio exponer.

  5. Ejecuta la verificación estructural.

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

    Compara claves y valores del front matter, importaciones, bloques de código, código en línea, destinos de enlaces, definiciones de referencia, niveles de encabezado, destinos de enlaces dentro de la página, etiquetas y atributos JSX, comentarios MDX, marcadores de admonición, etiquetas de notas al pie, forma de tablas, casillas de listas de tareas, saltos de línea duros, énfasis que no pueden cerrarse, rangos con tilde y términos que le pides conservar. No juzga la calidad de la traducción.

  6. Comprueba el renderizado para destinos CJK con render_check.mjs, y añade un espacio después de cualquier ** de cierre que siga a puntuación.

  7. Compila el sitio y haz clic en los enlaces. Abre la página en cada idioma, haz clic en cada enlace dentro de la página y lee los ejemplos de configuración. Una compilación exitosa solo demuestra que el archivo compila.

Para documentación donde la precisión importa, los pasos de terminología y revisión de nuestro flujo de trabajo de traducción técnica se aplican además de esto.

Dónde encaja BookTranslator

El traductor de TXT de BookTranslator acepta archivos .txt, .md y .mdx. Según la página del producto, los traduce manteniendo párrafos, saltos de línea, caracteres especiales y estructura del texto, y divide archivos grandes en segmentos para una traducción consciente del contexto, así que puedes subir un manual completo o un libro escrito en Markdown en lugar de pegarlo por partes.

La página del producto no describe un manejo especial para front matter, bloques de código o componentes MDX, y no ejecutamos esta muestra a través de BookTranslator para este artículo. Sea cual sea la herramienta que uses, haz los pasos 1 a 3 antes de traducir y los pasos 5 a 7 después. Un encabezado sin un ID fijo sigue perdiendo sus enlaces, y un rango escrito con tildes sigue convirtiéndose en tachado. Si publicas un libro en varios idiomas, nuestra guía para autopublicar en varios idiomas cubre el resto de esa tarea.

Obtén los archivos de prueba

Todo lo de esta prueba es libre de reutilizar:

Publicaciones relacionadas