TBL_promo_github.mp4
翻译书籍 · 本を翻訳する · 책을 번역하다 · किताबों का अनुवाद · Перевод книг · แปลหนังสือ · Μετάφραση βιβλίων · ترجمة الكتب
A desktop app that translates books, subtitles, and documents with AI - local or cloud. Drop a file, pick a language, get the result.
Formats: EPUB, SRT, DOCX, PDF, TXT, PGN
- No size limit. Process documents of any length - from a single page to thousand-page novels. The intelligent chunking system handles unlimited content while preserving context between segments.
- Perfect preservation. Your documents come out exactly as they went in: EPUB formatting, styles, and structure remain intact. SRT timecodes stay perfectly synchronized. Every tag, every timestamp, every formatting detail is preserved.
- Resume anytime. Interrupted translation? Pick up exactly where you left off. The checkpoint system saves progress automatically.
- Reusable writing styles. Extract a style preset from sample books (or write one by hand) and apply it to every chunk for a consistent register, rhythm, and imagery across the whole translation.
- Auto glossary & style. No glossary or preset ready? Pick Auto in the dropdown and the app derives both straight from the document being translated - one extra LLM call each before the job starts, nothing saved.
- PDF support. Text PDFs are translated into a new, reflowed PDF: headings, paragraphs, lists and images are kept, ruled tables are rebuilt as tables, and paragraph colours, background boxes and the font family (serif, sans-serif, monospace) are preserved, but the original page layout is not, and bold or colour inside a sentence is not. Scanned PDFs are not supported (no OCR), multi-column layouts are best effort, and the refinement pass is not available for PDF yet.
- Chess annotations (PGN). Only the comments of annotated games are translated; tags, moves, variations, NAGs and embedded commands such as
[%cal]arrows or ChessBase[#]diagrams are kept byte for byte. Moves quoted inside a comment ("after 12.Nf3 ...") must come back unchanged, otherwise that comment is retried and finally left in its original language. Moves keep their English piece letters (Nf3, not Cf3) so every chess program can read them. The output is UTF-8, and the refinement pass is not available for PGN yet.
Translation Quality Benchmarks - Find the best model for your target language.
- Download the release for your platform (buttons above), or grab it from the releases page.
- Extract the archive.
- Run
TranslateBook.exe(Windows) or./TranslateBook(macOS). - Open http://localhost:5000 in your browser.
That's it (就这么简单 · これだけ · 이게 다예요). On first launch, you choose a translation provider:
- Free & local - Install Ollama and pull a model (e.g.
ollama pull qwen3:14b). Nothing leaves your machine. - Cloud (often free tier available) - Paste an API key from one of the providers below.
Note: First run creates a
TranslateBook_Datafolder with your settings.macOS: On first launch, go to System Settings > Privacy & Security and click Open Anyway.
| Provider | Type | Get started |
|---|---|---|
| DeepSeek | Cloud | platform.deepseek.com |
| Gemini | Cloud | Google AI Studio |
| Mistral | Cloud | console.mistral.ai |
| NVIDIA NIM | Cloud | build.nvidia.com |
| Ollama | Local | ollama.com |
| OpenAI | Cloud | platform.openai.com |
| OpenAI-Compatible | Local or hosted (llama.cpp, LM Studio, vLLM, LocalAI...) | Point to your server's endpoint |
| OpenRouter | Cloud (200+ models) | openrouter.ai/keys |
| Poe | Cloud (multi-model) | poe.com/api_key |
See docs/PROVIDERS.md for detailed setup instructions.
| Problem | Solution |
|---|---|
| Ollama won't connect | Check Ollama is running, test curl http://localhost:11434/api/tags |
| Model not found | Run ollama list, then ollama pull model-name |
See docs/TROUBLESHOOTING.md for more solutions.
Install from source
Prerequisites: Python 3.8+, Ollama, Git
git clone https://github.com/hydropix/TranslateBooksWithLLMs.git cd TranslateBookWithLLM ollama pull qwen3:14b # Download a model # Windows start.bat # Mac/Linux chmod +x start.sh && ./start.sh
The web interface opens at http://localhost:5000.
Command line
# Basic (auto-generates "book (Chinese).epub") python translate.py -i book.epub -sl English -tl Chinese # With OpenRouter python translate.py -i book.txt --provider openrouter \ --openrouter_api_key YOUR_KEY -m anthropic/claude-sonnet-4 -tl French # With OpenAI python translate.py -i book.txt --provider openai \ --openai_api_key YOUR_KEY -m gpt-4o -tl French # With Gemini python translate.py -i book.txt --provider gemini \ --gemini_api_key YOUR_KEY -m gemini-2.0-flash -tl French # With Mistral python translate.py -i book.txt --provider mistral \ --mistral_api_key YOUR_KEY -m mistral-large-latest -tl French # With DeepSeek python translate.py -i book.txt --provider deepseek \ --deepseek_api_key YOUR_KEY -m deepseek-v4-pro -tl French # With Poe python translate.py -i book.txt --provider poe \ --poe_api_key YOUR_KEY -m Claude-Sonnet-4 -tl French # With NVIDIA NIM python translate.py -i book.txt --provider nim \ --nim_api_key YOUR_KEY -m meta/llama-3.1-8b-instruct -tl French # With local OpenAI-compatible server (llama.cpp, LM Studio, vLLM, etc.) python translate.py -i book.txt --provider openai \ --api_endpoint http://localhost:8080/v1/chat/completions -m your-model -tl French
| Option | Description | Default |
|---|---|---|
-i, --input |
Input file | Required |
-o, --output |
Output file | Auto: {name} ({lang}).{ext} |
-sl, --source_lang |
Source language | English |
-tl, --target_lang |
Target language | Chinese |
-m, --model |
Model name | qwen3:14b |
--provider |
ollama/openrouter/openai/gemini/mistral/deepseek/poe/nim | ollama |
--parallel |
Chunks translated concurrently (cloud only; Ollama stays at 1) | 1 |
--text-cleanup |
OCR/typographic cleanup | disabled |
--refine |
Second pass for literary polish | disabled |
--tts |
Generate audio (Edge-TTS) | disabled |
See docs/CLI.md for all options (TTS voices, rates, formats, etc.).
Configuration (.env)
Copy .env.example to .env and edit:
# Provider LLM_PROVIDER=ollama # Ollama API_ENDPOINT=http://localhost:11434/api/generate DEFAULT_MODEL=qwen3:14b # API Keys (if using cloud providers) OPENROUTER_API_KEY=sk-or-v1-... OPENAI_API_KEY=sk-... GEMINI_API_KEY=... MISTRAL_API_KEY=... DEEPSEEK_API_KEY=... POE_API_KEY=... NIM_API_KEY=... # Performance REQUEST_TIMEOUT=900 MAX_TOKENS_PER_CHUNK=450 # Token-based chunking (default: 450 tokens) PARALLEL_TRANSLATIONS=1 # Concurrent chunks (cloud only; Ollama stays at 1)
Faster on cloud providers? Set PARALLEL_TRANSLATIONS (or --parallel N, or the "Parallel requests" field in the web UI) above 1 to translate several chunks at once. Local providers (Ollama) ignore it since a single instance serializes requests. Higher values are faster but can hit provider rate limits.
Multiple API keys? Any *_API_KEY variable accepts a comma-separated list (e.g. GEMINI_API_KEY=key1,key2,key3). The system rotates between keys automatically when one hits a rate limit - useful to chain free-tier accounts. See docs/API_KEY_ROTATION.md.
Long jobs? Get a push notification on your phone (via ntfy), Discord, Slack, gotify, or any HTTP endpoint when a translation finishes. Set NOTIFY_WEBHOOK_URL in .env. See docs/NOTIFICATIONS.md.
Docker
docker build -t translatebook . docker run -p 5000:5000 -v $(pwd)/translated_files:/app/translated_files translatebook
See docs/DOCKER.md for more options.
One server is one shared workspace - there are no user accounts, so every browser pointed at it sees the same state. A running job's progress panel, paused/interrupted jobs, the completed translation history, and the files in translated_files/ are all shared: another device picks them up live (within a second or two) or on page load. A small set of preferences - source/target language, TTS, text cleanup, bilingual mode, plain-text mode, and the selected custom instruction - is synced too: the server wins at page load, the last change wins after that, and a tab that is already open picks up changes made elsewhere on its next reload.
Two things stay local to the device: if you queue several files, other devices only see the one currently translating, not the rest of the queue (it's held in the browser that built it); and the UI language is per-browser. Provider, model, API keys, and endpoints are never synced - they always come from the server's .env.
| Guide | Description |
|---|---|
| docs/PROVIDERS.md | Detailed provider setup (Ollama, LM Studio, OpenRouter, OpenAI, Gemini) |
| docs/API_KEY_ROTATION.md | Use multiple API keys per provider with automatic failover on rate-limit |
| docs/NOTIFICATIONS.md | Webhook notifications on completion (ntfy, gotify, Discord, Slack, custom) |
| docs/GLOSSARY.md | Force consistent term translations across a book (Web UI + CLI, auto-extract via NER) |
| docs/TERM_FIX.md | Fix a term in an already-translated book without translating again (Web UI + CLI) |
| docs/STYLE_EXTRACTION.md | Extract a reusable writing-style preset from sample books and apply it to every chunk (Web UI) |
| docs/CLI.md | Complete CLI reference |
| docs/TROUBLESHOOTING.md | Problem solutions |
| docs/DOCKER.md | Docker deployment guide |
If TBL saves you time, you can support its development on Ko-fi:
Thank you · 谢谢 · ありがとう · 감사합니다 · धन्यवाद · Спасибо · ขอบคุณ · Ευχαριστώ · شكرًا
License: AGPL-3.0