A Problem with Plural Localization in Swift

Viewed 57

I have a function to get a localized string for plural cases.

extension String {
  static func localizedStringForPlurals(
   formatKey key: String,
   comment: String = "",
   args: CVarArg... ) -> String
{
  let format = NSLocalizedString(key, comment: comment)
  var result = withVaList(args){
    (NSString(format: format,
      locale: NSLocale.current,
      arguments: $0) as String)
    }
    return result
 }
 ...
}

The key is NSLocalizedString, which gets a localized string for the plural case from the stringsdict file.

I have an example of how to get localized string for taps. If the int number is one, the localized string is "This tap"; if int is larger than one, i.e., others, the string is "These taps". See attachment: stringsdict file (English).

enter image description here

It works fine for English. For example:

var count: Int
...
let locS = String.localizedStringForPlurals(
  formatKey: "theseTaps", args: count)
  // "This tap" if count is 1
  // "These taps" if count is > 1

However, it does not work well for Chinese. Here is a similar stringsdict file for Chinese.

enter image description here

The result in Swift code is always a plural string, i.e., "这些点击"(These tap), even if the count is 1 (expected: This tap or 这个点击)

I am not sure if this is a bug in NSLocalizedString or not. I know that in Chinese in general, there are no plural cases. However, as in this example, there are plural cases, this tap or these tap. In Chinese, there is no plural for "taps", one word "tap" can refer to (one) tap or (>1) taps. but "this" and "these" in Chinese are different, and they mean plural cases.

I do like Apple's localization for the plural framework. In Swift code, there is no awareness of what language is being used, but the localized string is picked up from the localization framework. However, I would like this framework to work as a developer's expectation, as in my example in two dict files. Not to be too smart enough to always take the plural result, assuming that there is no plural rule in a language (like in Chinese).

I am not sure if there is way to resolve the issue? For example, turn off this kind of smart way (plural rule for a specific language. zero, one, others for English, others for Chinese, ...), and let developer to decide and layout the plural rule of how to get a localized string.

1 Answers

To answer your question -- if you want something else, you need to program it yourself. In fact, I did do this at Trello because we wanted English to have a "zero" where we said something like "You don't have any cards" instead of "You have 0 cards".

We had a function like yours and in it, it said (pseudocode)

   if (locale == "en" && numberForPlurals == 0) {
       pluralCategory = "zero";
   }

And we looked up the string ourselves based on the key and plural category.

Another option is to reword the phrase so that it works for any number -- this is obviously not ideal. An English example would be "You have 3 cat(s)" -- which is what you would do if you didn't have a pluralization capability.

You seem to know this, but for those that need more information:

Apple is just implementing the UNICODE/CLDR standard for pluralization -- this is not iOS specific -- it's a standard.

Not every language plurals based on 1, or 2+ like English does. Those categories you see are not really referring to the numbers -- they are categories that each language defines for itself.

I wrote an article about it here: https://www.atlassian.com/engineering/ios-i18n-plurals (note: this article and the implementation was written before plurals were supported on iOS directly)

Summary

  1. There are six categories of numbers that each language could use: zero, one, two, few, many and other
  2. You have to look up your language here: https://unicode-org.github.io/cldr-staging/charts/latest/supplemental/language_plural_rules.html
  3. Then see what the mapping from number to category is -- For example: english uses one and other: https://unicode-org.github.io/cldr-staging/charts/latest/supplemental/language_plural_rules.html#en
  4. Chinese uses only one category (other) and doesn't pluralize based on numbers: https://unicode-org.github.io/cldr-staging/charts/latest/supplemental/language_plural_rules.html#zh

So, you should only expect a Chinese translator to provide one string (just for other) and that's the only one you need. If you need something else, you have to write your own logic and function to provide the key to look up in the strings file.

NOTE: the names "zero", "one", "two", etc are misleading for most languages. There are six categories -- they could have just named them cat1, cat2, cat3, etc.

Related