Translate subtitle files using local LLMs (oMLX, Ollama) or OpenAI — with an Electron desktop app and a full CLI.
Built by Jens Stalder / Syneris Solutions GmbH · MIT License
I watch a lot of older TV shows that simply never got a German translation — or only got a bad one. Paying an API for every episode adds up fast, and I wanted something that runs fully offline using local LLMs on my Mac.
So I built this for two reasons:
- Gap filler — classic shows, cult films, obscure miniseries that exist only in English. Run them through a local model overnight and watch them in your language.
- Creative fun — the
--contextflag lets you steer the model's tone. Add emoji to emotional scenes, give characters distinct voices, make a dry documentary feel dramatic. The subtitle file is just text; the model can do a lot with the right prompt.
If you're in the same situation — foreign-language shows with no subtitles, or just want to experiment with LLM-driven translation — hopefully this saves you some time.
— Jens
- Local-first — works with oMLX, Ollama, LM Studio, or any OpenAI-compatible endpoint
- Resume-safe — re-run anytime; already-translated entries are skipped
- Token-efficient — strips timestamps, sends compact numbered batches
- Episode context — add a show description to improve name handling and tone
- Auto-retry — errored subtitles are retried once before the final export
- SQLite-backed — tracks every entry, status, and token usage per run
- Desktop app — full Electron UI with live batch progress
Download the latest .dmg from Releases, open it, and drag SRT Translator to your Applications folder.
I have not got around to adding a signed developer certificate yet. Currently you will need to sign it yourself with xattr -c /Applications/SRT\ Translator.app before it can be launched.
Requires Node.js v22+.
git clone https://github.com/syneris/srt-translator.git
cd srt-translator
npm install
npm run buildLink globally for CLI use:
npm link
srt-translator --helpStep 1 — configure your backend once:
# oMLX / LM Studio / llama.cpp (OpenAI-compatible)
srt-translator backend add local \
--type openai \
--url http://127.0.0.1:8234/v1 \
--key any \
--model your-model-name \
--default
# Ollama
srt-translator backend add local \
--type ollama \
--url http://localhost:11434 \
--model llama3.2 \
--default
# OpenAI
srt-translator backend add openai \
--type openai \
--key sk-... \
--model gpt-4o \
--defaultStep 2 — translate:
srt-translator translate episode01.srt --target GermanThe project is auto-created from the filename. Re-running is always safe — already-done entries are skipped.
Export manually:
srt-translator export episode01 -o episode01.de.srtOn completion, the translated .srt is automatically saved alongside the source file (e.g. episode01.german.srt).
One sentence dramatically improves translation quality for proper names, tone, and domain terms:
srt-translator translate episode01.srt \
--target German \
--context "Breaking Bad S01E01. A chemistry teacher starts cooking meth."for f in /path/to/season1/*.srt; do
srt-translator translate "$f" --target German
donebackend add <name> --type <openai|ollama> --model <m> [--url <u>] [--key <k>] [--default]
backend list
backend default <name>
backend remove <name>
translate <file.srt|project-name> --target <lang> [--context <text>]
[--profile <name>] [--batch-size 20] [--retry-errors]
export <project-name> [-o output.srt]
status <project-name> [--pending] [--errors] [--limit 50]
reset <project-name> [--errors-only]
project list
project info <name>
project set-context <name> <text>
project create -n <name> -f <srt> -t <lang> [-c <context>]
- Batch size: 15–25 is a good balance. Too large and the model may drop line numbering; too small wastes overhead.
- Local models: Qwen3 family works well. Models without thinking/reasoning capabilities are faster and use fewer tokens.
- Data location:
~/.srt-translator/—translations.db(SQLite) andconfig.json(profiles). Never committed.
npm run electron:dev # Electron app with DevTools
npm run dev # CLI via tsx (no build step)
npm run build # Compile TypeScript
npm run dist # Package → release/*.dmgMIT © Syneris Solutions GmbH
