use std::collections::HashMap;
use fluent_templates::Loader;
use fluent_templates::fluent_bundle::FluentValue;
use handlebars::{Context, Handlebars, Helper, HelperDef, HelperResult, Output, RenderContext, RenderError};
use serde_json::Value as Json;
pub struct FluentHandlebars<L: Loader + Send + Sync>{
loader: L
}
impl<L: Loader + Send + Sync> FluentHandlebars<L> {
pub fn new(ldr: L) -> FluentHandlebars<L> {
FluentHandlebars {
loader: ldr
}
}
}
impl<L: Loader + Send + Sync> HelperDef for FluentHandlebars<L> {
fn call<'reg: 'rc, 'rc>(
&self,
helper: &Helper<'reg, 'rc>,
_reg: &'reg Handlebars,
context: &'rc Context,
_rcx: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output,
) -> HelperResult {
let id = if let Some(id) = helper.param(0) {
id
} else {
return Err(RenderError::new(
"{{t}} must have at least one parameter",
));
};
if id.relative_path().is_some() {
return Err(RenderError::new(
"{{t}} takes a string literal, not a path",
));
}
let id = if let Json::String(ref s) = *id.value() {
s
} else {
return Err(RenderError::new("{{t}} takes a string parameter"));
};
let args: Option<HashMap<String, FluentValue>> = if !context.data().is_object() {
None
} else {
let map = context
.data()
.as_object().unwrap()
.iter()
.filter_map(|(k, v)| {
let val: FluentValue = match v {
Json::Number(n) => n.as_f64().unwrap().into(),
Json::String(s) => s.to_owned().into(),
_ => return None,
};
Some((k.to_string(), val))
})
.collect();
Some(map)
};
let lang = context
.data()
.get("lang")
.expect("Language not set in context")
.as_str()
.expect("Language must be string")
.parse()
.expect("Language not valid identifier");
let response = self.loader.lookup_complete(&lang, &id, args.as_ref());
out.write(&response).map_err(
|e| RenderError::from_error("fluent-handlebars-runtime helper", e)
)
}
}