¿Qué hace Lectura Bilingüe (Bilingual Reading)?
Resumen
Convierte un PDF técnico en inglés en una versión HTML offline con traducción párrafo a párrafo bilingüe: cada capítulo es un HTML autocontenido (UTF-8, imágenes base64 incrustadas, se puede abrir sin conexión), con un índice plegable fijo a la izquierda y un botón flotante 🌐 en la parte inferior derecha que alterna entre los modos «solo inglés», «solo chino» y «bilingüe», recordando el estado entre páginas.
Activación y entrada
- Entrada: PDF en inglés (ruta local o URL, se descarga primero).
- Salida:
index.html+ páginas de prefacio/postfacio +chapter-NN.html(un archivo por capítulo), empaquetado en zip final. - Si el PDF tiene marcadores (
get_toc()), la estructura de capítulos se basa en los marcadores y se confirma con el usuario; después de que el usuario confirme «no dividir», se produce en lote.
Reglas principales (no violables)
- El texto original se traduce párrafo por párrafo completamente, sin resúmenes ni fusiones.
- Un capítulo por archivo, sin dividir capítulos; dentro del capítulo, se siguen las páginas originales en orden.
- Los bloques de código (
<pre><code>) permanecen en inglés sin traducir; el código con llaves no se escribe dentro de f-strings. - Los párrafos en chino tienen fondo azul claro + barra lateral izquierda de 4px, diferenciándose de los párrafos en inglés; los elementos de lista en chino siguen la misma especificación.
- Las imágenes se comprimen y luego se incrustan en base64; después de traducir cada página del PDF original, se añade una marca de página (
page_mark(pdf_page)) que muestra el número de página original del PDF. - Los nombres de archivo están en minúsculas con guiones (
chapter-01.html,front-matter.html). - Las entradas del índice se generan según la jerarquía de marcadores (l2/l3); los enlaces entre capítulos se encadenan, y los del primer y último capítulo aparecen desactivados.
Flujo de trabajo general
① Definir rango de páginas → ② Extraer texto → ③ Extraer imágenes → ④ Comprimir y convertir a base64
→ ⑤ Leer texto original y traducir → ⑥ Escribir build_chN.py → ⑦ Correguir llaves → ⑧ Ejecutar para generar
→ ⑨ Encadenar navegación → Verificar → Entregar
Primero se hace un capítulo de muestra (normalmente ch1) para que el usuario apruebe el estilo; después de la aprobación, se consolida/reutiliza book_theme.py y se produce en lote de forma continua, sin necesidad de confirmaciones intermedias. Las páginas de prefacio/postfacio y index.html se unifican al final.
Pasos detallados
① Definir rango de páginas
Entrada: TOC del libro / número de capítulo. Usar PyMuPDF para leer marcadores:
import fitz
doc = fitz.open("book.pdf")
toc = doc.get_toc() # [[level, title, page_1based], ...]
Convertir números de página basados en 1 al intervalo basado en 0 de PyMuPDF. Los números de página de los marcadores a menudo tienen desplazamiento respecto a las páginas físicas; se usan los marcadores como referencia; listar la división de capítulos al usuario y confirmar antes de empezar.
② Extraer texto
text = "".join(doc[p].get_text("text", sort=True) for p in range(start0, end0+1))
open("chN_raw.txt", "w", encoding="utf-8").write(text)
sort=True asegura el orden de lectura, sin confundir columnas múltiples. Guardar texto original en chN_raw.txt por capítulo.
③ Extraer imágenes
Usar scripts/extract_assets.py:
python3 extract_assets.py book.pdf <start_page_1based> <end_page_1based> --out assets
page.get_images(full=True)deduplicado por xref →extract_image(xref).- jpx (JPEG2000), RGBA, modos P se convierten uniformemente a RGB y luego a JPEG (compatible con navegadores).
④ Comprimir y convertir a base64
Se realiza junto con el paso anterior (integrado en el script): abrir con PIL; si el ancho es >800px, escalar proporcionalmente a 800 (LANCZOS); JPEG q≈68 re-guardar; base64 escribir en assets/figN-M.txt. Cada imagen se comprime a 30~80KB.
⑤ Leer texto original y traducir
- Leer
chN_raw.txtpor segmentos (500~600 líneas cada vez), traducir párrafo por párrafo, y registrar las correspondencias de leyendas de imágenes (por ejemplo, diagrama de cuervo, convertirlo al texto correspondiente "notas"). - Saltar traducción de bloques de código; convertir tablas a HTML table; también traducir elementos de lista uno por uno sin fusionar.
⑥ Escribir script de construcción
Al inicio de build_chN.py: from book_theme import P, LI, CODE, INLINE, H, img_b64, page_mark, page; el contenido principal se escribe en el f-string body. Dentro del f-string, P()/LI() deben escribirse como {P(...)} para que se evalúen; los bloques de código se extraen como variables de cadena normales CODE_X = '''...''' y se concatenan con + CODE_X. Para la plantilla completa, ver el docstring al inicio de scripts/book_theme.py.
⑦ Post-procesamiento: corregir llaves
python3 scripts/fix_braces.py build_chN.py
Recorrer líneas: agregar { al inicio de líneas que comienzan con P('/LI('; buscar hacia adelante la primera línea que termina con ) y agregar } al final. No procesar llamadas a img_b64(/page( para evitar agregar } al final de las líneas page().
⑧ Ejecutar para generar
python3 build_chN.py # El script imprime el nombre del archivo y el tamaño en KB si tiene éxito
⑨ Encadenar navegación
Completar prev/next según el número de capítulo (ch1 prev=front-matter.html, último capítulo next=None); los botones del primero y último capítulo usan disabled como marcador de posición (ya manejado dentro de page()).
Cierre
- front-matter.html, closing.html (con/sin bibliografía recomendada, acordar con el usuario antes),
index.htmlcomo entrada principal (enlace a todos los capítulos). - Empaquetar con
python3 -m zipfile -c bilingual_reading.zip *.html, entregar el zip.
Ramas y manejo de excepciones
| Condición de activación | Método de manejo |
|---|---|
| Imagen es jpx / RGBA / modo P | extract_assets.py convierte uniformemente a RGB con convert() y luego guarda como JPEG |
| F-string contiene llaves de bloque de código (dict JSON) | No escribir dentro del f-string; extraer como CODE_X = '''...''' y concatenar con + CODE_X |
{<P( escrito por error | Corregir con sed 's/{<P(/{P(/g' |
Agregar } en lote accidentalmente al final de líneas page() | fix_braces.py ya lo evita; si ocurre, eliminar manualmente el } extra al final de esa línea |
| El usuario solicita "ver el resultado antes de continuar" | Solo hacer el capítulo de muestra, pausar y esperar retroalimentación |
| El usuario solicita "no traducir el código" | Todos los <pre><code> permanecen en inglés original (por defecto así) |
| Más elementos de depuración | Ver references/troubleshooting.md |
Índice de recursos
scripts/book_theme.py— Módulo compartido principal: CSS/JS/esqueleto de página + funciones P, LI, CODE, INLINE, H, img_b64, page_mark, page. Los cambios de estilo solo se hacen aquí.scripts/extract_assets.py— Pasos ③④: extraer imágenes, comprimir, convertir a base64, escribir en assets/.scripts/fix_braces.py— Paso ⑦: agregar llaves de f-string en lote.references/style-guide.md— Detalles de estilo e interacción (colores, diseño, componentes, comparación de aceptación).references/troubleshooting.md— Tabla de resolución de problemas y experiencia reutilizable.
Lista de verificación de aceptación
- El estilo del capítulo de muestra fue aprobado por el usuario (fondo azul claro para chino, elementos de lista en chino con la misma especificación, marca de página presente)
- El texto original está traducido párrafo por párrafo, los bloques de código no están traducidos, las imágenes están incrustadas en base64 y se pueden abrir sin conexión
- Cada capítulo HTML se puede abrir de forma independiente, el índice se puede plegar, los saltos de ancla funcionan correctamente
- El botón 🌐 alterna entre tres estados, se mantiene entre páginas (localStorage)
- Los enlaces entre capítulos están correctamente encadenados, los botones del primer y último capítulo están desactivados
- Todos los archivos en UTF-8, nombres de archivo en minúsculas con guiones, empaquetado en zip para entrega