Lecture Two: Format Strings and Plurals

In the last article we have run through the basics of internationalization and localization for the iOS and localized a simple app in Portuguese.

Today we will dig deeper and share some common problems faced during localization and how to fix them.

1. Format Strings

Format strings come in handy when you need to display string with data at runtime. For instance:

John Appleseed finished 1 out of 3 tasks.

would be the result of:


/* %@{username} finished %lu{progress} out of %lu{total} tasks. */
"user_task_progress_format" = "%@ finished %lu out of %lu tasks.";


NSString *messageFormat = NSLocalizedString(@"user_task_progress_format", @"%@{username} finished %lu{progress} out of %lu{total} tasks.");
NSString *message = [NSString stringWithFormat:messageFormat, username, progress, taskCount];

Tips: If you have difficulties understanding the above code, check out Apple’s String Programming Guide.

The Problem

The above format string works well for English, but what about other languages? Here’s the translation in Traditional Chinese:

John Appleseed 完成了 3 項任務中的 1 項。

As you can see the order of the arguments is different from the English version. So how do we achieve the above result with format string?

Positional Specifiers

One of the handy features of format string is positional specifiers, you can tell the formatter the order of the arguments by inserting n$ to the format specifier, e.g. %1$@, %2$lu, %3$lu. Now the format string for Traditional Chinese should look like this:


/* %@{username} 完成了 %lu{total} 項任務中的 %lu{progress} 項。 */
"user_task_progress_format" = "%1$@ 完成了 %3$lu 項任務中的 %2$lu 項。";

2. Plurals

If you are a detail-minded person you might have noticed another problem in the above example, what if there is only 1 task in total?

John Appleseed finished 1 out of 1 tasks. // grammatical mistake!

I have seen many people try to solve this problem by using another format specifier for the s or complex plural logic. There are also quite a number of 3rd-party libraries out there that promise to address this problem. But there’s a better solution supported officially since iOS 7, introducing:

Stringsdict File Format

The file extension is .stringsdict but it’s actually a plist file. It is not a replacement of .strings file but rather an addition that tells the system the rules to follow when dealing with plurals, the filename of the .stringsdict should match the .strings file accordingly. Let’s see how we can make use of this new file format for our example:


                 has finished %2$lu out of 1 task.
                 has finished %2$lu out of %3$lu tasks.

It might seem tedious at first but it gets easier once you get a hang of it. The best thing about this solution is that you don’t need to change a single line of code in your source file, no plural logic is needed.

Does .stringsdict also support gender rules?

While the release notes of OS X 10.9 mentioned support of both plural and gender rules, the .stringsdict file format can not handle gender rules as of iOS 8.3. The official documentation did not say a word about gender rules either. Hopefully it will be supported in a future release.

3. Next up

We now have a better understanding of how the system handles format strings and plurals. Download the source code at the box on the right (for web browswer) or below (for mobile browser). Let us know if you have any question and feedback!

In the next article we will discuss best practices when using NSLocalizedString and FAQ about the localization system on iOS.

Go back to OneSky Localization Academy

Go back to Lecture One: Basics

Go to Lecture Three: NSLocalizableString Best Practices and FAQ

Learn localization and reach global markets. Like these apps.

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