Comprehensive game localization workflows covering store listing localization, in-game text l10n, font coverage analysis, RTL layout support, locale-aware asset variants, and ASO keyword translation. Use when the user says "localize my game", "translate store listing", "add language support", "RTL layout", "CJK fonts", "localized screenshots", "localization plan", "i18n", "l10n", "multi-language", "Arabic support", "Japanese localization", "localized keywords", "ASO translation", or needs help with any localization or internationalization workflow.
The Localization skill covers the full i18n/l10n lifecycle for games — from in-game text to store listings to screenshot localization to ASO keyword translation. It integrates with Content-Factory's screenshot_localizer pipeline and the GDD localization plan.
Localization Plan (from GDD)
│
▼
┌── Localization Workflows ────────────────────────────────┐
│ │
│ In-Game Text → Store Listings → Screenshots → Keywords │
│ │ │ │ │ │
│ CSV/JSON LLM Translate Localizer ASO Tool │
│ per locale per store pipeline per market │
│ │
└──────────────────────────────────────────────────────────┘
│
▼
Localized Assets on S3 / in Build
All user-facing strings live in CSV or JSON string tables, one per language:
localization/
├── en.csv # English (base)
├── es-419.csv # Latin American Spanish
├── pt-BR.csv # Brazilian Portuguese
├── fr-FR.csv # French
├── de-DE.csv # German
├── ja-JP.csv # Japanese
├── ko-KR.csv # Korean
├── zh-Hans.csv # Simplified Chinese
├── ar-SA.csv # Arabic
└── hi-IN.csv # Hindi
key,text,context,max_chars
main_menu.play,"Play",Button label,10
main_menu.settings,"Settings",Button label,15
game.correct,"Correct!",Feedback on right answer,20
game.wrong,"Wrong!",Feedback on wrong answer,20
game.score,"Score: {0}",Score display with number placeholder,25
store.season_pass_title,"Season Pass",IAP display name,30
using IntelliVerseX.Localization;
var text = IVXLocalization.Get("main_menu.play");
var formatted = IVXLocalization.GetFormatted("game.score", score);
IVXLocalization.OnLanguageChanged += lang =>
{
RefreshAllUI();
};
python tools/localization/scan_hardcoded.py --src Assets/_QuizVerse/Scripts/ \
--ignore "Debug.Log" --ignore "nameof" \
--output reports/hardcoded_strings.csv
python tools/localization/translate_store.py \
--base-locale en \
--target-locales es-419,pt-BR,fr-FR,de-DE,ja-JP,ko-KR,zh-Hans \
--input design/store-metadata.md \
--output localization/store/
localization/store/
├── en/
│ ├── title.txt
│ ├── short_description.txt
│ ├── full_description.txt
│ └── keywords.txt
├── es-419/
│ ├── title.txt
│ ├── short_description.txt
│ ├── full_description.txt
│ └── keywords.txt
└── ... (per locale)
| Field | iOS | Google Play | Steam |
|---|---|---|---|
| App Name | 30 chars | 30 chars | Unlimited |
| Short Description | 45 chars (subtitle) | 80 chars | N/A |
| Full Description | 4000 chars | 4000 chars | Unlimited |
| Keywords | 100 chars | N/A (tags) | Up to 20 tags |
| What's New | 4000 chars | 500 chars | N/A |
Every translated store listing passes through Content-Factory's council_audit:
from council_server.server import compliance_check
result = await compliance_check(
content_metadata={"title": translated_title, "description": translated_desc},
platform="ios",
content_type="store_listing",
brand_context=brand_entity,
)
Uses Content-Factory's screenshot_localizer pipeline to overlay localized text on store screenshots.
curl -X POST http://localhost:8001/pipelines/screenshot_localizer \
-H "Content-Type: application/json" \
-d '{
"base_screenshots_dir": "store_launch/ios/screenshots/",
"locales": ["es-419", "pt-BR", "fr-FR", "de-DE", "ja-JP"],
"overlay_text": {
"screenshot_01": {"en": "Play Now!", "es-419": "¡Juega Ahora!"},
"screenshot_02": {"en": "20+ Categories", "es-419": "20+ Categorías"}
},
"font_config": {
"default": "Nunito-Bold",
"ja-JP": "NotoSansJP-Bold",
"ko-KR": "NotoSansKR-Bold",
"zh-Hans": "NotoSansSC-Bold",
"ar-SA": "NotoSansArabic-Bold",
"hi-IN": "NotoSansDevanagari-Bold"
}
}'
store_launch/ios/screenshots/
├── en/
│ ├── iphone_6.7_01_1290x2796.png
│ └── iphone_6.7_02_1290x2796.png
├── es-419/
│ ├── iphone_6.7_01_1290x2796.png
│ └── iphone_6.7_02_1290x2796.png
└── ja-JP/
├── iphone_6.7_01_1290x2796.png
└── iphone_6.7_02_1290x2796.png
| Script | Languages | Recommended Font | Fallback |
|---|---|---|---|
| Latin | en, es, fr, de, pt, it | Nunito, Fredoka One | Arial |
| CJK | ja, ko, zh-Hans, zh-Hant | Noto Sans CJK | Source Han Sans |
| Arabic | ar | Noto Sans Arabic | Amiri |
| Devanagari | hi | Noto Sans Devanagari | Mangal |
| Thai | th | Noto Sans Thai | Tahoma |
| Cyrillic | ru, uk | Noto Sans | Arial |
| Korean | ko | Noto Sans KR | Malgun Gothic |
python tools/localization/audit_fonts.py \
--string-table localization/ja-JP.csv \
--font Assets/Fonts/NotoSansJP-Regular.otf \
--report reports/font_coverage_ja.md
The audit checks every character in the string table against the font's glyph coverage and reports missing glyphs.
[Header("Localized Fonts")]
[SerializeField] private TMP_FontAsset _latinFont;
[SerializeField] private TMP_FontAsset _cjkFont;
[SerializeField] private TMP_FontAsset _arabicFont;
[SerializeField] private TMP_FontAsset _devanagariFont;
private TMP_FontAsset GetFontForLocale(string locale)
{
return locale switch
{
"ja-JP" or "ko-KR" or "zh-Hans" or "zh-Hant" => _cjkFont,
"ar-SA" or "he-IL" => _arabicFont,
"hi-IN" => _devanagariFont,
_ => _latinFont,
};
}
| Element | LTR (Default) | RTL (Arabic, Hebrew) |
|---|---|---|
| Text alignment | Left | Right |
| Reading order | Left → Right | Right → Left |
| Navigation flow | Left → Right | Right → Left |
| Progress bars | Fill left → right | Fill right → left |
| Scrolling lists | Standard | Mirrored |
| Icons with direction | → arrows | ← arrows |
| Number formatting | 1,234.56 | ١٬٢٣٤٫٥٦ (optional) |
using IntelliVerseX.Localization;
public class IVXRTLLayout : MonoBehaviour
{
[SerializeField] private RectTransform _container;
private void OnEnable()
{
IVXLocalization.OnLanguageChanged += ApplyDirection;
ApplyDirection(IVXLocalization.CurrentLocale);
}
private void ApplyDirection(string locale)
{
bool isRTL = locale is "ar-SA" or "he-IL" or "fa-IR" or "ur-PK";
var scale = _container.localScale;
scale.x = isRTL ? -1f : 1f;
_container.localScale = scale;
}
}
textComponent.isRightToLeftText = IVXLocalization.IsRTL;
textComponent.alignment = IVXLocalization.IsRTL
? TextAlignmentOptions.Right
: TextAlignmentOptions.Left;
Some visual assets need cultural adaptation beyond text translation.
| Scenario | Action |
|---|---|
| Hand gestures (thumbs up, OK) | Check cultural meaning per market |
| Character clothing/modesty | Create MENA-appropriate variants |
| Color symbolism (red = luck in China, danger in West) | Adjust palette |
| Food/drink imagery | Remove alcohol for MENA, adjust dietary imagery |
| Holiday-themed content | Localize to regional holidays |
| Currency symbols | Use locale-appropriate currency |
assets/characters/Hero/
├── default/
│ └── idle.png
├── ar-SA/
│ └── idle.png # Culturally adapted variant
└── zh-Hans/
└── idle.png # Variant with lucky-red accent
curl -X POST http://localhost:8001/pipelines/character_2d \
-H "Content-Type: application/json" \
-d '{
"brand_id": "my-studio",
"game_id": "my-game",
"character_id": "hero",
"locale_variants": ["ar-SA", "zh-Hans"],
"cultural_notes": {
"ar-SA": "Modest clothing, no exposed skin above elbow",
"zh-Hans": "Add red and gold accent colors for lucky appeal"
}
}'
Keywords are not direct translations — they need market-specific research.
python tools/localization/translate_keywords.py \
--base-keywords "trivia,quiz,brain,knowledge,puzzle,multiplayer" \
--target-locales es-419,pt-BR,ja-JP,ko-KR,de-DE \
--output localization/keywords/
localization/keywords/
├── en.txt # trivia,quiz,brain,knowledge,puzzle,multiplayer
├── es-419.txt # trivia,preguntas,cerebro,conocimiento,quiz,multijugador
├── ja-JP.txt # クイズ,トリビア,脳トレ,知識,パズル,マルチプレイヤー
└── ko-KR.txt # 퀴즈,상식,두뇌,지식,퍼즐,멀티플레이어
| Store | Max Keyword Length | Strategy |
|---|---|---|
| iOS | 100 characters total | Pack high-volume terms, no spaces |
| Google Play | 5 tags, each 30 chars | Use category-relevant phrases |
| Steam | 20 tags, each unlimited | Long-tail descriptive tags |
python tools/localization/qa_check.py \
--base localization/en.csv \
--translations localization/ \
--report reports/localization_qa.md
| Check | Description |
|---|---|
| Missing keys | Keys in base not present in translation |
| Extra keys | Keys in translation not in base |
| Placeholder mismatch | {0}, {1} counts differ |
| Max length exceeded | Translation exceeds max_chars |
| Empty translations | Key present but value is empty |
| Untranslated | Value is identical to English (possible miss) |
| HTML/markup broken | Tags not properly closed |
| Bidirectional mixing | LTR text embedded in RTL without markers |
Addressables labels per locale for async font loadingSystemLanguage for initial locale detection, allow user overrideFText and the Localization Dashboard.csv or .po formatTranslationServer with .po or .csv filestr() function for runtime translationLocalizationService with .csv translation tablesTranslator:FormatByKey() for parameterized stringsi18next or similar librarydirection: rtl for Arabic/Hebrew layoutsdesign/localization-plan.md (via GDD skill)localization/en.csv)screenshot_localizer pipeline