Migrating to String Catalogs in iOS
Learn about migration strategies from Localizable.strings to .xcstrings.
23 Mar 2026 · 3 min read
Many existing iOS projects still rely on Localizable.strings and Localizable.stringsdict files for localization. String Catalogs provide a more integrated workflow by allowing Xcode to manage localization keys automatically.
In this quick tip, we'll look at how to migrate an existing project to String Catalogs.

Why migrate to String Catalogs?
Before migrating, it's worth understanding what actually improves.
With traditional .strings files:
- keys are added manually
- unused keys can accumulate over time
String Catalogs improve this by:
- automatically detecting localization keys in code
- providing a visual editor in Xcode
- tracking states such as new, stale, and needs_review
For many projects, this reduces maintenance effort.
If a project uses third-party localization tools or services, it's worth verifying that they support String Catalogs before migrating.
Backward compatibility
When considering a migration, backward compatibility is often a concern.
String Catalogs are fully backward compatible. During the build process, Xcode converts the catalog back into .strings and .stringsdict files. This means existing APIs and runtime behavior remain unchanged.
Xcode's automatic migration
Xcode provides built-in support for migrating existing localization files. To migrate, simply right-click on the Localizable.strings file and select Migrate to String Catalog.
Xcode will:
- move existing keys into a .xcstrings file
- preserve translations for all languages
- convert pluralization rules automatically
Migrating over time
Migrating incrementally is possible and can work well when introducing clear boundaries.
Instead of converting the default Localizable.strings setup all at once, a practical approach is to create additional String Catalogs for new features. For example, we might create a catalog such as Checkout.xcstrings (instead of Localizable.xcstrings) and explicitly use it in code.
Text("checkout.title", tableName: "Checkout")
This way:
- existing keys remain in Localizable.strings
- new keys are added to Checkout.xcstrings
- both systems can coexist without duplicating keys
The important detail is that keys are only added to a specific String Catalog when that table is explicitly used in code. This makes it possible to migrate feature by feature over time.



Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips



