So far we have discussed the basic concepts and common problems of localization for iOS. In this article we will focus on localizable string best practices and answer some frequently asked questions about the localization system.
Unlike Android there’s no naming convention for string key on the iOS, you can use whatever you like as long as the key is unique in the .strings
file. Very often when developers first internationalize their apps, they would use the value in base language as the key, for example:
Localizable.strings
"Play" = "Play";
ViewController.m
NSString *play = NSLocalizedString(@"Play", nil);
One of the reasons that developers prefer the above is that by default NSLocalizedString(key, comment)
returns the key if it is not found in the .strings
file. So even if you don’t have the Localizable.strings
file or forget to add a string or two, the UI still looks normal.
It might seem convenient at first but it’s actually error-prone. First it’s difficult to spot missing translations at runtime, and more importantly a word can have multiple meanings in a language, how can your translators tell if you are referringPlay
as the verb or the noun?
We suggest following the conventions for naming resources in iOS (lowercase with _ as word separator) and using groups to provide context information about the string. Here are some examples:
Localizable.strings
"home_media_control_play" = "Play"; "home_media_control_stop" = "Stop"; "home_title" = "Home"; "home_streaming_failure_alert_title" = "Streaming Failed"; "common_action_okay" = "Okay"; "common_action_cancel" = "Cancel"; "user_profile_title_format" = "%@'s Profile";
It’s up to you to decide how the strings are grouped, but it should be consistent and clear.
In many cases the key alone is not enough to provide context information about the string. To make life easier for translators (and yourself), we can make use of comment.
Localizable.strings
/* Play action of media control */ "home_media_control_play" = "Play"; /* Stop action of media control */ "home_media_control_stop" = "Stop"; /* Title for home */ "home_title" = "Home"; /* Alert title for streaming failure in home page */ "home_streaming_failure_alert_title" = "Streaming Failed"; /* Okay action for all alerts in the app */ "common_action_okay" = "Okay"; /* Cancel action for all alerts in the app */ "common_action_cancel" = "Cancel"; /* Format for user profile title: %@{First name}'s Profile */ "user_profile_title_format" = "%@'s Profile";
It’s especially important when dealing with format strings since we do not have information about the format specifiers from the key. Adding comments can help you and other developers understand more about the variables to provide for the format string.
ViewController.m
NSString *userProfileFormat = NSLocalizedString(@"user_profile_title_format", @"Format for user profile title: %@{First name}'s Profile"); NSString *userProfileTitle = [NSString stringWithFormat:userProfileFormat, user.firstName];
.strings
FilesMost developers keep strings in Localizable.strings
file, which is the default file the system looks into when usingNSLocalizedString(key, comment)
. There is actually a less common sibling of NSLocalizedString(key, comment)
which allows you to call strings from other .strings
files.
NSLocalizedStringFromTable(@"string_key", @"TableName", @"Developer comment");
Table
here refers to the filename of the .strings
file without extension. In the above example, it looks for any string item that matches string_key
in TableName.strings
file.
.strings
files?If you work on a project along with several other developers and everyone accesses the same .strings
file, you will need to constantly update and merge the file. Instead you should create a .strings
file for each view controller or part of the app you are working on, that way you don’t need to worry about messing up other people’s work and vice versa.
Also as you work on more and more projects, you will find that there is a large number of strings that you use repeatedly, for example button titles for alerts, action sheets and bars. More importantly you might already have translations for these strings, you can extract these common strings and keep them in a separate Common.strings
.
The system will fallback to the development region (CFBundleDevelopmentRegion) specified in the Info.plist
, which is en
by default. If you want to change it to another language, you should also include it in Localizations
array ofInfo.plist
.
From the documentation:
This method returns the following when key is nil or not found in table:
- If key is nil and value is nil, returns an empty string.
- If key is nil and value is non-nil, returns value.
- If key is not found and value is nil or an empty string, returns key.
- If key is not found and value is non-nil and not empty, return value.
The localization system on the iOS is so flexible that sometimes you need some guidance to keep things manageable. If you have questions about NSLocalizedString or the localization system, feel free to ask us anything. Check out the box on the right (for web browser) or below (for mobile browser).