How to translate and localize iOS app with string catalogs in Xcode 15

Managing the localization and translation of an app’s string resources can be a challenging task. However, with the introduction of Xcode 15 and string catalogs, it has become much easier to localize iOS apps. In this blog post, I will show you how to work with the new string catalog and convert an existing project to utilize this feature.

In the past, managing strings used to be difficult with the localizable strings file. But now, the new string catalogs are based on the same file, which is great because it means you can use string catalogs for projects that support older iOS versions as well. This is a significant advantage, as it allows you to move forward without being held back, even if you still support older iOS versions.

One of the main advantages of using string catalogs is that it automatically tracks all the strings in your project. This eliminates the need to manually collect and manage strings, making the localization process much more efficient. Additionally, Xcode provides a progress indicator to motivate you and show how much work is still remaining.

Overall, using string catalogs in Xcode 15 greatly simplifies the localization and translation process for iOS apps. It provides a centralized and efficient way to manage all the string resources in your project, making it easier to maintain and update translations. By utilizing this feature, you can ensure a seamless user experience for your app’s international audience.

Note that I am not covering localisation of Date types in this post. You can read about it in this post Swift Date Formatting: 10 Steps Guide.

⬇️ Download the example files from my Github

How to add string catalog to your Xcode project

If you have a new project, add a new file and choose “String Catalog”. Xcode will ask you for a file name, keep the default “Localizable” name. 

Xcode will create a new file “Localizable.xcstrings”. Initially, your string catalog will be empty. You need to build and run your project. This will cause Xcode to search your files and collect all string resources into your string catalog. 

How do add more languages for localisation?

Xcode will by default create a string catalog with the base localization in English. If you want to add more languages, simply click the “plus” button in the xcstrings file and select the language. 

add additional languages to string catalog in xcoe
Xcode 15 settings for localisation
Xcode 15 automatically adds localisation settings for you projects when you add string catalogs with multiple languages.

Migrating an existing project to string catalogs

Right-click on the “Localaiable.strings” file and select “Migrate to String Catalog”. Xcode will show you a dialog to select which files to migrate. Click on “Translate”. Xcode will that remove the old “strings” type and add a new string catalog. Migration can take a few seconds depending on your project size. It uses all the values from your previous strings file and collects all your translations.

Additionally, it will collect strings from your project e.g. SwiftUI views. This is great as you will see what strings you have missed so far and can add translations.

How do you localise a string inside the iOS info plist file?

You might want to translate entries in your info plist files. This is not included in the default “Localizable.xcstrings” file. You need to create a dedicated string catalog and name it “InfoPlist”.

Once you build and run your project, you will see all the entries form the info plist file.

How to use multiple string catalog files when my project gets too big?

If your project gets too big and it is hard to keep track of all your string rescues in one file, you can add additional string catalogs. Create a new string catalog file and name it e.g. “Extra”. In code, you need to specify which table Xcode should add it. Use the LocalizedStringResource with the table and pass the string catalog name.

Additionally, you can specify a comment. This is useful if you want to send your string files to an external translator and want to give more context on how and where these strings are used. This might improve the translation quality.

struct ContentView: View {
    var body: some View {
        VStack {
            Text(LocalizedStringResource("This string will be added to the extra string cataloge",
                                         table: "Extra"))

            Text("Finish",
                 table: "Extra",
                 comment: "this is the button to finish a note, that is in the toolbar")
        }
    }
}
working with multiple string catalog files in Xcode

Keeping track of your translations with string catalogs

Xcode tracks your translation progress. Next to each language you can see how much of your strings are translated in percentage. This is great to keep you focused on the task. It shows all entries that are translated successfully (have a green checkmark).

Xcode string catalogs show progress of translations

Xcode assigns a state to each entry. Here is what each of them mean:

  • STALE: the string is no longer used in code (you probably deleted it recently). 
  • NEW: this is a new entry that you need to add translations to
  • NEEDS REVIEW: you can mark entries for review.
  • Green Checkmark: the entry is translated

How do I use localized strings in SwiftUI?

SwiftUI makes it very easy to localise your apps. Every time you use a Text view and pass a text as a localizable resource, Xcode will add it to your string catalog.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text("This will be localized")

            Text(verbatim: "This will not be localized")
            Text(String("This will also not be localized"))
        }
    }
}

That is because SwiftUI Text pass its argument as a localizable type e.g. LocalizedStringKey

Text(
    _ key: LocalizedStringKey,
    tableName: String? = nil,
    bundle: Bundle? = nil,
    comment: StaticString? = nil
)

When you define a property or function in your SwiftUI views, make sure to use either LocalizedStringKey or LocalizedStringResource. If you use String type, they will not be added to string catatog.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text(title())

            TitleView(text: "Will this be localized")
        }
    }

    func title() -> LocalizedStringKey {
        return "localize this text"
    }
}

struct TitleView: View {
    let text: LocalizedStringKey // or LocalizedStringResource

    var body: some View {
        Text(text)
            .foregroundStyle(.pink)
    }
}
Free SwiftUI Layout Book

Get Hands-on with SwiftUI Layout.

Master SwiftUI layouts with real-world examples and step-by-step guide. Building Complex and Responsive Interfaces.

Testing Translations in Xcode Preview to Localize iOS apps

Xcode preview uses the default language English. You can change this by overriding the environment value for locale. In the following I added a second preview for German:

#Preview("English") {
    ContentView()
}
#Preview("Deutsch") {
    ContentView()
        .environment(\.locale, Locale(identifier: "DE"))
}

You can use Xcode previews to test different translations for e.g. iOS. This is important to see if the text fits on screen and looks good.

Xcode preview with different locale. localize iOS apps

Plurals localization using String Catalogs in iOS

Plurals localization using string catalogs in iOS is a powerful tool that makes managing multiple variations of strings so much easier. With string catalogs, you can easily handle cases where you need to display different forms of a word based on the quantity, like “book” or “books.” By using the localized string resource and specifying the plural form, you can effortlessly handle singular and plural variations in different languages. This feature saves you from the hassle of manually tracking and translating each variation, and it gives you peace of mind knowing that your app is fully localized. So, don’t hesitate to use string catalogs for plurals localization in iOS. It’s a game-changer that will make your localization process much smoother.

In the following, I want to show a text that includes a book count. I want to show the following texts:

  • Singular Case: “You have one book in store”
  • Plural Case: “You have 10 books in store”
import SwiftUI
struct ContentView: View {

    let bookCount: Int = 10

    var body: some View {
        VStack {
            Text("You have \(bookCount) books in store")
        }
    }
}

Build the project and go to your string catalog file. Go into your default language which is for me English. Select the string with the multiple and choose “Vary by plural”.

You can now enter a string for the single and plural case separately.

dealing with multiple number in string variations English

Similarly, you can also deal with texts that have multiple plural variations e.g:

import SwiftUI
struct ContentView: View {

    let bookCount: Int = 10
    let storeCount: Int = 2

    var body: some View {
            Text("You have \(bookCount) books in \(storeCount) stores")
    }
}

Build the project and go to your string catalog file. Go into your default language which is for me English. Select the string with the multiple and choose “Vary by plural”. From the menu you can now add both arguments for “books” and “stores”. Enter the string values for both variations separately.

dealing with complex multiple number in string variations German

How do you localize image assets in iOS?

You can add images to the asset catalog and add localisation. In the below example, I use 3 different images for English, German and French:

import SwiftUI
struct ImageLocalizationView: View {
    var body: some View {
        VStack {
            Text("Hello, world!")
                .font(.title)
            Image("test_image")
                .resizable()
                .scaledToFit()
        }
    }
}
#Preview("en") {
    ImageLocalizationView()
}
#Preview("de") {
    ImageLocalizationView()
        .environment(\.locale, .init(identifier: "de"))
}
#Preview("fr") {
    ImageLocalizationView()
        .environment(\.locale, .init(identifier: "fr"))
}

Conclusion

In conclusion, using string catalogs in Xcode 15 makes localizing and managing string resources in iOS apps so much easier. With string catalogs, you can easily track and translate all the strings in your project, saving you time and hassle. It automatically collects the strings and allows you to add translations for different languages. Plus, it handles more advanced cases like plurals. So, if you’re looking to translate and localize your iOS app, string catalogs in Xcode 15 are definitely worth using.

Good luck with your app localization journey!

Further Reading:

5 thoughts on “How to translate and localize iOS app with string catalogs in Xcode 15”

  1. Hi, great article and very helpful but I have a question. What if I want to use a specific language e.g. “What the user sets in the app” and I want the translation for that specific language from the string catalog?

    Reply
    • You can use the environment to change the language:
      Tex("Translate this")
      .environment(\.locale, Locale(identifier: "ENG"))
      Tex("Translate this")
      .environment(\.locale, Locale(identifier: "DE"))

      The first text would be in English and the second in German. Keep in mind that it will only translate if you have an exact match in the string catalog

      Reply
  2. Great article. I have translated multiple languages very quickly now. My question is: Why does my project – info – page show all the languages as “0 Files Localized”? After all the translations have been done and I have green check marks next to each of them and testing each language on my actual device works perfectly. I have been raking my brain over this and cannot find a solution before I submit to app store.
    Thanks in advance

    Reply
  3. Very useful blog Karin. I wish I could figure how to toggle the Xcode string catalogue display between the comfortable rendering and the plain text rendering (e.g. “\nPoints: %@\n\n” : {
    “comment” : “for text buffer”,
    “localizations” : {
    “de” : { )
    …..
    Sometimes Xcode shows one, sometimes the other. It seems random.

    Reply

Leave a Comment

Subscribe to My Newsletter

Want the latest iOS development trends and insights delivered to your inbox? Subscribe to our newsletter now!

Newsletter Form