Xcstrings completion
Use when generating, completing, or translating entries in Xcode `.xcstrings` localization files (e.g. Localizable.xcstrings) — batch-translating to a new language, completing missing translations, fixing plural forms, or running validation on the file before buildFrom its SKILL.md
npx -y skills add metneo/skills --skill xcstrings-completionAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.0 KB, ~1.8k tokens by cl100k_base, as published. Nobody here has run it
xcstrings Completion
Generate, complete, and translate entries in Xcode's .xcstrings JSON format. Uses positional placeholders (%1$@, %2$@) and variations.plural for pluralized strings.
When to Use
- Batch-translating entries to a new target language
- Completing missing translations
- Fixing broken CLDR plural forms in an existing translation
- Validating a
.xcstringsfile before build (placeholder preservation, structure)
When NOT to use: legacy .strings/.stringsdict files; Strings Catalog auto-generated by Xcode (manual edits get overwritten); translation memory / glossary work (use a TMS); one-off string edits (Xcode's built-in editor is faster).
Pre-flight
- Git repo; current
Localizable.xcstringscommitted (merge rewrites the file) - Python 3.9+ (uses
from __future__ import annotations) -
cdto the project root (directory containing.xcodeproj,Package.swift, or.git) before running scripts —setup_pipeline.pycreates.agents/at CWD, not at the.xcstringslocation - Optional: allowlist
python3 scripts/*.pyin.claude/settings.jsonto drop permission prompts (seefewer-permission-promptsskill)
Format
See format-reference.md for the full JSON shape. At a glance:
stringUnit.state:new·translated·needs_review·manual(don't auto-updatemanual)- At key level:
stale= Xcode marked the entry for removal (delete it) - Plurals:
variations.plural.<form>per CLDR (zero/one/two/few/many/other); English often haszero+one+other, Chinese collapsesone+other, Arabic needs all six
Pipeline
run_pipeline.py --input <path> drives all steps with text prompts. For an LLM-driven flow using AskUserQuestion, follow the table directly. Do not Read the script source files to understand the API — the CLI is documented here.
| # | Step | Script / action |
|---|---|---|
| 0 | Setup (batch dir + load + detect plural candidates) | python3 scripts/setup_pipeline.py --input <path> — prints JSON with batch_dir, entry_path, translated_path, source_language, target_languages, plural_candidates |
| 1 | Confirm plurals | AskUserQuestion per candidate; if uniform, ask "Mark all <N>?" with "All"/"None"/"Per-key" first |
| 2 | Pick target lang | AskUserQuestion with one option per existing language + "All existing"; multiSelect: false. If user types manually, split on , ; \n \t or whitespace, trim, dedupe case-insensitively, reject if empty |
| 3 | Generate batch | python3 scripts/generate_batch.py --input <path> --lang <lang> --output <entry_path> --plural-keys <keys> |
| 4 | Translate | LLM Reads entry.json, Writes translated.json |
| 4.5 | User review | AskUserQuestion — "Apply / Edit / Cancel" — pause so the user can open translated.json in their editor and tweak before merge |
| 5 | Apply (validate → merge → re-validate in one call) | python3 scripts/apply_batch.py --input <path> --lang <lang> --batch <translated_path> |
| 6 | Done | file is ready to build |
Run Steps 3–5 once per language (3 Bash calls each: Step 0, Step 3, Step 5). If any iteration fails, stop and surface the error before continuing.
LLM-driven specifics
AskUserQuestionhas 4-option max. With "Enter manually" using one slot, list at most 3 existing languages — pick the 3 most common (English-speaking first if present) and let the user type the rest. Don't include the source language (usuallyen).- Step 4.5 question:
"<path> is ready. Apply it, edit first, or cancel?"with"Apply now"/"I'll edit first"/"Cancel". If "edit first", wait for the user's next message, re-Read the file, then run Step 5. If "cancel", exit cleanly. - Intermediate files live under
<project-root>/.agents/localizations/<timestamp>/(created by Step 0 at CWD). NOT next to.xcstrings, NOT in/tmp, NOT in the skill directory. Print the absolute path so the user can open it. Timestamp uses microsecond precision to avoid collisions.
Step 4 — translated.json shape
When the LLM writes translated.json, copy every field of entry.json verbatim and add (or replace only) the translations field. Don't add stringUnit, state, or a .value wrapper — the merge script does that wrapping later.
isPlural | translations value | What it becomes in .xcstrings |
|---|---|---|
false | string | <lang>.stringUnit.value |
true | object keyed by CLDR form (one/other/zero/few/many/two) | <lang>.variations.plural.<form>.stringUnit.value |
{
"targetLanguage": "fr",
"sourceLanguage": "en",
"entries": [
{"key": "Hello", "source": "Hello", "isPlural": false, "translations": "Bonjour"},
{"key": "%lld Files", "isPlural": true, "source": {"one": "%lld File", "other": "%lld Files"}, "translations": {"one": "%lld Fichier", "other": "%lld Fichiers"}}
]
}
Anti-patterns — all fail validation
translations: {"value": "..."}— must be a string for non-plural, not wrappedtranslations: {"stringUnit": {...}}— merge script adds this- Plural entry without
"isPlural": true— merge writes it as a simple string, dropping plural forms translation(singular) — accepted as fallback today but canonical istranslations; next validator revision may drop it- Mismatched plural forms — every CLDR form in
sourcemust appear intranslations(don't dropzero, don't invent extras) commentfield is translator context; do not paste it into the value- Placeholders dropped or added —
%1$@,%lld,%%must match the source verbatim - Auto-updating a
manual-state entry — preserve as-is - Missing
stateon a translated entry — validator passes but Xcode may treat it asnew
Common Mistakes — STOP and Start Over
- "I'll JSON-edit the file with regex" — Xcode's next export clobbers manual edits and can corrupt
variations.plural. Use the merge script. - "Skip the validator" — placeholder drops silently break runtime.
- "
%llddetected → must be plural" — some are literal (e.g. "Build #12345"). Confirm with the user. - "Just overwrite the existing entry" — the merge script preserves existing translations; manual overwrite loses them.
- "Skip Step 4.5" — users almost always want a chance to tweak before merge.
- "Write intermediate files to
/tmp" — use.agents/localizations/<timestamp>/at the project root. - "Call validate / merge / validate separately" — 3 permission prompts. Use
apply_batch.pyto collapse them. - "I'll Read the script source to understand the API" — the CLI is documented above; reading the source costs a permission prompt and tempts you to write a wrapper.
What ships with it: 9 files
33.9 KB alongside SKILL.md, 8 of them executable
references/
- format-reference.md2.2 KB
scripts/
- apply_batch.pyruns1.9 KB
- generate_batch.pyruns3.9 KB
- merge_to_xcstrings.pyruns2.7 KB
- run_pipeline.pyruns7.1 KB
- setup_pipeline.pyruns3.2 KB
- validate_batch.pyruns5.3 KB
- validate_xcstrings.pyruns3.0 KB
- xcstrings_parser.pyruns4.6 KB