Real-time, OCR-based chat translation overlay for Foxhole on Linux. Reads your screen, translates in a separate window. You copy-paste outbound messages yourself.
"There are no bots in Foxhole."
No game memory reading. No packet sniffing. No automation. Just Tesseract reading pixels off your screen and putting text in your clipboard.
Foxhole is a massively multiplayer war game where hundreds of players from around the world fight on the same server. The chat is a firehose of English, Russian, Korean, Chinese, Spanish, and more — often in the same channel at the same time. There's no built-in translation. If someone is calling out enemy armor positions in Cyrillic and you can't read it, you just miss it.
This tool sits on top of the game and gives you:
- Incoming chat log — OCR captures the game chat every ~2 seconds, deduplicates and aligns lines into a scrollable log, color-coded by channel (World, Intel, Logi, Region, etc.)
- Click-to-translate — click any line and the translation appears inline beneath it, like a reply on Reddit
- Outbound translation — type a message in your language, pick a target language, hit Enter, and copy the translation to paste into game chat
- Quick phrases — one-click common callouts ("Need shirts at {location}", "Flanking left", etc.) that auto-translate
| Backend | Config | Notes |
|---|---|---|
| Local LLM | --llm-url http://localhost:8080 |
Any OpenAI-compatible endpoint (llama-server, vLLM, Ollama, LM Studio, etc.) |
| Google Translate | --backend google |
Free, no config, works out of the box. Default. |
| Anthropic | --backend anthropic |
Requires ANTHROPIC_API_KEY env var |
The local LLM path is the most interesting — a Qwen2.5 14B Q4 (via bitsandbytes) handles translation + OCR confusable decoding surprisingly well, even for garbled Cyrillic-as-Latin text. See the technical notes below.
bash setup.shOr manually:
sudo apt install tesseract-ocr python3-tk python3-pip xclip
pip install mss pytesseract Pillow deep-translator requests numpyOptional Tesseract language packs for better multilingual OCR:
sudo apt install tesseract-ocr-kor tesseract-ocr-chi-sim tesseract-ocr-jpn tesseract-ocr-rus tesseract-ocr-araOpen Foxhole, get to a screen with chat visible, then:
python3 foxhole_translate.py --selectA screenshot is taken after a 3-second countdown. Draw a box around the chat text area. The coordinates are saved to ~/.config/foxhole-translator/config.json.
# With Google Translate (default, no config needed):
python3 foxhole_translate.py
# With a local LLM:
python3 foxhole_translate.py --llm-url http://localhost:8090
# With Anthropic:
export ANTHROPIC_API_KEY=sk-ant-...
python3 foxhole_translate.py --backend anthropicpython3 foxhole_translate.py --lang en # English (default)
python3 foxhole_translate.py --lang es # Spanish
python3 foxhole_translate.py --lang ko # Korean
python3 foxhole_translate.py --list-langs # Show all available codes- Click a line in the incoming chat log to translate it. Click again to dismiss.
- Type in the compose box at the bottom, select a target language, hit Enter. The translation appears below — click COPY to put it on your clipboard, then paste into game chat.
- Quick phrases at the bottom are one-click auto-translates for common callouts.
- Scroll up to read history. Auto-scroll resumes when you scroll back to the bottom.
- Clear wipes the log. Pause stops OCR capture.
python3 foxhole_translate.py [OPTIONS]
Options:
--select Select/reselect screen capture region
--region X Y W H Set capture region manually (absolute screen coords)
--lang LANG Your reading language (default: en)
--interval SECS Seconds between captures (default: 2.0)
--backend BACKEND google | local | anthropic
--llm-url URL Local LLM endpoint (e.g. http://localhost:8080)
--llm-model MODEL Model name (default: auto-detect from endpoint)
--llm-timeout SECS Request timeout (default: 30)
--list-langs Show all supported language codes
--monitors Show monitor layout and exit
--debug-ocr Save preprocessed OCR images to /tmp
--threshold N OCR brightness threshold 0-255 (default: 100)
--capture METHOD Force capture method: portal | mss | pipewire | dbus
The overlay color-codes lines to match the Foxhole client:
| Channel | Color |
|---|---|
| World (default) | Teal |
| Intel | Red-brown |
| Logi / Terminus | Gold |
| Region | Periwinkle |
| Local | White |
| Regiment | Orange |
| Squad | Green |
| Whisper | Magenta |
This is the most interesting technical problem in the project.
Tesseract frequently reads Cyrillic characters as their Latin visual lookalikes: а→a, В→B, Н→H, с→c, р→p, у→y, х→x, etc. So "Сомневатось" (to have doubts) comes through as ComHeBatocb, which looks like nonsense English to a translator and gets echoed back unchanged.
The fix has two parts:
Detection — a heuristic that spots OCR'd Cyrillic disguised as Latin. The telltale sign is mid-word uppercase letters that make no sense in English: the H and B in ComHeBatocb, the T in npuBeT. The detector also checks for high ratios of confusable characters in otherwise non-English-looking text.
Reverse mapping + hinting — when detected, a reverse confusable mapping converts Latin lookalikes back to Cyrillic (a→а, B→В, H→Н, etc.) to produce a "Cyrillic hint". Both the raw OCR text and the hint are sent to the LLM, whose system prompt explains the confusable situation with examples. This gives the model enough context to decode the garbled text and translate the meaning.
For the Google Translate path, we simply retry the translation with the reverse-mapped Cyrillic text if the first attempt returned the input unchanged.
This gets roughly ~90% accuracy on Cyrillic lines, which is dramatically better than the 0% baseline.
This was developed and tested with Qwen2.5 14B Q4 (quantized via bitsandbytes), served through llama-server. It handles translation and confusable decoding well at this size. Larger models will work too, but 14B Q4 is the sweet spot for running alongside a game without killing your framerate.
Any OpenAI-compatible /v1/chat/completions endpoint works:
# llama.cpp
llama-server -m qwen2.5-14b-q4.gguf --port 8090
# Ollama
ollama serve # then --llm-url http://localhost:11434
# vLLM
vllm serve Qwen/Qwen2.5-14B-Instruct --port 8090All settings are saved to ~/.config/foxhole-translator/config.json and persist between runs. CLI flags override saved settings and update the config file.
- OS: Linux (Ubuntu 22.04+ tested). Wayland and X11 both supported.
- Python: 3.10+
- Tesseract OCR:
tesseract-ocrpackage - Display: tkinter (
python3-tk) - Clipboard:
xclip
MIT