iOS Localization: The Ultimate Guide to the Right Developer Mindset
iOS gets a thumbs-up from many developers as a platform for developing apps. With its integrated development environment Xcode and its storyboards, it seems like a perfect match for the ordered, logical thought that goes into app creation. But what happens when you want to release your app in languages other than the one you normally speak or work in? iOS Localization!
iOS itself may be wonderfully rational, but rules about how to move from say English to Spanish, or to Chinese, can be flaky at best. Yet, with a little broad-mindedness, you’ll find that readying your app for release in different languages is not as daunting as it seems.
For one thing, iPhones and iPads are multilingual by nature, so a specific version for a particular country or language will appear automatically on a user’s iOS device – or at least, as soon as users set their preferred language from “Settings-> General -> International -> Language.” Indeed, overall, the iOS development environment makes the mechanics of localization relatively easy.
The hardest part may be getting to grips with the idiosyncrasies of language and dialect, and the need to think beyond “just English” (assuming that English is your default language.) However, by taking this guide to heart, you can be sure to have a head start.
Internationalization before Localization
Before you start to incorporate into your app the language content it needs for another country or region in particular, your app should be able to adapt to different languages and regions in general. For your app to succeed in foreign markets in general, it must appear as if it is a native app in each of the languages and regions supported. This is made possible through internationalization. Then, either individually or as a group, the specific language translations must be included in the app, which is the localization. People sometimes speak of internationalization and localization interchangeably, without differentiating between them. However, they are two distinct parts of the process. The iOS platform offers a number of tools to speed you through the following steps to the release of a localized version:
- Extract language and locale dependencies from your user interface and code.
- Use Xcode base internationalization to extract text seen by users from your .storyboard and .xib files.
- Extract other user-facing text from your code.
- Does your app support any accessibility features, like captions and audio descriptions? Make sure you don't forget about internationalizing tools like VoiceOver.
- In Interface Builder, use Auto Layout to adapt views as text length changes between languages.
- Use standard APIs to handle different language systems and locale formats for dates, numbers, and plurals, for instance.
- For right-to-left languages (Arabic and Hebrew, for example), mirror the user interface and change other text direction as required.
- Export and import specific language localizations using standard file formats, such as XLIFF
- Lock views in the user interface.
- Send the exported files to translators.
- Import specific language localization files
- Check changes and ensure suitability for release through user testing.
Which are the Language Priorities for iOS Localization?
If commercial success is the goal driving your app development, your marketing colleagues may have already answered this question, based on the marketing strategy of your enterprise. If you happen to be doing the marketing as well as the development, then estimates of sales potentials may help you establish release priorities accordingly. Base internationalization helps by organizing language support efficiently, so that additional languages are easy to add.
Don’t Reinvent the Wheel, Roue, Rueda, or Rad
As a general rule, when it comes to the mechanics of localization, iOS often already has a ready-made solution. This holds for items as intricate as the correct way to form plurals (some languages have as many as three ways of forming plurals, according the quantities involved.) So before embarking on extra code or logic, check to see if iOS has already solved the problem for you.
Understanding Locale and Language
In iOS, language IDs represent a language, dialect, or script. They may also refer to language-specific resource folders stored in the app bundle. A locale ID identifies a specific region and its cultural conventions, such as the way dates, times, and numbers are formatted. For example, “fr-CA” indicates French (“fr”) as used in Canada (“CA”) and “de-AT” indicates German (“de”) as used in Austria (“AT”).
Base internationalization in Xcode allows you to deal with one set of app content resources for different localizations, rather than several sets or resources (one set per localization.) For instance, if storyboards are localized in an app and a new user interface element is added, base internationalization allows you to deal with that new element just once, instead of having to add it to several separately localized sets of storyboards.
Base internationalization creates individual folders for each language or localized version. Xcode prompts you to define the resources to be used within base internationalization, and also asks you to define your default language, for example, English.
- .xib (and .nib) and .storyboard files are moved to the Base.lproj folder, which Xcode will create, if it does not already exist
- String elements are extracted to project locale folders, such as en.lproj for English, also created by Xcode for the occasion.
By saving new UI files for iOS localization to the Base.lproj folder, you enable them to support base internationalization too.
Adding a New Localization
When you select the resource files and language for the localization, Xcode will then:
- Scan the base storyboard
- Identify the text/UI elements to be localized
- Copy them into a strings file as key/value pairs.
This can include the visible strings of storyboards, such as label, button title, and navigation bar title.
Use of NSLocalizedString
The base internationalization in Xcode also provides the NSLocalizedString API to convert hardcoded strings in your app. For this, all the source files must be edited to change all the inline strings in the following way.
Suppose you have put the hardcoded text of “Greetings” into your app. With NSLocalizedString, you change this reference to NSLocalizedString(@”Greetings”, @”greetings message”). By doing this, “Greetings” becomes a token. The NSLocalizedString call will return the localized string according to the language being used for the application at that time. The other text, “greetings message” is a comment to give further information on the nature of the string (“Greetings”) being localized.
The Localizable.strings file must exist to hold all the output of the NSLocalizedString calls in one file (in the en.lproj localization directory in the first instance.) You can create your own Localizable.strings file for the outputs of the NSLocalizedString API or use the “genstrings” function. For this, in Terminal and from your project’s home directory, run the command:
find ./ -name "*.m" -print0 | xargs -0 genstrings -o en.lproj
This creates the Localizable.strings file in the en.lproj directory. The file can be modified directly, although its name should not be changed. It is also included in Xcode’s export of strings to be translated (see below.)
Localization of Different Parts of Your App
For each language for localization of your app, Xcode stores strings used in your app in a “.strings” file. Your code can simply use a method call to look up and retrieve the string required, according to the current language being used in the iOS device.
- Strings in Main.storyboard and ViewController.m that are to be localized must be put in a separate file, where they can be referenced (for different language versions.)
- The text of the label at the top of the screen is set in Main.storyboard, without the possibility to set this text programmatically (there is no IBOutlet.) To localize such storyboard elements without additional code, open the disclosure triangle to the left of Main.storyboard to see Main.storyboard (Base) and Main.storyboard (Language to localize into.)
- To localize “Localizable.strings”, select this file using the left pane. Then in the right pane, open the File Inspector. Click on the button marked “Localize” and select “English” (assuming this is your default language), then click Localize.
- Image files. Prepare or download the foreign language version of the image. In the project directory (use the finder), there should be two or more .lproj folders. One is en.lproj, and at least one other will correspond to the localization language: for example, for French, you will see the fr.lproj folder. The en.lproj folder corresponds to resource files for the English localization, and the fr.lrpoj to the files for the French localization. At this stage both folders hold the same image. In the fr.lproj folder, replace the existing image with the new localized one.
- Audio files. Prepare or download the default language and the localized audio file. Copy the default language audio file to the project. Open the file inspector for this file and use the Localize button to select both the default and the target localization language as the supported languages. Rename the localized audio file to have the same name as the default language audio file and copy it to the folder for the localized version, selecting the “Replace File” option in the finder to do this.
- App name. When a localized version of the app is created, Xcode also creates the localization version of InfoPlist.strings. Replace the corresponding key/value pairs in the InfoPlist.string file to override values, including the app name, currently in the Info.plist file.
Add Comments for Translators.
You can add comments for translators directly in Interface Builder. NSLocalizedString allows you to include both a unique key and a comment destined to help better understand what is to be translated. For example, in English, the same word “clear” is used as an adjective and a verb, where as in many other languages two separate words are used. The same is true of the English word “run”. A comment for translators to indicate how the word is being used will help them to make a suitable translation and enhance the user experience for the app in the target language.
Within base Internationalization, the NSLocalizedString macro will pick out the hard-coded texts in your app. Base Internationalization will also pick up the .xib files (the XML files defining graphic user interfaces developed in Interface Builder, with resources like “Label” and “Button”). However, Xcode builds a .strings file for every .xib resource, so you may want to deal with this before sending extracted text to be translated. One option is to add a comment to describe the resource (you can do this in Interface Builder directly) to say what it is, and (therefore) whether translators should translate it or ignore it. Another option is to simply delete such .strings files from the files that are given to translators.
Other languages may differ significantly in average word length, compared to English. Continental European languages such as French, German, and Spanish may be 20% to 50% longer, whereas Asian languages tend to be 30% to 50% shorter. By using Auto Layout, the views in your storyboard will not have fixed origins, widths or heights. Views will therefore be repositioned or resized appropriately if changes in a language or a locale cause changes in text length. Auto Layout is another reason why developers can work with one set of .storyboard and .xib files for all languages.
Plurals, Numbers, and Dates
Languages differ in how they handle plurals, whether for objects or for units of measurement. Some languages have one plural form, some have two, and others have three or more. For different plural rules, alternate strings are specified in a .stringsdict file, which is an XML property list with a .stringsdict extension. This allows you to use one string in your code that will then be localized using the plural rules in the .stringsdict file. The NSLocalizedString macro (see above) will search an existing .stringsdict file (such as Localizable.stringsdict) before searching any associated strings file with the same prefix (such as Localizable.strings). A .stringsdict file can be considered to be an addition to the corresponding .strings file to indicate which rules the system must follow when plurals are involved.
To represent or convert numbers in different formats, use a class in the iOS SDK called NSNumberFormatter. This class automatically adjusts any number to the user’s locale. For example, using NSNumberFormatter would result in displaying 5.4 in the US locale, and 5,4 in the French locale. For managing dates, there is the corresponding NSDateFormatter class.
Beware of English Short-Cuts
Some phrases in English allow you to freely interchange the subject and the object, where this would be impossible in other language. For example, the phrase “Chris told you” can be inverted to give “You told Chris” in English. If this worked in every language, then the string to be localized might be represented as “%@ told %@” with the localized version of “you” inserted in the right place. Unfortunately, this approach fails in both German and French, among other languages. In French, for example, “Chris told you” is “Chris t’a dit”, whereas “You told Chris” would be “Tu as dit à Chris”. So in this case, two localizable strings are required, “%@ told you” and “You told %@.” As a general rule, sentences (like these) should be kept together as complete localizable strings, instead of being divided into parts.
Avoid Automatic Translation
After the marvels of the various tools for the iOS platform, you might be tempted to try automatic translation of your strings files. This is unlikely to be a good idea, however. Even if the best automatic translation system can be surprisingly good in some cases, it may be abysmally bad in others. The problem is that you will never know when it is good or bad. Automatic translation is handy for making sense, more or less, of content created in a foreign language. However, it cannot provide the quality you need to make a favorable impression on native language speakers in the country or region where you wish to sell your app. Instead, you should choose a competent, reliable translation resource (a translator or a translation agency) to translate your strings properly.
How will you know if you found everything that needed to be localized? Xcode provides the possibility of “pseudolocalization” to help you see any instances of missing localization. You’ll have to check every screen that a user would see to verify that every string has been localized. If you can see any instance of your original, unmodified user-facing text, the necessary preparation for localization has not yet been completed.
By using double-length pseudolanguage, you double any visible text in the subviews of the storyboard. This lets you see the way in which long strings are displayed, for languages using long words, where English uses short ones. For example, in French, the English word “now” is typically translated as “maintenant”, which is more than three times as long.
This is another situation in which you will have to use judgment, rather than apply predefined rules. Having said that, one general rule still applies. If the pseudolocalization for example with double-length words and strings looks ugly, then it probably is ugly and needs fixing before being distributed to users using that language.
App Store Description and Keywords
The App Store description and keywords for your app must be localized as well. Once again, resist the temptation to use an automatic translator! Good keywords could mean the difference between market success and failure, but keywords are even less amenable to literal translation. To do well, a keyword used for the App Store should have high volume and low competition. In other words, many people should search on it, but few apps should correspond to this keyword. How people from certain countries or cultures search for keywords is an extra layer of complexity on top of the differences in terms of language.
Exporting and Importing Localization Strings
Xcode offers a quick export function to export all the .strings files for a given language within a single XLIFF file. XLIFF stands for XML Localization Interchange File Format and XLIFF files are used by many translation systems. The XLIFF file from Xcode will contain the base internationalization files (one per .storyboard and per .xib file), a Localizable.strings file, and an InfoPlist.strings file.
The XLIFF file will then be translated, i.e. localized, by your translation resource. Before you send the XLIFF file for translation, check that the development language copyright notice in the Info.plist file is correct (this is a human-readable copyright notice included by Xcode.) While translation is being done, you can continue to develop your iOS app. One XLIFF file per localization should be sent back to you with the appropriate language prefix: for example, es.xliff for Spanish, fr.xliff for French, and so on.
The first time you export localizations (in an XLIFF file), the project folder contains only the base internationalization with the .storyboard and .xib files. Xcode creates the strings files from the project files, for inclusion in the XLIFF file to be exported. However, the strings files are only added to the project when localizations are imported afterwards. At this moment (import), the language and the strings files for the language are added by Xcode to the project. For example, by importing fr.xliff in the standard XLIFF format with the target language attribute, the French language is added to the project. Xcode creates an fr.lproj folder in the project folder and adds a localized copy of Localizable.strings and InfoPlist.strings to the fr.lproj folder. The next time localizations are imported, the string files are merged with the existing project files.
Locking Views While Waiting for Translations
It may be advisable to lock views to avoid unintentional modification while waiting for translations to come back. By choosing a locking level, you can determine which set of properties to lock, blocking the possibility to change those properties in the inspector or project editor. You can also choose Inherited to use the lock profile from the parent view. As an example, if you are waiting for nib, strings or an XLIFF file to be localized, choose to lock Localizable Properties. On the other hand, if you are moving translations into a nib (xib) file, choose to lock Non-localizable Properties to avoid making any unwanted changes to the rest of the file.
Localizations, like any other aspect of an app, must be properly tested before an app is released. There are various possibilities:
- Preview the iOS localization in the Interface Builder
- Run the app with options to find text that has not been localized
- Run the app with all languages and regions supported
Perhaps most importantly, however, the app should be tested in its localized version by users who are native speakers of the language concerned.
The creation of versions of apps for the international market is increasingly a necessity, rather than a luxury. Depending on how you see things, iOS localization (and internationalization) of your app may offer you a stimulating challenge or take you further outside your comfort zone than you imagined. iOS and Xcode offer a range of tools to make your localization of your app easier, faster, and more reliable. However, the real success of your localization also depends on your awareness of the quirks of language, the quality of your (human) translators, and your determination to provide a great experience for your app for users of each language and culture for which localization takes place.
Looking to get deeper into iOS localization? Feel free to check out the following resources:
Last updated on October 28, 2022.