androidlocalizationplural

In French, plural system treats 0 as "other" instead of "one"


In res/values/strings.xml, I have

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <plurals name="days_amount">
        <item quantity="one">%d day EN</item>
        <item quantity="other">%d days EN</item>
</plurals>
</resources>

And in res/values-fr/strings.xml, i have

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <plurals name="days_amount">
        <item quantity="one">%d jour FR</item>
        <item quantity="other">%d jours FR</item>
    </plurals>
</resources>

With English locale res.getQuantityString(R.plurals.days_amount, 0, 0) returns:

"0 days"

which is okay per English rules (aka zero quantity <=> several quantities).


But with a French locale, it returns:

"0 jours"

which is NOT okay per French rules (aka zero quantity <=> singular quantity).

It should have returned "O jour"

French rules: http://www.unicode.org/cldr/charts/25/supplemental/language_plural_rules.html#fr


So, is this a bug, or am I doing something wrong ?


Solution

  • Indeed your concern is right, in French amount 0 should be treated as 'one' instead of 'other'. The issue is in some Android APIs: API <= 16

    So in case you want still to support API 16 just add an extra string key for the zero amount. Let's assume you have:

    <plurals name="label_message_reminder_text">
            <item quantity="other">Vous avez %1$s nouveaux messages</item>
            <item quantity="one">Vous avez %1$s nouveau message</item>
    </plurals>
    

    Just add an extra string:

    <string name="label_message_reminder_text_zero">Vous avez %1$s nouveau message</string>
    

    And then when retrieving plurals can do something like:

    String newMessagesText = getMyString(context, resourceId, amount);
    messageTextView.setText(String.format(newMessagesText, amount));
    

    And you can have a method to do the getMyString():

    public String getMyString(Context context, int resourceId, int amount){
    
      if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {    
         if(amount == 0) {
            switch (resourceId) {
               case R.plurals.label_message_reminder_text:
                  return context.getResources().getString(R.string.label_message_reminder_text_zero);
            }
         }
      }
    
      return context.getResources().getQuantityString(resourceId, amount);
    
    }