Localizing an iOS app with String Catalogs
Xcode 15 introduced String Catalogs, a single .xcstrings file that holds every language of an app. Older projects still use one Localizable.strings file per language inside an .lproj folder. Both work, and both can be generated from the same set of keys.
String Catalog or .strings?
A String Catalog is a JSON file. Each key lists its localizations, and each localization carries a value and a state such as translated or needs_review. Xcode shows the state in its catalog editor, so reviewers can see what is left at a glance.
A .strings file is a flat list of "key" = "value"; lines, one file per language. It has no notion of review state, but it diffs cleanly and every iOS version reads it.
New projects should use a String Catalog. Keep .strings if you support build tooling that expects it, or if you prefer one file per language in code review.
What a String Catalog looks like
LocalizeMe writes one Localizable.xcstrings for the whole project. Approved translations go out as translated, everything else as needs_review, so Xcode flags what a reviewer has not signed off yet. Keys are sorted, so the file diffs the same way every time.
{
"version": "1.0",
"sourceLanguage": "en",
"strings": {
"checkout.pay_button": {
"extractionState": "manual",
"localizations": {
"de": { "stringUnit": { "state": "translated", "value": "Jetzt bezahlen" } },
"en": { "stringUnit": { "state": "translated", "value": "Pay now" } }
}
}
}
}What a .strings file looks like
Each language exports as its own file. Quotes, backslashes and newlines are escaped the way Xcode expects, and the file ends with a newline so git diffs stay quiet. Place each one at de.lproj/Localizable.strings, fr.lproj/Localizable.strings and so on.
"checkout.pay_button" = "Jetzt bezahlen";
"checkout.total" = "Gesamt: %@";Keeping the catalog in sync
The usual pain is that Xcode rewrites the catalog while translators work somewhere else, and the two collide in a merge. Treat the catalog as a build output instead: keep the strings in LocalizeMe and pull the file before you build, locally or in CI.
An existing Localizable.xcstrings or .strings file imports as it is, so you can start from what the app already has.
pip install localizeme
localizeme init --project 42 --format ios-xcstrings --path ios/App/Localizable.xcstrings
localizeme pullQuestions
Which Xcode version supports .xcstrings?
String Catalogs arrived in Xcode 15. Apps built with it can still run on older iOS versions, because Xcode compiles the catalog into .strings files at build time.
Can I import an existing String Catalog?
Yes. LocalizeMe reads .xcstrings and .strings files, so an app can bring its current strings across before anything else changes.
Does a String Catalog hold every language?
Yes. One .xcstrings file carries all of them, which is why LocalizeMe exports it as a single file rather than one per language.
Other guides
Unlimited strings, one flat price
LocalizeMe never counts keys, strings or languages. Try Pro free for 14 days, no card needed.