dvPluralCategory function
The category count takes in locale.
locale may be a full tag: the region is ignored, because plural rules are
a property of the language. An unknown language falls back to the English
rule rather than throwing -- a missing rule should degrade to a plausible
plural, not take the application down mid-render.
Implementation
DVPluralCategory dvPluralCategory({
required String locale,
required num count,
}) {
final String language = dvLanguageOf(locale);
// CLDR operates on the absolute value; -1 file is still singular.
final num n = count.abs();
// The CLDR operands this needs: i is the integer part, v the number of
// visible fraction digits. `1.0` has v=0 once it is a double that prints
// without a fraction, which is why English calls 1.0 singular and 1.5 not.
final int i = n.floor();
final int v = _visibleFractionDigits(n);
switch (language) {
// One form for every number. Offering "one" here produces a string no
// speaker would write.
case 'ja':
case 'zh':
case 'ko':
case 'vi':
case 'th':
case 'id':
case 'ms':
case 'my':
case 'lo':
case 'km':
return DVPluralCategory.other;
case 'fr':
case 'hy':
case 'ff':
case 'kab':
// 0 and 1 are both singular.
return i == 0 || i == 1 ? DVPluralCategory.one : DVPluralCategory.other;
case 'pt':
return i == 0 || i == 1 ? DVPluralCategory.one : DVPluralCategory.other;
case 'pl':
if (v == 0 && i == 1) return DVPluralCategory.one;
if (v == 0 &&
i % 10 >= 2 &&
i % 10 <= 4 &&
!(i % 100 >= 12 && i % 100 <= 14)) {
return DVPluralCategory.few;
}
if (v == 0) return DVPluralCategory.many;
return DVPluralCategory.other;
case 'ru':
case 'uk':
if (v == 0 && i % 10 == 1 && i % 100 != 11) return DVPluralCategory.one;
if (v == 0 &&
i % 10 >= 2 &&
i % 10 <= 4 &&
!(i % 100 >= 12 && i % 100 <= 14)) {
return DVPluralCategory.few;
}
if (v == 0) return DVPluralCategory.many;
return DVPluralCategory.other;
case 'cs':
case 'sk':
if (i == 1 && v == 0) return DVPluralCategory.one;
if (i >= 2 && i <= 4 && v == 0) return DVPluralCategory.few;
// A fraction is its own category here, whatever its value.
if (v != 0) return DVPluralCategory.many;
return DVPluralCategory.other;
case 'ar':
if (n == 0) return DVPluralCategory.zero;
if (n == 1) return DVPluralCategory.one;
if (n == 2) return DVPluralCategory.two;
final int mod100 = i % 100;
if (mod100 >= 3 && mod100 <= 10) return DVPluralCategory.few;
if (mod100 >= 11 && mod100 <= 99) return DVPluralCategory.many;
return DVPluralCategory.other;
case 'lt':
if (i % 10 == 1 && !(i % 100 >= 11 && i % 100 <= 19)) {
return DVPluralCategory.one;
}
if (i % 10 >= 2 &&
i % 10 <= 9 &&
!(i % 100 >= 11 && i % 100 <= 19)) {
return DVPluralCategory.few;
}
if (v != 0) return DVPluralCategory.many;
return DVPluralCategory.other;
case 'ro':
if (i == 1 && v == 0) return DVPluralCategory.one;
if (v != 0 || n == 0 || (n != 1 && i % 100 >= 1 && i % 100 <= 19)) {
return DVPluralCategory.few;
}
return DVPluralCategory.other;
// en, de, es, it, nl, sv, da, nb, fi, et, and the rest of the
// one/other languages.
default:
return i == 1 && v == 0 ? DVPluralCategory.one : DVPluralCategory.other;
}
}