agentleFS
HeathWangHeathWang/hw-cc-plugin/skills/ios-i18n-workflow/SKILL.md

ios-i18n-workflow

Skill1 starsChanged 3 months agoMITView on GitHub

Use when iOS apps using SwiftGen L10n need localization work - adding keys, checking missing translations, or cleaning unused entries. Triggered by hardcoded strings, missing L10n references, incomplete translations across multiple languages, or unused localization cleanup requests.

  • Installs packages

The file

Show its rules and text

We split this skill into the rules it gives an agent

20 rules. About 0 are common, 19 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈19

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If missing keys found, return to incomplete target language phase

    line 120
  2. Distinctive:

    Update baseline language file and replace hardcoded strings with L10n references.

    line 124
  3. Distinctive:

    Add new/modified strings to baseline file following naming conventions

    line 127
  4. Distinctive:

    Critical: Run after ALL changes and verification.

    line 172
  5. Distinctive:

    Run SwiftGen: if any translations were added

    line 201
  6. Distinctive:

    Completion: ALL target languages have complete translations matching baseline.

    line 203
  7. Distinctive:

    Baseline as source: Always copy keys from baseline, never between target languages

    line 289
  8. Distinctive:

    Verify ALL languages: Every target language must be checked against baseline before SwiftGen

    line 290
  9. Distinctive:

    Use descriptive, domain-based names for clarity

    line 300
  10. Distinctive:

    Only add/modify missing or outdated keys identified by scripts or requirements

    line 367
  11. Distinctive:

    Do NOT edit existing, correct keys and values

    line 368
  12. Distinctive:

    Only modify the specific language file for that phase

    line 371
  13. Distinctive:

    Always verify with scripts before assuming completeness

    line 376
  14. Distinctive:

    Run SwiftGen after any localization file changes

    line 377
  15. Distinctive:

    Test translations in actual app context

    line 378
  16. Distinctive:

    Start with baseline phase first

    line 381
  17. Distinctive:

    Check ALL target languages, not just one

    line 387
  18. Distinctive:

    Run SwiftGen if any keys were added

    line 389
  19. Very specific:

    Always use --dry-run first

    line 392
  20. Distinctive:

    Keep backup files until verified in app

    line 395

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

iOS Internationalization Workflow

Complete workflow for managing iOS app internationalization (i18n) using SwiftGen L10n code generation. Supports any number of target languages. Covers three main scenarios: internationalizing code, verifying translation completeness, and cleaning unused entries.

When to Use

digraph when_to_use {
    rankdir=TB;
    "User provides code/folder for i18n?" [shape=diamond, style=filled, fillcolor=lightblue];
    "User asks to check missing translations?" [shape=diamond, style=filled, fillcolor=lightgreen];
    "User asks to clean unused i18n?" [shape=diamond, style=filled, fillcolor=lightyellow];
    "Standardize" [shape=box, style=filled, fillcolor=lightcoral];
    "CheckMissing" [shape=box, style=filled, fillcolor=lightcoral];
    "CleanUp" [shape=box, style=filled, fillcolor=lightcoral];

    "User provides code/folder for i18n?" -> "Standardize" [label="Yes\n(Full workflow)"];
    "User asks to check missing translations?" -> "CheckMissing" [label="Yes\n(Verify only)"];
    "User asks to clean unused i18n?" -> "CleanUp" [label="Yes\n(Cleanup only)"];
}

Three main scenarios:

  1. Internationalize code - User provides code or folder: "Here's my view controller, add i18n" → Run full workflow (baseline → ALL target languages → verify → SwiftGen)
  2. Check missing translations - User explicitly asks: "Check if translations are complete" or "Find missing i18n keys" → Run check_missing_localizations.py for each target language and fill gaps
  3. Clean unused entries - User explicitly asks: "Clean unused localizations" or "Remove unused i18n keys" → Run clean_unused_localizations.py with dry-run first

Key principle: Complete translations for ALL target languages before verification and SwiftGen generation.

Do NOT use when:

  • Projects using raw NSLocalizedString without SwiftGen
  • Non-iOS platforms (Android, Web)

Identifying User Intent

Determining which scenario applies:

Scenario 1: Full Workflow

User provides code files or folder paths, says things like "internationalize this" or "add i18n to this code"

Scenario 2: Check Missing

User asks to verify translation completeness with phrases like "check if translations complete" or "find missing i18n keys"

Scenario 3: Cleanup

User requests removal of unused entries with phrases like "clean unused localizations" or "remove unused i18n keys"

Quick decision guide:

  • Provides code/folder → Scenario 1 (Full workflow)
  • Asks to check/verify → Scenario 2 (Check missing)
  • Asks to clean/remove → Scenario 3 (Cleanup)

Red Flags - STOP and Re-read

For Scenario 1 (Full internationalization):

  • "I'll just run swiftgen real quick"
  • "The translations can wait"
  • "I'll add the keys manually"
  • "This phase doesn't apply to my case"
  • "I can skip phase 4 and run it later"
  • "No need to verify with scripts, trust me"

For Scenario 2 (Check missing):

  • "I can just eyeball the files"
  • "Checking one target language is enough"
  • "I'll add keys later"
  • "The other languages look fine"

For Scenario 3 (Cleanup):

  • "Just delete everything without checking"
  • "No need for --dry-run first"

All of these mean: Read the skill again and follow the correct workflow.

Configuration

Project-specific variables:

project_root: "/path/to/your/iOS/project"
localization_dir: "*/Localization"
baseline_language: "zh-Hans"  # Source of truth (can be any language)
target_languages: ["zh-Hant", "en", "ja", "ko", "de"]  # ALL target languages
generated_file: "Generated/Strings.swift"

Default structure:

<ProjectRoot>/path/<localization_dir>/
├── zh-Hans.lproj/Localizable.strings  # Baseline (source of truth)
├── zh-Hant.lproj/Localizable.strings  # Target 1
├── en.lproj/Localizable.strings       # Target 2
└── ja.lproj/Localizable.strings       # Target 3 (add more as needed)

Note: The baseline language can be any language (zh-Hans, en, ja, etc.). Choose the language you work with most frequently as baseline.

Scenario 1: Full Internationalization Workflow

Use when: User provides code/folder for internationalization

Flow: Sequential phases with iterative target language processing

Phase 1: Baseline → Phase 2+: Target Languages (repeat for ALL) → Verification → SwiftGen

Critical:

  • Complete ALL target language translations sequentially before verification
  • Verification step must confirm ALL languages aligned before SwiftGen
  • If missing keys found, return to incomplete target language phase

Phase 1: Baseline Localization

Update baseline language file and replace hardcoded strings with L10n references.

  1. Extract hardcoded strings from Swift/ObjC files
  2. Add new/modified strings to baseline file following naming conventions
  3. Replace strings with L10n.xxx calls

Completion: Baseline updated and code references replaced.

Phase 2+: Target Language Translations (Repeat for ALL Target Languages)

For EACH target language in your configuration:

  1. Identify new keys from Phase 1 - Review the keys added to baseline file
  2. Translate each new key from baseline language to this target language
  3. Add translations to this target language's .strings file following the same structure

Process:

  • Complete ONE target language fully before moving to the next
  • Copy new/modified keys from Phase 1 baseline
  • Translate values (not keys) to target language
  • Maintain same key names and structure as baseline
  • Preserve placeholders like %@, %d, etc.

Verification Step (CRITICAL)

After completing ALL target language translations, verify alignment:

This step confirms ALL translations are complete and aligned with baseline.

# Check each target language against baseline
for target_lang in "${target_languages[@]}"; do
  python3 <skill_path>/scripts/check_missing_localizations.py \
    <localization_dir>/<baseline_lang>.lproj/Localizable.strings \
    <localization_dir>/${target_lang}.lproj/Localizable.strings
done

Example: python3 scripts/check_missing_localizations.py Localization/zh-Hans.lproj/Localizable.strings Localization/en.lproj/Localizable.strings

Expected output for EACH language: ✅ [target] 文件没有缺失的键。

If missing keys found: Return to the incomplete target language phase and add missing translations.

Only proceed to Final Phase after verification confirms ALL languages aligned.

Final Phase: Generate Swift Code

Critical: Run after ALL changes and verification.

cd <project_root>
swiftgen

Completion: Code generated with all L10n references available for ALL languages.

Scenario 2: Check Missing Translations

Use when: User explicitly asks "Check if translations are complete" or "Find missing i18n keys"

Workflow

  1. Identify baseline language (usually zh-Hans or en)
  2. Check EACH target language against baseline:
python3 <skill_path>/scripts/check_missing_localizations.py \
  <localization_dir>/<baseline_lang>.lproj/Localizable.strings \
  <localization_dir>/<target_lang>.lproj/Localizable.strings

Repeat for ALL target languages.

  1. Review reports - Each check shows missing keys for that target language
  2. Add missing translations to each target language file
  3. Re-run verification for all modified languages to confirm all aligned
  4. Run SwiftGen if any translations were added

Completion: ALL target languages have complete translations matching baseline.

Scenario 3: Clean Unused Localizations

Use when: User explicitly asks "Clean unused localizations" or "Remove unused i18n keys"

Workflow

  1. Dry-run first (see what would be deleted):
cd <project_root>
python3 <skill_path>/scripts/clean_unused_localizations.py --dry-run
  1. Review the report - Shows unused entries and usage statistics
  2. Run actual cleanup (after confirmation):
python3 <skill_path>/scripts/clean_unused_localizations.py
  1. Run SwiftGen to regenerate code:
swiftgen

Safety:

  • Script creates .backup file before deletion
  • Prompts for confirmation before deleting
  • Requires explicit user confirmation

Completion: Unused entries removed, SwiftGen regenerated.

Quick Reference

Scenario 1: Full Internationalization

TaskCommand/ApproachPhase
Extract hardcoded stringsManual review of provided code1 (Baseline)
Add keys to baselineEdit baseline .strings file1
Replace with L10nL10n.Module.key syntax1
Translate to ALL targetsCopy keys from baseline, translate values sequentially2+
Verify alignmentpython3 scripts/check_missing_localizations.py <baseline> <target> for EACH targetAfter ALL translations
Generate Swift codeswiftgenFinal

Scenario 2: Check Missing Only

TaskCommand
Check each targetpython3 scripts/check_missing_localizations.py <baseline> <target> for ALL targets
Add missing keysEdit target .strings files
Verify fixedRe-run check script for all modified targets
Generate (if changed)swiftgen

Scenario 3: Cleanup Only

TaskCommand
Preview cleanuppython3 scripts/clean_unused_localizations.py --dry-run
Execute cleanuppython3 scripts/clean_unused_localizations.py
Regenerateswiftgen

Common Mistakes

MistakeFixScenario
Running swiftgen before syncing ALL translationsAlways complete ALL target language translations before SwiftGen1
Skipping verification stepAlways run check script after ALL target translations to confirm ALL languages aligned1
Only verifying some target languagesCheck EVERY target language against baseline before SwiftGen1, 2
Using string interpolation on format functionsCall as function: L10n.Xxx.func(arg1, arg2)1
Translating placeholders like %@Preserve placeholders exactly: %@, %d, etc.1, 2, 3, 4
Naming keys starting with numbersKeys must start with letters: secure3d not 3dsecure1, 4
Skipping final phase for "later"SwiftGen MUST run after all changes or code won't compile1, 2, 3
Cleanup without --dry-run firstAlways preview what will be deleted before actual cleanup3
Forgetting SwiftGen after cleanupMust regenerate code after removing unused keys3

Key Rules

0. Multi-Language Workflow (CRITICAL)

For projects with multiple target languages:

  • Sequential completion: Finish ONE target language completely before starting the next
  • Baseline as source: Always copy keys from baseline, never between target languages
  • Verify ALL languages: Every target language must be checked against baseline before SwiftGen

Workflow: Baseline → Target1 → Target2 → ... → TargetN → Verify ALL → SwiftGen (once)

1. Localization Key Naming

Core requirements:

  • Domain-like naming with hierarchical structure
  • All lowercase letters, numbers (after first character), and dots (.)
  • CRITICAL: Each segment MUST start with a letter (a-z), NOT a number
  • Use descriptive, domain-based names for clarity

Examples:

✅ common.ok
✅ market.header.name
✅ trade.confirm.title
✅ futuresrecords.header.amount_usdt

❌ symboldetail.24h.high (number in middle) → Use symboldetail.daily.high
❌ 2fa.enabled (starts with number) → Use twofa.enabled

2. L10n Code Reference Transformation

SwiftGen auto-transforms keys to code references:

  • All levels except last: Title Case (capitalize first letter only)
  • Last level:
    • Contains underscores (snake_case) → convert to camelCase
    • Single lowercase word → keep as-is
    • Compound words without underscores → stay lowercase

Examples:

Localization KeyL10n ReferenceNotes
common.okL10n.Common.okSingle level
market.header.nameL10n.Market.Header.nameAll Title Case
futuresrecords.header.amount_usdtL10n.Futuresrecords.Header.amountUsdtLast: snake_case → camelCase
paybridge.error.missingproductidL10n.Paybridge.Error.missingproductidCompound stays lowercase
challenge.status.inprogress.fullL10n.Challenge.Status.Inprogress.fullinprogress → Inprogress

3. Format Strings (with Parameters)

When localization strings contain format specifiers (%@, %d, %f, etc.), SwiftGen generates a FUNCTION, not a static property.

Format specifier examples:

  • %@ - Any object (String, etc.)
  • %d / %i - Integer
  • %f - Float/Double
  • %.2f - Formatted float
  • %% - Literal percent (does NOT create parameter)

Usage examples:

// Static property (no format specifiers)
button.setTitle(L10n.Common.ok, for: .normal)

// Function call (with format specifiers)
label.text = L10n.Challenge.Progress.stage(phaseText, statusText)
label.text = L10n.Futurestrading.Orderbook.fundingrate(8)

For detailed examples, troubleshooting, and migration guide: See references/naming-conventions.md

Helper Scripts

Located in scripts/ directory. For detailed usage, see scripts/README.md.

ScriptPurposeCommand
check_missing_localizations.pyCompare files for missing keyspython3 scripts/check_missing_localizations.py <baseline> <target>
clean_unused_localizations.pyFind/remove unused entriespython3 scripts/clean_unused_localizations.py --dry-run

Important Constraints

For ALL phases:

  • Only add/modify missing or outdated keys identified by scripts or requirements
  • Do NOT edit existing, correct keys and values
  • Preserve file structure, MARK comments, and formatting
  • Maintain alphabetical or logical grouping
  • Only modify the specific language file for that phase

Best Practices

For All Scenarios

  • Always verify with scripts before assuming completeness
  • Run SwiftGen after any localization file changes
  • Test translations in actual app context

For Scenario 1 (Full Workflow)

  • Start with baseline phase first
  • Complete ALL target language translations before running verification
  • Verify EVERY target language against baseline before SwiftGen
  • Complete each phase fully before next

For Scenario 2 (Check Missing)

  • Check ALL target languages, not just one
  • Re-run verification after adding missing keys
  • Run SwiftGen if any keys were added

For Scenario 3 (Cleanup)

  • Always use --dry-run first
  • Review the cleanup report before confirming
  • Clean periodically (e.g., before releases)
  • Keep backup files until verified in app

Requirements

  • Python 3.x
  • SwiftGen (brew install swiftgen)
  • iOS project using SwiftGen for localization
  • Access to *.lproj/Localizable.strings files

Advanced Usage

For CI/CD integration, automated translation, and performance optimization, see references/advanced-usage.md.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.