EPUB как второй вход в конвейер; листинги кода не переводятся и не ломают приёмку

- epub2html.py: EPUB -> тот же XHTML, что pdf2html.py, только стандартная
  библиотека. Уровень глав определяется по книге, а не берётся из <h1>:
  в EPUB там обычно название и части.
- pdf2html.py: листинг узнаётся по флагу моноширинного шрифта PyMuPDF,
  переносы и отступы внутри <pre> сохраняются, де-дефисация к коду не
  применяется.
- translate.py: <pre> исключён из проверок языка (английский код утягивал
  долю кириллицы ниже порога приёмки), рабочий каталог привязан к книге,
  устаревшие главы прошлого прогона чистятся, инлайновый <code> переживает
  переводчика.
- bookhtml.py: общий каркас документа и CSS для обоих входов.
- Тесты: test_epub2html.py на собранном в памяти EPUB, четыре новых случая
  в test_translate.py.
This commit is contained in:
chesirecatt
2026-08-20 17:58:09 +03:00
parent 6c81673b4f
commit db9fe5e0fa
7 changed files with 614 additions and 43 deletions
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""Общая сборка XHTML для pdf2html.py и epub2html.py.
Формат намеренно жёсткий: один блок — одна строка (кроме <pre>, где переносы
значимы). На этом держится мост translate.py — он правит блоки по номеру
строки, а всё, чего не узнал, доносит до результата нетронутым.
"""
import html
CSS = """
body { margin: 0 1em; }
h1 { text-align: center; margin: 2em 0 0.2em; page-break-before: always; }
h1.title { page-break-before: avoid; }
h2 { text-align: center; font-style: italic; font-weight: normal;
font-size: 1.1em; margin: 0.2em 0 1.5em; }
p { text-indent: 1.2em; margin: 0; text-align: justify; }
p.note { text-indent: 0; margin: 1em 2em; font-size: 0.9em;
font-family: sans-serif; }
p.li { text-indent: 0; margin: 0.3em 0 0.3em 1.5em; text-align: left; }
p.row { text-indent: 0; margin: 0.3em 0; text-align: left;
font-size: 0.9em; }
p.figure { text-indent: 0; text-align: center; margin: 1em 0; }
img { max-width: 100%; }
pre { font-family: monospace; font-size: 0.75em; margin: 1em 0;
white-space: pre-wrap; word-wrap: break-word; text-align: left;
text-indent: 0; }
code { font-family: monospace; font-size: 0.9em; }
"""
def document(title, parts):
"""parts: [(tag, cls, inner_html)]; tag 'figure' — псевдотег для картинки."""
buf = ['<?xml version="1.0" encoding="utf-8"?>',
'<html xmlns="http://www.w3.org/1999/xhtml"><head>',
"<title>%s</title>" % html.escape(title),
"<style>%s</style></head><body>" % CSS]
for tag, cls, txt in parts:
if tag == "figure":
buf.append('<p class="figure">%s</p>' % txt)
else:
c = ' class="%s"' % cls if cls else ""
buf.append("<%s%s>%s</%s>" % (tag, c, txt, tag))
buf.append("</body></html>")
return "\n".join(buf)