SwiftUI Localization Tutorial for iOS: Getting Started

Learn time-saving techniques to transform your team’s localization workflow! By Andy Pereira.

5 (4) · 1 Review

Download materials
Save for later
Share

There’s a long list of things to keep track of when you’re building apps. Thinking about making your app work in other languages may not be on your radar — especially if you don’t speak other languages. Luckily, Apple has made changes and improvements in SwiftUI that take a lot of the guesswork out of your localization workflow.

In this SwiftUI localization tutorial, you’ll take advantage of internationalization and localization techniques in SwiftUI and iOS 15 by learning how to:

  • Export and import strings from and to your project.
  • Preview localizations while developing.
  • Use new techniques to work with localized strings.
  • Localize asset catalog items.
  • Use Markdown to format localized strings.
  • Use automatic grammar agreement.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.

The app you’ll be working with, Country Quiz Time, is a short game that quizzes users on their world knowledge. It also keeps track of each question answered correctly. Open the starter project and look around. You’ll notice the app already has its strings, currently all in English, in two files:

  1. Localizable.strings. This is where your app will store most of its strings.
  2. Localizable.stringsdict. This file handles pluralizations. You’ll learn more about this later, but for now, it’s how you’ll handle nouns needing to be singular or plural.

Build and run, and give the quiz your best shot. :]

Country Quiz Time starter

Exporting and Importing Localizations

With every new version, Apple makes it easier to manage strings files for localization. Xcode 13 now automatically extracts any strings it finds in a variety of scenarios in your code. When you create a new project in Xcode 13, this setting is on by default. However, as you likely will want to use this with an existing project, you’ll need to turn this on.

In your project settings, go to Build Settings and search for Use compiler to Extract Swift Strings. Make sure to search All settings, not just the Basic ones. Change the value of this setting to Yes.

Screenshot showing 'Use Compiler to Extract Swift Strings' set to 'Yes' in the Build Settings of the CountryQuizTime Target of the CountryQuizTime project

In Xcode, go to Product ▸ Export Localizations…. Follow the prompts to save the folder to your desktop.

A save dialog showing CountryQuizTime Localizations being saved on the desktop, with English - Development Language selected

After making any changes to the exported xcloc file, import the changes back into your project using Product ▸ Import Localizations…. This way, translators can make changes to the displayed text without needing the whole project.

Using the xloc File

In Finder, navigate to the directory you created in the previous step and open the en.xcloc file. On the left-hand side, expand the folder and select Localizable.

en.xcloc file showing exported localized strings

Here, you’re looking at everything Xcode was able to identify as a string key used in one of your project files. There are four columns of information you’ll need to understand:

  1. Key: These are values used inside string literals in your code.
  2. English: This second column represents your reference or base localization language. This project’s base language is English, so you’ll see the English value here regardless of which language file you are viewing.
  3. English: The third column will have all the localizations for the language file you are viewing — in this case, also English. You can edit the values in this column.
  4. Comment: The comment column will show any notes left by the developer to help the translator understand the intent of each string.

This file is a place where you can make changes to all your localized files – not just your strings file. In the filter, search for points-count and expand all the values for the items it finds. You’ll see the following:

points-count value shown in Localizable.stringsdict

Here, you’re seeing the values found in the project’s stringsdict file. Because both the strings and stringsdict files have the same name, the values get combined in this view. If you create different filenames for different localizations, the editor window will break them out accordingly.

You can also translate your app’s name with this file. In the editor, select InfoPlist. You’ll see the following:

Viewing en.xcloc InfoPlist, showing the bundle name and bundle display name

Adjust the language’s bundle name or display name as needed. It’ll be up to you and your team to understand what makes the most sense to translate. Perhaps your app’s name makes sense across a few languages and translations are only needed for a few others.

Adding Another Language

To finish the tutorial, you’ll add another language to your project. Go to your project’s Project settings, then select Info. From there, select + under Localizations.

Screenshot of the Info tab for the project, showing the plus button under Localizations

In the menu that appears, select Spanish (es).

Screenshot of the Info tab for the project, showing Spanish (es) being selected from the plus menu under Localizations

A confirmation dialog will appear. Leave the settings as they are and select Finish.

Add Spanish Confirmation Dialog

This adds Spanish files under Localizable.strings and Localizable.stringsdict.

Screenshot showing 'Localizable (Spanish)' files under the two Localizable files in the Project navigator

Now you’re ready to localize your app into Spanish!

Viewing Localization During Development

For the most part, if an app uses traditional localization techniques, you can only see the other languages if your phone is set to that language. However, that can be quite difficult to manage in a development environment — especially if you’re unfamiliar with the language.

Open Localizable.strings (Spanish) and add the following line:

"Welcome to Country Quiz Time" = "Bienvenido a Country Quiz Time";

This will help you see how you can view localizations during development. Later on, you’ll fine-tune this translation and add more translations to this file.

You can see translations within the simulator by adjusting your target’s scheme. Open Product ▸ Scheme ▸ Edit Scheme… ▸ Run ▸ Options. For the setting App Language, select Spanish from the drop-down.

Changing the App Language to Spanish in the Run settings in the Edit Scheme dialog

Select Close, then build and run.

Scheme Running in Spanish

You’ll see your app’s title translated to Spanish.

Translated Previews

While it’s great to be able to change your simulator’s language during development, one of the benefits of SwiftUI is being able to see your code changes directly in the preview, in real time. Open ContentView.swift, and replace ContentView_Previews with the following:

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    Group {
      // 1
      ContentView(quiz: Quiz())
        .environment(\.locale, .init(identifier: "en"))
      // 2
      ContentView(quiz: Quiz())
        .environment(\.locale, .init(identifier: "es"))
    }
  }
}

Here’s what you added:

  1. For the first preview of this view that shows, you’ve set the environment’s locale to always be English. Because the scheme’s language affects the preview’s display language, it would otherwise show in Spanish based on what you did in the previous step.
  2. Next, you set the second preview’s locale to Spanish.

Refresh the preview, and you’ll see the translated title of your app:

SwiftUI Preview Localization

Now, do the same thing for QuestionView by opening QuestionView.swift and replacing QuestionView_Previews with the following:

struct QuestionView_Previews: PreviewProvider {
  static var previews: some View {
    QuestionView(question: Question.mockQuestion)
      .environmentObject(Quiz())
      .environment(\.locale, .init(identifier: "en"))
    QuestionView(question: Question.mockQuestion)
      .environmentObject(Quiz())
      .environment(\.locale, .init(identifier: "es"))
  }
}

Now, no matter what view you’re developing, the previews will always allow you to see both languages. This is also a great way to help developers on multilingual teams see their work in a language they might be more comfortable with. For now, the two previews of QuestionView will look the same because you haven’t translated anything shown in that view.