Real-Time Translation Is Mostly Waiting for the Slowest Thing
Teyvat Translator started with a simple wish: play Genshin in Chinese, understand the dialogue, and stop alt-tabbing into a dictionary every thirty seconds. Then I discovered that “real-time translation” is five different jobs arguing over the same second.
screen capture → OCR → text stability check → game-term lookup → translation → overlay
At first I tried to make every stage react immediately. The result was fast in the most useless sense of the word. Genshin text fades in character by character, so OCR would catch half a sentence, translate it, catch a slightly longer sentence, translate again, and make the overlay flicker like it was panicking.
I fixed that with a temporal voting buffer: wait until the same text appears across three consecutive frames before accepting it. Technically, I added delay. Practically, the tool felt faster because it stopped showing wrong work and replacing it a moment later.
The slowest stage changes
Sometimes OCR is the bottleneck. Sometimes the local MarianMT model is. Sometimes the difficult part is not translation at all, but recognising that 蒙德 is Mondstadt and should not become some heroic phrase about Mongol virtue.
That is why the pipeline ended up with game-specific term lookup, local translation, a cloud fallback, and a PyQt worker setup that keeps all of this away from the UI thread. The overlay should sit quietly on top of the game. Nobody wants a language-learning tool that freezes the thing they are trying to enjoy.
More than 700 downloads later, that is still my favourite lesson from the project. People forgive a small wait. They notice chaos immediately.