DLL for Unity IL2CPP games to machine-translate UI text on the fly
- Rust 100%
| .cargo | ||
| src | ||
| .gitattributes | ||
| .gitignore | ||
| build.rs | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
| rust-toolchain.toml | ||
| rustfmt.toml | ||
Unity Auto Translator
A dll that hooks into Unity IL2CPP (yes, only IL2CPP is supported for now)
games at runtime and machine-translates UI text on the fly
using Google Translate's free client=gtx endpoint (no API key needed).
You can use any loader/injector you want, I recommend something like UnityDllLoader
How it works
- Hooks
UnityEngine.UI.TextandTMPro.TMP_Text(their setters,OnEnable, andSetVerticesDirty) via inline hooking. - The first time a piece of text is seen, the original is shown immediately
while translation happens on a background thread. Once the result comes
back, it's pushed onto the same UI element, but only if that element is
still showing the same text (Unity likes to recycle components across
screens, so this check matters). Applying it back onto the UI has to
happen on the main thread, so a hook on
Canvas.SendWillRenderCanvases(called once per frame regardless of which text is involved) makes sure that handoff actually happens instead of waiting on some unrelated text to update first. - Translations are cached to disk (
unity_auto_translator/translations.jsonl) so repeated views are instant and don't hit the network again. - Numbers and rich-text tags (
<color=...>, etc.) are swapped out for placeholder tokens before being sent to Google and restored afterwards, so they don't get mistranslated, reordered, dropped or whatever. - Long text gets split into sentence/clause-sized pieces (never through one of our own tokens) and each piece is sent as its own request. Google's endpoint silently splits sufficiently long input into translation chunks internally, and that split can land in the middle of a placeholder token, corrupting it; keeping every request under that length avoids it entirely. If a number token still can't survive after retrying, the number gets sent as real text instead of a token, as a one-off, less cacheable fallback so the text still ends up translated.
- Requests already queued up together get batched into a single call to cut down on round-trips, with a configurable rate limit between requests.
Building
- Requires a nightly Rust toolchain.
- Works with both Windows toolchains:
x86_64-pc-windows-msvcx86_64-pc-windows-gnu
- Build with
cargo build --release, or pass an explicit target if needed:cargo build --release --target x86_64-pc-windows-msvccargo build --release --target x86_64-pc-windows-gnu
- Output:
target/<target-triple>/release/unity_auto_translator.dll
Usage
- Build (or just use prebuilt)
unity_auto_translator.dll. - Inject it into the target game process with your loader/injector of choice.
- On first run it creates
unity_auto_translator/config.ini(relative to the process's working directory) with some default values. - Set
SourceLanguageto the game's actual language and restart. This both improves translation quality and lets the filter skip text that obviously isn't in that language (pure latin labels, numbers, etc.) without wasting a request on it.
Configuration (config.ini)
[General]
SourceLanguage: language the game's text is written in (e.g.zh-CN,ja,auto).TargetLanguage: language to translate into (e.g.en).
[Filter]
ExcludedPrefixes: comma-separated text prefixes that should never be translated.ExcludedSubstrings: semicolon-separated substrings; text containing any of them is never translated.ExcludedPatterns: semicolon-separated regular expressions; text matching any of them is never translated. Invalid patterns are logged and skipped rather than failing startup.
[RateLimit]
MinDelayMs: minimum delay between translation requests.0disables it.
[Batching]
MaxSize: max number of texts combined into a single translation request.MaxChars: max combined length (as it would appear once percent-encoded into the request URL) before starting a new batch.
[Network]
MaxRetries: retry attempts before giving up on a translation.TimeoutMs: per-request network timeout.
Cache file
Translations live as newline-delimited JSON at
unity_auto_translator/translations.jsonl, one {"original": ..., "translated": ...}
per line. There's no separate override mechanism, just edit or append a
line and restart (the last entry for a given original wins on load).
Known limitations
- Google Translate only, no fallback provider.
config.iniisn't hot-reloaded, so changes need a game restart.- Right-to-left target languages (Arabic, Hebrew, ...) aren't handled specially, and Unity's own text layout doesn't support them well regardless.