Formats
.xcstrings
An Xcode string catalog holds every locale in one file. anylocale reads it whole and writes it whole, plurals and named substitutions included.
What you get
Everything the editor does, through the files you already ship.
Every plural form a language has
Each locale gets exactly the CLDR categories it uses, Arabic six and Japanese one, written in the format's own plural shape.
Placeholders round-trip
%@,%1$sand{count}come back as they went in, and a translation that drops or alters one is flagged before it is verified.AI drafts, a person verifies
Every language is drafted against your glossary and each key's length limit. A draft never ships until someone has verified it.
Pulls on every build
A Run Script phase above Compile Sources keeps the target on the latest verified text without anyone remembering to sync.
Xcode build phaseA spreadsheet for translators
Export a locale to CSV, hand it to someone who works in Excel or Numbers, and import the result in one push.
CSVUpdates over the air
Publish the verified strings and let the running app fetch them, so a fixed translation reaches users without a store release.
Over-the-air delivery
Set it up
From nothing to every language.
Step 1: Add a String Catalog to the target
File, New, File from Template, String Catalog, named Localizable. With Use Compiler to Extract Swift Strings on (the default since Xcode 15), every
Text("key")andString(localized:)lands in the catalog on the next build. The comment becomes the note translators and the AI draft see.ContentView.swiftimport SwiftUI struct ContentView: View { let count: Int var body: some View { VStack { Text("welcome_title", comment: "Headline on the first screen") Text("cart.items \(count)", comment: "Items in the cart, pluralised") } } }Step 2: Add the languages in Xcode
Project, Info, Localizations, and add each language the project has. A locale the target does not list is ignored by the build even when the catalog carries it.
Step 3: Install the CLI and log in
Homebrew or the one-line installer, then a token issued per project under Settings, Integrations. The read scope pulls; push writes source files and values; manage creates and deletes keys.
shellbrew install anylocale/tap/anylocale anylocale login --project my-appStep 4: Push the source file
The push is additive: keys missing from the file stay in place, so a truncated file cannot empty a project. Descriptions in the file become translator notes.
shellcurl -fsS -X POST "https://anylocale.com/api/loc/push?project=my-app&format=xcstrings" \ -H "Authorization: Bearer $ANYLOCALE_TOKEN" \ --data-binary @Localizable.xcstringsStep 5: Pull the catalog back
The format carries every locale, so the locale flag is required by the command but does not narrow the file. Every entry comes back with
extractionStateset to manual, which keeps Xcode from marking it stale.shellanylocale pull --project my-app --locale en \ --format xcstrings --out Localizable.xcstringsLocalizable.xcstrings{ "sourceLanguage" : "en", "strings" : { "cart.items" : { "comment" : "Items in the cart, pluralised", "extractionState" : "manual", "localizations" : { "de" : { "variations" : { "plural" : { "one" : { "stringUnit" : { "state" : "translated", "value" : "1 Artikel" } }, "other" : { "stringUnit" : { "state" : "translated", "value" : "%lld Artikel" } } } } } } } } }
Good to know
- One catalog per string table: a project with Localizable and Settings tables pulls two files.
- A pulled catalog marks every entry as manually extracted, so Xcode keeps entries whose key the compiler did not find in this build.
- Device variations (a different text on iPad or Mac) are refused on push with the key named. Plurals and substitutions are fine.
- Every pull carries the current text of every key, verified or not. Only over-the-air delivery is limited to verified strings.
Questions
- Does the catalog keep its plurals and device variations?
- Plurals and %#@name@ substitutions round-trip, with every category the locale has. Device variations do not: a catalog that carries one is refused on push with the key named, so keep such a key out of the catalog you push or drop the variation in Xcode.
- Can I push one string table at a time?
- Each catalog is one table, so Localizable.xcstrings and Settings.xcstrings are two pushes. A pull is one catalog covering the project's keys; the file flag that picks a table applies to .strings and .stringsdict only.
- What happens to a key I removed from the catalog?
- Nothing. The push is additive, so a key missing from the file stays in the project until it is deleted in the app or through the API with the manage scope. A truncated file cannot empty a project.
- Which other formats can the same project be pulled in?
- .xcstrings, .strings with .stringsdict, strings.xml, JSON, next-intl messages and CSV. A project is not tied to the format it was pushed in, which is how an iOS app and an Android app share one catalog..xcstrings.stringsstrings.xmlJSONnext-intlCSV
Start with the file your app already ships.
After checkout, import one strings file and read the first drafts within minutes.
Nothing to connect and nothing to install. The CLI is optional.