Pluralization on iOS and OS X

As of iOS 7 and Mac OS X 10.9 Mavericks, Foundation has the ability to specify localized strings according to pluralization and grammar rules. So no need to write code like this to deal with strings whose conjugations change based on a dynamic value anymore.

if (count == 1) {
  return NSLocalizedString(@"1 Person", nil);
} else {
  return [NSString stringWithFormat:NSLocalizedString(@"%d People", nil), count];
}

There is a new file format with .stringsdict suffix introduced. [NSBundle localizedStringForKey:value:table:] now accesses two files: .stringsdict and .strings. It queries the .stringsdict file first, then, .strings file.

The .stringsdict file contains the original key (e.g. @“%d files are selected”) with the value as an arbitrary property list (mostly dictionary or string). When the value is a dictionary, it must contain a key for the localized format string value and its format specifier configuration dictionaries. Here’s an example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>%d files are selected</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%#@num_files@ selected</string>
        <key>num_files</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>d</string>
            <key>zero</key>
            <string>No file is</string>
            <key>one</key>
            <string>A file is</string>
            <key>other</key>
            <string>%d files are</string>
        </dict>
    </dict>
</dict>
</plist>

A configuration key between two @s is used to query an item in the external format configuration dictionary.

Here, the num_files is the key defined in the string using the enhanced # format specifier and will be replaced depending on the passed value when using localizedStringWithFormat:. Its a bit difficult to understand at first looking at the xml file. Let us see how this plist will look like in json:

"%d files are selected": {
    "NSStringLocalizedFormatKey": "%#@num_files@ selected", // The string to format
    "num_files": {
        "NSStringFormatSpecTypeKey": "NSStringPluralRuleType", // Its a plural rule
        "NSStringFormatValueTypeKey": "d", // We expect an integer argument
        "zero": "No file is", // String to use in place of `num_files` when value is zero
        "one": "A file is",
        "other": "%d files are"
    }
}

How to use it: Just create a localizable.stringsdict file and add it to your XCode project and use it in code:

label.text = [NSString localizedStringWithFormat:NSLocalizedString(@"%d files are selected", @"%d files are selected"), numFilesSelected];

Note: It might not work on the simulator straight away, so you might want to try it on a device before you start pulling your hairs out!

Published 25 Nov 2014

I build mobile and web applications. Full Stack, Rails, React, Typescript, Kotlin, Swift
Pulkit Goyal on Twitter