Innovaptor Logo

A Localization Workflow that works well in Practice

Update

This blog post is outdated for swift. See this update for a worklow with swift. If you’re still using ObjC, the following workflow is still fine to use.

Original Article

For a long time, it wasn’t clear to me how to deal with the localization of Xcode projects in an acceptable way. I’ve tried some different ways in different projects but each one of them was inconvenient and had serious drawbacks. While working on the localization of iZurvive. I’ve tried yet another workflow that turned out to be pretty applicable in practice.

Requirements to a good Localization Workflow

What was the reason why I kept searching for other ways to do localizations? Here’s what I think is important:

  • Short distinct key
  • Detailed comment
  • Maintainability
  • Readability of code and localization files
  • Reuseability of localization files
The main problem is that using the genstrings tool can be really cumbersome. It has 2 options, either to replace the whole existing file, or to append everything. So if you have the file already translated and just have a few new localized strings, either your existing translations are overwritten or they get duplicated.

update_localization.py

In a discussion on stackoverflow, user nfred on posted a Python script for generating localizations, but it was lacking some essential features. Based on that I wrote my own script that supports the following features

  • Run genstrings on source-files, keep already translated strings and add only new strings
  • Specify file extensions, only files with that extension will be scanned by genstrings
  • Specify ignore patterns, files that fit the ignore patterns will be ignored by genstrings
  • Support for multiple translation tables
  • Support for interface-builder files with ibtool
I’ve created a ‘run script’ buildphase that runs the script prior to every build. That way the strings files are always up to date.

You can get the script here: https://github.com/iv-mexx/update_localization

Localizing Interface Files

In the past it was necessary to duplicate storyboard and xib files in order to localize them. Although generating and runtime selection of these localized files was done automatically, you had to keep track of changes in the interface manually, just like with genstrings. I somehow have the feeling that one is supposed to finish the whole app first and then localize it completely rather than keeping localizations up to date, but what would you do when you deliver an update to the app?

Anyway, in a recent release of Xcode, Apple has added the possibility to localize interface files with a strings file as well using ‘base localization’. The tool ibtool generates all the strings from a nib. It even has the support for incremental localization somehow but since I already had my script, I’ve extended the script to work with for interface files as well. Keep in mind though that base localization is only supported in iOS 6 and above. (We’ve had a serious crash-bug in iZurvive on iOS 5.1 because of this)

One thing to keep in mind is that ibtool creates the comments automatically, they don’t provide any context. I’d suggest that you provide them by hand in the generated strings file. The update_localization script gives priority of already existent comments to new comments for interfaces in order to keep your comments.

Maybe there is another way to provide comments for interface files? If you know something about that please let me know in the comments!

The Workflow

Searching for best practice tips, I found threads like this discussion on StackOverflow. One Suggestion was to use short keys and use the comment as a default value. The author redefined the NSLocalizedStrings macro to automatically use the comment as value if the value equals the key which indicates that the values has not yet been translated. I liked how easy this was to use and tried it, but soon I’ve realized that a real comment describing the context of the string is crucial and a localization file without these comments is practically useless for an external translator.

My current workflow ist the following:

  • Use the NSLocalizedStringWithDefaultValue macro.
  • Use short distinct keys like “connectionerroralerttitle” or “connectionerroralertmessage”. Keys that belong together are named with a common prefix so that they are grouped together in the .strings file.
  • Write detailed comments. If you watch the WWDC Session 244 ‘Internationalization Tips and Tricks’, the whole core message of that talk is how important comments are to clear up the context for translators.
  • Use different localization tables. I have a localization table named ‘StandardGui’ for common Interface-Elements like ‘OK’, ‘Cancel’, ‘Delete’ and so on that are not specific to the current app. Seperating them enables reusability of frequently used translation in a very simple way. Moreover, I’ve created Snippets for the most common strings so that I don’t have to type the whole 4 lines every time I need an ‘OK’-button. Of course it makes sense to further partition common strings- I have created another table for in-app purchase specific strings for example. Finally, all the strings that are really specific to the current app are grouped together in a table that is named after the app. Only these strings have to be translated each time you write a new app, all the others can be reused. Depending of the type of apps you write, this can save you a whole lot of work and time (and money if you have to pay external translators)
  • Run update_localization.pyin a ‘Run Script’ Buildphase on each build to keep the strings files up to date.
At first I wanted to create custom macros like ‘NSLocalizedGUIString’, where the localization table is already set to ‘StandardGui’ and the bundle is [NSBundle mainBundle] to make the code more readable by removing these two parameters that are always the same anyway. But unfortunately genstring was not able to find these custom macros anymore which makes sense but was a setback anyway.

So far, this workflow has worked out quite well for me. What do you think, are there any improvements that could be made? Let me know in the comments!

Markus Chmelar Portrait

Markus Chmelar, MSc

Markus is a technical mastermind and one of the founders of Innovaptor. He studied Computer Engineering at Vienna University of Technology and contributes a valuable diversification to Innovaptor's qualifications. Markus is eager to find innovative solutions to complex problems in order to provide products that are tailored directly to the customers' needs