Vetrenar612 downloadsTranslate PDF documents with overlay, supports OpenRouter, OpenAI, Gemini, Ollama, and custom endpoints. Includes layout detection, and persistent storage of translations..
Translate PDF documents in Obsidian using OpenRouter, OpenAI, Anthropic, Gemini, Ollama, and other LLM providers. Features overlay rendering, OCR for scanned documents, batch translation with background queue, and a BBox edit mode for manual overlay adjustments.
The plugin follows a multi-stage pipeline to translate PDF content:
1. Text extraction. When you open a PDF and trigger translation, the plugin extracts text from the PDF page. Two extraction engines are available:
fitz) child process that parses the PDF with a more sophisticated layout model. Requires Python 3.8+ and pip install pymupdf.Both engines produce the same output format: an array of text spans with bounding rectangles (relative to the page, as 0–1 fractions), font metadata, and the raw text content.
2. Layout detection. The extracted spans are grouped into paragraphs by the layout detector
Settings like contourIndentThreshold, fontSizeTolerance, maxMergePasses, columnGapThreshold, and decorationThreshold control how aggressive the splitting/merging is. The preserveStyle option (enabled by default) treats bold and italic as different font families, producing finer-grained paragraphs.
3. Translation. Each paragraph's text is sent to your configured LLM provider.
The maxBatchChars setting controls the maximum characters per batch. If the total exceeds this, paragraphs are split into multiple batches. A sequentialDelayMs setting adds a pause between batches to avoid rate-limiting.
4. Overlay rendering. Translated text is rendered as a position: absolute div overlay on top of the original PDF page.
5. Persistence. Translations are saved to a .translations.md file alongside the PDF (in the same folder, or a configurable storage folder). The file uses the V4 format (see below) with YAML frontmatter and Obsidian %% {...} %% comments containing per-overlay JSON metadata. Writes are atomic (temp file + rename) and serialized via a per-file write lock (writingPromises).
You can show or hide overlays without losing translations:
Toggle PDF overlay visibility (or hotkey) flips all overlays globallyvisibility: hidden — they become visible instantly when you toggle back onshowOverlayByDefault controls whether overlays appear when a PDF is first openedBBox Edit Mode is a non-invasive overlay editing system. When enabled:
innerText).translations.md file at the current page headingBBox Edit Mode does not pause the background translation queue. You can edit overlays while background translation is running — writes are serialized via the per-file lock.
The background queue translates entire PDFs (or page ranges) without blocking the UI:
PdfLayoutQueue processes pages sequentially within a file (extraction is serial, translation is parallel up to backgroundTranslationConcurrency). Multiple files are processed in FIFO order.concurrency × 10). If the queue is full, extraction pauses until translation drains it — prevents OOM on 1000+ page PDFs.Translation files (.translations.md) use the V4 format:
---
pdf-source: "[[document.pdf]]"
timestamp: 2026-08-13T12:00:00.000Z
format-version: 4
engine: openrouter/openai/gpt-4o-mini
layoutSettingsHash: a1b2c3d4e5f67890
---
# Translations for document
> Last updated: 2026-08-13 12:00
## Page 1
[[document.pdf#page=1|→ View page]]
%% {"r":{"l":0.12,"t":0.34,"w":0.56,"h":0.08},"page":1,"ot":"Original text","fs":12,"ff":"sans-serif","ofs":[12,12,11],"id":"a1b2c3d4e5f67890","engine":"openrouter/openai/gpt-4o-mini"} %%
Translated text here
| Field | Type | Description |
|---|---|---|
r |
{l,t,w,h} |
Relative bounding rect (0–1 fractions of page dimensions, 4-decimal precision) |
page |
number | Page number |
ot |
string | Original text content (used for edit-modal lookup) |
fs |
number | Font size (persisted but inert — rendering uses ofs instead) |
ff |
string | Font family |
ofs |
number[] | Original font sizes array (drives overlay rendering — dominant/mode size) |
id |
string | Stable hash hash(page + rect@2dec + textContent) — enables exact overlay lookup and merge-by-id |
engine |
string | <provider>/<model> that produced this translation |
| Field | Description |
|---|---|
pdf-source |
Wikilink to the source PDF (ties .translations.md to its PDF) |
timestamp |
ISO-8601 creation/update time (display only) |
format-version |
4 (V3 files are auto-migrated on first edit) |
engine |
Primary engine used for this file |
layoutSettingsHash |
Hash of layout settings — isCached invalidates on mismatch, forcing re-translate when layout preset changes |
Automatic on first edit/translate after plugin update:
format-version: 3) continue to work without changesid and engine are stamped on all overlays, format-version bumped to 4layoutSettingsHash added to frontmattermain.js, manifest.json, and styles.css to your vault's .obsidian/plugins/openrouter-pdf-translator/ folderThe following features require desktop Obsidian (Windows, macOS, Linux) and are not available on mobile (iOS/iPadOS):
layoutEngine: 'python'): Uses PyMuPDF for advanced layout detection. Requires Python 3.8+ and PyMuPDF installed on your system:pip install pymupdf
Export PDF with translations command): Renders a new PDF with translated text baked in. Same Python+PyMuPDF requirement.All other features (translation, overlay, OCR via cloud vision models, basic layout detection, BBox edit mode) work on both desktop and mobile.
| Provider | API Key Required | Default Model | Notes |
|---|---|---|---|
| OpenAI | Yes | gpt-4o-mini |
Full support including vision |
| Anthropic | Yes | claude-3-5-sonnet-latest |
Full support including vision |
| Google Gemini | Yes | gemini-2.0-flash-exp |
Full support including vision |
| OpenRouter | Yes | openai/gpt-4o-mini |
Aggregator — access many models |
| RouterAI | Yes | openai/gpt-4o |
Russian aggregator (routerai.ru) — OpenAI-compatible API |
| DeepSeek | Yes | deepseek-chat |
Text only |
| xAI (Grok) | Yes | grok-2 |
Text only |
| Groq | Yes | llama-3.3-70b-versatile |
Fast inference |
| Mistral | Yes | mistral-small-latest |
Text only |
| Together AI | Yes | meta-llama/Llama-3-8b-chat-hf |
Open-source models |
| Alibaba Qwen | Yes | qwen-plus |
Text only |
| Ollama | No | llama3 |
Local, requires Ollama running |
| LM Studio | No | (user-set) | Local, requires LM Studio running |
| vLLM | No | (auto-fetched) | Local, requires vLLM server |
| Custom | Varies | (user-set) | Bring your own endpoint |
Translate multiple pages... — Open the batch translation modal (page range, start/cancel)Translate and add overlay to current PDF page — Quick single-page translateReprocess/retranslate a text region — Re-translate a selected region (shift+drag)Retranslate using saved overlay layout... — Bulk re-translation from saved overlaysSave current PDF overlay — Save current page's overlays to diskRefresh current PDF overlay — Reload overlays from diskClear current PDF overlay — Remove all overlays from current pageToggle PDF overlay visibility — Show/hide all overlays globallyToggle BBox Edit Mode — Enable/disable overlay editing (non-invasive)OCR: recognize PDF to translated note — OCR with translation (multi-page)OCR: recognize current page — Single-page OCRBackground translation: open watched-folder queue — Open watcher modal (Card Stack layout: Active + Available sections)Layout: extract entire PDF (background) — Extract layout data in backgroundLayout: create file with originals — Create originals-only translation fileExport PDF with translations — Desktop-only, requires PythonRepair translation links — Fix pdf-source frontmatterRepair translation file — Re-parse and re-write translation files (triggers V3→V4 migration)Rebuild PDF-to-translation file map — Refresh internal mapClean unused translation files — Find and delete orphaned filesThe plugin has 14 settings sections:
maxBatchChars), concurrency, retry settings, reasoning mode.translations.md V4 format){TEXT}, {sourceLang}, {targetLang} placeholders)GLM-3.0 License — see LICENSE file for details.
This plugin includes two Python scripts (layout_engine.py and pdf_export.py) as embedded base64 resources. These are required for the Python layout engine and PDF export features (desktop-only). Both scripts are licensed under the GLM-3.0 License.
data.json).translations.md) are stored in your vault — you own all data