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.
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.
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
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.
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.
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.
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 SwiftGen
documentation, 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
strings:
inputs: ../Localization/en.lproj/Localizable.strings
outputs:
- 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.
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.