Implement `Localize` for `FixedDecimal` and primitive number types
Dependencies
- [2]
7FYXVNABIgnore comments in Fluent source code - [3]
3NMKD6I5Refactor `Localize` trait to use `std::io::Write` - [4]
AAERM7PBAdd selector tests for the `fr` locale - [5]
F5LG7WENEmit compilation errors from Fluent source code - [6]
6ABVDTXZImprove `fluent_embed_derive` test suite - [7]
XEEXWJLGAdd simple end-to-end test for selectors - [8]
5TEX4MNUSplit `fluent_embed` into `group` and `parse` modules - [9]
QFPQZR4KRefactor `fluent_embed` - [10]
NO3PDO7PRefactor `fluent_embed` to support structs - [*]
2SITVDYWHandle common errors in Fluent code - [*]
O77KA6C4Create `fluent_embed` crate - [*]
KZLFC7OWRename `fluent_embed_runtime` to `fluent_embed` - [*]
HHJDRLLNCreate `fluent_embed_runtime` crate - [*]
BFL2Y7GNAdd relative timestamps using `jiff` and `icu_relativetime` - [*]
UKFEFT6LCreate basic `Output` proc-macro - [*]
VNSHGQYNSupport using glob paths in `localize` macro - [*]
ROSR4HD5Parse captured glob as locale
Change contents
- replacement in fluent_embed_derive/tests/selectors.rs at line 14
fn expected_message(&self, locale: &str) -> String {fn expected_plural(&self, locale: &str) -> String { - replacement in fluent_embed_derive/tests/selectors.rs at line 18
// Only 1 is singular1 => format!("You have {unread_emails} unread email."),// Everything else is plural0 | 2.. => format!("You have {unread_emails} unread emails."),0..=999 => unread_emails.to_string(),&u64::MAX => "18,446,744,073,709,551,615".to_string(),_ => unreachable!(), - replacement in fluent_embed_derive/tests/selectors.rs at line 23
// Both 0 & 1 are singular0 | 1 => format!("Vous avez {unread_emails} e-mail non lu."),// Everything else is plural2.. => format!("Vous avez {unread_emails} e-mails non lus."),0..=999 => unread_emails.to_string(),&u64::MAX => "18 446 744 073 709 551 615".to_string(),_ => unreachable!(), - edit in fluent_embed_derive/tests/selectors.rs at line 29
}}fn expected_message(&self, locale: &str) -> String {match self {Self::Emails { unread_emails } => {let expected_plural = self.expected_plural(locale);match locale {"en-US" => match unread_emails {// Only 1 is singular1 => "You have 1 unread email.".to_string(),// Everything else is plural0 | 2.. => format!("You have {expected_plural} unread emails."),},"fr" => match unread_emails {// Both 0 & 1 are singular0 | 1 => format!("Vous avez {expected_plural} e-mail non lu."),// Everything else is plural2.. => format!("Vous avez {expected_plural} e-mails non lus."),},_ => unreachable!(),}} - replacement in fluent_embed_derive/tests/selectors.rs at line 67
data.message_for_locale(&mut buffer, &language_id);data.message_for_locale(&mut buffer, &language_id).unwrap(); - edit in fluent_embed_derive/src/fluent/ast.rs at line 6
use fixed_decimal::{FixedDecimal, FloatPrecision}; - replacement in fluent_embed_derive/src/fluent/ast.rs at line 62
match plural_rules.category_for(#match_target) {match plural_rules.category_for(*#match_target) { - replacement in fluent_embed_derive/src/fluent/ast.rs at line 70
parse_quote!(writer.write_all(#expression)?)parse_quote!(#expression.message_for_locale(writer, locale)?) - replacement in fluent_embed_derive/src/fluent/ast.rs at line 94
// FIXME: i128 is "good enough" for now but an incorrect representation!// e.g. decimals not supportedlet parsed_value = i128::from_str_radix(value, 10).unwrap();let number_literal = proc_macro2::Literal::i128_unsuffixed(parsed_value);parse_quote!(#number_literal)let parsed_value: f64 = value.parse().unwrap();// Check validity at compile-time, so we avoid generating code that will break at runtimeassert!(FixedDecimal::try_from_f64(parsed_value, FloatPrecision::Floating).is_ok());let float_literal = proc_macro2::Literal::f64_suffixed(parsed_value);parse_quote!(::fluent_embed::FixedDecimal::try_from_f64(#float_literal, ::fluent_embed::FloatPrecision::Floating).unwrap()) - replacement in fluent_embed_derive/src/fluent/ast.rs at line 141[4.6063]→[4.3783:3850](∅→∅),[4.9149]→[4.3783:3850](∅→∅),[4.3783]→[4.3783:3850](∅→∅),[4.3850]→[3.3639:3723](∅→∅)
ReferenceKind::EnumField => parse_quote!(*#ident),ReferenceKind::StructField => parse_quote!(message_context.#ident),ReferenceKind::EnumField => parse_quote!(#ident),ReferenceKind::StructField => parse_quote!(self.#ident), - edit in fluent_embed_derive/Cargo.toml at line 13
fixed_decimal = { version = "0.5.6", features = ["ryu"] } - edit in fluent_embed_derive/Cargo.toml at line 27
icu_decimal = "1.5.0"icu_provider = "1.5.0" - edit in fluent_embed/src/lib.rs at line 8
pub use fixed_decimal::{FixedDecimal, FloatPrecision}; - edit in fluent_embed/src/lib.rs at line 14
pub mod decimal; - file addition: decimal.rs[15.49]
use crate::Localize;use duplicate::duplicate_item;use fixed_decimal::{FixedDecimal, FloatPrecision};use icu_decimal::{options::FixedDecimalFormatterOptions, FixedDecimalFormatter};use icu_locid::{langid, LanguageIdentifier};use icu_provider::DataLocale;use writeable::Writeable;// Implementations of `Localize` for all primitive number types// These just convert to a `FixedDecimal` and then use its implementation#[duplicate_item(type_name conversion;[u8] [FixedDecimal::from(*self)];[u16] [FixedDecimal::from(*self)];[u32] [FixedDecimal::from(*self)];[u64] [FixedDecimal::from(*self)];[u128] [FixedDecimal::from(*self)];[usize] [FixedDecimal::from(*self)];[i8] [FixedDecimal::from(*self)];[i16] [FixedDecimal::from(*self)];[i32] [FixedDecimal::from(*self)];[i64] [FixedDecimal::from(*self)];[i128] [FixedDecimal::from(*self)];[isize] [FixedDecimal::from(*self)];[f32] [FixedDecimal::try_from_f64(*self as f64, FloatPrecision::Floating).unwrap()];[f64] [FixedDecimal::try_from_f64(*self, FloatPrecision::Floating).unwrap()];)]impl<W: std::io::Write> Localize<W> for type_name {const CANONICAL_LOCALE: LanguageIdentifier = langid!("en-US");fn available_locales(&self) -> Vec<LanguageIdentifier> {// TODO: keep track of all locales with Fluent data, and return only thosevec![<Self as Localize<W>>::CANONICAL_LOCALE]}fn message_for_locale(&self,writer: &mut W,locale: &LanguageIdentifier,) -> Result<(), crate::LocalizationError> {let fixed_decimal = conversion;fixed_decimal.message_for_locale(writer, locale)}}impl<W: std::io::Write> Localize<W> for FixedDecimal {const CANONICAL_LOCALE: LanguageIdentifier = langid!("en-US");fn available_locales(&self) -> Vec<LanguageIdentifier> {// TODO: keep track of all locales with Fluent data, and return only thosevec![<Self as Localize<W>>::CANONICAL_LOCALE]}fn message_for_locale(&self,writer: &mut W,locale: &LanguageIdentifier,) -> Result<(), crate::LocalizationError> {let data_locale = DataLocale::from(locale);let formatter =FixedDecimalFormatter::try_new(&data_locale, FixedDecimalFormatterOptions::default()).unwrap();let formatted_decimal = formatter.format(self);writer.write_all(formatted_decimal.write_to_string().as_bytes())?;Ok(())}} - edit in fluent_embed/Cargo.toml at line 10
duplicate = "1.0.0" - edit in fluent_embed/Cargo.toml at line 13
icu_decimal = "1.5.0" - edit in Cargo.lock at line 121
name = "duplicate"version = "1.0.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb"dependencies = ["heck","proc-macro-error",][[package]] - edit in Cargo.lock at line 187
"duplicate", - edit in Cargo.lock at line 190
"icu_decimal", - edit in Cargo.lock at line 205
"fixed_decimal", - edit in Cargo.lock at line 209[13.1952][19.575]
"icu_decimal", - edit in Cargo.lock at line 211[19.589][4.15009]
"icu_provider",