- pagerite/segments.py replaces masking.py: a fragment is parsed with the
project's own markdown-it (markdown.make_md(verbatim=True), byte-identical
tokens) and split into pure-prose segments with source spans; only the
segments plus per-segment context surrounds cross the wire (Job.texts /
contexts / Result.texts) and translations splice back by offset — markup
can no longer break, it never leaves the server. Count/empty/non-prose
results are rejected and skipped for the run.
- Localization machinery out of app.py: the translator dispatcher (clients,
job pipeline, validation skip-list) moves into translate.Dispatcher;
translated-edit recording moves into i18n (add_patch, set_title_translation,
clear_translations). app.py keeps only the routes.
- Structure editor localized: flag strip switches the language titles are
shown/edited in (GET /_api/pages?lang= flags translated rows, originals
dimmed); retitling in a translation writes a per-language title fragment
via StructureOp.lang — slugs, order and hierarchy stay language-independent.
- Localization tab: refresh-all button (DELETE /_api/translations) drops
machine translations, keeps user patches and clears the skip-list so the
dispatcher re-translates everything.
- PageEditor always opens in the primary language; editor socket gets
reconnect/doc-mismatch logging. Reference translator: per-segment calls
with context prompts, deterministic punctuation matching and the "<"
markup-bleed cut.