Formats
.strings
The legacy per-locale format. anylocale writes a full .lproj tree in one command, one .strings file per table.
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.
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.
Scriptable from the CLI
Push, pull and sync from a terminal, a build phase or a coding agent's shell, with a token in the environment.
The CLIPulls 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 phase
Set it up
From nothing to every language.
Step 1: Keep reading strings the way the target already does
NSLocalizedStringandString(localized:)look a key up in the current locale'sLocalizable.strings. The comment argument is what the translators and the AI draft see, so write it for them.WelcomeViewController.swiftimport UIKit final class WelcomeViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() titleLabel.text = NSLocalizedString("welcome_title", comment: "Headline on the first screen") } }Step 2: 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 3: Push the base .lproj
The source language's file, as the project keeps it. A block comment above an entry becomes that key's description.
shellcurl -fsS -X POST "https://anylocale.com/api/loc/push?project=my-app&format=strings" \ -H "Authorization: Bearer $ANYLOCALE_TOKEN" \ --data-binary @en.lproj/Localizable.stringsStep 4: Sync every locale
Downloads each locale as
<locale>.lproj/<Table>.strings, plus a .stringsdict where a table has plurals. Each file lands complete or not at all.shellanylocale sync --project my-app --out-dir Sources/Resourcesde.lproj/Localizable.strings/* Headline on the first screen */ "welcome_title" = "Willkommen"; /* Explains why the app needs the location */ "onboarding.location_permission" = "Standort & Wetter für %@ erlauben";Step 5: Or pull one table of one locale
The file flag names the string table. It applies to .strings and .stringsdict only.
shellanylocale pull --project my-app --locale de --format strings \ --file Localizable --out de.lproj/Localizable.strings
Good to know
- Add --no-comments to sync or pull to leave key descriptions out of the committed files.
- A trailing \n before a closing quote is reported as a warning; it is almost always an accident.
Questions
- Do the comments in the file survive?
- Key descriptions are written as the comment above each entry, so a translator reading the file sees the same note the editor shows. Add --no-comments to leave them out of committed files.
- Where do the plurals go?
- Into a .stringsdict beside the .strings file, written by the same sync for every table that has at least one plural key. A table without plurals gets no .stringsdict.
- Do I get unverified text when I pull?
- Yes. A pull carries the current text of every key, verified or not, so a build always has something to show. Only over-the-air delivery is limited to verified strings.
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.