Small, dependency-light Python scripts for building and maintaining MDict
(.mdx / .mdd) dictionaries: convert other dictionary formats into .mdx,
inspect what a .mdx contains, and fix up the support files (.css, .mdd)
that MDict and GoldenDict need on the desktop.
These were written while consolidating a large personal English-dictionary library. They are deliberately simple, single-file, and easy to read and adapt — not a framework.
tools/ reusable command-line utilities
examples/ worked one-off converters kept as reference (see examples/README.md)
requirements.txt
python3 -m pip install -r requirements.txtCore dependencies:
| package | used for |
|---|---|
mdict-utils |
packing the .mdx (writer.pack / pack_mdx_txt) |
readmdict |
reading .mdx / .mdd back (verification, extraction) |
pyglossary |
reading StarDict .ifo, Babylon .bgl, some .dsl |
pillow |
only for glyph-montage inspection (see examples) |
mobi |
only for the Kindle MOBI example |
Lenient DSL parser. Handles .dsl and dictzip/gzip .dsl.dz, auto-detects
encoding, converts the common [b] [i] [mN] [ref] <<...>> markup to HTML,
turns cross-references into entry:// links and alternate headwords into
@@@LINK= redirects. Unknown tags are dropped rather than aborting the entry —
this is the reason it exists, since pyglossary's DSL reader silently loses
entries on non-standard markup.
python3 tools/dsl2mdx.py input.dsl.dz "output.mdx" "My Dictionary" "Optional description"Wraps pyglossary's readers and emits a single .mdx. Give it a directory (it
picks the largest .ifo / .dsl / .bgl / .mdx inside) or a direct file
path. If handed an existing .mdx it just copies it along with its
.css / .mdd / image siblings.
python3 tools/stardict2mdx.py ./stardict-folder "output.mdx" "Title"Prints Title / Description / Encoding / Encrypted / CreationDate for .mdx and
.mdd files as JSON. Reads only the header, so it is instant on huge files.
python3 tools/mdx_inspect.py # every .mdx/.mdd in the cwd
python3 tools/mdx_inspect.py ./dictionaries # recurse a folder
python3 tools/mdx_inspect.py a.mdx b.mdd # named filesSamples entries across a folder tree of .mdx and reports which dictionaries
reference images/audio/fonts but ship no .mdd (NEEDS-MDD), and which
<link> a stylesheet that isn't next to them (NEEDS-CSS). Writes
res_audit.json.
python3 tools/audit_resources.py ./dictionariesMany dictionaries pack their .css inside the .mdd. This writes any such
.css out next to the .mdx and prints a file-type breakdown of every .mdd.
python3 tools/extract_css_from_mdd.py ./dictionariesMDict only loads a .mdd whose basename is byte-identical to the .mdx.
Downloads often differ by punctuation or word order. This fuzzy-matches each
unmatched .mdd to a sibling .mdx and renames it. Dry run by default:
python3 tools/pair_mdd.py ./dictionaries # show what it would do
python3 tools/pair_mdd.py ./dictionaries --apply # do itheadword
<definition html>
</>
alternate form
@@@LINK=headword
</>
- One record per block, terminated by a line containing only
</>. @@@LINK=targetmakes the headword a redirect totarget.- Internal cross-references are
<a href="entry://OTHER HEADWORD">. - Pack with
mdict_utils.writer:pack(out_mdx, pack_mdx_txt(src_txt, encoding="UTF-8"), title, desc, encoding="UTF-8").
- Verify after packing. Every converter re-opens the result with
readmdictand prints the key count. A drop of thousands of entries usually means a headword/body regex didn't match the source's markup. - Encoding. DSL is frequently UTF-16; StarDict is usually UTF-8; old Babylon
exports can be CP1251.
dsl2mdx.pytries a list; for others pass the right one to pyglossary. .mddis the same container as.mdx— it just holds files (\path\name.ext) instead of definitions. Build one withmdict_utils.writer.pack(target, dir, title, desc, is_mdd=True).
MIT — see LICENSE.