Repository navigation
Description
Use case
Currently ARB files support only following plural forms: =0, =1, =2, ..., few, many, other.
And gen_l10n generator ignores zero, one & two plural forms.
However, according to ICU standard here and here these numeric representation of plural forms (=0, =1, =2, ...) represent cases when the number is exactly that.
In order to properly cover plural forms among different languages according to ICU standard, ARB files should support zero, one & two plural forms as well.
These zero, one, two forms are meant to be applied in more cases than just those exact numbers.
Check here.
Proposal
Add support for plural forms like this one:
"pluralString": "{howMany, plural, zero{...} one{...} two{...} few{...} many{...} other {...}}"
which should generate the following Dart code:
String pluralString(int howMany) {
return intl.Intl.pluralLogic(
howMany,
locale: localeName,
zero: '...',
one: '...',
two: '...',
few: '...',
many: '...',
other: '...',
);
}
Activity
tiloc commentedon Jun 10, 2021
I recently ran into the same issue, would absolutely second that request. This would also make gen_l10n compatible with third-party translation tools, such as poeditor.com.
HansMuller commentedon Jun 10, 2021
CC @shihaohong - sounds like a reasonable request
shihaohong commentedon Jun 16, 2021
I'm a little confused here -- wouldn't it be fine if =0 and 'zero' treated the same way? In the tool, we basically just take =0 and then use it in
zero. We use =1 for 'one' and =2 for 'two' as well. See https://github.com/flutter/flutter/blob/master/packages/flutter_tools/lib/src/localizations/gen_l10n.dart#L189.I say this because I think the numerical cases would still be handled correctly by the 'other' value. I might be missing something though, so some clarification would be helpful!
tiloc commentedon Jun 16, 2021
@shihaohong for me it is mostly about the tooling. Several tools I have come across only know the "zero", "one", "two" which seem to be more commonly used than the "=0", "=1", "=2" which Flutter has chosen to use. It is annoying to do search & replace on the ARB file from a translation tool before feeding it into gen_l10n.
Also as the original poster pointed out, "=1" and "one" are semantically not the same. "=1" means "exactly one", where for instance "one" in Ukrainian means "any number ending with the digit 1". So the mapping in gen_l10n is mapping two semantically different concepts onto each other. The same with "two", which in Arabic means "any number beginning with the digit 2".
shihaohong commentedon Jun 17, 2021
Interesting -- thanks for the additional information. I'll see how we can make this change. The only issue is that it would likely be a breaking change, so we'll need to add an optional parameter to provide the fix and then phase it out.
shihaohong commentedon Jun 21, 2021
I took another look at this and what we could do is basically have the tool accept either the numeric representation (=1, =2) or the full English word ('one', 'two') and treat them the same.
Could you share some documentation that describes this difference? I don't seem to find a description of this in the ICU standard. Even so, this would be an
intlpackage issue since we use that under the hood and we would not be able to do much unless theintlpackage itself supported this behavior.[-]Add support for missing "zero", "one" & "two" plural forms to gen_l10n generator[/-][+][gen_l10n] Support for missing "zero", "one" & "two" as well as =0, =1, =2[/+]tiloc commentedon Jun 21, 2021
Here is the documentation, it is the "explicit 0 and 1 rules": https://unicode-org.github.io/cldr/ldml/tr35-numbers.html#a-nameexplicit01rules-hrefexplicit01rulesexplicit-0-and-1-rulesa
The override is mentioned here: The explicit “0” and “1” cases have precedence over the “zero” and “one” cases. For example, if for a particular element CLDR data includes values for both the “1” and “one” cases, then the “1” value is used for numeric values of exactly 1, while the “one” value is used for any other formatted numeric values matching the “one” plural rule for the language.
"=2" doesn't really seem to be a thing.
shihaohong commentedon Jun 21, 2021
I filed an issue to dart-lang/intl: dart-lang/i18n#21.
aDrIaNo34500 commentedon Jun 21, 2021
aDrIaNo34500 commentedon Jun 21, 2021
[-][gen_l10n] Support for missing "zero", "one" & "two" as well as =0, =1, =2[/-][+][gen_l10n] Support for explicit 0 and 1 rules for number formatting[/+]aleksakrstic commentedon Feb 24, 2022
Hi @shihaohong
Is there any update on this? It seems many devs face such issue.
Maybe just to start accepting ARB files with
zero&=0,one&=1,two&=2and treat them the same way, instead of accepting only=0,=1&=2?At least for starters?
It seems that would solve all the issues around this, without any noticable cons.
lonedfx commentedon Jan 31, 2026
This should be prioritized higher than P3, as it affects ANY nontrivial localized application.
Essentially, this issue is making the =0 category entirely useless unless one doesn't care about cross-language consistency. E.g, if I want my English string to be "No items found" for the zero case, all I can get for the French case is "0 element trouvé".
Example:
ARB file: =0{No items} =1{1 item} other{{count} items}
Expected behavior:
Actual behavior:
One might argue that it sorta "works" ("0 element" is accurate) but:
Also, I'm speaking about French here because that's what I'm knowledgeable about, but surely this exact same issue surfaces in other languages with even less trivial grammatical vs semantic mappings.
The person making the translation knows the language best and it should be clear which case they are covering. The =0 case should be matched first before CLDR categories are consulted. ICU specs do recognize this:
"When formatting, the input number is first matched against the explicitValue clauses. If there is no exact-number match, then a keyword is selected by calling the PluralRules..."
I understand this is going to be a breaking change, but leaving this bug in makes it is a bit of a nightmare to maintain proper localization.
Surely there is a way to keep the old behavior while a) fixing the behavior for new projects going forward and b) letting legacy projects opt into the new behavior.
[gen_l10n] Add `use-explicit-plural-values` option (flutter#194816)