placeholder

INTRODUCTION TO IOS LOCALIZATION

Lecture Three: NSLocalizableString Best Practices and FAQ

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.


1. Best Practices

String Key

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.

So What’s the Problem?

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?

A Better Approach

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.


Comment

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];

Multiple .strings Files

Most 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.

Why should I keep strings in different .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.


FAQ

What is the default fallback language if the system language is not supported?

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.

What if the system cannot find the key from the file at all?

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.

Conclusion

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).

Go back to OneSky Localization Academy

Go back to Lecture Two: Format Strings and Plurals

Trusted by hundreds of mobile games

  • Tango
  • Viber
  • Day One
  • Hootsuite
  • 500px
  • Truecaller
  • Glide
  • Wish
  • Secret