unity-localization
Installation
SKILL.md
Unity Localization
Make a casual iOS game shippable in any language with the Unity Localization package — externalize every user-facing string, swap text/fonts/assets per locale at runtime, and prove it renders (no tofu, no truncation) before a translator ever sees it. This is the i18n/l10n discipline that sits beside unity-ui-designer's font-glyph work; it executes through unity-mcp-bridge and feeds unity-qa-release / unity-aso-growth for the store side.
Doctrine (these override convenience)
- Externalize every user-facing string from day one — one source of truth. Retrofitting localization onto a finished game is the expensive path: you hunt scattered literals, re-layout every screen, and re-test. Route every visible string through a String Table key from the first screen, even if you ship one language. Hard-coded strings are localization failure points (SimpleLocalize); the i18n rule is externalize all user-facing strings, never concatenate (Microsoft Globalization). This is the same seam
unity-ui-designerbuilds for single-sourcing — Localization is its production-grade form. - Localize display, not logic. Gameplay rules, save data, asset keys, and analytics event names stay code-side in a fixed canonical form (English/ASCII). Only what the player reads or hears gets localized. A locale switch must never change game behavior, scoring, or the strings you log to analytics.
- Never concatenate translated fragments.
"You have " + n + " coins"is grammatically broken in most languages (plural, gender, word order). Use Smart Strings so the whole sentence is the translatable unit and grammar lives in the table, not in C#. - A locale is text + font + layout + assets — all four. Switching to Japanese without a CJK-covering font yields tofu (□); switching to German without text expansion clips buttons; switching to Arabic without RTL mirrors the UI wrong. Plan all four per target locale, not just the text.
- Pseudolocalize before you translate. Catch hardcoded strings, truncation, and layout breaks with a generated pseudo-locale first — it's free and instant; native review is slow and costs money. Don't send a build to translators until pseudoloc is clean.
Confirm the Editor is reachable (mcpforunity://editor/state, ready_for_tools==true) before driving any of this through MCP. Much of Localization is Editor-window-driven; use execute_code against LocalizationEditorSettings for the scriptable parts (see references/localization-workflow.md).
Package & settings setup
- Install
com.unity.localizationvia Package Manager (Window ▸ Package Manager ▸ add by namecom.unity.localization) or add it toPackages/manifest.jsonand let resolution run. A package add drops the MCP bridge for ~5s on domain reload — reconnect by focusing the Editor (seeunity-mcp-bridge). - Create Localization Settings (Project Settings ▸ Localization ▸ Create). This makes the
LocalizationSettingsasset that holds available locales, startup selectors, and the string/asset database. Add it to Preloaded Assets so it loads on iOS. - Add Locales with the Locale Generator (Window ▸ Asset Management ▸ Localization Tables, or via
LocalizationEditorSettings.AddLocale). Pick real target markets (e.g. en, ja, ko, zh-Hans, de, fr, es, pt-BR, ar) — don't add locales you can't actually translate/QA.