Expand description
🚧 [Experimental] APIs and Data Structures for Plural Rules
A single Plural Rule is an expression which tests the value of PluralOperands
against a condition. If the condition is truthful, then the PluralCategory
to which the Rule is assigned should be used.
§Examples
In this example we’re going to examine the AST, parsing and resolving of a set of English Cardinal Plural Rules.
A CLDR JSON source contains the following entry:
{
"one": "i = 1 and v = 0 @integer 1",
"other": " @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …"
}
When the user provides a number for which the PluralCategory
is to be selected,
the system will examine a rule for each category in order, and stop on the first
category which matches.
In our example, the user provided an input value 1
.
That value expanded into PluralOperands
might look something like this, in its
internal representation of plural operand values, or something logically equivalent:
PluralOperands {
i: 1,
v: 0,
w: 0,
f: 0,
t: 0,
c: 0,
};
Now, the system will parse the first rule, assigned to PluralCategory::One
, and
test if it matches.
The value of the rule is:
i = 1 and v = 0 @integer 1
The Rule
contains a Condition
i = 1 and v = 0
and a Sample
@integer 1
.
When parsed, the resulting AST
will look like this:
use icu::plurals::rules::reference::ast::*;
use icu::plurals::rules::reference::parse_condition;
let input = "i = 1 and v = 0 @integer 1";
let ast = parse_condition(input.as_bytes()).expect("Parsing failed.");
assert_eq!(
ast,
Condition(vec![AndCondition(vec![
Relation {
expression: Expression {
operand: Operand::I,
modulus: None,
},
operator: Operator::Eq,
range_list: RangeList(vec![RangeListItem::Value(Value(1))])
},
Relation {
expression: Expression {
operand: Operand::V,
modulus: None,
},
operator: Operator::Eq,
range_list: RangeList(vec![RangeListItem::Value(Value(0))])
},
]),])
);
Finally, we can pass this AST
(in fact, just the Condition
node),
to a resolver alongside the PluralOperands
to test if the Rule
matches:
use icu::plurals::rules::reference::parse_condition;
use icu::plurals::rules::reference::test_condition;
use icu::plurals::PluralOperands;
let input = "i = 1 and v = 0 @integer 1";
let operands = PluralOperands::from(1_u32);
let ast = parse_condition(input.as_bytes()).expect("Parsing failed.");
assert!(test_condition(&ast, &operands));
Since the rule for PluralCategory::One
matches, we will return this category.
Otherwise, we’d test the next rule, in this case PluralCategory::Other
, which has an
empty Condition
, meaning that it’ll match all operands.
§Summary
For PluralRuleType::Cardinal
in English, we can restate the rule’s logic as:
When the PluralOperands::i
is 1
and PluralOperands::v
is 0
(or equivalent thereof), PluralCategory::One
should be used, otherwise PluralCategory::Other
should be used.
For other locales, there are different/more PluralCategories
defined in the PluralRules
(see PluralRules::categories
),
and possibly more complicated Rules
therein.
§Difference between Category and Number
While in English PluralCategory::One
overlaps with an integer value 1
,
in other languages, the category may be used for other numbers as well.
For example, in Russian PluralCategory::One
matches numbers such as 11
, 21
, 121
etc.
§Runtime vs. Resolver Rules
ICU4X
provides two sets of rules AST and APIs to manage it:
reference
is the canonical implementation of the specification intended for tooling and testing to use. This module provides APIs for parsing, editing and serialization of the rules.runtime
is a non-public, non-mutable runtime version optimized for performance and low memory overhead. This version provides runtime resolver used by thePluralRules
itself.
Structs§
- 🚧 [Experimental] A struct for low-level users who want to construct a
PluralOperands
directly based on the LDML Plural Operand definitions.