Xcode String Catalogs (.xcstrings): The Complete Guide
Xcode String Catalogs (.xcstrings) replaced .strings and .stringsdict as Apple's recommended localization format in Xcode 15. A single JSON file holds all your translations across every language, with built-in support for plurals, device variations, and string extraction. If you are starting a new iOS or macOS project, this is the format to use.
How .xcstrings works
A String Catalog is a single JSON file that stores every localization key, its source value, and translations for all target languages. Xcode displays it in a table-based editor, but under the hood it is plain JSON you can read, diff, and edit outside Xcode.
Key concepts
- Source language - the base language (usually English) where keys are defined
- String unit - a single translatable entry with a key, value, and state per language
- State - each translation is marked as new, translated, needs_review, or stale
- Variations - one key can have plural forms, device-specific text, or width variations
{
"sourceLanguage": "en",
"version": "1.0",
"strings": {
"welcome_title": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Welcome to MyApp"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Bienvenue sur MyApp"
}
},
"de": {
"stringUnit": {
"state": "needs_review",
"value": "Willkommen bei MyApp"
}
}
}
}
}
}Migrating from .strings to .xcstrings
If your project already uses .strings or .stringsdict files, you can migrate to String Catalogs without losing existing translations. Xcode handles most of the conversion automatically.
Migration from .strings to .xcstrings
Export current translations
In Xcode, go to Product > Export Localizations. This creates XLIFF files containing all your current strings and translations as a backup.
Create a String Catalog in Xcode
Right-click your project in the navigator, select New File, and choose String Catalog. Name it Localizable.xcstrings. Xcode will offer to migrate existing .strings files.
Accept the migration
Xcode detects your existing .strings and .stringsdict files and imports all keys and translations into the new catalog. Review the imported entries in the String Catalog editor.
Verify and delete old files
Build your project and run it in each language to confirm translations appear correctly. Once verified, delete the old .strings and .stringsdict files from your project.
Auto-detection
Xcode 15+ automatically detects Text() and NSLocalizedString calls and adds them to your String Catalog during build.
Working with String Catalogs in SwiftUI
SwiftUI makes String Catalogs particularly easy to use. Text views automatically look up their string argument in your catalog. No explicit NSLocalizedString calls needed.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(spacing: 16) {
// Automatically looks up "Welcome" in your String Catalog
Text("Welcome")
.font(.largeTitle)
// String interpolation works with LocalizedStringKey
Text("Hello, \(username)")
.font(.headline)
// Explicit key with default value
Text("settings_title")
.font(.title2)
}
}
}import SwiftUI
// String interpolation in String Catalogs
// The key in your .xcstrings becomes: "Hello, %@"
let greeting = LocalizedStringKey("Hello, \(name)")
// Plurals work automatically when you use string interpolation
// The key becomes: "%lld items in your cart"
let cartLabel = LocalizedStringKey("\(itemCount) items in your cart")
// You can also use String(localized:) for non-View contexts
let title = String(localized: "notification_title")LocaleKit + .xcstrings
LocaleKit reads .xcstrings files natively. Run localekit scan to detect your String Catalog and localekit translate to fill in missing translations.
Pluralization in String Catalogs
String Catalogs handle plurals through variations. Instead of a separate .stringsdict file, plural rules live directly in the catalog. Xcode shows a dropdown for each plural category the language needs.
{
"item_count": {
"localizations": {
"en": {
"variations": {
"plural": {
"one": {
"stringUnit": {
"state": "translated",
"value": "%lld item"
}
},
"other": {
"stringUnit": {
"state": "translated",
"value": "%lld items"
}
}
}
}
},
"ar": {
"variations": {
"plural": {
"zero": { "stringUnit": { "state": "translated", "value": "لا عناصر" } },
"one": { "stringUnit": { "state": "translated", "value": "عنصر واحد" } },
"two": { "stringUnit": { "state": "translated", "value": "عنصران" } },
"few": { "stringUnit": { "state": "translated", "value": "%lld عناصر" } },
"many": { "stringUnit": { "state": "translated", "value": "%lld عنصرًا" } },
"other": { "stringUnit": { "state": "translated", "value": "%lld عنصر" } }
}
}
}
}
}
}String Catalog FAQ
Are .xcstrings backward compatible with older Xcode versions?
No. String Catalogs require Xcode 15 or later. Your project's deployment target can be older (back to iOS 13), but you need Xcode 15+ to edit the catalog. Older Xcode versions will not recognize the file.
Can I use .xcstrings in CI/CD pipelines?
Yes. Since .xcstrings is a JSON file, you can parse it, validate it, and run translation tools against it in CI. LocaleKit's CLI reads and writes .xcstrings directly, so you can run localekit translate and localekit validate in your pipeline.
Is it safe to edit .xcstrings by hand?
Yes, but be careful with the JSON structure. A missing comma or bracket will break the file. Use localekit validate after manual edits to catch structural issues. For bulk edits, a tool or script is safer than hand-editing.
Can I export .xcstrings to XLIFF for external translators?
Yes. Xcode's Export Localizations (Product > Export Localizations) reads your .xcstrings and generates standard XLIFF files. External translators work with the XLIFF, and you import it back into the catalog.
String Catalogs cut our localization workflow from a full day to under an hour. Having everything in one file instead of scattered .strings files across 14 languages was the biggest quality-of-life improvement in Xcode 15 for our team.
Stop managing translation files manually
LocaleKit detects, translates, and syncs all your localization files — iOS, Android, Flutter, and more. Everything runs locally on your machine.
Privacy-first. No cloud required.