Architecture¶
Version 1.3 is about 1,100 lines of Python in ten modules. This page follows one document through them.
Module map¶
src/vexy_markliff/
├── __init__.py # lazy VexyMarkliff wrapper, lazy imports, __version__
├── __version__.py # generated by hatch-vcs at build time (not in Git)
├── cli.py # VexyMarkliffCLI + main(), Fire entry point
├── config.py # ConversionConfig, ConversionConfig.load()
├── exceptions.py # VexyMarkliffError and subclasses
├── utils.py # whitespace, language-code and logging helpers
├── core/
│ ├── __init__.py # exports VexyMarkliff, MarkdownParser, HTMLParser
│ ├── converter.py # VexyMarkliff: the four conversion methods
│ └── parser.py # MarkdownParser, HTMLParser
└── models/
├── __init__.py # lazy exports of the models
└── xliff.py # TranslationUnit, XLIFFFile, XLIFFDocument (Pydantic)
The console script vexy-markliff maps to vexy_markliff.cli:main in pyproject.toml.
Markdown to XLIFF, step by step¶
Take "# Hello\n\nThis is **bold** text.\n" with source_lang="en" and target_lang="fr".
- Entry.
VexyMarkliff.markdown_to_xliffin__init__.pyimportscore.converter.VexyMarkliffon first use and forwards the call. - Validation. The core converter rejects empty content and checks both language codes with
utils.validate_language_code. -
Markdown rendering.
MarkdownParser.parserenders withmarkdown-it-py(CommonMark preset,htmlandbreakson,tableandstrikethroughenabled): -
HTML parsing.
HTMLParser.parsecallslxml.html.fromstring, which wraps the two top-level elements in a<div>._extract_segmentswalks the tree and yields: -
Model building.
XLIFFDocument(source_lang="en", target_lang="fr", content=...)creates oneXLIFFFilewith idfile_1and aTranslationUnitper segment (unit_1…unit_4, statenew). - Serialization.
XLIFFDocument.to_xml()builds the<xliff>tree withlxml.etreeand returns a pretty-printed string.
The element names collected in step 4 are not written to the XLIFF; the models have no field for them.
XLIFF back to text¶
XLIFFDocument.from_xmlparses the string and readstrans-unitelements in the…:document:2.1namespace.- The
contentproperty turns units back into segment dictionaries using thesourcetext. HTMLParser.reconstructwraps each segment in<p>…</p>and joins them with newlines.MarkdownParser.reconstructcalls the same method.
Lazy imports¶
markdown-it-py, lxml and Pydantic are imported only inside conversion methods. The top-level VexyMarkliff class lives in __init__.py so that from vexy_markliff import VexyMarkliff does not import core.converter. models/__init__.py and the package __getattr__ do the same for the models, ConversionConfig and VexyMarkliffCLI.
Error flow¶
ValidationError (empty input, bad language code) ──► raised directly
anything raised inside the conversion try-block ──► logged, re-raised as ConversionError
The CLI catches every exception from a conversion and calls sys.exit(1). It also exits with 1 if the input path does not exist, before reading it.
Dependencies¶
| Package | Used for |
|---|---|
markdown-it-py |
Markdown to HTML |
lxml |
HTML parsing, XLIFF building and parsing |
pydantic |
XLIFF data models |
fire |
CLI |
pyyaml |
ConversionConfig.load |
rich |
Declared in pyproject.toml; not imported by the 1.3 source |
Planned architecture¶
The design overview describes the intended pipeline: skeleton files with ###uN### placeholders, Format Style (fs:fs, fs:subFs) annotations, inline <mrk> and <ph> codes, sentence segmentation and a two-document alignment mode.