fluent-template-helper 0.2.0

Template engine helpers for the Fluent internationalization framework
Documentation
use fluent_bundle::FluentValue;
use serde_json::Value as Json;
use snafu::OptionExt;
use std::collections::HashMap;

use super::FluentHelperFunction;
use crate::Loader;

type Result<T, E = Error> = std::result::Result<T, E>;

const LANG_KEY: &str = "_lang";
const FLUENT_KEY: &str = "_id";

#[derive(Debug, snafu::Snafu)]
enum Error {
    #[snafu(display("No `lang` argument provided."))]
    NoLangArgument,
    #[snafu(display("No `_id` argument provided."))]
    NoFluentArgument,
    #[snafu(display("Couldn't convert JSON to Fluent value."))]
    JsonToFluentFail,
}

impl From<Error> for tera::Error {
    fn from(error: Error) -> Self {
        tera::Error::msg(error)
    }
}

fn json_to_fluent(json: Json) -> Result<FluentValue> {
    match json {
        Json::Number(ref n) => Ok(FluentValue::Number(n.to_string())),
        Json::String(ref s) => Ok(FluentValue::String(s.to_string())),
        _ => Err(Error::JsonToFluentFail),
    }
}

impl<L: Loader + Send + Sync> tera::Function for FluentHelperFunction<L> {
    fn call(&self, args: &HashMap<String, Json>) -> Result<Json, tera::Error> {
        let lang = args
            .get(LANG_KEY)
            .and_then(Json::as_str)
            .context(self::NoLangArgument)?;
        let id = args
            .get(FLUENT_KEY)
            .and_then(Json::as_str)
            .context(self::NoFluentArgument)?;
        let fluent_values = args
            .values()
            .cloned()
            .map(json_to_fluent)
            .collect::<Result<Vec<_>>>()?;

        let fluent_args = args.keys().map(String::as_str).zip(fluent_values).collect();

        let response = self.loader.lookup(lang, &id, Some(&fluent_args));

        Ok(Json::String(response))
    }
}