Skip to content

Commit

Permalink
Support passing arguments to terms
Browse files Browse the repository at this point in the history
  • Loading branch information
PPakalns committed Jun 5, 2024
1 parent 2e7c25e commit 8be41e6
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 11 deletions.
31 changes: 21 additions & 10 deletions fluent-bundle/src/resolver/inline_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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) {
Expand All @@ -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) =
Expand All @@ -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()
}
}
74 changes: 74 additions & 0 deletions fluent-bundle/tests/terms-references-with-arguments.rs
Original file line number Diff line number Diff line change
@@ -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);
}
2 changes: 1 addition & 1 deletion fluent-syntax/src/parser/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 8be41e6

Please sign in to comment.