Most of the changes are "noise" - the refactor touched most parts of the codebase. The main change is that instead of returning the output of format!
, the generated code now calls writer.write_all()
and returns an empty Ok(())
on success. This should make things a bit cleaner and hopefully reduce the amount of unncecessary allocation at compile-time.
3NMKD6I57ONAGHEN4PZIAV2KPYESVR4JL3DTWSHXKCMVJBEQ4GIQC
CESJ4CTO26X4GBZBPXRXLOJT3JQJOGFN5EJSNAAZELNQRZF7QSYAC
IRW6JACS3KVVA6HW5SBNBOHOQ2WRBHYGDND3FUWJYKJC7ZMOAVOQC
AAERM7PBDVDFDEEXZ7UJ5WWQF7SPEJQQYXRBZ63ETB5YAVIECHMAC
XEEXWJLGVIPIGURSDU4ETZMGAIFTFDPECM4QWFOSRHU7GMGVOUVQC
HHJDRLLNN36UNIA7STAXEEVBCEMPJNB7SJQOS3TJLLYN4AEZ4MHQC
NO3PDO7PY7J3WPADNCS5VD6HKFY63E23I3SDR4DHXNVQJTG27RAAC
XGNME3WRU3MJDTFHUFJYARLVXWBZIH5ODBOIIFTXHNCBTZQH2R7QC
4MRF5E76QSW3EPICI6TNEGJ2KSBWODWMIDQPLYALDWBYWKAV5LJAC
F5LG7WENUUDRSCTDMA4M6BAC5RWTGQO45C4ZEBZDX6FHCTTHBVGQC
5TEX4MNUC4LDDRMNEOVCFNUUEZAGUXMKO3OIEQFXWRQKXSHY2NRQC
QFPQZR4K4UZ7R2GQZJG4NYBGVQJVL2ANIKGGTOHAMIRIBQHPSQGAC
D652S2N3MHR7NJWSJIT7DUH5TPEFF6YII7EGV4C7IYWARXLMGAWQC
HJMYJDC77NLU44QZWIW7CELXJKD4EK4YZ6CCILYBG6FWGZ2KMBVAC
KZLFC7OWYNK3G5YNHRANUK3VUVCM6W6J34N7UABYA24XMZWAVVHQC
2SITVDYW6KANM24QXRHVSBL6S77UHKJLOSOHSUZQBJFL5NAAGQYAC
BFL2Y7GN6NBXXNAUSD4M6T6CIVQ2OLERPE2CAFSLRF377WFFTVCQC
7U2DXFMPZO4P53AMWYCVXG3EPB7UIAPEY4PDDINX4TTABHD5NGMQC
UKFEFT6LSI4K7X6UHQFZYD52DILKXMZMYSO2UYS2FCHNPXIF4BEQC
fn localize(&self) -> String {
let available_locales = #locales;
let selected_locale = ::fluent_embed::locale_select::match_locales(&available_locales, &Self::CANONICAL_LOCALE);
self.message_for_locale(&selected_locale)
fn message_for_locale(
&self,
writer: &mut W,
locale: &::fluent_embed::icu_locid::LanguageIdentifier,
) -> Result<(), ::fluent_embed::LocalizationError> {
#message_body
let mut format_body = String::new();
let mut format_arguments = Vec::new();
let mut write_expressions: Vec<syn::Expr> =
Vec::with_capacity(message_context.pattern.elements.len());
PatternElement::TextElement { value } => format_body.push_str(value),
PatternElement::TextElement { value } => {
let byte_string_literal = proc_macro2::Literal::byte_string(value.as_bytes());
write_expressions.push(parse_quote!(writer.write_all(#byte_string_literal)?));
}
let target = inline_expression(selector, message_context)?;
let mut arms: Vec<syn::Arm> = Vec::with_capacity(variants.len());
let match_target = inline_expression(selector, message_context)?;
let default_arm = OnceCell::new();
let mut additional_arms = Vec::with_capacity(variants.len());
let ident = format_ident!("{}", name.to_pascal_case());
parse_quote!(::fluent_embed::icu_plurals::PluralCategory::#ident)
let ident_pascal_case =
format_ident!("{}", name.to_pascal_case());
parse_quote!(::fluent_embed::icu_plurals::PluralCategory::#ident_pascal_case)
// Default patterns match anything else
// TODO: this can potentially generate unreachable patterns,
// should be replaced with a more sophisticated implementation
let pattern = if variant.default {
parse_quote!(#base_pattern | _)
if variant.default {
default_arm
.set(quote!(#variant_pattern | _ => #variant_body))
.expect("Multiple default patterns for match statement.");
let format_body_literal = proc_macro2::Literal::string(format_body.to_string().as_str());
Ok(parse_quote!(
format!(#format_body_literal, #(#format_arguments),*)
))
Ok(parse_quote! {
{
#(#write_expressions;)*
}
})
impl Localize for RelativeTime {
const CANONICAL_LOCALE: LanguageIdentifier = DEFAULT_LOCALE;
impl<W: std::io::Write> Localize<W> for RelativeTime {
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 those
vec![<Self as Localize<W>>::CANONICAL_LOCALE]
}
pub trait Localize {
#[derive(thiserror::Error, Debug)]
pub enum LocalizationError {
#[error("invalid locale selected")]
InvalidLocale,
#[error("unable to write localized output")]
IO(#[from] std::io::Error),
}
pub trait Localize<W: std::io::Write> {
// TODO: this should be project-wide and tracked at build time
fn message_for_locale(&self, locale: &LanguageIdentifier) -> String;
fn localize(&self) -> String;
fn available_locales(&self) -> Vec<LanguageIdentifier>;
fn message_for_locale(
&self,
writer: &mut W,
locale: &LanguageIdentifier,
) -> Result<(), LocalizationError>;
fn localize(&self, writer: &mut W) -> Result<(), LocalizationError> {
let available_locales = self.available_locales();
let selected_locale = locale_select::match_locales(
&available_locales,
&<Self as Localize<W>>::CANONICAL_LOCALE,
);
self.message_for_locale(writer, &selected_locale)
}