From 46aace91159ebd9b081240d35b50c4f8da6c092f Mon Sep 17 00:00:00 2001 From: Blayne Marjama Date: Fri, 26 Jul 2024 17:12:13 -0700 Subject: [PATCH] Adding Percent Formatter to Experimental (#5255) --- CONTRIBUTING.md | 4 +- components/decimal/src/lib.rs | 6 + components/experimental/src/dimension/mod.rs | 1 + .../src/dimension/percent/format.rs | 222 ++++++++++++++++ .../src/dimension/percent/formatter.rs | 169 ++++++++++++ .../experimental/src/dimension/percent/mod.rs | 9 + .../src/dimension/percent/options.rs | 43 ++++ .../src/dimension/provider/percent.rs | 64 +++-- .../data/percent_essentials_v1_marker.rs.data | 6 +- provider/data/experimental/fingerprints.csv | 123 ++++----- .../debug/percent/essentials@1/ar-EG.json | 30 ++- .../data/debug/percent/essentials@1/ar.json | 30 ++- .../data/debug/percent/essentials@1/bn.json | 30 ++- .../data/debug/percent/essentials@1/ccp.json | 30 ++- .../debug/percent/essentials@1/en-001.json | 30 ++- .../debug/percent/essentials@1/en-ZA.json | 30 ++- .../data/debug/percent/essentials@1/en.json | 30 ++- .../debug/percent/essentials@1/es-AR.json | 30 ++- .../data/debug/percent/essentials@1/es.json | 30 ++- .../data/debug/percent/essentials@1/fil.json | 30 ++- .../data/debug/percent/essentials@1/fr.json | 30 ++- .../data/debug/percent/essentials@1/ja.json | 30 ++- .../data/debug/percent/essentials@1/ru.json | 30 ++- .../debug/percent/essentials@1/sr-Latn.json | 30 ++- .../data/debug/percent/essentials@1/sr.json | 30 ++- .../data/debug/percent/essentials@1/th.json | 30 ++- .../data/debug/percent/essentials@1/tr.json | 30 ++- .../data/debug/percent/essentials@1/und.json | 30 ++- provider/source/src/cldr_serde/numbers.rs | 2 + provider/source/src/percent/mod.rs | 243 +++++++++++++----- 30 files changed, 1119 insertions(+), 313 deletions(-) create mode 100644 components/experimental/src/dimension/percent/format.rs create mode 100644 components/experimental/src/dimension/percent/formatter.rs create mode 100644 components/experimental/src/dimension/percent/mod.rs create mode 100644 components/experimental/src/dimension/percent/options.rs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5cfa2db9885..8f8e4fe391a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,7 +78,9 @@ See the [Testing](#testing) section below for more information on the various te There are various files that auto-generated across the ICU4X repository. Here are some of the commands that you may need to run in order to recreate them. These files may be run in more comprehensive tests such as those included in `cargo make ci-job-test` or `cargo make ci-all`. -- `cargo make testdata` - regenerates all test data in the `provider/testdata` directory. +- `cargo make testdata` - regenerates all test data in the `provider/source/debug` directory. + - `cargo make bakeddata` - regenerates baked data in the `provider/data` directory. + - `cargo make bakeddata foo` can be used to generate data in `provider/data/foo` only. - `cargo make generate-readmes` - generates README files according to Rust docs. Output files must be committed in git for check to pass. - `cargo make diplomat-gen` - recreates the Diplomat generated files in the `ffi/capi` directory. diff --git a/components/decimal/src/lib.rs b/components/decimal/src/lib.rs index c756d4b8f57..0db54b7176f 100644 --- a/components/decimal/src/lib.rs +++ b/components/decimal/src/lib.rs @@ -119,6 +119,12 @@ pub struct FixedDecimalFormatter { symbols: DataPayload, } +impl AsRef for FixedDecimalFormatter { + fn as_ref(&self) -> &FixedDecimalFormatter { + self + } +} + impl FixedDecimalFormatter { icu_provider::gen_any_buffer_data_constructors!( diff --git a/components/experimental/src/dimension/mod.rs b/components/experimental/src/dimension/mod.rs index 9cb03b05690..3db81b6b7bf 100644 --- a/components/experimental/src/dimension/mod.rs +++ b/components/experimental/src/dimension/mod.rs @@ -5,5 +5,6 @@ //! Experimental. pub mod currency; +pub mod percent; pub mod provider; pub mod units; diff --git a/components/experimental/src/dimension/percent/format.rs b/components/experimental/src/dimension/percent/format.rs new file mode 100644 index 00000000000..40261f0047b --- /dev/null +++ b/components/experimental/src/dimension/percent/format.rs @@ -0,0 +1,222 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use fixed_decimal::{FixedDecimal, Sign}; +use icu_decimal::FixedDecimalFormatter; + +use crate::alloc::borrow::ToOwned; +use alloc::borrow::Cow; +use writeable::Writeable; + +use crate::dimension::provider::percent::PercentEssentialsV1; + +use super::options::{Display, PercentFormatterOptions}; + +struct Append(W1, W2); +// This allows us to combines two writeables together. +impl Writeable for Append { + fn write_to(&self, sink: &mut W) -> core::result::Result<(), core::fmt::Error> + where + W: core::fmt::Write + ?Sized, + { + self.0.write_to(sink)?; + self.1.write_to(sink) + } +} + +pub struct FormattedPercent<'l> { + pub(crate) value: &'l FixedDecimal, + pub(crate) essential: &'l PercentEssentialsV1<'l>, + pub(crate) options: &'l PercentFormatterOptions, + pub(crate) fixed_decimal_formatter: &'l FixedDecimalFormatter, +} + +impl<'l> Writeable for FormattedPercent<'l> { + fn write_to(&self, sink: &mut W) -> core::result::Result<(), core::fmt::Error> + where + W: core::fmt::Write + ?Sized, + { + // Removing the sign from the value + let abs_value = match self.value.sign() { + Sign::Negative => self.value.clone().with_sign(Sign::None), + _ => self.value.to_owned(), + }; + + let value = self.fixed_decimal_formatter.format(&abs_value); + + match self.options.display { + // In the Standard display, we take the unsigned pattern only when the value is positive. + Display::Standard => { + if self.value.sign() == Sign::Negative { + self.essential + .signed_pattern + .interpolate((value, &self.essential.minus_sign)) + .write_to(sink)? + } else { + self.essential + .unsigned_pattern + .interpolate([value]) + .write_to(sink)? + }; + } + Display::Approximate => { + let sign = if self.value.sign() == Sign::Negative { + // The approximate sign gets pre-pended + Append( + &self.essential.approximately_sign, + &self.essential.minus_sign, + ) + } else { + Append(&self.essential.approximately_sign, &Cow::Borrowed("")) + }; + + self.essential + .signed_pattern + .interpolate((value, sign)) + .write_to(sink)?; + } + Display::ExplicitSign => self + .essential + .signed_pattern + .interpolate(( + value, + if self.value.sign() == Sign::Negative { + &self.essential.minus_sign + } else { + &self.essential.plus_sign + }, + )) + .write_to(sink)?, + }; + + Ok(()) + } +} + +writeable::impl_display_with_writeable!(FormattedPercent<'_>); + +#[cfg(test)] +mod tests { + use icu_locale_core::locale; + use writeable::assert_writeable_eq; + + use crate::dimension::percent::{ + formatter::PercentFormatter, + options::{Display, PercentFormatterOptions}, + }; + + #[test] + pub fn test_en_us() { + let locale = locale!("en-US").into(); + // Positive case + let positive_value = "12345.67".parse().unwrap(); + let default_fmt = PercentFormatter::try_new(&locale, Default::default()).unwrap(); + let formatted_percent = default_fmt.format(&positive_value); + assert_writeable_eq!(formatted_percent, "12,345.67%"); + + // Negative case + let neg_value = "-12345.67".parse().unwrap(); + let formatted_percent = default_fmt.format(&neg_value); + assert_writeable_eq!(formatted_percent, "-12,345.67%"); + + // Approximate Case + let approx_value = "12345.67".parse().unwrap(); + let approx_fmt = PercentFormatter::try_new( + &locale, + PercentFormatterOptions { + display: Display::Approximate, + }, + ) + .unwrap(); + let formatted_percent = approx_fmt.format(&approx_value); + assert_writeable_eq!(formatted_percent, "~12,345.67%"); + + // ExplicitSign Case + let explicit_fmt = PercentFormatter::try_new( + &locale, + PercentFormatterOptions { + display: Display::ExplicitSign, + }, + ) + .unwrap(); + let formatted_percent = explicit_fmt.format(&positive_value); + assert_writeable_eq!(formatted_percent, "+12,345.67%"); + } + + #[test] + pub fn test_tr() { + let locale = locale!("tr").into(); + // Positive case + let positive_value = "12345.67".parse().unwrap(); + let default_fmt = PercentFormatter::try_new(&locale, Default::default()).unwrap(); + let formatted_percent = default_fmt.format(&positive_value); + assert_writeable_eq!(formatted_percent, "%12.345,67"); + + // Negative case + let neg_value = "-12345.67".parse().unwrap(); + let formatted_percent = default_fmt.format(&neg_value); + assert_writeable_eq!(formatted_percent, "-%12.345,67"); + + // Approximate Case + let approx_value = "12345.67".parse().unwrap(); + let approx_fmt = PercentFormatter::try_new( + &locale, + PercentFormatterOptions { + display: Display::Approximate, + }, + ) + .unwrap(); + let formatted_percent = approx_fmt.format(&approx_value); + assert_writeable_eq!(formatted_percent, "~%12.345,67"); + + // ExplicitSign Case + let explicit_fmt = PercentFormatter::try_new( + &locale, + PercentFormatterOptions { + display: Display::ExplicitSign, + }, + ) + .unwrap(); + let formatted_percent = explicit_fmt.format(&positive_value); + assert_writeable_eq!(formatted_percent, "+%12.345,67"); + } + + #[test] + pub fn test_blo() { + let locale = locale!("blo").into(); + // Positive case + let positive_value = "12345.67".parse().unwrap(); + let default_fmt = PercentFormatter::try_new(&locale, Default::default()).unwrap(); + let formatted_percent = default_fmt.format(&positive_value); + assert_writeable_eq!(formatted_percent, "%\u{a0}12\u{a0}345,67"); + + // Negative case + let neg_value = "-12345.67".parse().unwrap(); + let formatted_percent = default_fmt.format(&neg_value); + assert_writeable_eq!(formatted_percent, "%\u{a0}-12\u{a0}345,67"); + + // Approximate Case + let approx_value = "12345.67".parse().unwrap(); + let approx_fmt = PercentFormatter::try_new( + &locale, + PercentFormatterOptions { + display: Display::Approximate, + }, + ) + .unwrap(); + let formatted_percent = approx_fmt.format(&approx_value); + assert_writeable_eq!(formatted_percent, "%\u{a0}~12\u{a0}345,67"); + + // ExplicitSign Case + let explicit_fmt = PercentFormatter::try_new( + &locale, + PercentFormatterOptions { + display: Display::ExplicitSign, + }, + ) + .unwrap(); + let formatted_percent = explicit_fmt.format(&positive_value); + assert_writeable_eq!(formatted_percent, "%\u{a0}+12\u{a0}345,67"); + } +} diff --git a/components/experimental/src/dimension/percent/formatter.rs b/components/experimental/src/dimension/percent/formatter.rs new file mode 100644 index 00000000000..1253ffc76db --- /dev/null +++ b/components/experimental/src/dimension/percent/formatter.rs @@ -0,0 +1,169 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Experimental. + +use fixed_decimal::FixedDecimal; +use icu_decimal::options::FixedDecimalFormatterOptions; +use icu_decimal::FixedDecimalFormatter; +use icu_provider::{ + DataError, DataIdentifierBorrowed, DataLocale, DataPayload, DataProvider, DataRequest, +}; + +use super::super::provider::percent::PercentEssentialsV1Marker; +use super::format::FormattedPercent; +use super::options::PercentFormatterOptions; + +extern crate alloc; + +/// A formatter for percent values. +/// +/// [`PercentFormatter`] supports: +/// 1. Rendering in the locale's percent system. +pub struct PercentFormatter { + /// Essential data for the percent formatter. + essential: DataPayload, + + /// Options bag for the percent formatter to determine the behavior of the formatter. + options: PercentFormatterOptions, + + /// A fixed decimal formatter used to format the percent value. + fixed_decimal_formatter: R, +} + +impl PercentFormatter { + icu_provider::gen_any_buffer_data_constructors!( + (locale, options: PercentFormatterOptions) -> error: DataError, + functions: [ + try_new: skip, + try_new_with_any_provider, + try_new_with_buffer_provider, + try_new_unstable, + Self + ] + ); + + /// Creates a new [`PercentFormatter`] from compiled locale data and an options bag. + /// + /// ✨ *Enabled with the `compiled_data` Cargo feature.* + /// + /// [📚 Help choosing a constructor](icu_provider::constructors) + #[cfg(feature = "compiled_data")] + pub fn try_new( + locale: &DataLocale, + options: PercentFormatterOptions, + ) -> Result { + let fixed_decimal_formatter = + FixedDecimalFormatter::try_new(locale, FixedDecimalFormatterOptions::default())?; + + PercentFormatter::try_new_with_fixed_decimal_formatter( + locale, + fixed_decimal_formatter, + options, + ) + } + + #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)] + pub fn try_new_unstable( + provider: &D, + locale: &DataLocale, + options: PercentFormatterOptions, + ) -> Result + where + D: ?Sized + + DataProvider + + DataProvider, + { + let fixed_decimal_formatter = FixedDecimalFormatter::try_new_unstable( + provider, + locale, + FixedDecimalFormatterOptions::default(), + )?; + + PercentFormatter::try_new_with_fixed_decimal_formatter_unstable( + provider, + locale, + fixed_decimal_formatter, + options, + ) + } + + /// Formats a [`FixedDecimal`] value for the given percent code. + /// + /// # Examples + /// ``` + /// use icu::experimental::dimension::percent::formatter::{ + /// PercentFormatter, + /// }; + /// use icu::locale::locale; + /// use writeable::Writeable; + /// + /// let locale = locale!("en-US").into(); + /// let fmt = PercentFormatter::try_new(&locale, Default::default()).unwrap(); + /// let value = "12345.67".parse().unwrap(); + /// let formatted_percent = fmt.format(&value); + /// let mut sink = String::new(); + /// formatted_percent.write_to(&mut sink).unwrap(); + /// assert_eq!(sink.as_str(), "12,345.67%"); + /// ``` + pub fn format<'l>(&'l self, value: &'l FixedDecimal) -> FormattedPercent<'l> { + FormattedPercent { + value, + essential: self.essential.get(), + fixed_decimal_formatter: &self.fixed_decimal_formatter, + options: &self.options, + } + } +} + +impl PercentFormatter +where + R: AsRef, +{ + /// Creates a new [`PercentFormatter`] from compiled locale data, an options bag and fixed decimal formatter. + /// + /// ✨ *Enabled with the `compiled_data` Cargo feature.* + /// + /// [📚 Help choosing a constructor](icu_provider::constructors) + #[cfg(feature = "compiled_data")] + pub fn try_new_with_fixed_decimal_formatter( + locale: &DataLocale, + fixed_decimal_formatter: R, + options: PercentFormatterOptions, + ) -> Result { + let essential = crate::provider::Baked + .load(DataRequest { + id: DataIdentifierBorrowed::for_locale(locale), + ..Default::default() + })? + .payload; + + Ok(Self { + essential, + options, + fixed_decimal_formatter, + }) + } + + #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)] + pub fn try_new_with_fixed_decimal_formatter_unstable( + provider: &(impl DataProvider + ?Sized), + locale: &DataLocale, + fixed_decimal_formatter: R, + options: PercentFormatterOptions, + ) -> Result { + let essential = provider + .load(DataRequest { + id: DataIdentifierBorrowed::for_locale(locale), + ..Default::default() + })? + .payload; + + Ok(Self { + essential, + options, + fixed_decimal_formatter, + }) + } +} diff --git a/components/experimental/src/dimension/percent/mod.rs b/components/experimental/src/dimension/percent/mod.rs new file mode 100644 index 00000000000..c81b3432259 --- /dev/null +++ b/components/experimental/src/dimension/percent/mod.rs @@ -0,0 +1,9 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Experimental. + +pub mod format; +pub mod formatter; +pub mod options; diff --git a/components/experimental/src/dimension/percent/options.rs b/components/experimental/src/dimension/percent/options.rs new file mode 100644 index 00000000000..8630bdc31c6 --- /dev/null +++ b/components/experimental/src/dimension/percent/options.rs @@ -0,0 +1,43 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Options for [`PercentFormatter`](crate::dimension::percent::formatter::PercentFormatter). + +/// A collection of configuration options that determine the formatting behavior of +/// [`PercentFormatter`](crate::dimension::percent::formatter::PercentFormatter). +#[derive(Copy, Debug, Eq, PartialEq, Clone, Default)] +#[non_exhaustive] +pub struct PercentFormatterOptions { + /// The display of the percent format. + pub display: Display, +} + +impl From for PercentFormatterOptions { + fn from(display: Display) -> Self { + Self { display } + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[non_exhaustive] +pub enum Display { + /// Format the Percent to display with the standard formatting for the locale. + /// + /// For example 123 -> 123% in en-US. + Standard, + /// Format the Percent to display as an approximate value. + /// + /// For example 123 -> ~123% in en-US. + Approximate, + /// Format the Percent to display with an explicit sign. + /// + /// For example 123 -> +123% in en-US. + ExplicitSign, +} + +impl Default for Display { + fn default() -> Self { + Self::Standard + } +} diff --git a/components/experimental/src/dimension/provider/percent.rs b/components/experimental/src/dimension/provider/percent.rs index 24e2b72137e..01128c3040d 100644 --- a/components/experimental/src/dimension/provider/percent.rs +++ b/components/experimental/src/dimension/provider/percent.rs @@ -10,56 +10,50 @@ //! Read more about data providers: [`icu_provider`] use alloc::borrow::Cow; +use icu_pattern::{DoublePlaceholderPattern, SinglePlaceholderPattern}; use icu_provider::prelude::*; +#[cfg(feature = "compiled_data")] +/// Baked data +/// +///
+/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. In particular, the `DataProvider` implementations are only +/// guaranteed to match with this version's `*_unstable` providers. Use with caution. +///
+pub use crate::provider::Baked; + #[icu_provider::data_struct(PercentEssentialsV1Marker = "percent/essentials@1")] -#[derive(Default, Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] #[cfg_attr( feature = "datagen", derive(serde::Serialize, databake::Bake), databake(path = icu_experimental::dimension::provider::percent), )] #[cfg_attr(feature = "serde", derive(serde::Deserialize))] +/// A struct including the essentials to create a Percent. +/// +/// If an `approximate` or `explicit plus` are required, use the negative pattern as explained below: +/// +/// pub struct PercentEssentialsV1<'data> { - /// The index of the number placeholder in the standard pattern. - pub number_index: u8, - - /// Prefix and suffix to apply to a percent sign when needed. #[cfg_attr(feature = "serde", serde(borrow))] - pub percent_sign_affixes: PercentAffixesV1<'data>, + /// Represents the standard pattern for signed percents. + /// NOTE: place holder 0 is the place of the percent value. + /// place holder 1 is the place of the plus, minus, or approximate signs. + pub signed_pattern: DoublePlaceholderPattern>, - /// The percent symbol. #[cfg_attr(feature = "serde", serde(borrow))] - pub percent_sign_symbol: Cow<'data, str>, - - /// The index of the percent symbol in the standard pattern. - pub percent_symbol_index: u8, + /// Represents the standard pattern for unsigned percents. + pub unsigned_pattern: SinglePlaceholderPattern>, - /// Represents the standard pattern. #[cfg_attr(feature = "serde", serde(borrow))] - pub standard: Cow<'data, str>, -} - -/// A collection of strings to affix to a percent number. -/// -///
-/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -///
-#[derive(Default, Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr( - feature = "datagen", - derive(serde::Serialize, databake::Bake), - databake(path = icu_experimental::dimension::provider::percent), -)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -pub struct PercentAffixesV1<'data> { - /// String to prepend before the percent sign. + /// The localize approximate sign. + pub approximately_sign: Cow<'data, str>, #[cfg_attr(feature = "serde", serde(borrow))] - pub prefix: Cow<'data, str>, - - /// String to append after the percent sign. + /// The localize minus sign. + pub minus_sign: Cow<'data, str>, #[cfg_attr(feature = "serde", serde(borrow))] - pub suffix: Cow<'data, str>, + /// The localize plus sign. + pub plus_sign: Cow<'data, str>, } diff --git a/provider/data/experimental/data/percent_essentials_v1_marker.rs.data b/provider/data/experimental/data/percent_essentials_v1_marker.rs.data index 6c6e265754b..67f3fb2e8b2 100644 --- a/provider/data/experimental/data/percent_essentials_v1_marker.rs.data +++ b/provider/data/experimental/data/percent_essentials_v1_marker.rs.data @@ -4,8 +4,8 @@ /// `icu`'s `_unstable` constructors. /// /// Using this implementation will embed the following data in the binary's data segment: -/// * 267B for the lookup data structure (59 data identifiers) -/// * 1035B[^1] for the actual data (9 unique structs) +/// * 276B for the lookup data structure (60 data identifiers) +/// * 2945B[^1] for the actual data (22 unique structs) /// /// [^1]: these numbers can be smaller in practice due to linker deduplication #[doc(hidden)] @@ -16,7 +16,7 @@ macro_rules! __impl_percent_essentials_v1_marker { const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; #[clippy::msrv = "1.70"] impl $provider { - const DATA_PERCENT_ESSENTIALS_V1_MARKER: icu_provider_baked::zerotrie::Data = icu_provider_baked::zerotrie::Data { trie: icu_provider_baked::zerotrie::ZeroTrieSimpleAscii { store: b"\xD4abcdefghklmnopqrstux\x0E\x1D&9_lr|~\x84\x86\x8D\x8F\x91\x93\x9C\xA8\xBD\xC0\xC2rs\t\x80-S\xC2AO\x01\x81\x81\x82\xC4elnr\x01\x03\x04\x83o\x84\x82\x83x\x82\xC3asv\x01\x02\x83\x83\x83\xC3aes\x01\x0B\x83\x83-\xC2CL\x02H\x85I\x85b\x83\xC3nsu\x19\x1F-\xC5ADFIS\x02\x08\n\x0CT\x83\xC2EK\x01\x83\x83I\x83N\x82E\x83\x83-419\x85\x86\xC3ior\x01\x02\x83\x83\x83-CH\x85\xC2lu\x01\x83\x82\xC3irs\x01\x02\x82\x83b\x83u\x87\xC2bt\x01\x83\x83k\x83\xC2do\x02s\x83\x83c\x88a\x82u\x83\xC3mou\x01\x02\x83\x83\x83\xC4aklv\x01\x02\x03\x82\x83\x83\x83\xC4akrt\n\x0B\x0C\x82-\xC2MS\x02Y\x85G\x85\x83\x87\x83nd\x85nr\x82" }, values: &[icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 0u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed(""), suffix: alloc::borrow::Cow::Borrowed("") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("\u{200e}%\u{200e}"), percent_symbol_index: 5u8, standard: alloc::borrow::Cow::Borrowed("#,##0%") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 0u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed(""), suffix: alloc::borrow::Cow::Borrowed("") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("٪"), percent_symbol_index: 5u8, standard: alloc::borrow::Cow::Borrowed("#,##0%") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 0u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed(""), suffix: alloc::borrow::Cow::Borrowed("") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("%"), percent_symbol_index: 8u8, standard: alloc::borrow::Cow::Borrowed("#,##,##0%") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 0u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed("\u{a0}"), suffix: alloc::borrow::Cow::Borrowed("") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("%"), percent_symbol_index: 7u8, standard: alloc::borrow::Cow::Borrowed("#,##0\u{a0}%") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 3u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed(""), suffix: alloc::borrow::Cow::Borrowed("\u{a0}") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("%"), percent_symbol_index: 0u8, standard: alloc::borrow::Cow::Borrowed("%\u{a0}#,#0;%\u{a0}-#,#0") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 0u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed(""), suffix: alloc::borrow::Cow::Borrowed("") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("%"), percent_symbol_index: 5u8, standard: alloc::borrow::Cow::Borrowed("#,##0%") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 3u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed(""), suffix: alloc::borrow::Cow::Borrowed("\u{a0}") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("%"), percent_symbol_index: 0u8, standard: alloc::borrow::Cow::Borrowed("%\u{a0}#,##0") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 1u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed(""), suffix: alloc::borrow::Cow::Borrowed("") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("%"), percent_symbol_index: 0u8, standard: alloc::borrow::Cow::Borrowed("%#,##0") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { number_index: 0u8, percent_sign_affixes: icu::experimental::dimension::provider::percent::PercentAffixesV1 { prefix: alloc::borrow::Cow::Borrowed("\u{202f}"), suffix: alloc::borrow::Cow::Borrowed("") }, percent_sign_symbol: alloc::borrow::Cow::Borrowed("%"), percent_symbol_index: 8u8, standard: alloc::borrow::Cow::Borrowed("#,##0\u{202f}%") }] }; + const DATA_PERCENT_ESSENTIALS_V1_MARKER: icu_provider_baked::zerotrie::Data = icu_provider_baked::zerotrie::Data { trie: icu_provider_baked::zerotrie::ZeroTrieSimpleAscii { store: b"\xD5abcdefghjklmnopqrstuy\n\x17 3Xlnxz\x80\x87\x89\x95\x98\x9A\x9C\xA6\xB2\xBB\xC2r\x80-S\xC2AO\x01\x81\x81\xC4elrs\x01\x03\x04\x82o\x83\x84\x85\xC3asv\x01\x02\x84\x84\x84\xC3aes\x01\x0B\x84\x82-\xC2CL\x02H\x85I\x85b\x82\xC4nstu\x15\x1B\x1C-\xC4ADFS\x02\x08\nT\x84\xC2EK\x01\x84\x84I\x84E\x84\x84-419\x86\x87\x88\xC4aior\x01\x02\x03\x89\x8A\x8A\x8B-C\xC2AH\x01\x82\x8Cl\x84\xC3ers\x01\x02\x8D\x8Ab\x82a\x8E\xC2au\x01\x85\x8F\xC2bt\x01\x84\x90\0k\x82\xC3dno\x02\x04s\x84\x90\x01\x90\x02c\x90\x03s\x89u\x84\xC3mou\x02\x03\x90\x01\x84\x82\xC4klqv\x01\x02\x03\x84\x8A\x85\x8A\xC3krt\x01\x02\x84\x8F\x84\xC2nr\x02d\x86\x8Do\x90\x04-BJ\x90\x05" }, values: &[icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{200e}%\u{200e}")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{200e}%\u{200e}")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("\u{200e}-"), plus_sign: alloc::borrow::Cow::Borrowed("\u{200e}+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}٪")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}٪")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("\u{200e}-"), plus_sign: alloc::borrow::Cow::Borrowed("\u{200e}+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{a0}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{a0}%")), approximately_sign: alloc::borrow::Cow::Borrowed("≈"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\t\u{8}%\u{a0}")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{4}%\u{a0}")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{a0}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{a0}%")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("≈"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("≈"), minus_sign: alloc::borrow::Cow::Borrowed("−"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{8}%\u{a0}")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{4}%\u{a0}")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("−"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("\u{200e}−"), plus_sign: alloc::borrow::Cow::Borrowed("\u{200e}+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{a0}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{a0}%")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("−"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{a0}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{a0}%")), approximately_sign: alloc::borrow::Cow::Borrowed("≃"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("≃"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("\u{200e}-"), plus_sign: alloc::borrow::Cow::Borrowed("\u{200e}+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("約"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{4}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{2}%")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{a0}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{a0}%")), approximately_sign: alloc::borrow::Cow::Borrowed("∼"), minus_sign: alloc::borrow::Cow::Borrowed("−"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{a0}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{a0}%")), approximately_sign: alloc::borrow::Cow::Borrowed("≈"), minus_sign: alloc::borrow::Cow::Borrowed("−"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{a0}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{a0}%")), approximately_sign: alloc::borrow::Cow::Borrowed("ca."), minus_sign: alloc::borrow::Cow::Borrowed("−"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}\u{202f}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}\u{202f}%")), approximately_sign: alloc::borrow::Cow::Borrowed("~"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("dáàṣì"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }, icu::experimental::dimension::provider::percent::PercentEssentialsV1 { signed_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{3}\u{2}%")), unsigned_pattern: icu_pattern::Pattern::::from_store_unchecked(alloc::borrow::Cow::Borrowed("\u{1}%")), approximately_sign: alloc::borrow::Cow::Borrowed("dáàshì"), minus_sign: alloc::borrow::Cow::Borrowed("-"), plus_sign: alloc::borrow::Cow::Borrowed("+") }] }; } #[clippy::msrv = "1.70"] impl icu_provider::DataProvider for $provider { diff --git a/provider/data/experimental/fingerprints.csv b/provider/data/experimental/fingerprints.csv index d45825f2a34..9c1e435121a 100644 --- a/provider/data/experimental/fingerprints.csv +++ b/provider/data/experimental/fingerprints.csv @@ -1588,67 +1588,68 @@ duration/digital@1, sr-Latn, 33B, -> da duration/digital@1, su, 33B, -> da duration/digital@1, tk, 33B, 52bd330c6674d78 duration/digital@1, und, 33B, 5031d069e9fdd05c -percent/essentials@1, , 267B, 59 identifiers -percent/essentials@1, , 1035B, 9 unique payloads -percent/essentials@1, ar, 117B, 8ebf290af62091f -percent/essentials@1, ar-SA, 112B, ecd0b989802662bd -percent/essentials@1, ar-SO, 112B, -> ar-SA -percent/essentials@1, as, 114B, b4a6277fe6669d66 -percent/essentials@1, be, 115B, 54dc1327d49df2d7 -percent/essentials@1, blo, 123B, 32bdbf88ad60f974 -percent/essentials@1, bn, 114B, -> as -percent/essentials@1, br, 115B, -> be -percent/essentials@1, brx, 114B, -> as -percent/essentials@1, ca, 115B, -> be -percent/essentials@1, cs, 115B, -> be -percent/essentials@1, cv, 115B, -> be -percent/essentials@1, da, 115B, -> be -percent/essentials@1, de, 115B, -> be -percent/essentials@1, de-CH, 111B, 9db4866484555169 -percent/essentials@1, de-LI, 111B, -> de-CH -percent/essentials@1, dsb, 115B, -> be -percent/essentials@1, en-AT, 115B, -> be -percent/essentials@1, en-DE, 115B, -> be -percent/essentials@1, en-DK, 115B, -> be -percent/essentials@1, en-FI, 115B, -> be -percent/essentials@1, en-IN, 114B, -> as -percent/essentials@1, en-SE, 115B, -> be -percent/essentials@1, es, 115B, -> be -percent/essentials@1, es-419, 111B, -> de-CH -percent/essentials@1, eu, 115B, 6b84ba314c244989 -percent/essentials@1, fi, 115B, -> be -percent/essentials@1, fo, 115B, -> be -percent/essentials@1, fr, 115B, -> be -percent/essentials@1, fr-CH, 111B, -> de-CH -percent/essentials@1, gl, 115B, -> be -percent/essentials@1, gu, 114B, -> as -percent/essentials@1, hi, 114B, -> as -percent/essentials@1, hr, 115B, -> be -percent/essentials@1, hsb, 115B, -> be -percent/essentials@1, ku, 111B, 9bd8c79ed3eb8cb2 -percent/essentials@1, lb, 115B, -> be -percent/essentials@1, lt, 115B, -> be -percent/essentials@1, mk, 115B, -> be -percent/essentials@1, nds, 115B, -> be -percent/essentials@1, no, 115B, -> be -percent/essentials@1, oc, 117B, cae723fba37be8aa -percent/essentials@1, pa, 114B, -> as -percent/essentials@1, qu, 115B, -> be -percent/essentials@1, rm, 115B, -> be -percent/essentials@1, ro, 115B, -> be -percent/essentials@1, ru, 115B, -> be -percent/essentials@1, sa, 114B, -> as -percent/essentials@1, sk, 115B, -> be -percent/essentials@1, sl, 115B, -> be -percent/essentials@1, sv, 115B, -> be -percent/essentials@1, ta, 114B, -> as -percent/essentials@1, ta-MY, 111B, -> de-CH -percent/essentials@1, ta-SG, 111B, -> de-CH -percent/essentials@1, tk, 115B, -> be -percent/essentials@1, tr, 111B, -> ku -percent/essentials@1, tt, 115B, -> be -percent/essentials@1, und, 111B, -> de-CH -percent/essentials@1, xnr, 114B, -> as +percent/essentials@1, , 276B, 60 identifiers +percent/essentials@1, , 2945B, 22 unique payloads +percent/essentials@1, ar, 146B, edc3be8e2018c220 +percent/essentials@1, ar-SA, 136B, beaef11f50f18d14 +percent/essentials@1, ar-SO, 136B, -> ar-SA +percent/essentials@1, be, 134B, 270549dbb73b8d1b +percent/essentials@1, blo, 132B, c76e9fad67137e99 +percent/essentials@1, br, 132B, 6f5a7b80e9a1355e +percent/essentials@1, bs, 130B, d462e9d702d2400a +percent/essentials@1, ca, 132B, -> br +percent/essentials@1, cs, 132B, -> br +percent/essentials@1, cv, 132B, -> br +percent/essentials@1, da, 132B, -> br +percent/essentials@1, de, 134B, -> be +percent/essentials@1, de-CH, 130B, -> bs +percent/essentials@1, de-LI, 130B, -> bs +percent/essentials@1, dsb, 134B, -> be +percent/essentials@1, en-AT, 132B, -> br +percent/essentials@1, en-DE, 132B, -> br +percent/essentials@1, en-DK, 132B, -> br +percent/essentials@1, en-FI, 132B, -> br +percent/essentials@1, en-SE, 132B, -> br +percent/essentials@1, es, 132B, -> br +percent/essentials@1, es-419, 128B, 489fbe892a946316 +percent/essentials@1, et, 132B, 847b6d1f74bfaca6 +percent/essentials@1, eu, 134B, e83b63d8295277af +percent/essentials@1, fa, 136B, 37c9a88a44182abb +percent/essentials@1, fi, 134B, c222e3d560ec5bf3 +percent/essentials@1, fo, 134B, -> fi +percent/essentials@1, fr, 134B, 3a1b6cdd5712814c +percent/essentials@1, fr-CA, 134B, -> be +percent/essentials@1, fr-CH, 130B, 74d2a508f94ce38d +percent/essentials@1, gl, 132B, -> br +percent/essentials@1, he, 134B, 922d1c049b2b8a0b +percent/essentials@1, hr, 134B, -> fi +percent/essentials@1, hsb, 134B, -> be +percent/essentials@1, ja, 130B, 21b9afaa9a8d39d +percent/essentials@1, ka, 130B, -> bs +percent/essentials@1, ku, 128B, d2eec7fa00e8b201 +percent/essentials@1, lb, 132B, -> br +percent/essentials@1, lt, 136B, 42a22e9a836a777f +percent/essentials@1, mk, 134B, -> be +percent/essentials@1, nds, 132B, -> br +percent/essentials@1, nn, 136B, ede3aabd9b4d2262 +percent/essentials@1, no, 136B, 9f71e46a67f4fc26 +percent/essentials@1, oc, 134B, c8d341ba634aa3de +percent/essentials@1, ps, 136B, -> fa +percent/essentials@1, qu, 132B, -> br +percent/essentials@1, rm, 136B, -> nn +percent/essentials@1, ro, 132B, -> br +percent/essentials@1, ru, 134B, -> be +percent/essentials@1, sk, 132B, -> br +percent/essentials@1, sl, 134B, -> fi +percent/essentials@1, sq, 130B, -> bs +percent/essentials@1, sv, 134B, -> fi +percent/essentials@1, tk, 132B, -> br +percent/essentials@1, tr, 128B, -> ku +percent/essentials@1, tt, 132B, -> br +percent/essentials@1, und, 128B, -> es-419 +percent/essentials@1, ur, 134B, -> he +percent/essentials@1, yo, 137B, 32944bd377e74c43 +percent/essentials@1, yo-BJ, 136B, c0cc5111253e1ab7 personnames/personnames@1, , 652B, 131 identifiers personnames/personnames@1, , 313398B, 127 unique payloads personnames/personnames@1, af, 2123B, 5acdc79f93e47b40 diff --git a/provider/source/data/debug/percent/essentials@1/ar-EG.json b/provider/source/data/debug/percent/essentials@1/ar-EG.json index 00bc7247192..7a8f4f5eeaa 100644 --- a/provider/source/data/debug/percent/essentials@1/ar-EG.json +++ b/provider/source/data/debug/percent/essentials@1/ar-EG.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "‎%‎", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "‎%‎" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "‎%‎" + } + ], + "approximately_sign": "~", + "minus_sign": "‎-", + "plus_sign": "‎+" } diff --git a/provider/source/data/debug/percent/essentials@1/ar.json b/provider/source/data/debug/percent/essentials@1/ar.json index 00bc7247192..7a8f4f5eeaa 100644 --- a/provider/source/data/debug/percent/essentials@1/ar.json +++ b/provider/source/data/debug/percent/essentials@1/ar.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "‎%‎", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "‎%‎" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "‎%‎" + } + ], + "approximately_sign": "~", + "minus_sign": "‎-", + "plus_sign": "‎+" } diff --git a/provider/source/data/debug/percent/essentials@1/bn.json b/provider/source/data/debug/percent/essentials@1/bn.json index e36d98f5a9a..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/bn.json +++ b/provider/source/data/debug/percent/essentials@1/bn.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 8, - "standard": "#,##,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/ccp.json b/provider/source/data/debug/percent/essentials@1/ccp.json index e36d98f5a9a..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/ccp.json +++ b/provider/source/data/debug/percent/essentials@1/ccp.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 8, - "standard": "#,##,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/en-001.json b/provider/source/data/debug/percent/essentials@1/en-001.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/en-001.json +++ b/provider/source/data/debug/percent/essentials@1/en-001.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/en-ZA.json b/provider/source/data/debug/percent/essentials@1/en-ZA.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/en-ZA.json +++ b/provider/source/data/debug/percent/essentials@1/en-ZA.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/en.json b/provider/source/data/debug/percent/essentials@1/en.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/en.json +++ b/provider/source/data/debug/percent/essentials@1/en.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/es-AR.json b/provider/source/data/debug/percent/essentials@1/es-AR.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/es-AR.json +++ b/provider/source/data/debug/percent/essentials@1/es-AR.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/es.json b/provider/source/data/debug/percent/essentials@1/es.json index 933d63e6fcf..ecee649198d 100644 --- a/provider/source/data/debug/percent/essentials@1/es.json +++ b/provider/source/data/debug/percent/essentials@1/es.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": " ", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 7, - "standard": "#,##0 %" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": " %" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": " %" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/fil.json b/provider/source/data/debug/percent/essentials@1/fil.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/fil.json +++ b/provider/source/data/debug/percent/essentials@1/fil.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/fr.json b/provider/source/data/debug/percent/essentials@1/fr.json index 933d63e6fcf..0cc8a4d5a33 100644 --- a/provider/source/data/debug/percent/essentials@1/fr.json +++ b/provider/source/data/debug/percent/essentials@1/fr.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": " ", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 7, - "standard": "#,##0 %" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": " %" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": " %" + } + ], + "approximately_sign": "≃", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/ja.json b/provider/source/data/debug/percent/essentials@1/ja.json index 9cce63b0e1d..96c90a6c067 100644 --- a/provider/source/data/debug/percent/essentials@1/ja.json +++ b/provider/source/data/debug/percent/essentials@1/ja.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "約", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/ru.json b/provider/source/data/debug/percent/essentials@1/ru.json index 933d63e6fcf..3086faed1e0 100644 --- a/provider/source/data/debug/percent/essentials@1/ru.json +++ b/provider/source/data/debug/percent/essentials@1/ru.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": " ", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 7, - "standard": "#,##0 %" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": " %" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": " %" + } + ], + "approximately_sign": "≈", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/sr-Latn.json b/provider/source/data/debug/percent/essentials@1/sr-Latn.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/sr-Latn.json +++ b/provider/source/data/debug/percent/essentials@1/sr-Latn.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/sr.json b/provider/source/data/debug/percent/essentials@1/sr.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/sr.json +++ b/provider/source/data/debug/percent/essentials@1/sr.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/th.json b/provider/source/data/debug/percent/essentials@1/th.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/th.json +++ b/provider/source/data/debug/percent/essentials@1/th.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/tr.json b/provider/source/data/debug/percent/essentials@1/tr.json index d45bc796186..c353cb83ce7 100644 --- a/provider/source/data/debug/percent/essentials@1/tr.json +++ b/provider/source/data/debug/percent/essentials@1/tr.json @@ -1,10 +1,24 @@ { - "number_index": 1, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 0, - "standard": "%#,##0" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Literal": "%" + }, + { + "Placeholder": "Place0" + } + ], + "unsigned_pattern": [ + { + "Literal": "%" + }, + { + "Placeholder": "Singleton" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/data/debug/percent/essentials@1/und.json b/provider/source/data/debug/percent/essentials@1/und.json index 9cce63b0e1d..963e0e43124 100644 --- a/provider/source/data/debug/percent/essentials@1/und.json +++ b/provider/source/data/debug/percent/essentials@1/und.json @@ -1,10 +1,24 @@ { - "number_index": 0, - "percent_sign_affixes": { - "prefix": "", - "suffix": "" - }, - "percent_sign_symbol": "%", - "percent_symbol_index": 5, - "standard": "#,##0%" + "signed_pattern": [ + { + "Placeholder": "Place1" + }, + { + "Placeholder": "Place0" + }, + { + "Literal": "%" + } + ], + "unsigned_pattern": [ + { + "Placeholder": "Singleton" + }, + { + "Literal": "%" + } + ], + "approximately_sign": "~", + "minus_sign": "-", + "plus_sign": "+" } diff --git a/provider/source/src/cldr_serde/numbers.rs b/provider/source/src/cldr_serde/numbers.rs index 824d93460cc..11a38513d6d 100644 --- a/provider/source/src/cldr_serde/numbers.rs +++ b/provider/source/src/cldr_serde/numbers.rs @@ -15,6 +15,8 @@ use std::collections::HashMap; #[derive(PartialEq, Debug, Deserialize)] pub(crate) struct Symbols { // This list is not comprehensive; add more fields when needed + #[serde(rename = "approximatelySign")] + pub(crate) approximately_sign: String, pub(crate) decimal: String, pub(crate) group: String, #[serde(rename = "minusSign")] diff --git a/provider/source/src/percent/mod.rs b/provider/source/src/percent/mod.rs index 92dd1cfe491..35b6417c240 100644 --- a/provider/source/src/percent/mod.rs +++ b/provider/source/src/percent/mod.rs @@ -2,6 +2,7 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use std::borrow::Cow; use std::collections::HashSet; use crate::cldr_serde; @@ -9,6 +10,11 @@ use crate::IterableDataProviderCached; use crate::SourceDataProvider; use icu::experimental::dimension::provider::percent::*; +use icu_pattern::DoublePlaceholder; +use icu_pattern::DoublePlaceholderPattern; +use icu_pattern::Pattern; +use icu_pattern::SinglePlaceholder; +use icu_pattern::SinglePlaceholderPattern; use icu_provider::prelude::*; use icu_provider::DataProvider; @@ -64,12 +70,125 @@ fn extract_percent_essentials<'data>( .get("latn") .ok_or_else(|| DataError::custom("Could not find the percent symbol"))?; - let standard_pattern = &percent_patterns.standard; + let localized_approximately_sign = symbols.approximately_sign.to_owned(); + let localized_minus_sign = symbols.minus_sign.to_owned(); + let localized_percent_sign = symbols.percent_sign.to_owned(); + let localized_plus_sign = symbols.plus_sign.to_owned(); - let percent_sign = '%'; - let percent_sign_index = standard_pattern.find(percent_sign).unwrap(); - let first_num_index = standard_pattern.find(['0', '#']).unwrap(); - let last_num_index = standard_pattern.rfind(['0', '#']).unwrap(); + let standard_pattern = percent_patterns.standard.to_owned(); + + let mut split = standard_pattern.split(';'); + let unsigned_pattern = split.next().unwrap(); + + let signed_pattern: Cow = match split.next() { + Some(negative) => Cow::Borrowed(negative), + None if standard_pattern.contains('-') => Cow::Borrowed(&standard_pattern), + // When there is no explicit negative subpattern, + // an implicit negative subpattern is formed from the positive pattern with a prefixed "-" + // Ex: "#,##0%" -> "-#,##0%" || "% #,##0" -> "-% #,##0" + None => Cow::Owned(String::from("-") + &standard_pattern), + }; + + Ok(PercentEssentialsV1 { + unsigned_pattern: create_unsigned_pattern(unsigned_pattern, &localized_percent_sign)?, + signed_pattern: create_signed_pattern(&signed_pattern, &localized_percent_sign)?, + approximately_sign: localized_approximately_sign.into(), + minus_sign: localized_minus_sign.into(), + plus_sign: localized_plus_sign.into(), + }) +} + +/// Used to create a percent pattern for negative, approximate, or explicit plus. +fn create_signed_pattern<'a>( + pattern: &str, + localized_percent_sign: &str, +) -> Result>, DataError> { + // While all locales use the `%`, some include non-breaking spaces. + // Hence using the literal `%` char here. + let percent_pattern_index = pattern.find('%').unwrap(); + let first_num_pattern_index = pattern.find(['0', '#']).unwrap(); + let last_num_pattern_index = pattern.rfind(['0', '#']).unwrap(); + let sign_pattern_index = pattern.rfind(['-']).unwrap(); + + // Grab all the indexes + let mut symbol_indexes = [ + sign_pattern_index, + percent_pattern_index, + first_num_pattern_index, + ]; + // Sort them to get the correct order + symbol_indexes.sort(); + + // For the prefix, if the first character is a percent sign, then we have no prefix. + // If the percent sign is first, then all characters before the percent sign are the prefix. + // If the percent comes after, then all characters between final number and the percent sign are the prefix. + let percent_prefix = if percent_pattern_index == 0 { + "" + } else if percent_pattern_index < first_num_pattern_index + || percent_pattern_index < sign_pattern_index + { + let next_symbol_index = std::cmp::min(first_num_pattern_index, sign_pattern_index); + &pattern[0..next_symbol_index] + } else { + &pattern[last_num_pattern_index + 1..percent_pattern_index] + }; + + // Index of the percent symbol inside the symbols vec. + // Not to be confused with the index inside the pattern. + let precent_symbol_index = symbol_indexes + .iter() + .position(|&i| i == percent_pattern_index) + .unwrap(); + + // If there are more symbols following the percent, then get all chars between. + // Otherwise we're the last symbol, so get all chars until end of string + let percent_suffix: &str = if symbol_indexes.len() > precent_symbol_index + 1 { + let next_symbol_index = symbol_indexes.get(precent_symbol_index + 1).unwrap(); + &pattern[percent_pattern_index + 1..next_symbol_index.to_owned()] + } else { + &pattern[(percent_pattern_index + 1)..] + }; + + // Combine the prefix, localized sign, and suffix to create the localized symbol. + let percent_symbol = format!("{percent_prefix}{localized_percent_sign}{percent_suffix}"); + + let pattern_vec: Vec<&str> = symbol_indexes + .into_iter() + .map(|index| { + if index == percent_pattern_index { + return percent_symbol.as_str(); + } + if index == sign_pattern_index { + return "{1}"; + } + + "{0}" + }) + .collect(); + + // Example: "#,##0%", "#,##0 %", "%#,##0", "% #,##0" + let pattern = pattern_vec + .concat() + .parse::>() + .map_err(|e| DataError::custom("Could not parse pattern").with_display_context(&e))?; + + let pattern: Pattern> = + Pattern::from_store_unchecked(Cow::Owned(pattern.take_store())); + + Ok(pattern) +} + +/// Used only for positive percents. +/// If you need an approximate, explicit plus, or negative percent, use the negative pattern. +fn create_unsigned_pattern<'a>( + pattern: &str, + localized_percent_sign: &str, +) -> Result>, DataError> { + // While all locales use the `%`, some include non-breaking spaces. + // Hence using the literal `%` char here. + let percent_sign_index = pattern.find('%').unwrap(); + let first_num_index = pattern.find(['0', '#']).unwrap(); + let last_num_index = pattern.rfind(['0', '#']).unwrap(); // For the prefix, if the first character is a percent sign, then we have no prefix. // If the percent sign is first, then all characters before the percent sign are the prefix. @@ -77,36 +196,42 @@ fn extract_percent_essentials<'data>( let percent_prefix = if percent_sign_index == 0 { "" } else if percent_sign_index < first_num_index { - &standard_pattern[0..percent_sign_index] + &pattern[0..percent_sign_index] } else { - &standard_pattern[last_num_index + 1..percent_sign_index] + &pattern[last_num_index + 1..percent_sign_index] }; // For the suffix, if the first character is a percent sign, OR the percent sign is before the first number, // then all characters between are the suffix. // If the percent sign comes after the first number, then all proceeding characters are the suffix. let percent_suffix = if percent_sign_index == 0 || percent_sign_index < first_num_index { - &standard_pattern[1..first_num_index] + &pattern[1..first_num_index] } else { - &standard_pattern[percent_sign_index + 1..] + &pattern[percent_sign_index + 1..] }; - Ok(PercentEssentialsV1 { - standard: standard_pattern.to_owned().into(), - percent_sign_symbol: symbols.percent_sign.to_owned().into(), - percent_symbol_index: percent_sign_index as u8, - number_index: first_num_index as u8, - percent_sign_affixes: PercentAffixesV1 { - prefix: percent_prefix.to_owned().into(), - suffix: percent_suffix.to_owned().into(), - }, - }) + let percent_symbol = String::new() + percent_prefix + localized_percent_sign + percent_suffix; + + // Example: "#,##0%", "#,##0 %", "%#,##0", "% #,##0" + let pattern = if percent_sign_index > first_num_index { + "{0}".to_owned() + &percent_symbol + } else { + percent_symbol + "{0}" + } + .parse::>() + .map_err(|e| DataError::custom("Could not parse pattern").with_display_context(&e))?; + + let pattern: Pattern> = + Pattern::from_store_unchecked(Cow::Owned(pattern.take_store())); + + Ok(pattern) } #[test] fn test_basic() { use icu::experimental::dimension::provider::percent::*; use icu::locale::langid; + use writeable::assert_writeable_eq; let provider = SourceDataProvider::new_testing(); @@ -117,40 +242,10 @@ fn test_basic() { }) .unwrap(); - assert_eq!( - en.payload.get().to_owned(), - PercentEssentialsV1 { - standard: "#,##0%".into(), - percent_sign_symbol: "%".into(), - percent_symbol_index: 5, - number_index: 0, - percent_sign_affixes: PercentAffixesV1 { - prefix: "".into(), - suffix: "".into(), - }, - } - ); - - let fr: DataResponse = provider - .load(DataRequest { - id: DataIdentifierCow::from_locale(langid!("fr").into()).as_borrowed(), - ..Default::default() - }) - .unwrap(); - - assert_eq!( - fr.payload.get().to_owned(), - PercentEssentialsV1 { - standard: "#,##0\u{a0}%".into(), - percent_sign_symbol: "%".into(), - percent_symbol_index: 7, - number_index: 0, - percent_sign_affixes: PercentAffixesV1 { - prefix: "\u{a0}".into(), - suffix: "".into(), - }, - } - ); + // en Should resemble "#,##0%" + let en_pattern = en.payload.get().to_owned(); + assert_writeable_eq!(en_pattern.unsigned_pattern.interpolate(["123"]), "123%"); + assert_writeable_eq!(en_pattern.signed_pattern.interpolate(["123", "+"]), "+123%"); let tr: DataResponse = provider .load(DataRequest { @@ -159,19 +254,10 @@ fn test_basic() { }) .unwrap(); - assert_eq!( - tr.payload.get().to_owned(), - PercentEssentialsV1 { - standard: "%#,##0".into(), - percent_sign_symbol: "%".into(), - percent_symbol_index: 0, - number_index: 1, - percent_sign_affixes: PercentAffixesV1 { - prefix: "".into(), - suffix: "".into(), - }, - } - ); + // tr Should resemble "%#,##0" + let tr_pattern = tr.payload.get().to_owned(); + assert_writeable_eq!(tr_pattern.unsigned_pattern.interpolate(["345"]), "%345"); + assert_writeable_eq!(tr_pattern.signed_pattern.interpolate(["345", "+"]), "+%345"); let ar_eg: DataResponse = provider .load(DataRequest { @@ -180,8 +266,27 @@ fn test_basic() { }) .unwrap(); - assert_eq!( - ar_eg.payload.get().to_owned().percent_sign_symbol, - "\u{200e}%\u{200e}" // "٪؜" + // ar_eg Should resemble "#,##0‎%‎" + let ar_eg_pattern = ar_eg.payload.get().to_owned(); + assert_writeable_eq!( + ar_eg_pattern.unsigned_pattern.interpolate(["456"]), + "456\u{200e}%\u{200e}" ); + assert_writeable_eq!( + ar_eg_pattern.signed_pattern.interpolate(["456", "+"]), + "+456\u{200e}%\u{200e}" + ); +} + +#[test] +fn blo_test() { + use writeable::assert_writeable_eq; + + let blo_positive_pattern = create_unsigned_pattern("% #,#0", "%").unwrap(); + assert_writeable_eq!(blo_positive_pattern.interpolate(["123"]), "% 123"); + + let blo_negative_pattern = create_signed_pattern("% -#,#0", "%").unwrap(); + assert_writeable_eq!(blo_negative_pattern.interpolate(["123", "+"]), "% +123"); + assert_writeable_eq!(blo_negative_pattern.interpolate(["123", "-"]), "% -123"); + assert_writeable_eq!(blo_negative_pattern.interpolate(["123", "~"]), "% ~123"); }