Skip to main content

Translate Markdown docs into multiple languages using LLMs with smart caching and custom prompts

Project description

mdxlate

Translate Markdown docs into multiple languages using LLMs.
Batteries included: prompt template, CLI, OpenAI/OpenRouter provider switch, and a simple change-detection cache.

📚 Documentation

Read the full documentation →

Install

pip install -e .

Quick start

  1. Initialize the editable prompt (creates ~/.mdxlate/translation_instruction.txt):
mdx init
  1. Run translations:
export OPENAI_API_KEY=sk-...   # or use OPEN_ROUTER_API_KEY when provider=openrouter
mdx run docs_src out --languages de fr --model gpt-4o-mini

Result: translated files under out/<lang>/..., preserving the original folder structure. A cache file .mdxlate.hashes.json is written in docs_src.

CLI

mdx run [OPTIONS] DOCS_SRC OUT_DIR

Options

  • --base-language TEXT – Base language (default: en)
  • --languages TEXT... – Target languages, space-separated (default: de)
  • --model TEXT – Model name (default: gpt-4o-mini)
  • --provider [openai|openrouter] – Backend provider (default: openai)
  • --api-key TEXT – API key (overrides env)
  • --api-env-key TEXT – Env var to read (default: OPENAI_API_KEY)
  • --base-url TEXT – Custom base URL (e.g., OpenRouter)
  • --prompt-path PATH – Use a custom prompt file instead of the default
  • --force – Force re-translation, bypassing cache
  • --cache-dir PATH – Directory for cache file (defaults to source directory)

Examples

OpenAI (env var):

export OPENAI_API_KEY=sk-...
mdx run docs_src out --languages de fr --model gpt-4o-mini

OpenRouter:

export OPEN_ROUTER_API_KEY=or-...
mdx run docs_src out --languages de --provider openrouter --model google/gemini-2.5-pro

Custom prompt:

mdx run docs_src out --languages de --prompt-path ./my_prompt.txt

Custom cache directory (for read-only CI/CD):

mdx run docs_src out --languages de --cache-dir /tmp

Error Handling

If any file fails to translate (e.g., due to API errors, rate limits, or network issues), mdxlate will:

  1. Continue processing other files instead of crashing
  2. Save the cache for successful translations
  3. Generate a failure report at .mdxlate.failures.json with details about what failed

Example failure report:

{
  "failures": [
    {
      "file": "docs/advanced.md",
      "error": "Rate limit exceeded",
      "error_type": "RateLimitError"
    }
  ]
}

After fixing the issue (e.g., waiting for rate limits to reset), re-run the translation. Only failed files will be retried thanks to the cache.

Behavior

  • Prompt: default lives at ~/.mdxlate/translation_instruction.txt (created by mdx init). You can edit it freely or pass --prompt-path.
  • Cache: re-translation is skipped if file bytes + prompt content + model + language are unchanged. By default, cache is written to source directory as .mdxlate.hashes.json. Use --cache-dir for read-only environments.
  • Structure: each language gets its own mirror tree under OUT_DIR/<lang>/.

Programmatic use

from pathlib import Path
from mdxlate.start_translation import start_translation

start_translation(
    docs_src=Path("docs_src"),
    out_dir=Path("out"),
    base_language="en",
    languages=["de", "fr"],
    model="gpt-4o-mini",
    provider="openai",  # or "openrouter"
    api_key=None,       # pass explicitly or rely on env
    base_url=None,
    prompt_path=None,
    cache_dir=None,     # optional: specify custom cache directory
)

Integrations

  • Jekyll – Complete guide for translating Jekyll sites with frontmatter preservation

Files of interest

  • mdxlate/cli.py – Typer CLI (mdx init, mdx run)
  • mdxlate/client.pymake_client() factory (OpenAI/OpenRouter)
  • mdxlate/translator.py – translation, hashing, and I/O
  • mdxlate/translation_instruction.txt – default prompt template

Development

Setup

pip install -e .
pip install ruff mypy pytest

Code Quality

This project uses Ruff for linting and formatting, and Mypy for type checking:

# Lint code
ruff check src tests

# Auto-fix linting issues
ruff check --fix src tests

# Format code
ruff format src tests

# Type check
mypy src --ignore-missing-imports

# Run tests
pytest tests/

CI/CD

The .github/workflows/quality.yml workflow runs automatically on every push and PR:

  • ✅ Ruff linting
  • ✅ Ruff formatting check
  • ✅ Mypy type checking

License

MIT

Layout

repo/
  pyproject.toml
  README.md
  src/
    mdxlate/
      __init__.py
      cli.py
      client.py
      translator.py
      start_translation.py
      translation_instruction.txt
  tests/            # optional
  main.py           # optional local test runner

---

# pyproject.toml
```toml
[build-system]
requires = ["setuptools>=69", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "mdxlate"
version = "0.1.0"
description = "Translate Markdown docs into multiple languages using LLMs."
readme = "README.md"
requires-python = ">=3.10"
license = { text = "MIT" }
authors = [{ name = "Tobias Bück" }]
dependencies = [
  "typer>=0.12",
  "openai>=1.40",
  "tenacity>=8.2",
]

[project.scripts]
mdx = "mdxlate.cli:app"

[tool.setuptools]
package-dir = {"" = "src"}

[tool.setuptools.packages.find]
where = ["src"]
include = ["mdxlate*"]

[tool.setuptools.package-data]
mdxlate = ["translation_instruction.txt"]

[tool.pytest.ini_options]
addopts = "-q"
testpaths = ["tests"]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mdxlate-1.1.4.tar.gz (17.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mdxlate-1.1.4-py3-none-any.whl (12.0 kB view details)

Uploaded Python 3

File details

Details for the file mdxlate-1.1.4.tar.gz.

File metadata

  • Download URL: mdxlate-1.1.4.tar.gz
  • Upload date:
  • Size: 17.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.22

File hashes

Hashes for mdxlate-1.1.4.tar.gz
Algorithm Hash digest
SHA256 c3b80e629a55a6409157d82a50f796aa26154fbd9f7ce48640e7d2ad2ee79833
MD5 d4116b0775bc7579cf5cafc4eb1a4692
BLAKE2b-256 c116478505cd25f5980e7741798aee6b31b8714f969bdc950c552d8ae4428279

See more details on using hashes here.

File details

Details for the file mdxlate-1.1.4-py3-none-any.whl.

File metadata

  • Download URL: mdxlate-1.1.4-py3-none-any.whl
  • Upload date:
  • Size: 12.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.22

File hashes

Hashes for mdxlate-1.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 14536e4311954dd16d52c7f0dc558fd3c9ce99e3269a065d5bfb2e5152aba740
MD5 161eb5b2eff295f2c8a36e02ae15ccca
BLAKE2b-256 8a64f8f16e84ea16abc3faa16e2df9c94e8c4fb22a1e75cd322269c0fde1eba6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page