I Couldn’t Understand WoW Chat, So I Vibe-Coded a Translator

notion image
I was playing World of Warcraft: Forever on a Taiwanese server when I ran into a fairly fundamental problem: I couldn’t understand much of the chat.
People were talking, organising groups and trading. I could see the conversation happening, but following it in Traditional Chinese was another matter. A word-by-word dictionary could help with individual terms, but that didn’t always tell me what someone actually meant.
So I decided to vibe-code a translator.
As usual, I started by creating a PRD to explore the options, the constraints and what I actually wanted the experience to do. Then I used Claude Code to build the first version, which gave me a separate chat overlay for the translations.
The idea sounded simple enough: take incoming chat, translate it into natural English and show the result beside the original. In practice, the interesting part wasn’t just the translation. It was figuring out how to get the message out of the game and the answer back without pretending the game’s restrictions didn’t exist.
This was the initial version that started. Just an empty overlay box.
This was the initial version that started. Just an empty overlay box.
 
I ran my first command /wft flush. Nothing happened.
notion image
Claude later couldn’t find the log file. Neither could I. After probing it realised the issue was the app dropping whatever /chatlog writes. Flush drown the drain, probably.

The plan: translate the conversation, not just the words

I wanted to understand complete sentences, including Taiwanese gaming slang and the shorthand players use when looking for a group. The original chat needed to remain visible, and the translation needed to stay associated with the right message. I wasn’t trying to send replies or automate gameplay.
The first preference was to put the English directly into WoW’s chat window. That would have made the translation feel like part of the game rather than another app sitting alongside it.
There was just one small problem. Actually, several.

Addons can’t simply call a translation API

WoW addons run in a restricted Lua environment. They can’t open network sockets, make an HTTP request to a translation provider or read arbitrary files whenever they like.
That ruled out the neatest version of the idea: an addon that sees a message, calls an AI model and writes the answer straight back into chat.
I looked at using SavedVariables, the mechanism addons use to persist data. They can carry information out when the interface reloads, but they’re not a live, two-way communication channel. Getting translations back into the running addon would require another reload. That’s technically interesting, but not a particularly lovely way to play.
I also considered the approach of reading game memory, which some existing tools use. I chose not to use it because of the potential risk under Blizzard’s rules. Finding a workaround wasn’t worth pretending the policy question had disappeared.

The chat log looked promising, until it wasn’t

The first architecture used WoW’s /chatlog feature (honestly I didn’t even know what most of the features or backend worked)
Claude’s plan was for the game to write chat to a log file, then for a small Windows companion app to watch that file, translate new messages and show the English in an overlay.
It was a sensible plan. It also didn’t work on my Forever client.
The log file was created, but stayed at zero bytes even while chat was flowing. The command appeared to be accepted, yet there was nothing for the companion to read. So the log-based design had to go.
This was one of those moments where a good-looking architecture diagram loses an argument with a real test.

The compromise: an addon, a reload and an overlay

The version I ended up with splits the job in two:
  1. A small addon captures readable chat events in the game.
  2. A macro runs /wft flush followed by /reload, which causes the addon’s saved data to be written to disk.
  3. A Windows companion notices the new messages, sends eligible text to the translation provider and displays the results in an overlay.
The overlay shows the channel, sender and English translation. The original stays in WoW’s chat window, so I can read the two side by side without duplicating everything on screen. It’s resizable, stays on top and remembers where I left it.
It’s not the seamless, live in-chat experience I originally imagined. I have to trigger a reload to move captured messages across, and that interrupts play. But it gives me a usable way to understand open-world and city chat without relying on a broken chat log or a memory-reading approach.
The companion also keeps track of messages using references, rather than assuming translations arrive in the same order they were sent. That matters when several people are talking at once. A good translation attached to the wrong person is still a bad result.

The dungeon problem

There was another constraint specific to this client. Inside instances, chat text can be exposed to addons as “secret values”. An addon may receive a value but be unable to read or serialise it. That means the SavedVariables approach doesn’t give me the same access to party and raid chat inside dungeons.
Rather than trying to bypass that restriction, I built an alternative using screen OCR, which reads text from the visible chat area. It can be used as a fallback for those situations, but it comes with its own trade-offs.
In testing, mixed English and Chinese text could confuse the OCR, and other chat activity, such as loot and combat messages, added noise. A dedicated chat tab helps, but the result is less tidy than the addon-based approach. I’ve kept it as an option, not presented it as a perfect fix.

Finding a translator that understood the game

I tried a few provider options along the way. DeepL’s free offering turned out not to be the sustainable fit I expected, and some Gemini model choices were unavailable or required billing. Eventually I landed on Gemini Flash Lite for this build, using a prompt that gives it the Taiwanese WoW context.
The difference between translating words and understanding the situation showed up in the sample tests. For example, a message asking for “坦跟奶” came back as needing a tank and healer, rather than treating those words as unrelated literal terms. Four sample translations worked in the live provider test, including gaming slang and an item name.
That’s encouraging, not a full quality study. I still want to assess a larger sample of real player messages, and any cloud translation choice means considering what chat text is sent to the provider and how it is handled.

Where it stands

The current version is a personal Windows companion and addon, with the reload-based capture as the default for readable open-world chat. There’s also the noisier OCR fallback for situations where addon access is restricted.
It isn’t a polished public release, and it doesn’t put translations directly into WoW’s native chat. I’ve left CurseForge packaging for later. The next useful test is a proper sample of real conversations, especially to see how well the translations hold up beyond the initial examples.
I started with a very human problem: there was a conversation happening around me, and I wanted to understand it. Vibe-coding helped me explore a solution, but the useful part was testing each assumption against the actual game, then being willing to change the plan when it didn’t work.
Sometimes the thing you build is not the thing you first pictured. In this case, a small overlay and an imperfect reload are a lot more useful than a beautifully imagined addon that can’t actually talk to a translator.

A short detour through screen OCR

notion image
Before I settled on the reload, I spent an afternoon trying the opposite approach: skip the addon entirely and have the companion read my chat frame straight off the screen.
It sounded cleaner. No game-side pieces to maintain, no reload interruption, and it would still work inside dungeons where the addon’s access gets restricted.
I built the whole thing. Tesseract, a region picker to draw a rectangle over the chat area, Traditional and Simplified Chinese language files bundled with the project, a preprocessing step that upscales and sharpens the image before OCR to help with CJK characters, and a filter that rejects lines that obviously aren’t chat.
Then I ran it against my actual chat frame and watched it struggle.
The chat tab had chat and combat messages and loot and skill-up notifications and level announcements all sharing the same box. Even after turning most of those off, the OCR still fought with mixed English and Chinese on a single line, which it tended to split in unhelpful ways. A few characters came back as near-lookalikes. A player with a Chinese name happened to be named something like “didn’t expect it to be like this”, and the model occasionally translated the name itself as if it were the message. Interesting bugs, but not confidence-inspiring ones.
I asked myself a boring question: would I actually use this to understand real chat? And the honest answer was no. It felt like work.
So I switched back. OCR is still in the project because it’s the only option inside instances where the addon can’t read the text. But it isn’t the default anymore, and I try not to rely on it.

What the other addons actually do

There’s an existing addon on CurseForge called WoW Translator, and at some point I opened it up to see how it works. I’d been treating it as a crude dictionary tool, something our project would politely replace.
It is a dictionary tool. But it’s a better-engineered one than I’d given it credit for.
The source is well organised. Hooks into the chat message filter so the translation appears inline. Hundreds of kilobytes of hand-curated phrase tables. Longest-match-first lookup. Careful handling of item and spell links so they survive the translation step. It won’t ever translate a sentence it hasn’t seen before, which is its ceiling, but within what it ships with, it’s solid and genuinely in-game.
That reframed how I thought about what I was building. We weren’t competing. The dictionary approach runs instantly, inside the chat frame, for every message. My companion gives a proper full-sentence translation on demand, with the trade-off of a reload. Together they cover two different needs: quick hints for every line, and a real translation when I want to understand what was actually said.
So I’ve stopped trying to put a dictionary inside my own addon. The one I have alongside it already does that job. My companion stays focused on the sentence-quality side, which is the part I actually needed.

Making it feel at home

Once the mechanics were working, I spent a bit of time on the overlay itself.
The default Tkinter look felt like a utility window stapled next to the game. So I restyled it with a dark parchment background, double bronze border, gold serif title, and WoW’s own channel colours. It now reads as if it belongs beside the chat frame rather than fighting it.
I made the overlay resizable by dragging the bottom-right corner, and it remembers the position and size between launches. The close button hides it instead of killing the companion, so it slips out of the way when I’m focused on playing. A small icon lives in the system tray to bring it back, or shut everything down cleanly.
I also added a one-click Windows launcher, so starting the companion doesn’t involve opening a terminal every time. Small things, but they changed how it feels from “a project I’m testing” to “a tool I’m using”.
And I renamed it. Nas WoW Translator rather than the working title. If the thing is going to sit on my desktop every time I play, it may as well have a name I like.

Where it ended up, really

I started this wanting a live, inline, native-looking chat translation. I ended up with something quieter: an addon that watches my chat, a macro I press when I want to catch up, and a small themed window beside the game that shows the English.
It isn’t the version I pictured at the start. It’s the version that survived being tested against a real client, real policy constraints, and the actual question of whether I’d use it day to day.
The gap between those two versions is the project.
Until the