Full localization pipeline: scan for hardcoded strings, extract and manage string tables, validate translations, generate translator briefings, run cultural/sensitivity review, manage VO localization, test RTL/platform requirements, enforce string freeze, and report coverage.
Localization is not just translation — it is the full process of making a game feel native in every language and region. Poor localization breaks immersion, confuses players, and blocks platform certification. This skill covers the complete pipeline from string extraction through cultural review, VO recording, RTL layout testing, and localization QA sign-off.
Modes:
scan — Find hardcoded strings and localization anti-patterns (read-only)extract — Extract strings and generate translation-ready tablesvalidate — Check translations for completeness, placeholders, and lengthstatus — Coverage matrix across all localesbrief — Generate translator context briefing document for an external teamcultural-review — Flag culturally sensitive content, symbols, colours, idiomsvo-pipeline — Manage voice-over localization: scripts, recording specs, integrationrtl-check — Validate RTL language layout, mirroring, and font supportfreezeqa — Run the full localization QA cycle before releaseIf no subcommand is provided, output usage and stop. Verdict: FAIL — missing required subcommand.
Search src/ for hardcoded user-facing strings:
tr(), Tr(), NSLocalizedString, GetText, etc.)%s, %d) instead of named ones ({playerName})Search for localization anti-patterns:
1,000 vs 1.000)assets/)"You won!" — exclamation styles vary by locale)Report all findings with file paths and line numbers. This mode is read-only — no files are written.
assets/data/strings/[category].[subcategory].[description]
ui.hud.health_label, dialogue.npc.merchant.greeting, menu.main.play_buttoncontext field — a translator comment explaining:
{playerName} = the player's chosen display name)Output a diff of new strings to add to the string table.
Present the diff to the user. Ask: "May I write these new entries to assets/data/strings/strings-en.json?"
If yes, write only the diff (new entries), not a full replacement. Verdict: COMPLETE — strings extracted and written.
Read all string table files in assets/data/strings/. For each locale, check:
{name} but translation omits it or adds extrascontext fieldsrc/ references the keyReport validation results grouped by locale and severity. This mode is read-only — no files are written.
## Localization Status
Generated: [Date]
String freeze: [Active / Not yet called / Lifted]
| Locale | Total | Translated | Missing | Stale | Coverage |
|--------|-------|-----------|---------|-------|----------|
| en (source) | [N] | [N] | 0 | 0 | 100% |
| [locale] | [N] | [N] | [N] | [N] | [X]% |
### Issues
- [N] hardcoded strings found in source code (run /localize scan)
- [N] strings exceeding character limits
- [N] placeholder mismatches
- [N] orphaned keys
- [N] strings added after freeze was called (freeze violations)
This mode is read-only — no files are written.
Generate a translator context briefing document. This document is sent to the external translation team or localisation vendor alongside the string table export.
Read:
design/gdd/ — extract game genre, tone, setting, character namesassets/data/strings/strings-en.json — the source string tabledesign/narrative/Generate production/localization/translator-brief-[locale]-[date].md:
# Translator Brief — [Game Name] — [Locale]
## Game Overview
[2-3 paragraph summary of the game, genre, tone, and audience]
## Tone and Voice
- **Overall tone**: [e.g., "Darkly comic, not slapstick — think Terry Pratchett, not Looney Tunes"]
- **Player address**: [e.g., "Second person, informal. Never formal 'vous' — always 'tu' for French"]
- **Profanity policy**: [e.g., "Mild — PG-13 equivalent. Match intensity to source, do not soften or escalate"]
- **Humour**: [e.g., "Wordplay exists — if a pun cannot translate, invent an equivalent local joke; do not translate literally"]
## Character Glossary
| Name | Role | Personality | Notes |
|------|------|-------------|-------|
| [Name] | [Role] | [Personality] | [Do not translate / transliterate as X] |
## World Glossary
| Term | Meaning | Notes |
|------|---------|-------|
| [Term] | [What it means] | [Keep in English / translate as X] |
## Do Not Translate List
The following must appear verbatim in all locales:
- [Game name]
- [UI terms that match in-engine labels]
- [Brand or trademark names]
## Placeholder Reference
| Placeholder | What it represents | Example |
|-------------|-------------------|---------|
| `{playerName}` | Player's chosen display name | "Shadowblade" |
| `{count}` | Integer quantity | "3" |
## Character Limits
Tight UI fields with hard limits are marked in the string table `context` field.
Where no limit is stated, target ±30% of the English length as a guideline.
## Contact
Direct questions to: [placeholder for user/team contact]
Delivery format: JSON, same schema as strings-en.json
Ask: "May I write this translator brief to production/localization/translator-brief-[locale]-[date].md?"
Spawn localization-lead via Task. Ask them to audit the following for cultural sensitivity across the target locales (read from assets/data/strings/ and assets/):
Symbols and gestures
Colours
Numbers
Humour and idioms
Violence and content ratings
Names and representations
Present findings as a table:
| Finding | Locale(s) Affected | Severity | Recommended Action |
|---|---|---|---|
| [Description] | [Locale] | [BLOCKING / ADVISORY / NOTE] | [Change / Flag for review / Accept] |
BLOCKING = must fix before shipping that locale. ADVISORY = recommend change. NOTE = informational only.
Ask: "May I write this cultural review report to production/localization/cultural-review-[date].md?"
Manage the voice-over localization process. Determine the sub-task from the argument:
vo-pipeline scan — identify all dialogue lines that require VO recordingvo-pipeline script — generate recording scripts with director notesvo-pipeline validate — check that all recorded VO files are present and correctly namedvo-pipeline integrate — verify VO files are correctly referenced in code/assetsRead assets/data/strings/ and design/narrative/. Identify:
dialogue.*) with source textassets/audio/vo/)Output a recording manifest:
## VO Recording Manifest — [Date]
| Key | Character | Source Line | Status |
|-----|-----------|-------------|--------|
| dialogue.npc.merchant.greeting | Merchant | "Welcome, traveller." | Recorded |
| dialogue.npc.merchant.haggle | Merchant | "That's my final offer." | Needs recording |
Generate a recording script document for each character, grouped by scene. Include:
[Warm, welcoming], [Annoyed, clipped])Ask: "May I write the VO recording scripts to production/localization/vo-scripts-[locale]-[date].md?"
Glob assets/audio/vo/[locale]/ for all .wav/.ogg files. Cross-reference against the VO manifest. Report:
Grep src/ for VO audio references. Verify each referenced path exists in assets/audio/vo/[locale]/. Report broken references.
Right-to-left languages (Arabic, Hebrew, Persian, Urdu) require layout mirroring beyond just translating text. This mode validates the implementation.
Read .claude/docs/technical-preferences.md to determine the engine. Then check:
Layout mirroring
Control.layout_direction, Unity: RTL Support package, Unreal: text direction flags)Text rendering
String assembly
{placeholder} positions in sentences work correctly when sentence structure is reversed?Asset review
Grep patterns to check:
HBoxContainer, LinearLayout, HorizontalBox nodes — verify layout_direction settings+ near dialogue or UI codeReport findings. Flag BLOCKING issues (content unreadable without fix) vs ADVISORY (cosmetic improvements).
Ask: "May I write this RTL check report to production/localization/rtl-check-[date].md?"
String freeze locks the source (English) string table so that translations can proceed without the source changing under the translators.
Check current freeze status in production/localization/freeze-status.md (if it exists).
If already frozen:
"String freeze is currently ACTIVE (called [date]). [N] strings have been added or modified since freeze. These are freeze violations — they require re-translation or an approved freeze lift."
If not frozen, present the pre-freeze checklist:
Pre-Freeze Checklist
[ ] All planned UI screens are implemented
[ ] All dialogue lines are final (no further narrative revisions planned)
[ ] All system strings (error messages, tutorial text) are complete
[ ] /localize scan shows zero hardcoded strings
[ ] /localize validate shows no placeholder mismatches in source (en)
[ ] Marketing strings (store description, achievements) are final
Use AskUserQuestion:
[A] Yes — call string freeze now / [B] No — I still have strings to addIf [A]: Write production/localization/freeze-status.md:
# String Freeze Status
**Status**: ACTIVE
**Called**: [date]
**Called by**: [user]
**Total strings at freeze**: [N]
## Post-Freeze Changes
[Any strings added or modified after freeze are listed here automatically by /localize extract]
If argument includes lift: update freeze-status.md Status to LIFTED, record the reason and date. Warn: "Lifting the freeze requires re-translation of all modified strings. Notify the translation team."
When extract mode finds new or modified strings and freeze-status.md shows Status: ACTIVE — append the new keys to ## Post-Freeze Changes and warn:
"⚠️ String freeze is active. [N] new/modified strings have been added. These are freeze violations. Notify your localization vendor before proceeding."
Localization QA is a dedicated pass that runs after translations are delivered but
before any locale ships. This is not the same as /validate (which checks completeness)
— this is a structured playthrough-based quality check.
Spawn localization-lead via Task with:
design/gdd/ or /content-audit output)/localize validate reportAsk the localization-lead to produce a QA plan covering:
Output a QA verdict per locale:
## Localization QA Verdict — [Locale]
**Status**: PASS / PASS WITH CONDITIONS / FAIL
**Reviewed by**: localization-lead
**Date**: [date]
### Findings
| ID | Area | Description | Severity | Status |
|----|------|-------------|----------|--------|
| LOC-001 | UI Overflow | "Settings" button text overflows on [Screen] | BLOCKING | Open |
| LOC-002 | Translation | [Key] translation is literal — sounds unnatural | ADVISORY | Open |
### Conditions (if PASS WITH CONDITIONS)
- [Condition 1 — must resolve before ship]
### Sign-Off
[ ] All BLOCKING findings resolved
[ ] Producer approves shipping [Locale]
Ask: "May I write this localization QA report to production/localization/loc-qa-[locale]-[date].md?"
Gate integration: The Polish → Release gate requires a PASS or PASS WITH CONDITIONS verdict for every locale being shipped. A FAIL blocks release for that locale only — other locales may still proceed if their QA passes.
context field with translator notes, character limits, and placeholder meaning/localize scan → find hardcoded strings
/localize extract → build string table
/localize freeze → lock source before sending to translators
/localize brief → generate translator briefing document
[Send to translators]
/localize validate → check returned translations
/localize cultural-review → flag culturally sensitive content
/localize rtl-check → if shipping Arabic / Hebrew / Persian
/localize vo-pipeline → if shipping dubbed VO
/localize qa → full localization QA pass
After qa returns PASS for all shipping locales, include the QA report path when running /gate-check release.