Swift By Rahul

Localizing iOS Apps with String Catalogs

In today's global market, reaching users worldwide is crucial for app success. A key component of this is localization – adapting your app to different languages and regions. For years, iOS developers have relied on .strings files, but with Xcode 15, Apple introduced a significant improvement: String Catalogs.

String Catalogs (.xcstrings files) offer a more robust, integrated, and developer-friendly approach to managing your app's translatable content. They streamline the localization workflow, reduce common errors, and provide powerful features like built-in pluralization rules. If you're still using .strings files, it's time to embrace this modern solution.

In this article, we'll dive deep into String Catalogs, exploring their benefits, how to integrate them into your iOS projects, and best practices for localizing your app effectively.

String Catalog Workflow Overview Source Code Extract String Catalog (Localizable.xcstrings) en, fr, es, de... Translate / Runtime Localized App

The Evolution of Localization in iOS

Before String Catalogs, localization in iOS primarily relied on .strings files. For each language, you'd have a separate .lproj folder containing Localizable.strings for app-specific strings, and InfoPlist.strings for strings displayed in the system (like app name or privacy messages). This approach, while functional, had several drawbacks:

  • Manual Key Management: You had to manually define keys in your .strings files and reference them in code, leading to potential typos and runtime crashes if a key was missing.
  • Scattered Files: Localization files were spread across multiple .lproj directories, making it harder to get an overview of all translatable content.
  • No Built-in Pluralization: Handling plural forms (e.g., "1 item" vs. "2 items") required complex logic or separate .stringsdict files, which were cumbersome to manage.
  • Limited Xcode Tooling: Xcode offered basic .strings file editing but lacked advanced features for managing the localization workflow.

String Catalogs address these issues by consolidating all localization data for a target into a single .xcstrings file.

Old Way (.strings files):            New Way (String Catalogs):
┌─────────────┐                      ┌────────────────────┐
│  Project    │                      │    Project         │
│  └── en.lproj ─┐                   │    └── Localizable.xcstrings │
│      ├── Localizable.strings │      (contains all languages, keys, values, plurals)
│      └── InfoPlist.strings │
│  └── fr.lproj ─┐
│      ├── Localizable.strings │
│      └── InfoPlist.strings │
└─────────────┘                      └────────────────────┘

What are String Catalogs?

A String Catalog (.xcstrings) is a unified file format introduced in Xcode 15 that centralizes all localizable strings for your app, framework, or package. Instead of separate .strings files per language, a single .xcstrings file contains all base strings, their translations for every supported language, and metadata like comments and state.

Key benefits include:

  • Automatic Extraction: Xcode can automatically detect and extract localizable strings from your code, reducing manual effort and errors.
  • Visual Editor: A rich, interactive editor in Xcode allows you to view, add, edit, and translate strings for all languages in one place.
  • Built-in Pluralization: String Catalogs directly support pluralization rules based on CLDR (Common Locale Data Repository), simplifying the handling of different plural forms across languages.
  • Compile-Time Safety: Missing keys or incorrect format specifiers can generate compile-time warnings, catching issues before they reach users.
  • Streamlined Collaboration: Translators can easily export and import XLIFF files directly from the String Catalog editor.
  • Source Control Friendly: The .xcstrings file is a well-defined format that plays nicely with Git and other version control systems.

Getting Started: Enabling String Catalogs

For new projects, String Catalogs are often enabled by default. For existing projects, you can easily migrate:

  1. Add a New String Catalog: In Xcode, go to File > New > File... (or ⌘N). Select "String Catalog" under the "Resource" section. Name it Localizable.xcstrings (or any other meaningful name). Add it to your target.
  1. Enable String Catalogs for your Target: Select your project in the Xcode Project Navigator. Go to your target's settings, then the "Info" tab. Scroll down to the "Localization" section. You'll see an option: "Use String Catalogs". Ensure this checkbox is selected.
  1. Migrating Existing .strings files (Optional but Recommended): If you have existing Localizable.strings or InfoPlist.strings files, you can migrate them. Select the .strings file in Xcode's Project Navigator, then go to Editor > Migrate to String Catalog.... Xcode will create a new .xcstrings file and populate it with your existing translations. After migration, you can delete the old .strings files.

Localizing UI Elements

Once your String Catalog is set up, localizing strings in your UI is straightforward, whether you're using SwiftUI or UIKit.

SwiftUI

SwiftUI's Text view has built-in support for localized strings. When you pass a String literal to Text, SwiftUI automatically looks for a matching key in your String Catalog.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            // Basic localized string
            Text("WelcomeMessage") // Looks up "WelcomeMessage" in Localizable.xcstrings

            // Localized string with a variable
            let userName = "Rahul"
            Text("Hello, \(userName)") // Xcode extracts "Hello, %@"

            // Explicitly referencing a String Catalog (useful for multiple catalogs)
            Text(String(localized: "Greeting", table: "CustomStrings")) // If you have CustomStrings.xcstrings
        }
    }
}

When you build your project, Xcode scans your SwiftUI views and automatically adds "WelcomeMessage" and "Hello, %@" as entries to your Localizable.xcstrings file. You'll then see them in the String Catalog editor, ready for translation.

UIKit

For UIKit, you continue to use NSLocalizedString(_:comment:), but now it automatically integrates with String Catalogs instead of .strings files.

import UIKit

class ViewController: UIViewController {

    let welcomeLabel = UILabel()
    let countLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Basic localized string
        welcomeLabel.text = NSLocalizedString("WelcomeMessage", comment: "A welcome message for the user")
        view.addSubview(welcomeLabel)

        // Localized string with a variable
        let itemCount = 5
        countLabel.text = String(localized: "ItemCount \(itemCount)", comment: "Number of items in the cart")
        view.addSubview(countLabel)
    }
}

Notice how for the variable, we use String(localized: ...) directly. Xcode will extract "ItemCount %lld" (or similar format specifier) into the String Catalog.

Working with Plurals and Variables

One of the most powerful features of String Catalogs is their integrated support for pluralization and variables.

Variables

When you include variables in your localized strings, Xcode automatically detects the data type and uses the appropriate format specifier (e.g., %@ for objects, %ld for integers, %f for floats).

// Example with multiple variables
let firstName = "Rahul"
let lastName = "Sharma"
let score = 123.45

// In SwiftUI:
Text("User \(firstName) \(lastName) scored \(score)")
// Xcode extracts: "User %@ %@ scored %f"

// In UIKit:
let message = String(localized: "User \(firstName) \(lastName) scored \(score)",
                     comment: "User's full name and score")
// Xcode extracts: "User %@ %@ scored %f"

In the String Catalog editor, you'll see placeholders like %1$@, %2$@, etc., allowing translators to reorder arguments if needed for grammatical correctness in their language.

Pluralization

String Catalogs make pluralization incredibly easy, leveraging CLDR plural rules.

// SwiftUI Example
struct PluralView: View {
    let photoCount: Int

    var body: some View {
        Text(String(localized: "Photos count \(photoCount)",
                    defaultValue: "You have \(photoCount) photos.",
                    comment: "Number of photos the user has"))
    }
}

// Usage:
// PluralView(photoCount: 0) -> "You have 0 photos."
// PluralView(photoCount: 1) -> "You have 1 photo."
// PluralView(photoCount: 5) -> "You have 5 photos."

When Xcode extracts Photos count \(photoCount), it recognizes photoCount as a plural argument. In the String Catalog editor, you'll see a special "Plural" section for that string, allowing you to provide different translations for "zero", "one", "two", "few", "many", and "other" categories as defined by the CLDR rules for each language.

For example, for English, you might only need "one" and "other". For Arabic, you'd likely use more categories.

// UIKit Example with pluralization
func updatePhotoCountLabel(count: Int) {
    let localizedString = String(localized: "Photos count \(count)",
                                 defaultValue: "You have \(count) photos.",
                                 comment: "Number of photos the user has")
    myLabel.text = localizedString
}

// In your view controller:
updatePhotoCountLabel(count: 1) // "You have 1 photo."
updatePhotoCountLabel(count: 5) // "You have 5 photos."

The defaultValue parameter in String(localized:...) is crucial. It provides the base string for Xcode to extract and serves as a fallback if a translation is missing.

Adding New Languages and Managing String Catalogs

Adding Languages

  1. Select your project in the Xcode Project Navigator.
  2. Go to the project settings, then the "Info" tab.
  3. Under the "Localization" section, click the + button to add a new language.
  4. Xcode will ask which resources to localize. Ensure your Localizable.xcstrings file is selected.

Once added, the new language will appear as a column in your String Catalog editor.

The String Catalog Editor

Open your Localizable.xcstrings file in Xcode. You'll see a table with columns for:

  • Key: The identifier for your string (often derived automatically from your code).
  • State: Indicates if the string is new, needs review, or is translated.
  • Comment: Translator notes.
  • Default (Base Language): The string in your app's base language.
  • [Language 1]: Translation for the first language.
  • [Language 2]: Translation for the second language, and so on.

For strings with variables or plurals, Xcode provides a dedicated interface within the editor to manage these complexities for each language.

Exporting/Importing for Translators

String Catalogs simplify the process of sending strings to translators and importing them back.

  1. Export: Select your Localizable.xcstrings file in Xcode. Go to Editor > Export Localizations.... This generates an XLIFF file (XML Localization Interchange File Format), which is a standard format for localization tools.
  2. Import: Once translators provide the translated XLIFF file, select your Localizable.xcstrings file again and go to Editor > Import Localizations.... Xcode will automatically update your String Catalog with the new translations.

Tips and Best Practices

  • Don't Hardcode Strings: Always use Text("key") or String(localized: "key") for any user-facing text.
  • Meaningful Default Values: Provide clear and concise default values (your base language strings) in String(localized: "key", defaultValue: "..."). These are what Xcode extracts and what translators initially see.
  • Contextual Comments: Use the comment parameter in String(localized:...) or add comments directly in the String Catalog editor. This provides crucial context for translators, helping them choose appropriate wording.
  • Test Thoroughly: Always test your localized app on devices or simulators set to different languages. Pay special attention to text truncation, layout issues, and correct plural forms.
  • Review String States: Regularly check the "State" column in your String Catalog editor. "New" strings need translation, "Needs Review" might indicate a change in the base string, and "Stale" means the string is no longer used in code.
Traditional Strings vs String Catalogs Comparison Traditional .strings String Catalogs (.xcstrings) ❌ Manual Key Management ❌ Separate .strings files per language ❌ No built-in pluralization rules ❌ No visual editor in Xcode ❌ Prone to typos & runtime errors ❌ Less efficient translator workflow ✅ Automatic String Extraction ✅ Single .xcstrings file for all languages ✅ Integrated pluralization rules ✅ Rich visual editor in Xcode ✅ Compile-time warnings, reduced errors ✅ Streamlined XLIFF export/import

Summary

String Catalogs represent a significant leap forward in iOS localization. By consolidating all localized strings into a single .xcstrings file and providing powerful Xcode tooling, they simplify the entire localization workflow. From automatic string extraction and built-in pluralization to a visual editor and streamlined XLIFF export/import, String Catalogs empower developers to create truly global apps with less effort and fewer errors.

Migrating to String Catalogs is a highly recommended step for any iOS project aiming for broader international appeal.

Happy Swifting!