Plurals localization using Stringsdict in iOS

🌍 🌏 🌎

What it is about?

If you’re interested in the title, then you’re probably as concerned as I am about the localization issue of your iOS (macOS) application. A solid approach to the localization process of your application is a simple and effective way to increase the volume of your target audience. Often it makes no sense to put language barrier between the app and your target audience.

Ask yourself - how many of your friends or relatives can freely use an application that is not available on their native language? Ain’t they gonna constantly tend to search for alternative that is more user friendly?

May be you are young IT startup and localization task does not look like a first rank task for you. Let me tell you that even in that case you should keep in mind the future perspective of localization task appearing from the very beginning of you project. I’m telling about using Localizable.stirngs with NSLocalizableString macro in your code. There is a hundreds of about this topic exists.

But here I’ll try to describe a problem that lays a bit deeper.

Example project links:
Objective-C
Swift

Problem 1. Noun plurals

Describing plurals of noun with variable amount is not a trivial task. Moreover, as we will convince later, it’s not a software engineer task from the beginning.

Let’s take a look at simple example below:

Now how can we try to implement task of building text string just like in “Expected text” column depending on “Noun” and “Column” columns?

Lets try to init our string with format:

Results will look like this:

//a == 0 -> John has 0 pineapple
//a == 1 -> John has 1 pineapple
//a == 4 -> John has 4 pineapple

Noticed the noun ending? Sure it has to be different depending on its count. Also “has 0” part is not so fancy too, “has no” would suit better. Overall, current result is not what our user would be pleased to see.

Lucky we that plurals rules in English is relatively simple. Right?

Example 1. Simple solution (wrong one)

Lets try to solve the task of building text string describing amount of pineapples owned by John in our source code using programming language only.

It is going to be a separate function that will take a pineapple count as a parameter and return a string:

It’s already looks like a problem getting solved in a wrong place. But first lets check how it works:

a == 0 -> John has no pineapples
a == 1 -> John has 1 pineapple
a == 4 -> John has 4 pineapples

Not bad, now what can go wrong?

Problem 2. Noun plurals localization

Inevitable localization task of our pineapple counting application is approaching. Here starts the real challenge.

Lets see how text string we building should look in Russian language:

Now we are in trouble. Noun plurals rules in Russian language is not so simple as in English.

Check out how our text string building function can be implemented for Russian localization purpose:

Quite tricky. Believe me, it’s works well, but ain’t we going nowhere with such approach?

You see now that with growing number of supported localizations our task solution is going to gain huge amount of code that will enumerate device prefered localization and apply appropriate function.

Have a look at variaty of ways to express noun plurals using different languages of the world:

Sure it’s obvious that solving task of building text strings that includes noun plurals using probramming language only is the most plain (in case of English especially), but exclusivelly destructive approach in a terms of future project scalability and overall code style.

Does software engineers even have to deal with such tasks? No doubt there have to be a right way to deal with it.

Stringsdict using Plural Rule

Unlike simple Localizable.strings file, Localizable.strigsdict file is a structure much more sophisticated, and so much more functional. It is applicable not only to replace the incoming string with its localized equivalent, but also is able to take into account the formatting parameters included in the string and build the result in accordance with the selected rule for each one of the parameter.

Plural Rule serves as such a rule. It’s one of the methods to process a single parameter of the incoming string, indicating that the value of this parameter should be processed in accordance with the CLDR Language Plural Rules.

Default Stringsdict file structure:

Localized String Key — a text constant in your code. Serves as a key to find a match when passed to the NSLocalizedString macro. The constant should be given an expressive name, “johns pineapples count” in our case.

Localized Format Key — the format of processing result with the parameters included. The first and only default parameter named “VARIABLE”. The name “v1_pineapples_count” will suit purposes of our example.

Variable — the rules dictionary that applies to the VARIABLE parameter. If the parameter name is changed, the dictionary of its rules should be renamed accordingly (“v1_pineapples_count” in our case).

Language Rule Type — parameter processing rule. It’s all about Plural Rule in our case so we will leave it as is. Thus, our parameter will be processed according to the rules of noun plurals transformation.

Number Format Specifier — specifies the format of the parameter. Our parameter “v1_pineapples_count” of type UInt, denoting the number of fruits, will correspond to the value of “u”. You can read more about data conversion formats in a row in the Apple Developer Library.

Zero, one, two, few, many, other —corresponds to the categories of cardinal numbers distribution according to CLDR Language Plural Rules. Each key that is involved in a particular localization must have a string returned when the “VARIABLE” parameter falls into one of the categories.

You can read more details about Stringsdict inner structure in Apple Developer Library.

Example 2. Applying Stringsdict

Now we are about to solve out text string building task without any noun amount counting inside of source code, but only with the power of Stringsdict and Plural Rule inside of it.

To do so we have to determine a constant string to relate from the source code to Stringsdict file using NSLocalizedString macro, than create a Localizable.stringsdict file and fill its content in accordance to Plural Rule.

Let’s go step by step:

Step 1

To get a string of the form “John n pineapples” we need determine an expressive constant like “johns pineapples count” and denote that there will be one numeric parameter of the type UInt to build a string.

Step 2

In the context menu of the project file, select the option “New File…” and add a new file format Stringsdict. Let’s call it Localizable.stringsdict.



Step 3

Let’s determine what kind of string should be passed for formatting, and what kind of string should be expected as a result.
In our simple example, the string has only one parameter — the number of objects (pineapples), and one related parameter that describes how many objects are owned by John. Thus, the view of our Localized.stringsdict file (for English language) will look as follows:



johns pineapples count — text constant to be called from NSLocalizedString macro.

v1_pineapples_count — input parameter title whose value will be processed.

NSStringLocalizedFormatKey : %#@v1_pineapples_count@ — format of the result string.

NSStringFormatValueTypeKey : u — means that our “v1_pineapples_count” parameter is going to be a UInt type value. You can read more about data conversion formats in a row in the Apple Developer Library.

zero, one, other — corresponds to the categories of cardinal numbers distribution according to CLDR Language Plural Rules. In case of English localization, only two fields are mandatory — “one” and “other”. The “zero” one used only for decoration purposes.

Step 4

Now we can get a formatted string using only the formatting constant and applying an UInt parameter into it, indicating the number of objects. No additiona inside-code processing need.

Let’s implement a universal function, that will return formatted text string including noun plural depending on Localizable.stringsdict file:

And function test results will be:

count==0, resultString=="John has no pineapples"
count==1, resultString=="John has 1 pineapple"
count==2, resultString=="John has 2 pineapples"

Nice, that’s it for English.

Localization

Now what about localization task?

Let’s say that now we need the resulting string to be localized into Russian in case the application was launched on a device with the appropriate language preferences.

Great news is that there is no more need for that huge, Russian-specific string building function. The solution is to import the original text data to be localized by a specialist and than import the processing results back into the project.

Xcode 9 provides the ability to solve such task of exporting and importing data for localization using the XLIFF format, which is widely used and created specifically for this purpose.

Consider the step-by-step implementation in the context of our example:

Step 1. Export

We start with adding Russian localization into our project and choosing Localizable.stringsdict as the file we want to be affected:


Click “+” and choose “Russian”

Choose “Localizable.stringsdict”

Exporting files for localization

Choose a folder so save XLIFF file(s)

Step 2. Localization

Localization task using XLIFF files is a common practice among lozalization specialists and should be delegated to a professional.

Consider this process in the context of our simple example.

Let’s open ru.xliff file, we just exported from the project, and pay attention to the content of a “trans-unit” sections:


<source> — source string of localization target.

<target> — a string value that should contain localization result. By default, it is filled with the original, English value.

<one:dict, other:dict, zero:dict, many:dict, few:dict> —every section characterizes trans-unit category of plurals that it belongs to. Notice additional categories that appeared because of Russian specific noun pluralization rules. I’m talking about “many” and “new”.

Now have a look at post-localization variant of our ru.xliff file and notice the changes in <target> tag:



Great, localized ru.xliff file is ready to be imported back into the project.

Step 3. Import

Importing localized ru.xliff file back into project is just as simple as exporting it. We just have to provide it to Xcode and it will auto-fill all stuff that changed:


Choose “Editor” and click “Import Localizations…”

Locate localized ru.xliff file

Check the changes and press “Import”

Localizable.stringsdict (Russian) final look

Final test

Now our project is capable of building target “johns pineapples count” strings independently of count parameter and prefered system localization (if Localizable.stringsdict is available).

It does not mater what is system localization, we will use same function we created earlier:


English localization example

Russian localization example

You can check out project using links below:

Objective-C

Swift

Summary

In the case when your project faces a task of building text string with the inclusion of sets of nouns with variable number and their subsequent localization, the sequence of your actions will be approximately as follows:

  1. Determine the string constant and set of its including parameters that will be processed to generate the string processing result.
  2. Create Localizable.stringsdict file and define your string constant in accordance with Plural Rule.
  3. Enable target language localization for Localizable.stringsdict.
  4. Export Localizable.stringsdict into XLIFF file for target localization.
  5. Provide XLIFF file to localization specialist for processing.
  6. Export post-localized XLIFF file back into your project.
  7. Test your project.

Any comments, questions and suggestions are welcome! Have a nice day! Sorry my English! Thanks!