-
-
Notifications
You must be signed in to change notification settings - Fork 36
Add case selection specification #170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
## Variant Case Selection | ||
|
||
> This is a fragment of the full MessageFormat 2 specification, | ||
> intended for later merge into a complete spec document. | ||
|
||
### Prerequisites | ||
|
||
The following assumptions are made about the **data model** and **function registry**, | ||
as prerequisites for the following algorithm: | ||
|
||
1. The data model supports a message type that allows for selecting | ||
one variant **case** of a message based on the value of one or more **selectors**. | ||
|
||
2. The value of a selector may be determined by a literal value, | ||
a function defined in the function registry, | ||
a dynamic variable provided at runtime, | ||
the formatted value of another message, | ||
or some subset of these. | ||
The process for determining the value of any of the above is defined elsewhere. | ||
|
||
3. For each selector, a default or **fallback** value is defined. | ||
This may be a fixed value such as `"other"`, | ||
or a string or integer value defined separately for each selector. | ||
|
||
4. In the data model, the selectors are defined by an ordered list. | ||
|
||
5. In the data model, the variant cases are defined by an ordered list of entries. | ||
In addition to the case's actual message **value**, | ||
each entry contains the **key** for the case as an ordered list of string and integer values. | ||
These key values are aligned with the selectors. | ||
The length of any key list is not greater than the length of the selector list. | ||
|
||
6. If the function registry contains a `plural` selector function, | ||
that function may be called with one number argument, | ||
and be expected to return a list of string and integer values. | ||
The returned values correspond to the numerical value of the argument as well as | ||
the identifier of the cardinal plural category of the argument. | ||
|
||
7. The cases are sorted, such that numerical keys are before string keys and | ||
default or fallback key values are after all other key values. | ||
If a fallback key has a number value, it is sorted after all non-fallback keys. | ||
|
||
### Algorithm | ||
|
||
1. The value `s` of each selector is determined: | ||
|
||
1. The initial value `v` of the selector is resolved (see prereq. 2) | ||
2. If `v` is a string value or a list of string and integer values, `s = v` is set. | ||
3. Else if `v` is a number and a `plural` function is defined, `s = plural(v)` is set. | ||
4. Else if `v` is a number, `s = v` is set. | ||
5. Else, `v` is forcibly stringified: `s = String(v)`. | ||
|
||
At this point, we have a list `S` of selector values, | ||
each of which is a string, number, or a list of a string and integer values. | ||
|
||
2. For each case (in order), its key `K` is compared to the selector values. | ||
Each string or integer `k` in `K` is compared to its corresponding selector value `s` | ||
as well that selector's fallback value `d`: | ||
|
||
1. If `s` is a string or number and `k == s`, the match succeeds. | ||
2. Else if `s` if a list of string and integer values and `k` is in `s`, the match succeeds. | ||
3. Else if `k == d`, the match succeds. | ||
4. Else, the match fails. | ||
|
||
If the match succeeds for all `k` in `K`, | ||
the case is selected and its value is selected as the value of the whole message. | ||
|
||
3. If no case matches the selector value, an empty string is selected as the message value. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer the data model to be more explicit, i.e. the selector should already encode that it will use the
plural
function for resolution.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intent with this is to handle cases where the data model representation does not make it clear whether the input value might or might not be a number. For instance, take the default message used by the Fluent Playground:
Specifically, consider the
$photoCount
selector: at what point can it be known whether it represents a numeric value vs. e.g. the literal string'one'
? The implicitplural
allows us to ask that question only when we actually have the value; any earlier, we'd need additional input on its data type, or we'd need to add an explicitplural
wrapper on every single selector.As I mention in the discussion, the algorithm does of course allow for explicit
plural
wrappers, and that is in fact required when doing anything other than simple cardinal plural selection.