Localization
SkillDev toolsInspect and edit Xcode String Catalogs (.xcstrings) via bundled l10n.sh and find_unused_keys.sh scripts, and apply Apple localization conventions.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Localization skill
What this skill tells your AI
The instructions your AI receives, as published by camillescholtz/swmpc in .agents/skills/localization/SKILL.md and read by ahel’s review.
The scripts work on any Xcode String Catalog (.xcstrings). They auto-discover
the catalog by searching the project for .xcstrings files (preferring
Localizable.xcstrings when several exist) and can be pointed at a specific
one with the L10N_FILE env var. Run l10n.sh file to see which catalog is
targeted.
String catalogs are usually too large to open with the Read/Edit tools — use
the scripts instead. They operate on the catalog with jq, write changes back
atomically, and re-serialize to Xcode's exact on-disk format (Xcode writes
"key" : value with spaces around the colon; without normalization every edit
would produce a huge spurious git diff).
Both scripts resolve the project root from their own location, so they can be run from any working directory.
l10n.sh
.claude/skills/localization/scripts/l10n.sh <command> [args]
| Command | Purpose |
|---|---|
file | Print the resolved catalog path |
keys | List all translatable keys |
search <pattern> | Search keys (case-insensitive) |
search-values <pattern> | Search translation values; prints key⇥lang⇥value |
get <key> | Show all translations for a key (raw JSON) |
comment <key> [text] | Show or set the translator comment for a key |
set <key> <lang> <value> | Set a single translation |
set-plural <key> <lang> <cat> <value> | Set a plural variant (zero|one|two|few|many|other) |
batch-set <file.tsv> | Bulk set from a TSV file (key⇥lang⇥value), single pass |
missing <lang> | Keys missing or pending (state ≠ translated) for <lang> |
stats [lang] | Per-language translated counts, plus pending/stale totals |
stale | Keys Xcode marked extractionState: "stale" (removed from code) |
rename <old> <new> | Rename a key, preserving translations |
delete <key> [lang] | Delete a key, or just one language's translation |
normalize | Re-serialize the file to Xcode's exact .xcstrings format |
Notes
- Adding a new string: set the source-language value first (e.g.
set "New key" en "New key"), then other languages, then a translator comment (comment <key> <text>). Keys are created on firstset. - Bulk translations: prefer
batch-setover manysetcalls — it applies all rows in one pass. Build a TSV with onekey⇥lang⇥valuerow per cell;\nand\tescapes in values become real newlines/tabs. - Plurals: a localization holds either a flat value or variations, never
both —
setrefuses keys that use variations; useset-plural, which also converts a flat value to plural form. Fill every category the language requires (English: one/other; Russian: one/few/many/other; …). - Languages: use the BCP-47 codes as they appear in the catalog (
en,de,fr, …). Runstatsto see which languages exist. set,set-plural, andbatch-setmark each unitstate: "translated".- Renaming keys: Xcode re-extracts strings from code on every build, so also update the source references or the old key comes back.
find_unused_keys.sh
.claude/skills/localization/scripts/find_unused_keys.sh
Lists catalog keys not referenced anywhere in the project sources (Swift,
ObjC, storyboards/xibs). Matching accounts for format specifiers (%@,
%lld, …), Swift string-escape forms, and interpolation; placeholder-only
keys it cannot verify are listed separately. Matching is textual, so keys
built dynamically at runtime are invisible to it — verify each hit, then
remove confirmed-unused keys with l10n.sh delete <key>. Cross-check with
l10n.sh stale for keys Xcode itself no longer extracts.
Best practices
Full guidance distilled from Apple's docs lives in references/best-practices.md — consult it when writing or reviewing localizable Swift code. The short version:
- SwiftUI literals in
Text/Label/etc. are auto-localizable; elsewhere useString(localized:), and pass strings around asLocalizedStringResource, notString. In frameworks/packages, passbundle: #bundle. - Give every string a translator comment describing where it appears and what its placeholders are.
- Never concatenate sentence fragments or branch on plural count in code — use one key with interpolation, and plural variations for counts.
- Never hand-format user-visible dates, numbers, currencies, measurements, or
lists — use Foundation's
formatted(…)styles, which localize per locale. - Mark brand names and symbols
shouldTranslate: falseinstead of deleting them; keep unreviewed machine translations inneeds_reviewstate.
Signals
- GitHub stars
- 235
- Forks
- 15
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
localization-camillescholtz- Source
- github.com/camillescholtz/swmpc