extern crate fluent_locale;
use self::fluent_locale::negotiate_languages;
use self::fluent_locale::NegotiationStrategy;
static LOCALES: &[&'static str] = &[
"af", "ak", "am", "ar", "asa", "az", "be", "bem", "bez", "bg", "bh", "bm", "bn", "bo", "br",
"brx", "bs", "ca", "cgg", "chr", "cs", "cy", "da", "de", "dv", "dz", "ee", "el", "en", "eo",
"es", "et", "eu", "fa", "ff", "fi", "fil", "fo", "fr", "fur", "fy", "ga", "gd", "gl", "gsw",
"gu", "guw", "gv", "ha", "haw", "he", "hi", "hr", "hu", "id", "ig", "ii", "is", "it", "iu",
"ja", "jmc", "jv", "ka", "kab", "kaj", "kcg", "kde", "kea", "kk", "kl", "km", "kn", "ko",
"ksb", "ksh", "ku", "kw", "lag", "lb", "lg", "ln", "lo", "lt", "lv", "mas", "mg", "mk", "ml",
"mn", "mo", "mr", "ms", "mt", "my", "nah", "naq", "nb", "nd", "ne", "nl", "nn", "no", "nr",
"nso", "ny", "nyn", "om", "or", "pa", "pap", "pl", "ps", "pt", "rm", "ro", "rof", "ru", "rwk",
"sah", "saq", "se", "seh", "ses", "sg", "sh", "shi", "sk", "sl", "sma", "smi", "smj", "smn",
"sms", "sn", "so", "sq", "sr", "ss", "ssy", "st", "sv", "sw", "syr", "ta", "te", "teo", "th",
"ti", "tig", "tk", "tl", "tn", "to", "tr", "ts", "tzm", "uk", "ur", "ve", "vi", "vun", "wa",
"wae", "wo", "xh", "xog", "yo", "zh", "zu",
];
fn is_between(n: f32, start: f32, end: f32) -> bool {
start <= n && n <= end
}
fn is_in(n: f32, list: &[f32]) -> bool {
list.contains(&n)
}
static PLURAL_RULES: &[fn(f32) -> &'static str] = &[
|_| "other",
|n| {
if is_between(n % 100.0, 3.0, 10.0) {
return "few";
}
if n == 0.0 {
return "zero";
}
if is_between(n % 100.0, 11.0, 99.0) {
return "many";
}
if n == 2.0 {
return "two";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if n != 0.0 && (n % 10.0) == 0.0 {
return "many";
}
if n == 2.0 {
return "two";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| if n == 1.0 { "one" } else { "other" },
|n| {
if is_between(n, 0.0, 1.0) {
"one"
} else {
"other"
}
},
|n| {
if is_between(n, 0.0, 2.0) {
"one"
} else {
"other"
}
},
|n| {
if n == 0.0 {
return "zero";
}
if (n % 10.0) == 1.0 && (n % 100.0) != 11.0 {
return "one";
}
"other"
},
|n| {
if n == 2.0 {
return "two";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if is_between(n, 3.0, 6.0) {
return "few";
}
if is_between(n, 7.0, 10.0) {
return "many";
}
if n == 2.0 {
return "two";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if n == 0.0 || n != 1.0 && is_between(n % 100.0, 1.0, 19.0) {
return "few";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if is_between(n % 10.0, 2.0, 9.0) && !is_between(n % 100.0, 11.0, 19.0) {
return "few";
}
if n % 10.0 == 1.0 && !is_between(n % 100.0, 11.0, 19.0) {
return "one";
}
"other"
},
|n| {
if is_between(n % 10.0, 2.0, 4.0) && !is_between(n % 100.0, 12.0, 14.0) {
return "few";
}
if n % 10.0 == 0.0 || is_between(n % 10.0, 5.0, 9.0) || is_between(n % 100.0, 11.0, 14.0) {
return "many";
}
if n % 10.0 == 1.0 && n % 100.0 != 11.0 {
return "one";
}
"other"
},
|n| {
if is_between(n, 2.0, 4.0) {
return "few";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if is_between(n % 10.0, 2.0, 4.0) && !is_between(n % 100.0, 12.0, 14.0) {
return "few";
}
if n != 1.0 && is_between(n % 10.0, 0.0, 1.0) || is_between(n % 10.0, 5.0, 9.0)
|| is_between(n % 100.0, 12.0, 14.0)
{
return "many";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if is_between(n % 100.0, 3.0, 4.0) {
return "few";
}
if n % 100.0 == 2.0 {
return "two";
}
if n % 100.0 == 1.0 {
return "one";
}
"other"
},
|n| {
if n == 0.0 || is_between(n % 100.0, 2.0, 10.0) {
return "few";
}
if is_between(n % 100.0, 11.0, 19.0) {
return "many";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if n % 10.0 == 1.0 && n != 11.0 {
"one"
} else {
"other"
}
},
|n| {
if n == 3.0 {
return "few";
}
if n == 0.0 {
return "zero";
}
if n == 6.0 {
return "many";
}
if n == 2.0 {
return "two";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if n == 0.0 {
return "zero";
}
if is_between(n, 0.0, 2.0) && n != 0.0 && n != 2.0 {
return "one";
}
"other"
},
|n| {
if is_between(n, 2.0, 10.0) {
return "few";
}
if is_between(n, 0.0, 1.0) {
return "one";
}
"other"
},
|n| {
if (is_between(n % 10.0, 3.0, 4.0) || n % 10.0 == 9.0)
&& !(is_between(n % 100.0, 10.0, 19.0) || is_between(n % 100.0, 70.0, 79.0)
|| is_between(n % 100.0, 90.0, 99.0))
{
return "few";
}
if n % 1000000.0 == 0.0 && n != 0.0 {
return "many";
}
if n % 10.0 == 2.0 && !is_in(n % 100.0, &[12.0, 72.0, 92.0]) {
return "two";
}
if n % 10.0 == 1.0 && !is_in(n % 100.0, &[11.0, 71.0, 91.0]) {
return "one";
}
"other"
},
|n| {
if n == 0.0 {
return "zero";
}
if n == 1.0 {
return "one";
}
"other"
},
|n| {
if is_between(n, 0.0, 1.0) || is_between(n, 11.0, 99.0) {
return "one";
}
"other"
},
|n| {
if is_between(n, 0.0, 1.0) || is_between(n, 11.0, 99.0) {
"one"
} else {
"other"
}
},
|n| {
if is_between(n, 3.0, 10.0) || is_between(n, 13.0, 19.0) {
return "few";
}
if is_in(n, &[2.0, 12.0]) {
return "two";
}
if is_in(n, &[1.0, 11.0]) {
return "one";
}
"other"
},
];
fn get_plural_rule(loc: &str) -> Option<usize> {
let num = match loc {
"af" => 3,
"ak" => 4,
"am" => 4,
"ar" => 1,
"asa" => 3,
"az" => 0,
"be" => 11,
"bem" => 3,
"bez" => 3,
"bg" => 3,
"bh" => 4,
"bm" => 0,
"bn" => 3,
"bo" => 0,
"br" => 20,
"brx" => 3,
"bs" => 11,
"ca" => 3,
"cgg" => 3,
"chr" => 3,
"cs" => 12,
"cy" => 17,
"da" => 3,
"de" => 3,
"dv" => 3,
"dz" => 0,
"ee" => 3,
"el" => 3,
"en" => 3,
"eo" => 3,
"es" => 3,
"et" => 3,
"eu" => 3,
"fa" => 0,
"ff" => 5,
"fi" => 3,
"fil" => 4,
"fo" => 3,
"fr" => 5,
"fur" => 3,
"fy" => 3,
"ga" => 8,
"gd" => 24,
"gl" => 3,
"gsw" => 3,
"gu" => 3,
"guw" => 4,
"gv" => 23,
"ha" => 3,
"haw" => 3,
"he" => 2,
"hi" => 4,
"hr" => 11,
"hu" => 0,
"id" => 0,
"ig" => 0,
"ii" => 0,
"is" => 3,
"it" => 3,
"iu" => 7,
"ja" => 0,
"jmc" => 3,
"jv" => 0,
"ka" => 0,
"kab" => 5,
"kaj" => 3,
"kcg" => 3,
"kde" => 0,
"kea" => 0,
"kk" => 3,
"kl" => 3,
"km" => 0,
"kn" => 0,
"ko" => 0,
"ksb" => 3,
"ksh" => 21,
"ku" => 3,
"kw" => 7,
"lag" => 18,
"lb" => 3,
"lg" => 3,
"ln" => 4,
"lo" => 0,
"lt" => 10,
"lv" => 6,
"mas" => 3,
"mg" => 4,
"mk" => 16,
"ml" => 3,
"mn" => 3,
"mo" => 9,
"mr" => 3,
"ms" => 0,
"mt" => 15,
"my" => 0,
"nah" => 3,
"naq" => 7,
"nb" => 3,
"nd" => 3,
"ne" => 3,
"nl" => 3,
"nn" => 3,
"no" => 3,
"nr" => 3,
"nso" => 4,
"ny" => 3,
"nyn" => 3,
"om" => 3,
"or" => 3,
"pa" => 3,
"pap" => 3,
"pl" => 13,
"ps" => 3,
"pt" => 3,
"rm" => 3,
"ro" => 9,
"rof" => 3,
"ru" => 11,
"rwk" => 3,
"sah" => 0,
"saq" => 3,
"se" => 7,
"seh" => 3,
"ses" => 0,
"sg" => 0,
"sh" => 11,
"shi" => 19,
"sk" => 12,
"sl" => 14,
"sma" => 7,
"smi" => 7,
"smj" => 7,
"smn" => 7,
"sms" => 7,
"sn" => 3,
"so" => 3,
"sq" => 3,
"sr" => 11,
"ss" => 3,
"ssy" => 3,
"st" => 3,
"sv" => 3,
"sw" => 3,
"syr" => 3,
"ta" => 3,
"te" => 3,
"teo" => 3,
"th" => 0,
"ti" => 4,
"tig" => 3,
"tk" => 3,
"tl" => 4,
"tn" => 3,
"to" => 0,
"tr" => 0,
"ts" => 3,
"tzm" => 22,
"uk" => 11,
"ur" => 3,
"ve" => 3,
"vi" => 0,
"vun" => 3,
"wa" => 4,
"wae" => 3,
"wo" => 0,
"xh" => 3,
"xog" => 3,
"yo" => 0,
"zh" => 0,
"zu" => 3,
_ => return None,
};
return Some(num);
}
pub struct PluralRules {
pub locale: String,
selector: Box<Fn(f32) -> &'static str>,
}
impl PluralRules {
pub fn new(locales: &[&str]) -> PluralRules {
let supported =
negotiate_languages(locales, LOCALES, Some("en"), &NegotiationStrategy::Lookup);
let locale = supported[0].to_owned();
let f = match get_plural_rule(supported[0]) {
Some(n) => Box::new(PLURAL_RULES[n]),
None => unimplemented!("Plural rule for this language is not available"),
};
PluralRules {
locale: locale,
selector: f,
}
}
pub fn select(&self, num: f32) -> &'static str {
(self.selector)(num)
}
}