Skip to content

Commit

Permalink
Default lang argument in Tera templates (#14)
Browse files Browse the repository at this point in the history
* Default lang argument in Tera templates

this makes lang argument optional by providing global default value

See #13

* generate tests only for enabled features

before this commit tests generated for disabled features were empty

* add tests for defautlt lang feature

* documentation for with_default_lang
  • Loading branch information
technic authored Jul 18, 2020
1 parent 1fde45b commit dc6ece5
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 10 deletions.
5 changes: 4 additions & 1 deletion templates/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@
//! what language to get that key for. Optionally you can pass extra arguments
//! to the function as arguments to the resource. `fluent-templates` will
//! automatically convert argument keys from Tera's `snake_case` to the fluent's
//! preferred `kebab-case` arguments.
//! preferred `kebab-case` arguments.
//! The `lang` parameter is optional when the default language of the corresponding
//! `FluentLoader` is set (see [`FluentLoader::with_default_lang`]).
//!
//! ```toml
//!fluent-templates = { version = "*", features = ["tera"] }
Expand Down Expand Up @@ -276,6 +278,7 @@
//! [`static_loader!`]: ./macro.static_loader.html
//! [`StaticLoader`]: ./struct.StaticLoader.html
//! [`ArcLoader`]: ./struct.ArcLoader.html
//! [`FluentLoader::with_default_lang`]: ./struct.FluentLoader.html#method.with_default_lang
//! [`handlebars::Context`]: https://docs.rs/handlebars/3.1.0/handlebars/struct.Context.html
#![warn(missing_docs)]

Expand Down
16 changes: 15 additions & 1 deletion templates/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,26 @@ where
/// for integrating with different libraries.
pub struct FluentLoader<L> {
loader: L,
default_lang: Option<LanguageIdentifier>,
}

impl<L> FluentLoader<L> {
/// Create a new `FluentLoader`.
pub fn new(loader: L) -> Self {
Self { loader }
Self {
loader,
default_lang: None,
}
}

/// Set default language for this `FluentLoader`.
/// Template engines can use this value when rendering translations.
/// Sofar this feature is only implemented for Tera.
pub fn with_default_lang(self, lang: LanguageIdentifier) -> Self {
Self {
loader: self.loader,
default_lang: Some(lang),
}
}
}

Expand Down
24 changes: 16 additions & 8 deletions templates/src/loader/tera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use fluent_bundle::FluentValue;
use serde_json::Value as Json;
use snafu::OptionExt;
use std::collections::HashMap;
use unic_langid::LanguageIdentifier;

use crate::Loader;

Expand Down Expand Up @@ -35,15 +36,22 @@ fn json_to_fluent(json: Json) -> crate::Result<FluentValue<'static>, Error> {
}
}

fn parse_language(arg: &Json) -> crate::Result<LanguageIdentifier, Error> {
arg.as_str()
.context(self::LangArgumentInvalid)?
.parse::<LanguageIdentifier>()
.ok()
.context(self::LangArgumentInvalid)
}

impl<L: Loader + Send + Sync> tera::Function for crate::FluentLoader<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)?
.parse::<unic_langid::LanguageIdentifier>()
.ok()
.context(self::LangArgumentInvalid)?;
let lang_arg = args.get(LANG_KEY).map(parse_language).transpose()?;
let lang = lang_arg
.as_ref()
.or(self.default_lang.as_ref())
.context(self::NoLangArgument)?;

let id = args
.get(FLUENT_KEY)
.and_then(Json::as_str)
Expand All @@ -64,7 +72,7 @@ impl<L: Loader + Send + Sync> tera::Function for crate::FluentLoader<L> {
);
}

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

Ok(Json::String(response))
}
Expand Down
33 changes: 33 additions & 0 deletions templates/tests/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ macro_rules! generate_tests {
};
}

#[cfg(feature = "handlebars")]
mod handlebars {
generate_tests! {
fn english(handlebars, "en-US") {
Expand Down Expand Up @@ -127,6 +128,7 @@ mod handlebars {
}
}

#[cfg(feature = "tera")]
mod tera {
generate_tests! {
fn english(tera, "en-US") {
Expand All @@ -152,4 +154,35 @@ mod tera {
assert_eq!(r#"{{ fluent(key="fallback", lang="{lang}") }}"#, "this should fall back");
}
}

/// Default lang argument works
#[test]
fn use_default_lang() {
let loader = FluentLoader::new(&*super::LOCALES).with_default_lang("de".parse().unwrap());
let mut tera = tera::Tera::default();
tera.register_function("fluent", loader);
let context = tera::Context::new();
assert_eq!(
tera.render_str(r#"{{ fluent(key="hello-world") }}"#, &context)
.unwrap(),
"Hallo Welt!"
);
assert_eq!(
tera.render_str(r#"{{ fluent(key="hello-world", lang="fr") }}"#, &context)
.unwrap(),
"Bonjour le monde!"
);
}

/// Rendering fails when no default and no explicit lang argument is provided
#[test]
fn no_default_and_no_argument_error() {
let loader = FluentLoader::new(&*super::LOCALES);
let mut tera = tera::Tera::default();
tera.register_function("fluent", loader);
let context = tera::Context::new();
assert!(tera
.render_str(r#"{{ fluent(key="hellow-world") }}"#, &context)
.is_err());
}
}

0 comments on commit dc6ece5

Please # to comment.