use std::collections::HashMap;
use fluent_syntax::ast::{Entry, Message, Resource};
use icu_locid::Locale;
use syn::parse_quote;
#[derive(Clone, Debug)]
struct LocaleGroup {
locale: Locale,
messages: Box<[Option<Message<String>>]>,
}
impl LocaleGroup {
fn new(
locale: Locale,
resource: Resource<String>,
canonical_messages: &[Message<String>],
) -> Self {
let mut messages = vec![None; canonical_messages.len()].into_boxed_slice();
for entry in resource.body {
if let Entry::Message(message) = entry {
let index = canonical_messages
.iter()
.position(|canonical_message| canonical_message.id.name == message.id.name)
.expect("Message ID must be in canonical group");
assert!(messages[index].is_none());
messages[index] = Some(message);
}
}
Self { locale, messages }
}
}
#[derive(Clone, Debug)]
pub struct Group {
canonical_locale: Locale,
canonical_messages: Vec<Message<String>>,
extra_locales: Vec<LocaleGroup>,
}
impl Group {
pub fn new(canonical_locale: Locale, mut resources: HashMap<Locale, Resource<String>>) -> Self {
let canonical_resource = resources.remove(&canonical_locale).unwrap();
let mut canonical_messages = Vec::new();
for entry in canonical_resource.body {
if let Entry::Message(message) = entry {
canonical_messages.push(message);
}
}
let extra_locales = resources
.into_iter()
.map(|(locale, resource)| LocaleGroup::new(locale, resource, &canonical_messages))
.collect::<Vec<_>>();
Self {
canonical_locale,
canonical_messages,
extra_locales,
}
}
fn messages_in_column(
&self,
message_column: usize,
) -> impl Iterator<Item = (&Locale, &Message<String>)> {
self.extra_locales.iter().filter_map(move |locale_group| {
locale_group
.messages
.get(message_column)
.unwrap()
.as_ref()
.map(|message| (&locale_group.locale, message))
})
}
pub fn message(&self, id: &str) -> syn::ExprBlock {
let message_column = self
.canonical_messages
.iter()
.position(|message| message.id.name == id)
.expect("Message id must be valid");
let additional_locale_names = self
.messages_in_column(message_column)
.map(|(locale, _message)| locale.to_string())
.map(|locale_string| syn::LitStr::new(&locale_string, proc_macro2::Span::call_site()));
let additional_locale_messages = self
.messages_in_column(message_column)
.map(|(_locale, message)| crate::parse_fluent::message(message));
parse_quote! {{
#(if locale.normalizing_eq(#additional_locale_names) { return #additional_locale_messages })else*
}}
}
pub fn canonical_message(&self, id: &str) -> syn::Expr {
let message_column = self
.canonical_messages
.iter()
.position(|message| message.id.name == id)
.expect("Message id must be valid");
crate::parse_fluent::message(&self.canonical_messages[message_column])
}
}