Refactor `fluent_embed::Localize` to support overriding locales
Dependencies
- [2]
KZLFC7OWRename `fluent_embed_runtime` to `fluent_embed` - [3]
NO3PDO7PRefactor `fluent_embed` to support structs - [4]
HHJDRLLNCreate `fluent_embed_runtime` crate - [5]
BFL2Y7GNAdd relative timestamps using `jiff` and `icu_relativetime` - [6]
OCR4YRQ2Parse group from fluent file specified by macro attribute - [7]
XGNME3WRMove `Group::derive_enum` to new `crate::parse_macro` module - [8]
2XQ6ZB4WStore multiple locales in a single `Group` - [9]
QSK7JRBAAdd simple `attribute_path` function - [10]
4MRF5E76Generate simple locale matching code in `localize()` - [11]
5FIVUZYFUnify `fluent_embed` macro API as `localize()` - [12]
VNSHGQYNSupport using glob paths in `localize` macro - [13]
P6FW2GGORemove unnecessary parameters in generated `localize()` function - [14]
F5LG7WENEmit compilation errors from Fluent source code - [15]
V5S5K33AAdd basic error handling for invalid paths in proc_macro attribute - [16]
QFPQZR4KRefactor `fluent_embed` - [*]
O77KA6C4Create `fluent_embed` crate - [*]
5TEX4MNUSplit `fluent_embed` into `group` and `parse` modules - [*]
3WEPY3OXAdd `locale` parameter to derived `localize()` function
Change contents
- edit in fluent_embed_derive/src/lib.rs at line 82
let locales = match &derive_input.data {syn::Data::Struct(_struct_data) => derive::locales_for_ident(&group, &derive_input.ident),syn::Data::Enum(enum_data) => derive::locales_for_enum(&group, &enum_data.variants),syn::Data::Union(_) => todo!(),}; - replacement in fluent_embed_derive/src/lib.rs at line 89
let body = match &derive_input.data {let message_body = match &derive_input.data { - replacement in fluent_embed_derive/src/lib.rs at line 91
derive::for_struct(group, &derive_input.ident, &struct_data.fields)derive::message_for_struct(group, &derive_input.ident, &struct_data.fields) - replacement in fluent_embed_derive/src/lib.rs at line 93
syn::Data::Enum(enum_data) => derive::for_enum(group, &enum_data.variants),syn::Data::Enum(enum_data) => derive::messages_for_enum(group, &enum_data.variants), - edit in fluent_embed_derive/src/lib.rs at line 103
fn message_for_locale(&self, locale: &::fluent_embed::icu_locid::LanguageIdentifier) -> String {#message_body} - replacement in fluent_embed_derive/src/lib.rs at line 109
#bodylet available_locales = #locales;let selected_locale = ::fluent_embed::locale_select::match_locales(&available_locales, &Self::CANONICAL_LOCALE);self.message_for_locale(&selected_locale) - edit in fluent_embed_derive/src/fluent/group.rs at line 113[20.1114][19.6614]
pub fn locales_for_message<'a>(&'a self, id: &'a str) -> impl Iterator<Item = &Locale> + 'a {self.locales.iter().filter(|(_locale, messages)| messages.contains_expression(id)).map(|(locale, _source_file)| locale)} - edit in fluent_embed_derive/src/derive.rs at line 39[3.510]→[3.1729:1985](∅→∅),[3.1985]→[2.372:434](∅→∅),[2.434]→[3.2055:2066](∅→∅),[3.2055]→[3.2055:2066](∅→∅),[3.2066]→[2.435:532](∅→∅),[2.532]→[3.625:626](∅→∅),[3.902]→[3.625:626](∅→∅),[3.2171]→[3.625:626](∅→∅),[3.625]→[3.625:626](∅→∅)
// Create a list of available locales to choose fromlet available_locales = [// The canonical locale will always be availableSelf::CANONICAL_LOCALE,// Any additional locales that contain this message#(::fluent_embed::langid!(#additional_locales)),*];let locale = ::fluent_embed::select_locale(&available_locales, &Self::CANONICAL_LOCALE); - replacement in fluent_embed_derive/src/derive.rs at line 41
const plural_rule_type: ::fluent_embed::PluralRuleType =const PLURAL_RULE_TYPE: ::fluent_embed::PluralRuleType = - replacement in fluent_embed_derive/src/derive.rs at line 43
let plural_rules = ::fluent_embed::plural_rules(&locale, plural_rule_type).unwrap();let plural_rules = ::fluent_embed::plural_rules(&locale, PLURAL_RULE_TYPE).unwrap(); - replacement in fluent_embed_derive/src/derive.rs at line 68
pub fn for_struct(pub fn locales_for_ident(group: &fluent::Group, ident: &syn::Ident) -> TokenStream {let id = ident.to_string().to_kebab_case();let locale_literals = group.locales_for_message(&id).map(|locale| locale.id.to_string()).map(|locale_string| syn::LitStr::new(&locale_string, proc_macro2::Span::call_site()));// There is only one message for this struct, so just list every supported localequote!(vec![#(::fluent_embed::langid!(#locale_literals)),*])}pub fn message_for_struct( - replacement in fluent_embed_derive/src/derive.rs at line 101
pub fn for_enum(pub fn locales_for_enum(group: &fluent::Group,enum_variants: &Punctuated<syn::Variant, syn::token::Comma>,) -> TokenStream {let mut match_arms: Vec<TokenStream> = Vec::with_capacity(enum_variants.len());for enum_variant in enum_variants {let variant_ident = &enum_variant.ident;// Simplify match code by always ignoring enum fields (even if they don't exist)// We are matching the variant name, not any data, so each arm will have something like:// Self::VariantName { .. }// Even if `Self::VariantName` doesn't contain any datalet locales_for_variant = locales_for_ident(group, variant_ident);match_arms.push(quote!(Self::#variant_ident { .. } => #locales_for_variant));}quote! {match self {#(#match_arms),*}}}pub fn messages_for_enum( - edit in fluent_embed/src/time.rs at line 21
const CANONICAL_LOCALE: LanguageIdentifier = DEFAULT_LOCALE; - edit in fluent_embed/src/time.rs at line 26
}impl crate::Localize for RelativeTime {const CANONICAL_LOCALE: LanguageIdentifier = DEFAULT_LOCALE; - replacement in fluent_embed/src/time.rs at line 27
fn localize(&self) -> String {pub fn localize(&self) -> String { - edit in fluent_embed/src/lib.rs at line 16
fn localize(&self) -> String;} - replacement in fluent_embed/src/lib.rs at line 17
/// Select which locale to use, falling back to the canonical locale if nothing matchespub fn select_locale(available_locales: &[LanguageIdentifier],canonical_locale: &LanguageIdentifier,) -> LanguageIdentifier {locale_select::match_locales(available_locales, canonical_locale)fn message_for_locale(&self, locale: &LanguageIdentifier) -> String;fn localize(&self) -> String;