diff --git a/fluent-bundle/src/resolver/inline_expression.rs b/fluent-bundle/src/resolver/inline_expression.rs index 3f8c8d4f..c793fe82 100644 --- a/fluent-bundle/src/resolver/inline_expression.rs +++ b/fluent-bundle/src/resolver/inline_expression.rs @@ -3,6 +3,7 @@ use super::{ResolveValue, ResolverError, WriteValue}; use std::borrow::Borrow; use std::fmt; +use std::ops::Deref; use fluent_syntax::ast; use fluent_syntax::unicode::{unescape_unicode, unescape_unicode_to_string}; @@ -157,8 +158,12 @@ impl<'bundle> ResolveValue<'bundle> for ast::InlineExpression<&'bundle str> { M: MemoizerKind, { match self { - Self::StringLiteral { value } => unescape_unicode_to_string(value).into(), - Self::NumberLiteral { value } => FluentValue::try_number(value), + Self::StringLiteral { value } => { + return unescape_unicode_to_string(value).into(); + } + Self::NumberLiteral { value } => { + return FluentValue::try_number(value); + } Self::VariableReference { id } => { if let Some(local_args) = &scope.local_args { if let Some(arg) = local_args.get(id.name) { @@ -171,7 +176,7 @@ impl<'bundle> ResolveValue<'bundle> for ast::InlineExpression<&'bundle str> { if scope.local_args.is_none() { scope.add_error(self.into()); } - FluentValue::Error + return FluentValue::Error; } Self::FunctionReference { id, arguments } => { let (resolved_positional_args, resolved_named_args) = @@ -181,16 +186,22 @@ impl<'bundle> ResolveValue<'bundle> for ast::InlineExpression<&'bundle str> { if let Some(func) = func { let result = func(resolved_positional_args.as_slice(), &resolved_named_args); - result + return result; } else { - FluentValue::Error + return FluentValue::Error; } } - _ => { - let mut result = String::new(); - self.write(&mut result, scope).expect("Failed to write"); - result.into() + Self::Placeable { expression } => { + if let ast::Expression::Inline(expression) = expression.deref() { + return expression.resolve(scope); + } } - } + _ => {} + }; + + // Fallback to text serialization + let mut result = String::new(); + self.write(&mut result, scope).expect("Failed to write"); + result.into() } } diff --git a/fluent-bundle/tests/terms-references-with-arguments.rs b/fluent-bundle/tests/terms-references-with-arguments.rs new file mode 100644 index 00000000..185abee0 --- /dev/null +++ b/fluent-bundle/tests/terms-references-with-arguments.rs @@ -0,0 +1,74 @@ +use fluent_bundle::types::FluentNumber; +use fluent_bundle::{FluentArgs, FluentBundle, FluentResource, FluentValue}; + +#[test] +fn test_function_resolve() { + // 1. Create bundle + let ftl_string = String::from( + " +-liked-count = { $count -> + [0] No likes yet. + [one] One person liked your message + *[other] { $count } people liked your message +} + +annotation = Beautiful! { -liked-count(count: $num) } + ", + ); + + let res = FluentResource::try_new(ftl_string).expect("Could not parse an FTL string."); + let mut bundle = FluentBundle::default(); + + bundle + .add_function("NUMBER", |positional, named| match positional.first() { + Some(FluentValue::Number(n)) => { + let mut num = n.clone(); + num.options.merge(named); + + FluentValue::Number(num) + } + _ => FluentValue::Error, + }) + .expect("Failed to add a function."); + + bundle + .add_resource(res) + .expect("Failed to add FTL resources to the bundle."); + + // 1. Example with passing custom argument to term + let mut args = FluentArgs::new(); + args.set("num", FluentValue::from(1)); + + let msg = bundle + .get_message("annotation") + .expect("Message doesn't exist."); + let mut errors = vec![]; + let pattern = msg.value().expect("Message has no value."); + let value = bundle.format_pattern(pattern, Some(&args), &mut errors); + assert_eq!("Beautiful! One person liked your message", &value); + + let mut args = FluentArgs::new(); + args.set("num", FluentValue::from(5)); + + let msg = bundle + .get_message("annotation") + .expect("Message doesn't exist."); + let mut errors = vec![]; + let pattern = msg.value().expect("Message has no value."); + let value = bundle.format_pattern(pattern, Some(&args), &mut errors); + assert_eq!( + "Beautiful! \u{2068}5\u{2069} people liked your message", + &value + ); + + let mut args = FluentArgs::new(); + args.set("num", FluentValue::from(0)); + + let msg = bundle + .get_message("annotation") + .expect("Message doesn't exist."); + let mut errors = vec![]; + let pattern = msg.value().expect("Message has no value."); + let value = bundle.format_pattern(pattern, Some(&args), &mut errors); + assert_eq!("Beautiful! No likes yet.", &value); +} diff --git a/fluent-syntax/src/parser/expression.rs b/fluent-syntax/src/parser/expression.rs index c5ccb32b..ff6dfd9b 100644 --- a/fluent-syntax/src/parser/expression.rs +++ b/fluent-syntax/src/parser/expression.rs @@ -190,7 +190,7 @@ where } self.ptr += 1; self.skip_blank(); - let val = self.get_inline_expression(true)?; + let val = self.get_inline_expression(false)?; argument_names.push(id.name.clone()); named.push(ast::NamedArgument {