Published in


Localization workflow in iOS

Using SwiftGen and [Phrase]


In this article, I’ll show you one of my favorites Localization flows I use for iOS applications. As you might already know, localization is an essential part of almost every iOS app but unfortunately, it’s usually relegated to later phases where sometimes it’s too late, thus very expensive and hard to refactor. With this flow that I am about to elaborate on(as well as many others on the internet), it’s possible to easily isolate what is happening on the localization side (pulling strings, generating constant files, and others), and also make the maintenance smoother and more error-prone. Without further ado, let’s get started.

Setup the Project

[Jump to next step if you already know how to localize an iOS project]

First, let’s create a new Xcode Project, and enable base, for this, open the .xcodeproj file, select the project and under the tab Info, select Use Base Internationalization.

Enable base internationalization in the Xcode project.

We can now add the languages in which we want to localize our app. In the same project settings, Go to localization, click on the plus button and select the languages from the dropdown.

Add languages to the project localization settings.

To finish the basic setup of the project, we need to add a strings file, which for this article I am going to call Localizable.strings and it will be located at Resources > Localization > Localizable.strings

Localizable.strings file location.

To get our Localizable.strings file actually localized into all the previously added languages, click on the file > Localize… and when the prompt shows up, select the desired languages.

Localize the Localizable.strings file.

For now and for the sake of this tutorial, let’s manually add a few strings to our Localizable.strings file, and later in this article we’ll improve that by using Phrase and a nice script.

Add localization strings with and without placeholders.

Aggregate target + Script Phase

Once languages are enabled and localizable files are added to our project, let’s add something called an aggregate target which will allow us to add build phase scripts(and many other things) keeping it separate from the main target, which normally tends to grow quite fast.

  • Go to the project file.
  • Click on the plus button to add a new target.
  • Under the tab Other, select Aggregate.
  • Name the target Localization.
Add a new target from the project settings.

Now we can add a Run script to the previously created aggregate target.

  • Go to Project settings.
  • Select the Localization aggregate target.
  • Select the tab Build Phases.
  • Add new Run Script Phase.
  • Add the following bash code.

According to the SwiftGendocumentation, we may need to add a configuration file (swiftgen-localization.yml) to the project in which we’ll specify the path to our Localizable.strings file, as well as the path to generated constants file L10n.swift

inputs: ../Localization/en.lproj/Localizable.strings
- templateName: structured-swift5
output: ../Localization/L10n.swift

Time to build the targets

The possible errors that can occur when compiling the aggregate target, can be either the paths to the files are incorrect(which happens to me all the time) or SwiftGen is not installed properly on your computer — Hopping that the aggregate target has compiled properly, let’s select the main target and compile it as well. Since we haven’t done anything with it yet, it shouldn’t show any error. Finally, we can add the L10n.swift file to the project so the constants file generated by SwiftGen is visible to our entire project.

This is a quick example of how to use the L10n constants file, it is not rocket science at all, strings are converted into static variables, snake case is converted to camel case, string placeholders such as %s, %d etc. are conveniently converted into parameters in a function, as per in the following code snippet.

ViewModel that uses L10n.swift constants file we’ve created.

Strings management with Phrase

To complete the localization flow, we need to populate the Localizable.strings file with the actual strings. In this step, I am using Phrase[2] because it’s the one I’ve used the most as an iOS developer, but it can easily be substituted with any other tool that offers a CLI(command line interface), curl requests or just write a script to convert .csv to .strings files. However, from my experience in the field, for collaboration with translators and designer tools, Phrase offers a nice tool. Said that, these are the regular steps I follow to implement phrase in my iOS projects.

  • Create a Phrase account and create a project.
  • Add locales and strings to the project.
  • Create an API token to pull phrases from the clients.
  • Install Phrase CLI on your computer.
  • Make sure you copy the locale_id’s, project_id, and API token from the website and paste it into a configuration .yml file. (For more details see Phrase docs).
  • [Important] Add a new Run Script Phase to the Aggregate target, right before the one we’ve created earlier, and just add the line phrase pull.

Once more, Phrase is just a tool that offers me a good experience as a developer, but it doesn’t have to be the same for you. If your project is smaller and you just want use spreadsheets, you can download the .csv file and use a csv2strings conversion tools, or your can even use open-source translations tools, and it should not be a big difference.

It always varies depending on which tool you want to use, and how you want to implement it, but don’t let that ever rule how your project behaves.

Thanks for reading. I hope you have enjoyed this small tutorial, and if it was useful for you, don’t be shy to 👏 on this article. See you next time.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Cristhian Leon

Curious, passionate iOS Developer, interested in game design, and clean code principles.