A subtitle translator looks simple from the outside: give it a video, choose a language, receive an SRT. The difficult part is everything between those points. A useful result needs stable timing, enough context for natural language, recovery when an engine misses a line, and a way to inspect what happened.

The motivation was fairly personal. Some niche Japanese films and videos I watch do not come with usable subtitles. When subtitles are available, overly literal machine translation can make the dialogue feel awkward. Instead of translating one file and forgetting about it, I started building a workflow that I could reuse and keep improving.

From video to a stable SRT

The project is a menu-driven Windows tool rather than a single translation script. It can generate subtitles from video with Whisper or WhisperX, translate an existing SRT, combine generation and translation in one unattended run, or clean up timing overlaps and very short segments. Translation can use Gemini CLI, a local Ollama model, NLLB offline, or a primary-engine-plus-NLLB fallback flow.

The flow begins by creating or loading an SRT file. Transcription can run locally with Whisper or WhisperX; the source language is detected from the subtitle text. From there, the translator works with numbered subtitle blocks instead of treating the whole file as one loose paragraph.

The important stages in the pipeline.
video or existing SRT
  → transcription and source-language detection
  → genre or content-type context
  → numbered batches for translation
  → validation of missing or unchanged segments
  → local fallback and retry
  → line wrapping, preview, and SRT output
text

Generation and translation remain separate operations even when the menu runs them back to back. That separation matters: someone can reuse an existing SRT without transcribing again, choose a fully offline path, or stop after generation. Batch file entry points handle file discovery and environment choices, while the Python translation layer owns parsing, engine calls, validation, and output.

Context without giving up structure

The pipeline asks AI to identify a likely genre or content type before translation. That context helps set the language register: dialogue from a documentary should not read like casual comedy, and a short reaction should remain short enough to read on screen. It is guidance, not a claim that one genre label can solve every translation decision.

An illustrative comparison: the same Japanese subtitle with and without scene context.
AI-DETECTED CONTEXT
Contemporary workplace drama.
A junior speaks warmly but respectfully
after a senior solves a difficult problem.

JAPANESE SUBTITLE
先輩、やっぱりすごいですね。

WITHOUT CONTEXT
Senior, as expected, you are amazing.

WITH CONTEXT
I knew you’d pull it off, senpai.
text

The contextual version is less literal, but it sounds more like spoken dialogue and preserves the junior–senior relationship without becoming formal or stiff. This is only an example, not a benchmark: another scene could justify a different line, and names or relationship terms still need human review.

The prompt is only one component. The reliable part is the flow around it.

Each batch carries its subtitle number. The translation engine is asked to return the same numbered lines and nothing else, while timestamps stay outside the translation task. This makes missing lines detectable and lets the script put translated text back into the original SRT structure without asking the model to recreate timing data.

A simplified input contract for one batch.
[142] I will be back before sunset.
[143] Do not wait for me.

Return only:
[142] <translated line>
[143] <translated line>
text

Sending one subtitle line at a time loses conversational context, while sending the whole file makes retries expensive and output harder to validate. The tool builds bounded batches and prefers to break near sentence-ending punctuation. Numbered segments retain identity across the round trip, so a failed batch can be retried without throwing away completed work.

Designing for incomplete output

A local LLM or Gemini can produce the most natural first pass, but a segment can be skipped, returned unchanged, or retain source-language characters. The flow detects those cases and sends only the missing pieces to an offline NLLB fallback. If repetitive output appears, the primary engine gets a retry; progress is cached so an interrupted run can continue instead of starting from zero.

A successful process exit does not prove that every subtitle was translated. The validation step looks for missing numbers, text identical to the source, and source-language characters that remain in the result. It also checks repetitive NLLB output. Only the affected segments move to fallback or retry, and the final quality report records how much came from each engine.

Translation jobs can be slow enough that interruption is normal. Per-batch results and detected language or genre context are stored in a temporary folder beside the subtitle. Running the job again can continue from cached progress. The cache is removed after a successful run, so it acts as recovery state rather than permanent application data.

Output quality includes readability

Finally, the tool wraps long translations to a maximum of two lines, writes the original timestamps back into a new SRT, shows a short preview, and reports which engines produced the result. A separate cleanup operation can fix overlapping timestamps and merge fragments that are too short to be useful. Translation quality is therefore treated as structure, timing, and reading comfort as well as word choice.

Local transcription and translation depend heavily on the machine running them. The installer checks GPU support and the menu recommends Whisper models according to available VRAM, while CPU execution remains possible. Offline models also have a first-run download and storage cost. Exposing those constraints is better than letting a large model fail after the user has already started a job.

What remains unfinished

The current project grew from practical scripts, so the next useful improvements are clearer automated tests for malformed model responses, stronger separation between engine adapters, and a small machine-readable run report. Those changes would make it easier to add another translation engine without duplicating validation and retry logic.

This is a workflow for producing and reviewing subtitles more reliably, not a promise that AI eliminates human judgement. Names, cultural references, humor, sensitive material, and licensing of individual models still deserve a human check. Good tooling makes that check smaller and clearer; it does not pretend it is unnecessary.