-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathcustom_formatter.rs
145 lines (132 loc) · 5.68 KB
/
custom_formatter.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// This is an example of an application which uses a custom formatter
// to format selected types of values.
//
// This allows users to plug their own number formatter to Fluent.
use unic_langid::LanguageIdentifier;
use fluent_bundle::memoizer::MemoizerKind;
use fluent_bundle::types::{FluentNumber, FluentNumberOptions};
use fluent_bundle::{FluentArgs, FluentBundle, FluentResource, FluentValue};
fn custom_formatter<M: MemoizerKind>(num: &FluentValue, _intls: &M) -> Option<String> {
match num {
FluentValue::Number(n) => Some(format!("CUSTOM({})", n.value)),
_ => None,
}
}
fn main() {
// 1. Bootstrap a FluentBundle with a number of messages which use
// number formatting in different forms.
let ftl_string = String::from(
"
key-implicit = Here is an implicitly encoded number: { 5 }.
key-explicit = Here is an explicitly encoded number: { NUMBER(5) }.
key-var-implicit = Here is an implicitly encoded variable: { $num }.
key-var-explicit = Here is an explicitly encoded variable: { NUMBER($num) }.
key-var-with-arg = Here is a variable formatted with an argument { NUMBER($num, minimumFractionDigits: 5) }.
",
);
let res = FluentResource::try_new(ftl_string).expect("Could not parse an FTL string.");
let lang: LanguageIdentifier = "en".parse().unwrap();
let mut bundle = FluentBundle::new(vec![lang]);
bundle
.add_resource(res)
.expect("Failed to add FTL resources to the bundle.");
bundle
.add_function("NUMBER", |positional, named| {
match positional.first() {
Some(FluentValue::Number(n)) => {
let mut num = n.clone();
// This allows us to merge the arguments provided
// as arguments to the function into the new FluentNumber.
num.options.merge(named);
FluentValue::Number(num)
}
_ => FluentValue::Error,
}
})
.expect("Failed to add a function.");
bundle.set_use_isolating(false);
let mut errors = vec![];
// 2. First, we're going to format the number using the implicit formatter.
// At the moment the number will be formatted in a very dummy way, since
// we do not have a locale aware number formatter available yet.
let msg = bundle
.get_message("key-implicit")
.expect("Message doesn't exist.");
let pattern = msg.value().expect("Message has no value.");
let value = bundle.format_pattern(pattern, None, &mut errors);
assert_eq!(value, "Here is an implicitly encoded number: 5.");
println!("{}", value);
// 3. Next, we're going to plug our custom formatter.
bundle.set_formatter(Some(custom_formatter));
// 4. Now, when you attempt to format a number, the custom formatter
// will be used instead of the default one.
let msg = bundle
.get_message("key-implicit")
.expect("Message doesn't exist.");
let pattern = msg.value().expect("Message has no value.");
let value = bundle.format_pattern(pattern, None, &mut errors);
assert_eq!(value, "Here is an implicitly encoded number: CUSTOM(5).");
println!("{}", value);
// 5. The same custom formatter will be used for explicitly formatter numbers,
// and variables of type number.
let msg = bundle
.get_message("key-explicit")
.expect("Message doesn't exist.");
let pattern = msg.value().expect("Message has no value.");
let value = bundle.format_pattern(pattern, None, &mut errors);
assert_eq!(value, "Here is an explicitly encoded number: CUSTOM(5).");
println!("{}", value);
let msg = bundle
.get_message("key-var-implicit")
.expect("Message doesn't exist.");
let pattern = msg.value().expect("Message has no value.");
let mut args = FluentArgs::new();
args.set("num", FluentValue::from(-15));
let value = bundle.format_pattern(pattern, Some(&args), &mut errors);
assert_eq!(
value,
"Here is an implicitly encoded variable: CUSTOM(-15)."
);
println!("{}", value);
let msg = bundle
.get_message("key-var-explicit")
.expect("Message doesn't exist.");
let pattern = msg.value().expect("Message has no value.");
let mut args = FluentArgs::new();
args.set("num", FluentValue::from(-15));
let value = bundle.format_pattern(pattern, Some(&args), &mut errors);
assert_eq!(
value,
"Here is an explicitly encoded variable: CUSTOM(-15)."
);
println!("{}", value);
// 6. The merging operation on FluentNumber options allows the
// options provided from the localizer to be merged into the
// default ones and ones provided by the developer.
let msg = bundle
.get_message("key-var-explicit")
.expect("Message doesn't exist.");
let pattern = msg.value().expect("Message has no value.");
let mut args = FluentArgs::new();
let num = FluentNumber::new(
25.2,
FluentNumberOptions {
maximum_fraction_digits: Some(8),
minimum_fraction_digits: Some(1),
..Default::default()
},
);
args.set("num", num);
let value = bundle.format_pattern(pattern, Some(&args), &mut errors);
// Notice, that since we specified minimum and maximum fraction digits options
// to be 1 and 8 when construction the argument, and then the minimum fraction
// digits option has been overridden in the localization the formatter
// will received options:
// - minimum_fraction_digits: Some(5)
// - maximum_fraction_digits: Some(8)
assert_eq!(
value,
"Here is an explicitly encoded variable: CUSTOM(25.2)."
);
println!("{}", value);
}