AI Coding Assistant Orientation & Context Last Updated: 2026-10-24 | Version: 0.2.0
UnityLocalizer is a high-performance, autonomous, desktop translation and localization automation suite for games built on the Unity engine.
Following the design legacy of its sister projects RenLocalizer (Ren'Py) and RPGMLocalizer (RPG Maker & WOLF RPG), UnityLocalizer provides ahead-of-time (AOT) batch translation and patch deployment: translation uses the selected engine once, and the deployed patch runs fully offline.
- Read-only harvest, two delivery routes (
EngineProfiler._determine_routes):- Harvest channels: serialized assets (
level*,*.assets,data.unity3d, AssetBundles) via read-onlyUnityPy(TypeTree-aware for Unity LocalizationStringTable, I2LanguageSourceData, Dialogue System; raw length-prefixed scan otherwise), code literals (Mono#USstream / IL2CPPglobal-metadata.dat), and looseStreamingAssetsfiles (.json,.csv,.tsv,.xml,.txt,.yarn,.nani, compiled Ink). "Route 2" (read-only asset extraction) is this harvest, not a separate delivery mechanism. - Route 1 (Native Static Patcher, opt-in): rewrites loose
StreamingAssetsfiles in place (patch_loose_files,.bakoriginals, re-runs always read the.bak). - Route 3 (Runtime Hook, always recommended): BepInEx 5 (Mono) / BepInEx 6 (IL2CPP) +
XUnity.AutoTranslatoras an offline dictionary loader (Endpoint=empty). Asset and code text can only reach the game this way.has_bepinexmeans proxy DLL +BepInEx/core+ XUnity plugin (src/core/hook_layout.py), never just aBepInExfolder. - XUnity facts (verified in its source): it loads every
*.txtbelowDirectory(keepTranslation\{Lang}\Text);_-prefixed files and the OutputFile ignore regex entries, and the OutputFile has the lowest priority and is pruned on startup, so we writeUnityLocalizer.txt; an unescaped//anywhere in a line is a comment;%3Ddecodes to=;r:"pattern"="replacement"entries are tried only when no direct lookup matches (match.Result, so${N}/$$).
- Harvest channels: serialized assets (
- Comprehensive Font Management (uGUI & TMP SDF): Solves the missing glyph / "tofu" (□) crisis across both legacy
UnityEngine.UI.Text(viaOverrideFontand custom.ttf/.otffont installation toBepInEx/fonts/) and TextMeshPro (via prebuilt ArialUnicode SDF AssetBundle deployed toBepInEx/font/asFallbackFontTextMeshProorOverrideFontTextMeshProfor system fonts). - Dynamic Choice & Prefix Regex (
xunity_regex.py): Automatically produces prefix-preserving.NETregexes for runtime-numbered dialogue choices (1.,[1]) and CRPG skill tags ([Charm],[Strength]), ensuring choices translate in-game even when formatted dynamically. - IL2CPP & Unity 6 Runtime Optimization (
font_bootstrap.py): Automatically selects OS TrueType fonts (OverrideFontTextMeshPro) on IL2CPP builds to avoid strippedAssetBundle.LoadFromFile_Internalcrashes, and disables unsupported IMGUI hooks (EnableIMGUI=False). - Linux & Steam Deck Ready: Exported patch packages include native POSIX shell scripts (
Install_Patch.sh,Uninstall_Patch.sh) alongside Windows.batscripts, providing automated instructions for Steam Deck Proton launcher overrides (WINEDLLOVERRIDES="winhttp=n,b" %command%). EngineProfiler also detects Linux.x86_64executables and ELF headers. - Automatic Source-Language Detection (
src/core/lang_detect/): when the source language isauto, the pipeline detects the game's language right after harvesting: Unicode script counting (Han/kana/Hangul/Thai/Hebrew/Greek) -> offlinepy3langidmodel (confidence >= 0.90, spread of prose lines) -> Google majority vote (keyless engines only, so users of private/paid engines keep text local). The detected code feeds the engine, CSV column selection and XUnityFromLanguage; when nothing is certain the run keepsauto/English and the user gets a warning toast. - User Notifications (
NOTIFICATION_LEVELSinsrc/core/progress.py): progress events listed there become toast + warning/info log entries (language detection result, glyph coverage, unknown Unity version) instead of silent console lines. - AST Syntax Guard: Tokenizes Unity RichText tags (
<color>,<size>,<b>,<sprite>) and C# formatting patterns ({0},{playerName},\n) into immutable placeholders before translation and validates them upon restoration. - RenLocalizer Translation Engines: Integrates battle-tested multi-mirror Google Translate (13 mirrors + Lingva fallback), Google Gemini (
google-genai), OpenAI, DeepSeek, Local LLM (Ollama/LM Studio), DeepL, and LibreTranslate. - Modern UI: Single-window responsive PyQt6 + Qt Quick (QML) dashboard.
Language: Python 3.10+ | GUI: PyQt6 + QML | License: GPL-3.0
UnityLocalizer/
├── run.py # Entry point & Qt bootstrap (--self-check verifies runtime dependencies)
├── run.bat / build.bat # Windows quick launch / build
├── build.py # PyInstaller build + frozen --self-check
├── requirements.txt # Python dependencies
├── AGENTS.md # AI orientation & architecture guide
├── README.md # User documentation
├── CHANGELOG.md # Release changelog
├── LICENSE # GNU General Public License v3.0
├── icon.ico / icon.png # Application branding
├── .github/workflows/ci.yml # Lint + tests + self-check on Windows, Python 3.10/3.12/3.14
│
├── src/
│ ├── version.py # Version info (VERSION = "0.1.0")
│ │
│ ├── core/ # Core engine & localization pipeline
│ │ ├── engine_profiler.py # Unity version, Mono/IL2CPP, bitness, platform, frameworks, routes
│ │ ├── hook_layout.py # BepInEx/XUnity file layout & "runtime really installed" check
│ │ ├── syntax_guard.py # RichText/format token guard (protected + glossary terms)
│ │ ├── rtl_shaper.py # Static Arabic/Persian/Hebrew shaping & tag-safe bidi reordering
│ │ ├── languages.py # 134-language catalog & per-engine language code mapping
│ │ ├── lang_detect/ # Source-language detection (script -> offline py3langid -> Google vote)
│ │ ├── cache.py # SQLite translation cache (batched get_many/set_many)
│ │ ├── translation_memory.py # TMX/CSV/TSV/JSON translation memory with fuzzy matching
│ │ ├── glossary.py # Glossary: terms hidden from engines, replaced in one pass
│ │ ├── constants.py # Google/Bing endpoints and router limits
│ │ ├── progress.py # Locale-neutral progress events & cancellation
│ │ │
│ │ ├── harvesters/ # Read-only static text harvesters
│ │ │ ├── text_filter.py # Shared "is this player-visible text?" rules
│ │ │ ├── metadata_harvester.py # IL2CPP global-metadata.dat string pool extractor
│ │ │ ├── assembly_harvester.py # Mono #US user-string extractor
│ │ │ ├── asset_harvester.py # UnityPy TextAsset/TextMesh/MonoBehaviour extractor (per-file progress)
│ │ │ ├── typetree_text.py # Field-aware TypeTree text rules (StringTable, I2, Dialogue System)
│ │ │ ├── typetree_provider.py # Optional TypeTreeGeneratorAPI loader for stripped player builds
│ │ │ ├── bundle_locator.py # Discovers scenes, .assets, data.unity3d & Addressables
│ │ │ └── harvest_collector.py # Aggregates assets, code & StreamingAssets into one pool
│ │ │
│ │ ├── parsers/ # File & framework format parsers
│ │ │ ├── base.py # BaseParser interface
│ │ │ ├── streaming_assets.py # StreamingAssets (JSON, CSV, TSV, TXT, XML, Yarn, Naninovel, Ink)
│ │ │ ├── auto_translator.py # XUnity dictionary writer (plain entries + generated regex section)
│ │ │ ├── xunity_codec.py # Codec mirroring XUnity TextHelper (// comments, %3D, \uXXXX)
│ │ │ ├── xunity_regex.py # r:"..." entries for runtime-formatted strings ({0}, {name}, %s)
│ │ │ ├── text_formats.py # Format sniffing & line splitters (JSON, CSV, XML, Yarn)
│ │ │ ├── loc_table.py # Column-aware string tables (I2 exports, key/source/target columns)
│ │ │ ├── yarn_lines.py # Yarn line splitter (speaker, body, #line tags, <<commands>>)
│ │ │ ├── ink_json.py # Compiled Ink (.ink.json) display text extraction & patching
│ │ │ └── naninovel_parser.py # Naninovel .nani text/choices, inline commands preserved
│ │ │
│ │ ├── hook_manager/ # Runtime hooks & font infrastructure
│ │ │ ├── installer.py # SHA256-pinned BepInEx 5.4.23.5 / 6 (pre.2 or be.764 by metadata) + XUnity 5.6.2
│ │ │ ├── font_bootstrap.py # AutoTranslatorConfig.ini (offline) & TMP fallback wiring
│ │ │ ├── ini_merge.py # Line-preserving INI merge (forced keys + missing defaults)
│ │ │ ├── font_provisioner.py # Maps Unity version to prebuilt SDF bundle (5.5-6000)
│ │ │ └── glyph_coverage.py # Checks deployed characters against the TMP fallback character table
│ │ │
│ │ ├── translators/ # Modular translation subsystem (from RenLocalizer)
│ │ │ ├── base.py # BaseTranslator, TranslationEngine, TranslationResult
│ │ │ ├── google.py # Health-aware family routing, separator batches, integrity recovery
│ │ │ ├── google_transport.py # HTTP calls per Google family (POST primary, batchexecute, clients5, Lingva)
│ │ │ ├── bing.py # Edge keyless Bing: chunking, backoff, size splitting, Google fallback
│ │ │ ├── deepl.py # DeepL Free/Pro with formality
│ │ │ ├── libretranslate.py # LibreTranslate (self-hosted or public)
│ │ │ ├── services.py # Pseudo-localization engine (debug only)
│ │ │ ├── network.py # NetworkSettings (concurrency, delay, timeout, retries) & ProxyPool
│ │ │ ├── ai_translator.py # Gemini, OpenAI(-compatible), DeepSeek, Local LLM; fatal-error handling
│ │ │ ├── manager.py # TranslationManager: cache, memory, glossary, engine factory
│ │ │ └── router.py # Thread-safe EndpointRouter: IP 429 cooldown, circuit breaker, mirror bans
│ │ │
│ │ └── pipeline/ # Workflow orchestration
│ │ ├── orchestrator.py # Unified pipeline (Profile -> Harvest -> Translate -> Validate -> Deploy)
│ │ ├── translation_runner.py # Quality-gated parallel batch runner with engine circuit breaker
│ │ ├── review_session.py # Post-run review rows, guarded manual edits, shippable set
│ │ ├── patch_exporter.py # Standalone offline patch packager (preflight, payload, config, ZIP)
│ │ └── patch_scripts.py # Manifest-style install/uninstall .bat scripts & README
│ │
│ ├── backend/ # PyQt6 QObject bridge layer
│ │ ├── app_backend.py # Main bridge (signals, slots, background jobs, pipeline outcome)
│ │ ├── editor_backend.py # Review editor bridge (filter, guarded edits, save to game)
│ │ ├── settings_schema.py # Typed/clamped schema for every user setting (setSetting)
│ │ └── locale_manager.py # Dynamic i18n manager for 12 languages
│ │
│ ├── gui/ # QML interface
│ │ ├── i18n/ # UI translations (12 languages: tr, en, de, es, fr, ru, pt-BR, ja, zh-CN, ko, it, fa)
│ │ └── qml/
│ │ ├── Main.qml # Main window & Multi-Theme layout (Obsidian, Daylight, Cyber Neon)
│ │ ├── views/ # DashboardView, ToolboxView, SettingsView, ConsoleView, EditorView, AboutView
│ │ └── components/ # Theme singleton, archetype buttons (Primary/Secondary), NeonSelect, toasts
│ │
│ └── utils/ # Utilities
│ ├── paths.py # Resource paths & user data dir (%APPDATA%, .portable)
│ ├── data_migration.py # One-time copy of legacy data beside the app
│ ├── file_ops.py # Atomic safe_write, .bak backups, pristine_source()
│ ├── downloader.py # SHA256-verified cached downloader for runtime dependencies
│ ├── logger.py # Root logging (rotating app.log) with secret masking
│ ├── self_check.py # Runtime dependency checks for --self-check
│ └── config.py # JSON configuration manager
│
└── tests/ # Test suite (pytest)
- Language Policy:
- Conversations & Architecture discussions: Turkish
- Code symbols, classes, functions, docstrings, technical docs & commit messages: English
- Single Responsibility Principle (SRP):
- Every class and function must have a single clear responsibility. Keep functions under 50 lines.
- No Monolithic Files:
- Always divide subsystems into logical subpackages (
core,harvesters,parsers,translators,backend,gui,utils).
- Always divide subsystems into logical subpackages (
- Never Leave Placeholders:
- No
# TODO: implement lateror// rest of code. Always provide complete, functional logic.
- No
- Type Hints & Docstrings:
- Every function signature must include complete type hints. Use modern typing (
list[str],dict[str, Any],X | None).
- Every function signature must include complete type hints. Use modern typing (
- No Silent Error Swallowing:
- Never use bare
try-except: pass. Handle root causes or log exceptions with appropriate severity.
- Never use bare
- Read-Only UnityPy Rule:
UnityPyis strictly for reading and extraction. Never attempt raw.assetsin-place repacking for modern Unity releases.
- Atomic File I/O:
- All disk mutations must go through
safe_writeinsrc/utils/file_ops.pywith automatic.bakcreation.
- All disk mutations must go through
- Scene & Shared Asset Files (
level*,sharedassets*.assets,resources.assets):- Text Component Types:
TextMeshProUGUI,TextMeshPro,UnityEngine.UI.Text,ScriptableObject. - Binary Serialization: Stored as
MonoBehaviour(classID 114) with4-byte Little-Endian length prefix + UTF-8 string + 4-byte padding alignment. - Coverage: Represents 70–80% of all UI labels, main menus ("Continue", "Settings", "Gallery", "Credits", "Quit"), HUD, tooltips, and dialogues.
- Text Component Types:
- CIL Managed Assemblies (
Managed/Assembly-CSharp.dll,*-firstpass.dll):- Binary Stream: String literals stored in the
#US(User String) stream of .NET PE metadata as UTF-16LE. - Coverage: Dynamic code strings, format templates, exception messages, code-driven UI text.
- Binary Stream: String literals stored in the
- IL2CPP String Literal Pool (
il2cpp_data/Metadata/global-metadata.dat):- Binary Stream: Extracted from
StringLiteralandStringLiteralDataheader definitions. - Coverage: All compiled C# string literals in AOT builds.
- Binary Stream: Extracted from
- Loose External Files (
StreamingAssets/):- File Formats: Loose
.json,.csv,.tsv,.txt,.xmltables.
- File Formats: Loose
- I2 Localization Framework (
I2Languages.asset):- Structure:
LanguageSourceDataScriptableObject holdingmTermsarray of(Term, TermType, Languages[]). - Storage: Found in
resources.assetsor AssetBundles.
- Structure:
- Unity Localization Package (
com.unity.localization):- Structure:
StringTableCollectionwithSharedTableData(KeyIds) and per-localeStringTableMonoBehaviour objects.
- Structure:
- Visual Novel Engines (Naninovel):
- Structure:
.naniscript files inStreamingAssets/NaninovelorResources/Naninovel.
- Structure:
- Narrative & Dialogue Engines (Yarn Spinner, Fungus, Inkle Ink):
- Yarn Spinner:
.yarnor compiledYarnProjectTextAssets. - Fungus:
SayandMenublocks serialized in scenes (level*). - Ink: Compiled
.ink.jsonTextAssets.
- Yarn Spinner:
- Pixel Crushers Dialogue System for Unity:
- Structure:
DialogueDatabaseScriptableObject (conversations, actor names, dialogue entries).
- Structure:
- Addressables & Modular AssetBundles (
*.bundle,catalog.json):- Dynamic DLCs and modular asset packages.
- Tools like UABEA attempt in-place bundle re-compression (LZ4/LZMA) which breaks CRC checksums and TypeTree alignments on modern Unity builds (Unity 2020–2023+), leading to game startup crashes.
- UnityLocalizer's Hybrid Solution:
- Read-Only Deep Extraction: Safely dumps strings from
.assets,level*, assemblies, andStreamingAssetsusingUnityPylength-prefixed scanner without touching original bundles. - Zero-Latency In-Memory Redirection: Loads translated strings into BepInEx + AutoTranslator strictly as an offline dictionary (
Endpoint=) with zero network lag and zero crash risk. - UI Layout Collision Protection: Sets
ForceUIResizing=FalseandEnableUIResizing=Trueto prevent translated text from stretching buttons and overlapping neighboring UI elements.
- Read-Only Deep Extraction: Safely dumps strings from