String Catalogs (.xcstrings) replaced the old .strings files starting with Xcode 15, and as of 2026 they're the standard for iOS app localization. They're JSON files with rich metadata - compile-time validation, plural rules, variant support, translation status tracking - that Xcode edits in a dedicated UI. For new apps, there's no reason to use anything else.
This guide covers the working patterns for String Catalogs in production iOS apps: how the file is structured, how to export and import translations efficiently, and the runtime language switching gotcha that catches almost every team adding in-app language picker.
What's in a String Catalog and why it's better than .strings
A .xcstrings file is a JSON document with one entry per source key, plus per-locale translations and per-translation metadata. In Xcode it's edited via a table UI showing source language column (usually English), one column per target locale, status badge (untranslated, new, needs review, translated), inline plural variants (one/other/zero/two/few/many), inline device variants (iPhone vs iPad vs Mac vs Watch) and free-form translator comments.
What you get vs legacy .strings:
Compile-time validation. Xcode warns when you reference a localization key that doesn't exist in the catalog. With .strings, typos silently fell back to the key name showing in the UI.
Automatic extraction. Xcode automatically discovers String(localized:) calls in your Swift code and adds new keys to the catalog when you build. No more manually maintaining the .strings file.
Plural and device variants in one file. Legacy .strings required a separate .stringsdict file for plurals. .xcstrings handles everything in one place.
Format specifier safety. Xcode checks that %d, %@, %.2f appear in the same order in every translation, catching the common bug where a translator accidentally drops a placeholder.
Translator workflow and the runtime language gotcha
Export for translators. In Xcode: Editor - Export Localizations - choose target locales - generates an .xcloc bundle per locale. The bundle is a folder containing the strings to translate in XLIFF format (industry standard) plus context files.
Hand the .xcloc to a professional translator. They open it in their CAT tool (Trados, MemoQ, Crowdin, Phrase - all support XLIFF) and return the translated version. You import it via Editor - Import Localizations and Xcode merges the translations into the .xcstrings file.
For agile teams shipping rapid iterations, services like Crowdin or Phrase can be wired directly to your repo via CLI: crowdin upload sources pushes English changes, crowdin download translations pulls completed work back. The .xcstrings format is supported natively by both.
The runtime language switching gotcha. The most common bug when adding in-app language switching: developers reach for .environment(\.locale, Locale(identifier: "fr")) on the root view and expect everything to switch. It doesn't.
Why: String(localized:) reads from Bundle.main directly, ignoring the SwiftUI environment. The environment locale affects number/date formatters, but not the strings themselves.
The fix: override Bundle.main's string lookup using a method swizzle. The pattern is well-established, with a PrivateBundle subclass that consults UserDefaults.standard.stringArray(forKey: "AppleLanguages") first. Then force SwiftUI to redraw by changing a .id() modifier on the root view.
This is verbose enough that most teams put it in a reusable LocalizationManager class. Once written, it's a 50-line file you ship in every app.
Quick comparison
| Option | Best for | Cost / effort | Notes |
|---|---|---|---|
| .xcstrings | Native catalog format | Xcode 15+ | JSON with metadata |
| Editor - Export | For translators | Per locale | XLIFF bundle |
| Crowdin / Phrase | Continuous translation | CLI integration | Native .xcstrings support |
| Runtime switch | In-app language picker | Bundle override | Plus .id() redraw |
Common pitfalls and how to avoid them
Across every domain this article touches, the same shape of mistake recurs. Practitioners new to the field overweight the most visible piece of the system — the screenshot, the paywall, the exam question, the headline price — and underweight the underlying constraint that actually determines outcomes.
The five most common failure modes:
- Optimising for the demo, not the durability. A working demo in a controlled environment proves nothing about reliability under real conditions. In iOS development, an in-app purchase flow that works in the Xcode Simulator says nothing about how it behaves in App Store sandbox with network latency and Ask to Buy approvals. In an exam, a 100% score on an untimed quiz tells you nothing about whether you can do 49/50 in 45 minutes with no second guesses. Build for the hardest realistic case from the start.
- Skipping the first-principles documentation. Every system has a canonical specification. App Review Guidelines for iOS, the official EU regulations for tax deductibility, the CITB question bank for CSCS, the OMIE market rules for Spanish electricity. Reading them takes a few hours but saves weeks of wrong-direction work. Secondary sources (blogs, tutorials, this article included) are useful as orientation but never authoritative.
- Ignoring the rate limit. Every external system has rate limits — explicit (APNs silent push throttling, RevenueCat API quotas, exam retake fees) or implicit (App Review patience, customer attention spans, your own working memory). Plan around them. A workflow that requires more rate-limited operations than the system allows will fail in production, not on day one but during the first stress event.
- Underweighting localisation and regional variation. What is true for Germany is not always true for Italy. What is true for English-speaking users is not always true for Japanese ones. What is true for the UK CSCS test is not always true for the Irish equivalent. Always check the local rule before applying a general one.
- Treating the documentation as static. Apple updates App Review Guidelines. The Bundeslaender change Schonzeiten. OMIE adjusts market clearing algorithms. Set up a periodic review (quarterly is enough for most things) and re-read the canonical sources. Workflows that worked perfectly a year ago can be silently broken today.
None of these are dramatic. The dramatic mistakes (catastrophic bugs, audit findings, exam failures) are the visible tip of a longer-running iceberg of small misses. Catching the small misses is what separates routine outcomes from problematic ones.
Key takeaways
- .xcstrings — Native catalog format. JSON with metadata.
- Editor - Export — For translators. XLIFF bundle.
- Crowdin / Phrase — Continuous translation. Native .xcstrings support.
- Runtime switch — In-app language picker. Plus .id() redraw.
The pattern that runs through every section above: start with the constraint, not the wishlist. In an exam, the constraint is the question bank and the pass mark. In an electricity market, it is the auction clearing rule. In a tax workflow, it is the receipt-retention requirement. In a code architecture, it is the platform's design decision (StoreKit's transaction lifecycle, App Review's guideline, APNs's authentication model). Get the constraint right and the rest follows.
The opposite failure mode — designing for an aesthetic ideal, then trying to retro-fit the constraint — is the most common cause of wasted work in every domain covered here. A beautiful paywall that hangs in sandbox is rejected at App Review. A polished freelancer expense report that lacks receipts is disallowed by the tax office. A study plan that ignores the actual question distribution leaves the candidate stuck below the pass mark.
The practical recommendation: read the official rules of whatever system you are operating in, extract the binding constraints, and treat them as inputs to the design — not afterthoughts. Every section of this article is the application of that principle to a specific domain.
FAQ
Should I migrate from .strings to .xcstrings?
For new apps: yes, no question. For existing apps: when you can spare a sprint. Xcode has Editor - Migrate to String Catalogs which converts automatically. Worth doing on the next major version.
How many languages should I localize for?
Depends on your market. For broad consumer apps: English, German, French, Spanish, Italian, Portuguese (BR), Japanese, Korean, Chinese (Simplified) cover ~80% of App Store revenue globally.
Can I auto-translate with AI?
Yes, but with human review. Tools like Crowdin's AI translation are fast for first-pass drafts. Always have a native speaker review before shipping - automatic translation regularly gets gender, plurals and formal/informal tone wrong.
Do enum computed properties work with .xcstrings?
There's a SwiftUI caching gotcha: computed properties on enums get cached, so language changes don't refresh them. Use methods instead (call once per render) or move the localized text to the view layer.
Further reading and references
The references below cover the official sources for the rules cited in this article. Where applicable, they include the canonical documentation, regulatory text, or vendor-provided guides. For each one, prefer the official source over secondary commentary — secondary sources go stale fast and frequently misquote the binding rule.
- Official documentation of the system in question (linked from each app or service's own help centre).
- Apple Developer Documentation for any iOS/macOS reference — the WWDC session videos and the corresponding Human Interface Guidelines pages are the authoritative source.
- For EU regulatory questions (taxation, data protection, energy market structure), consult the relevant national authority — most publish their guidance in English.
- For Spain and Italy energy market data, OMIE and GME both publish full historical price series in CSV format from their public websites — no API key required.
- For UK CSCS prep, the CITB publishes the official question bank book each year — buy a current copy if you want the authoritative source.
If you find a contradiction between this article and an official source, the official source wins. Article rules of thumb are summaries — they have edge cases, exceptions, and regional variations that the source documents specify exactly.
iOS localization done right
I localize iOS apps into 26 locales as standard. EU + global high-value markets covered.
Book a discovery call