Achieving Compile-Time Localization Validation

Dorian Grolaux
Sep 2, 2019 · 4 min read

This article is written with XCode & Swift in mind. With that being said, notions & ideas explored below can be applied to any programming language / IDE. I leave that part as an exercise to the reader ;)

guard let templateString = NSLocalizedString("hello", tableName: "Greetings", comment: "") else { print("Missing localization"); return }

Sounds familiar ?

Let’s face it: Localization sucks. It’s all String-based. It’s messy. And even with the best effort put into arranging your .strings files, you always end-up forgetting which key to use, or with duplicates all over the place.

Not only that, but it’s also nearly impossible to keep track of changes made over time, since XCode won’t help you in the slightest if some key were to disappear or are otherwise renamed.

Now, what if I were to tell you there is a better way ? What if I told you the following is possible ?

label.text = Greetings.hello("world").localized()
// returns "Hello, world" in English,
// "Hallo, world" in German, etc.

And

Before we do anything, we need to find a generic structure that can be reused for the many localized fields our app contains.

As with most things in programming, we’ll want some sort of Manager to make our logic reusable. At OneFit, I opted for a protocol which I called LocalizationManager

LocalizationManager protocol

As you can see, it’s quite straightforward. It also comes with its own convenient default implementation, which I’m sure you’re very familiar with.

The power of this protocol shines when you implement it with Enums; Swift Enums are among the most powerful and versatile of them all, and the perfect tool in this situation.

For instance, let’s say we are working on a shopping app, and have a few localized strings for the shopping cart. Given this example strings file:

LocalizedShoppingCart.strings

let’s declare the following ShoppingCartStrings Enum:

ShoppingCartStrings.swift

I’ve added the actual english values of these keys as documentation so that it shows up when we’re using auto-completion 👌

Now, that enum on its own is not going to do much. To fix that, all we need to do is to make it conform to LocalizationManager :

ShoppingCartStrings+LocalizationManager

And just like this, we’ve gotten ourselves a very convenient way of getting localized strings. All you need to do is call ShoppingCartStrings.itemsMultiple(count: 3).localized() and you’ve got a formatted & localized string! Pretty neat.

Now this is all fine and dandy, but what about all the remaining strings files & keys, I hear you say. “Do I have to write all of them manually ?”

Fear not, there are good news; I wrote a Swift script that generates these Enums automatically!

Not only that, but as shown at the beginning of this article, it also adds specific warnings when keys or even files are missing.

I explain how to set that up in the next section, so tag along!

Automatic Localization Manager Generation

To get started, you’ll need a copy of the script. Download it and save it in your project’s root folder (where your .xcodeproj / .xcworkspace file lives)

Once that’s done, go to your target settings, add a new build phase and name it “Generate LocalizationManagers”, then copy & paste the following script invocation:

Generate Localization Manager Build Phase

Make sure to place that phase before the Compile Source phase, as it will otherwise mess up the build process.

Then, go ahead and build your project. The script will be invoked and a bunch of Swift source files will be generated in the output folder you specified. Don’t forget to link them to your project (necessary for each file that wasn’t previously added. The first time, that’s all of them).

Once all that’s done, you’re finally ready to remove all previous calls to NSLocalizedString and replace them with their new equivalent.

Next time your strings files change, you’ll immediately get compiler warnings/errors 💪

Going beyond

By default, the script uses en.lproj as the main localization base file. All enums will be generated following its structure.

For now, the only way to change this is by editing the script directly, but who knows, in the future this might be supported right from the input parameters.

The script also highlights any issues with your strings files; any keys that are not present for each supported language will raise a warning in your main language’s strings file.

The same happens if an entire strings file is missing.

TL;DR

Download the script: https://gist.github.com/MrSkwiggs/9cffc243a77a0b3088ab019fa0939b5e

Add a build phase: https://gist.github.com/MrSkwiggs/e5b28fea20ca47fbbb97242ac4949a23/

Build. Add Generated Files to Project. Profit 💪

Urban Sports Club Engineering

Creating a world where everyone enjoys doing sports, using the power of technology

Urban Sports Club Engineering

Creating a world where everyone enjoys doing sports, using the power of technology. Urban Sports Club Platform allows people to integrate sports into their lifestyle and offering diversity, flexibility and bringing a social aspect in every workout.

Dorian Grolaux

Written by

iOS Engineer at App Annie — skwiggs.dev

Urban Sports Club Engineering

Creating a world where everyone enjoys doing sports, using the power of technology. Urban Sports Club Platform allows people to integrate sports into their lifestyle and offering diversity, flexibility and bringing a social aspect in every workout.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

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