From d4e4049445064bfcdd2f8dd95cf0a1dc14b42e1a Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Wed, 21 Aug 2024 22:34:40 +0200 Subject: [PATCH] add explicit cases to pluralcategory --- .../datetime/src/pattern/runtime/plural.rs | 12 +++--- .../src/compactdecimal/provider.rs | 2 + .../experimental/src/relativetime/provider.rs | 37 ++++++++++++++----- components/plurals/benches/fixtures/mod.rs | 4 +- components/plurals/src/lib.rs | 33 ++++++++++++++++- components/plurals/src/provider.rs | 10 +++++ ffi/capi/src/pluralrules.rs | 8 +++- ffi/ecma402/src/pluralrules.rs | 2 + .../source/src/cldr_serde/currencies/data.rs | 6 +++ provider/source/src/cldr_serde/date_fields.rs | 4 ++ provider/source/src/cldr_serde/numbers.rs | 6 +++ provider/source/src/cldr_serde/units/data.rs | 12 ++++++ provider/source/src/currency/patterns.rs | 2 + provider/source/src/relativetime/mod.rs | 2 + provider/source/src/units/data.rs | 2 + 15 files changed, 121 insertions(+), 21 deletions(-) diff --git a/components/datetime/src/pattern/runtime/plural.rs b/components/datetime/src/pattern/runtime/plural.rs index 352f56822cb..e2c407c5832 100644 --- a/components/datetime/src/pattern/runtime/plural.rs +++ b/components/datetime/src/pattern/runtime/plural.rs @@ -72,8 +72,8 @@ impl<'data> PluralPattern<'data> { return; } match category { - PluralCategory::Zero => self.zero = Some(pattern), - PluralCategory::One => self.one = Some(pattern), + PluralCategory::Zero | PluralCategory::Explicit0 => self.zero = Some(pattern), + PluralCategory::One | PluralCategory::Explicit1 => self.one = Some(pattern), PluralCategory::Two => self.two = Some(pattern), PluralCategory::Few => self.few = Some(pattern), PluralCategory::Many => self.many = Some(pattern), @@ -83,8 +83,8 @@ impl<'data> PluralPattern<'data> { pub(crate) fn variant(&self, category: PluralCategory) -> &Pattern<'data> { let variant = match category { - PluralCategory::Zero => &self.zero, - PluralCategory::One => &self.one, + PluralCategory::Zero | PluralCategory::Explicit0 => &self.zero, + PluralCategory::One | PluralCategory::Explicit1 => &self.one, PluralCategory::Two => &self.two, PluralCategory::Few => &self.few, PluralCategory::Many => &self.many, @@ -95,8 +95,8 @@ impl<'data> PluralPattern<'data> { pub fn patterns_iter(&self) -> impl Iterator> { PluralCategory::all().filter_map(move |cat| match cat { - PluralCategory::Zero => self.zero.as_ref(), - PluralCategory::One => self.one.as_ref(), + PluralCategory::Zero | PluralCategory::Explicit0 => self.zero.as_ref(), + PluralCategory::One | PluralCategory::Explicit1 => self.one.as_ref(), PluralCategory::Two => self.two.as_ref(), PluralCategory::Few => self.few.as_ref(), PluralCategory::Many => self.many.as_ref(), diff --git a/components/experimental/src/compactdecimal/provider.rs b/components/experimental/src/compactdecimal/provider.rs index 87d2bbe2ad1..ca4c57ecb6a 100644 --- a/components/experimental/src/compactdecimal/provider.rs +++ b/components/experimental/src/compactdecimal/provider.rs @@ -110,6 +110,8 @@ impl From for Count { Few => Count::Few, Many => Count::Many, Other => Count::Other, + Explicit1 => Count::Explicit1, + Explicit0 => Count::Zero, } } } diff --git a/components/experimental/src/relativetime/provider.rs b/components/experimental/src/relativetime/provider.rs index 758f96b9780..3a7eac939ee 100644 --- a/components/experimental/src/relativetime/provider.rs +++ b/components/experimental/src/relativetime/provider.rs @@ -119,8 +119,11 @@ pub struct PluralPattern<'data, B: PatternBackend> { impl<'data, B: PatternBackend> PluralPattern<'data, B> { /// Creates a [`PluralPattern`] from the given patterns. #[cfg(feature = "datagen")] + #[allow(clippy::too_many_arguments)] // I didn't make the plural cases pub fn try_new( other: &str, + explicit_zero: Option<&str>, + explicit_one: Option<&str>, zero: Option<&str>, one: Option<&str>, two: Option<&str>, @@ -133,7 +136,6 @@ impl<'data, B: PatternBackend> PluralPattern<'data, B> { { let optional_convert = |category, pattern: Option<&str>| { pattern - .filter(|p| *p != other) .map(|s| { Ok(PluralCategoryStr( category, @@ -148,11 +150,19 @@ impl<'data, B: PatternBackend> PluralPattern<'data, B> { Ok(Self { specials: (&[ - (optional_convert(PluralCategory::Zero, zero)?), - (optional_convert(PluralCategory::One, one)?), - (optional_convert(PluralCategory::Two, two)?), - (optional_convert(PluralCategory::Few, few)?), - (optional_convert(PluralCategory::Many, many)?), + optional_convert( + PluralCategory::Explicit0, + explicit_zero.filter(|&p| p != zero.unwrap_or(other)), + )?, + optional_convert( + PluralCategory::Explicit1, + explicit_one.filter(|&p| p != one.unwrap_or(other)), + )?, + optional_convert(PluralCategory::Zero, zero.filter(|&p| p != other))?, + optional_convert(PluralCategory::One, one.filter(|&p| p != other))?, + optional_convert(PluralCategory::Two, two.filter(|&p| p != other))?, + optional_convert(PluralCategory::Few, few.filter(|&p| p != other))?, + optional_convert(PluralCategory::Many, many.filter(|&p| p != other))?, ] .into_iter() .flatten() @@ -168,14 +178,21 @@ impl<'data, B: PatternBackend> PluralPattern<'data, B> { /// Returns the pattern for the given [`PluralCategory`]. pub fn get(&'data self, c: PluralCategory) -> &'data Pattern { - Pattern::from_ref_store_unchecked(if c == PluralCategory::Other { - &*self.other - } else { + let lookup = |c: PluralCategory| { self.specials .iter() .filter_map(|ule| (ule.0 == c.to_unaligned()).then_some(&ule.1)) .next() - .unwrap_or(&*self.other) + }; + Pattern::from_ref_store_unchecked(match c { + PluralCategory::Other => &*self.other, + PluralCategory::Explicit0 => lookup(c) + .or_else(|| lookup(PluralCategory::Zero)) + .unwrap_or(&*self.other), + PluralCategory::Explicit1 => lookup(c) + .or_else(|| lookup(PluralCategory::One)) + .unwrap_or(&*self.other), + _ => lookup(c).unwrap_or(&*self.other), }) } } diff --git a/components/plurals/benches/fixtures/mod.rs b/components/plurals/benches/fixtures/mod.rs index bd24fd7be85..dcef9694b3e 100644 --- a/components/plurals/benches/fixtures/mod.rs +++ b/components/plurals/benches/fixtures/mod.rs @@ -50,8 +50,8 @@ impl LocalePluralRulesFixture { #[allow(dead_code)] pub fn get(&self, category: &PluralCategory) -> Option<&String> { match category { - PluralCategory::Zero => self.zero.as_ref(), - PluralCategory::One => self.one.as_ref(), + PluralCategory::Zero | PluralCategory::Explicit0 => self.zero.as_ref(), + PluralCategory::One | PluralCategory::Explicit1 => self.one.as_ref(), PluralCategory::Two => self.two.as_ref(), PluralCategory::Few => self.few.as_ref(), PluralCategory::Many => self.many.as_ref(), diff --git a/components/plurals/src/lib.rs b/components/plurals/src/lib.rs index 58b44fcfe63..30a181f1462 100644 --- a/components/plurals/src/lib.rs +++ b/components/plurals/src/lib.rs @@ -208,6 +208,18 @@ pub enum PluralCategory { /// - 1 in Japanese (ja), Korean (ko), Chinese (zh), Thai (th), ... /// - 2 in English (en), German (de), Spanish (es), ... Other = 5, + /// The explicit 1 case, see . + /// + /// There's exactly one number that has this category: 0. + /// + /// If no data is available for this category, data for `Zero` needs to be used. + Explicit0 = 6, + /// The explicit 1 case, see . + /// + /// There's exactly one number that has this category: 1. + /// + /// If no data is available for this category, data for `One` needs to be used. + Explicit1 = 7, } impl PluralCategory { @@ -234,6 +246,8 @@ impl PluralCategory { /// [`Plural Categories`]: PluralCategory pub fn all() -> impl ExactSizeIterator { [ + Self::Explicit1, + Self::Explicit0, Self::Few, Self::Many, Self::One, @@ -252,6 +266,8 @@ impl PluralCategory { /// Returns the PluralCategory corresponding to given TR35 string as bytes pub fn get_for_cldr_bytes(category: &[u8]) -> Option { match category { + b"0" => Some(PluralCategory::Explicit0), + b"1" => Some(PluralCategory::Explicit1), b"zero" => Some(PluralCategory::Zero), b"one" => Some(PluralCategory::One), b"two" => Some(PluralCategory::Two), @@ -489,8 +505,23 @@ impl PluralRules { /// [`Plural Category`]: PluralCategory /// [`Plural Operands`]: operands::PluralOperands pub fn category_for>(&self, input: I) -> PluralCategory { - let rules = self.0.get(); let input = input.into(); + if let PluralOperands { + i: 0 | 1, + v: 0, + w: 0, + f: 0, + t: 0, + c: _, + } = input + { + return if input.i == 0 { + PluralCategory::Explicit0 + } else { + PluralCategory::Explicit1 + }; + } + let rules = self.0.get(); macro_rules! test_rule { ($rule:ident, $cat:ident) => { diff --git a/components/plurals/src/provider.rs b/components/plurals/src/provider.rs index c2524adbbde..1547a8edf80 100644 --- a/components/plurals/src/provider.rs +++ b/components/plurals/src/provider.rs @@ -142,6 +142,10 @@ mod ranges { Few = 4, /// CLDR "many" plural category. Many = 5, + /// TODO + Explicit1 = 6, + /// TODO + Explicit0 = 7, } impl RawPluralCategory { @@ -155,6 +159,8 @@ mod ranges { Self::Two => "two", Self::Few => "few", Self::Many => "many", + Self::Explicit1 => "1", + Self::Explicit0 => "0", } } } @@ -168,6 +174,8 @@ mod ranges { RawPluralCategory::Two => PluralCategory::Two, RawPluralCategory::Few => PluralCategory::Few, RawPluralCategory::Many => PluralCategory::Many, + RawPluralCategory::Explicit1 => PluralCategory::Explicit1, + RawPluralCategory::Explicit0 => PluralCategory::Explicit0, } } } @@ -181,6 +189,8 @@ mod ranges { PluralCategory::Few => RawPluralCategory::Few, PluralCategory::Many => RawPluralCategory::Many, PluralCategory::Other => RawPluralCategory::Other, + PluralCategory::Explicit1 => RawPluralCategory::Explicit1, + PluralCategory::Explicit0 => RawPluralCategory::Explicit0, } } } diff --git a/ffi/capi/src/pluralrules.rs b/ffi/capi/src/pluralrules.rs index cc7473dcad2..d423f279ccc 100644 --- a/ffi/capi/src/pluralrules.rs +++ b/ffi/capi/src/pluralrules.rs @@ -22,6 +22,8 @@ pub mod ffi { Few, Many, Other, + Explicit1, + Explicit0, } impl PluralCategory { @@ -138,8 +140,10 @@ pub mod ffi { }, |mut categories, category| { match category { - icu_plurals::PluralCategory::Zero => categories.zero = true, - icu_plurals::PluralCategory::One => categories.one = true, + icu_plurals::PluralCategory::Zero + | icu_plurals::PluralCategory::Explicit0 => categories.zero = true, + icu_plurals::PluralCategory::One + | icu_plurals::PluralCategory::Explicit1 => categories.one = true, icu_plurals::PluralCategory::Two => categories.two = true, icu_plurals::PluralCategory::Few => categories.few = true, icu_plurals::PluralCategory::Many => categories.many = true, diff --git a/ffi/ecma402/src/pluralrules.rs b/ffi/ecma402/src/pluralrules.rs index 9befa3c5ade..7c41654fa8d 100644 --- a/ffi/ecma402/src/pluralrules.rs +++ b/ffi/ecma402/src/pluralrules.rs @@ -127,6 +127,8 @@ pub(crate) mod internal { PluralCategory::Other => "other", PluralCategory::Two => "two", PluralCategory::Zero => "zero", + PluralCategory::Explicit1 => "1", + PluralCategory::Explicit0 => "0", } } diff --git a/provider/source/src/cldr_serde/currencies/data.rs b/provider/source/src/cldr_serde/currencies/data.rs index 518b724afba..0f0b85f82d4 100644 --- a/provider/source/src/cldr_serde/currencies/data.rs +++ b/provider/source/src/cldr_serde/currencies/data.rs @@ -21,6 +21,12 @@ pub(crate) struct CurrencyPatterns { #[serde(rename = "displayName")] pub(crate) display_name: Option, + #[serde(rename = "displayName-count-0")] + pub(crate) explicit_zero: Option, + + #[serde(rename = "displayName-count-1")] + pub(crate) explicit_one: Option, + #[serde(rename = "displayName-count-zero")] pub(crate) zero: Option, diff --git a/provider/source/src/cldr_serde/date_fields.rs b/provider/source/src/cldr_serde/date_fields.rs index 563fa8481ea..9fbf7da4238 100644 --- a/provider/source/src/cldr_serde/date_fields.rs +++ b/provider/source/src/cldr_serde/date_fields.rs @@ -16,6 +16,10 @@ use serde::{ #[derive(Debug, Deserialize, Default)] pub(crate) struct PluralRulesPattern { + #[serde(rename = "relativeTimePattern-count-0")] + pub(crate) explicit_zero: Option, + #[serde(rename = "relativeTimePattern-count-1")] + pub(crate) explicit_one: Option, #[serde(rename = "relativeTimePattern-count-zero")] pub(crate) zero: Option, #[serde(rename = "relativeTimePattern-count-one")] diff --git a/provider/source/src/cldr_serde/numbers.rs b/provider/source/src/cldr_serde/numbers.rs index a1733936c7c..9edb3a047a2 100644 --- a/provider/source/src/cldr_serde/numbers.rs +++ b/provider/source/src/cldr_serde/numbers.rs @@ -120,6 +120,12 @@ pub(crate) struct CurrencyFormattingPatterns { #[serde(rename = "standard-alphaNextToNumber")] pub(crate) standard_alpha_next_to_number: Option, + #[serde(rename = "unitPattern-count-0")] + pub(crate) pattern_explicit_zero: Option, + + #[serde(rename = "unitPattern-count-1")] + pub(crate) pattern_explicit_one: Option, + #[serde(rename = "unitPattern-count-zero")] pub(crate) pattern_zero: Option, diff --git a/provider/source/src/cldr_serde/units/data.rs b/provider/source/src/cldr_serde/units/data.rs index a9e09c3d42f..7e22a005c00 100644 --- a/provider/source/src/cldr_serde/units/data.rs +++ b/provider/source/src/cldr_serde/units/data.rs @@ -16,6 +16,12 @@ use std::collections::BTreeMap; /// https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules #[derive(PartialEq, Debug, Deserialize, Clone)] pub(crate) struct Patterns { + #[serde(rename = "displayName-count-0")] + pub(crate) explicit_zero: Option, + + #[serde(rename = "displayName-count-1")] + pub(crate) explicit_one: Option, + #[serde(rename = "unitPattern-count-zero")] pub(crate) zero: Option, @@ -43,6 +49,12 @@ pub(crate) struct Patterns { #[serde(rename = "compoundUnitPattern1")] pub(crate) compound_unit_pattern1: Option, + #[serde(rename = "compountUnitPattern1-count-0")] + pub(crate) explicit_zero_compound_unit_pattern1: Option, + + #[serde(rename = "compountUnitPattern1-count-1")] + pub(crate) explicit_one_compound_unit_pattern1: Option, + #[serde(rename = "compoundUnitPattern1-count-zero")] pub(crate) zero_compound_unit_pattern1: Option, diff --git a/provider/source/src/currency/patterns.rs b/provider/source/src/currency/patterns.rs index 907fc56f979..cacd5a84dc8 100644 --- a/provider/source/src/currency/patterns.rs +++ b/provider/source/src/currency/patterns.rs @@ -59,6 +59,8 @@ impl DataProvider for SourceDataProvider { .with_debug_context(currency_patterns) .with_debug_context(&req.id) })?, + patterns.pattern_explicit_zero.as_deref(), + patterns.pattern_explicit_one.as_deref(), patterns.pattern_zero.as_deref(), patterns.pattern_one.as_deref(), patterns.pattern_two.as_deref(), diff --git a/provider/source/src/relativetime/mod.rs b/provider/source/src/relativetime/mod.rs index ec34c2b853f..000a35a56df 100644 --- a/provider/source/src/relativetime/mod.rs +++ b/provider/source/src/relativetime/mod.rs @@ -130,6 +130,8 @@ impl TryFrom<&cldr_serde::date_fields::PluralRulesPattern> fn try_from(field: &cldr_serde::date_fields::PluralRulesPattern) -> Result { PluralPattern::try_new( &field.other, + field.explicit_zero.as_deref(), + field.explicit_one.as_deref(), field.zero.as_deref(), field.one.as_deref(), field.two.as_deref(), diff --git a/provider/source/src/units/data.rs b/provider/source/src/units/data.rs index 6d3873a97b4..230abef0b6f 100644 --- a/provider/source/src/units/data.rs +++ b/provider/source/src/units/data.rs @@ -54,6 +54,8 @@ impl DataProvider for SourceDataProvider { .other .as_deref() .ok_or_else(|| DataErrorKind::IdentifierNotFound.into_error())?, + unit_patterns.explicit_zero.as_deref(), + unit_patterns.explicit_one.as_deref(), unit_patterns.zero.as_deref(), unit_patterns.one.as_deref(), unit_patterns.two.as_deref(),