A free, open-source desktop app that translates Ren'Py visual novels — dialogue, narration, and menu choices — without breaking tags, variables, or the game's tl/ folder structure.
- What it does
- What's new
- Download
- Run from source
- How to use it
- Choosing a translation engine
- Running LibreTranslate locally (Docker)
- What never gets translated, on purpose
- Logs & troubleshooting
- Project structure
- License
Ren'Py Translator scans a game's .rpy/.rpym scripts, extracts every user-visible string, sends it to a translation engine of your choice, and writes the result into the standard game/tl/<language>/ folder Ren'Py expects — so the translation shows up as a normal language option in the game itself, with the original scripts left untouched (backed up first).
It handles two situations:
- Source projects, where
.rpyfiles are visible and editable. - Packaged games, where the game only ships
.rpaarchives and compiled.rpycscripts. The app extracts and decompiles those into a separate workspace first, so nothing happens to your real install until you choose to apply it.
The latest update is a substantial rework of the app, on top of the original scan/translate/write pipeline:
- Redesigned interface — a frameless window with a custom title bar, card-based layout, soft shadows, and a live status indicator (idle / working / success / error) instead of the previous flat UI.
- Four translation engines instead of one:
- LibreTranslate (public endpoint or your own local server)
- Argos Translate — fully offline, no account, no server, downloads its language pack automatically on first use
- Google Translate (bring your own API key)
- DeepL (bring your own API key)
- One-click local translation server — the app now detects Docker, and automatically creates/starts the local LibreTranslate container and waits for it to be ready. You no longer have to run
docker runby hand. - Faster translation — strings are now sent in batches (up to 100 per request) instead of one at a time.
- More reliable Ren'Py-safety — improved protection for text tags (
{i}...{/i}), interpolations ([player_name]), and%-style formatting so translated builds are less likely to crash. - Persistent crash-safe logging — every session is now logged to a rotating file on disk (
Help → Open logs folder…), independent of the in-app log panel, so a crash or restart doesn't erase the trail you'd need to debug it. - Full interface translation — the app itself now runs in English, French, or Spanish (
Settings → Preferences…), not just the games it translates.
The simplest way to use the app on Windows — no Python install required:
- Grab the latest
RenPyTranslator.exefrom the GitHub Releases page. - Double-click it to launch. If Windows SmartScreen warns you, click More info only if you trust the release source.
- Click Choose game and select the folder that contains your project's
game/directory.
Translating a packaged game decompiles
.rpycscripts using therpycdecpackage. It ships withrequirements.txtfor the source install, but if you only run the packaged.exe, make surerpycdecis also available to a system-wide Python (pip install rpycdec) so the.execan call it.
Use this if you want to read/modify the code, or build your own executable.
git clone https://github.com/AnwarAllal23/renpy-translator-gui.git
cd renpy-translator-gui
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -r requirements.txt
python entrypoint.pyRequires Python 3.11+. To build a standalone Windows executable yourself:
pip install pyinstaller
pyinstaller RenPyTranslator.specThe result is written to dist/RenPyTranslator.exe.
To build the macOS app bundle instead:
pip install pyinstaller
pyinstaller RenPyTranslator-macos.specThe result is written to dist/RenPy Translator.app (ad-hoc signed, ready to run on the machine that built it).
- Project → Choose game… and select the project's root folder (the one that contains
game/). - Click Analyze — it scans every
.rpy/.rpymfile and extracts dialogue, narration, and menu-choice text. The file tree on the left updates with a status icon and a dialogue count per file. - Pick a source language and a target language.
- Pick a translation engine (see below).
- Click Translate. The app automatically:
- creates a
.rpy.bakbackup of every script before touching it, - writes
game/tl/<lang>/zz_auto_strings.rpyplus the runtime helper files it needs.
- creates a
- Launch the game and switch language from Ren'Py's own Preferences screen, if the game exposes one.
- Anytime: Tools → View changes… shows a side-by-side diff of what got translated; Tools → Restore originals (from backup) reverts every script to its pre-translation state.
- Project → Choose game… and select the game's root folder anyway (the one whose
game/folder contains.rpaarchives and/or.rpycscripts instead of.rpy). - The app detects there are no
.rpysources and says so in the log — go to Tools → Prepare packaged game (.rpa/.rpyc)….- This copies the whole game into a separate workspace (under
~/.renpy_translator_workspace/…). Your real game install is not touched at this stage. - It extracts every
.rpaarchive, then attempts to decompile every.rpyc/.rpyb/.rpymcscript on a best-effort basis. A few heavily-obfuscated scripts can fail to decompile — the rest of the game still translates normally.
- This copies the whole game into a separate workspace (under
- Once the workspace is ready, continue exactly like a normal project: Analyze → pick languages → Translate, but everything happens inside the workspace copy.
- Click Apply to original game — this copies the generated
game/tl/<lang>/folder from the workspace back into your real game folder. - Launch the real game and switch language in-game, same as a source project.
| Engine | Account needed | Runs offline | Notes |
|---|---|---|---|
| LibreTranslate (Public) | No | No | Default. Free, but shared and can be rate-limited. |
| LibreTranslate (Local) | No | Yes (after setup) | Runs in Docker on your machine — see below. Unlimited, faster. |
| Argos Translate | No | Yes | Fully offline. The app downloads the language pack the first time you use a given language pair (roughly 50–200 MB). |
| Google Translate | Yes (API key) | No | Paste your own API key from Google Cloud. Higher translation quality. |
| DeepL | Yes (API key) | No | Paste your own API key from DeepL. Higher translation quality. |
The public endpoint is fine for a quick test, but it's shared and can be slow. Running LibreTranslate locally removes all of that.
Prerequisite: Docker Desktop installed and running.
Easiest path: in the app, set the endpoint to http://localhost:5000/translate (or click Local (advanced) for a guided setup) and click Translate. The app checks whether Docker is installed, creates/starts the renpy_translator_libretranslate container for you, waits for it to finish loading its language models, and then translates — no manual commands needed.
Manual path, if you'd rather control it yourself:
docker run -d -p 5000:5000 libretranslate/libretranslate --load-only en,fr,es,de,it,pt,ja,zh,ar,ru --disable-web-ui--load-only …downloads only the languages this app supports, instead of all of them.--disable-web-uiskips LibreTranslate's own web page since only the API is needed.- First run downloads the language models, so it can take a few minutes — later starts are fast.
Managing the container afterwards:
docker ps # see it running, and grab its container id/name
docker stop <container> # stop it
docker start <container> # start it again later
docker rm -f <container> # remove it completelyTroubleshooting:
- "Local server not reachable" → make sure Docker Desktop is running (
docker infoshould succeed). - Port 5000 already used → stop whatever else is using it, or run the container with a different host port (e.g.
-p 5001:5000) and usehttp://localhost:5001/translate. - A language isn't translating → it wasn't included in
--load-only; recreate the container with that language code added.
Ren'Py strings often carry tags, variables, and formatting markers. Changing them can crash the game, so the app treats them as protected text:
| Pattern | Example | Rule |
|---|---|---|
| Text tags | {i}...{/i}, {color=#fff}...{/color} |
Kept identical, same spelling and order |
| Interpolations | [player_name], [score] |
Kept identical, never translated |
| Percent formatting | %s, %(name)s |
Placeholders preserved; a literal % (e.g. 100%) is escaped to %% automatically |
See DOC_EN.txt / DOC_FR.txt for the full rules and a troubleshooting guide for common Ren'Py errors.
- The Logs panel (bottom-right of the main window) shows what the app is doing in real time.
- Help → Open logs folder… opens a persistent log file on disk (
%LOCALAPPDATA%\RenPyTranslator\logs\). Unlike the on-screen panel, it survives app restarts and crashes, so it's the first place to check if something goes wrong.
renpy-translator-gui/
├── entrypoint.py # App entrypoint: boots Qt, installs the crash logger, shows the main window
├── app/
│ ├── main_window.py # Main window, menus, and the translate/analyze workflow
│ ├── settings.py # Settings dialog + all UI strings (EN/FR/ES)
│ └── theme.py # Qt stylesheet (dark theme)
├── core/
│ ├── project_scanner.py # Detects a Ren'Py project and lists its .rpy/.rpa/.rpyc files
│ ├── rpy_parser.py # Extracts translatable strings from .rpy scripts
│ ├── extractor.py # Orchestrates parsing across a whole project
│ ├── translator.py # LibreTranslate / Argos / Google / DeepL backends
│ ├── rpy_rewriter.py # Rewrites scripts, handles .rpy.bak backups and restore
│ ├── tl_writer.py # Writes the game/tl/<lang>/ output files
│ ├── packaged_tools.py # Workspace prep for packaged (.rpa/.rpyc) games
│ ├── rpa_extractor.py # .rpa archive extraction
│ ├── docker_manager.py # Auto-starts/monitors the local LibreTranslate Docker container
│ └── log_setup.py # Persistent rotating log file + uncaught-exception hook
├── requirements.txt
└── RenPyTranslator.spec # PyInstaller build configuration
MIT — free to use, modify, and redistribute. When you distribute a translation, make sure you still respect the original game's own license and copyright.
