|
| 1 | +# Selection on Numerical Values |
| 2 | + |
| 3 | +Status: **Accepted** |
| 4 | + |
| 5 | +<details> |
| 6 | + <summary>Metadata</summary> |
| 7 | + <dl> |
| 8 | + <dt>Contributors</dt> |
| 9 | + <dd>@eemeli</dd> |
| 10 | + <dt>First proposed</dt> |
| 11 | + <dd>2023-09-06</dd> |
| 12 | + <dt>Pull Request</dt> |
| 13 | + <dd><a href="https://github.com/unicode-org/message-format-wg/pull/471">#471</a></dd> |
| 14 | + </dl> |
| 15 | +</details> |
| 16 | + |
| 17 | +## Objective |
| 18 | + |
| 19 | +Define how selection on numbers happens. |
| 20 | + |
| 21 | +## Background |
| 22 | + |
| 23 | +As discussed by the working group and explicitly identified in |
| 24 | +<a href="https://github.com/unicode-org/message-format-wg/pull/457">discussion of #457</a>, |
| 25 | +there is a need to support multiple types of selection on numeric values in MF2. |
| 26 | + |
| 27 | +MF1 supported selection on either cardinal plurals or ordinal numbers, |
| 28 | +via the `plural` and `selectordinal` selectors. |
| 29 | +It also customized this selection beyond the capabilities of `com.ibm.icu.text.PluralRules` |
| 30 | +by allowing for explicit value matching and an `offset` parameter. |
| 31 | + |
| 32 | +As pointed out by <a href="https://github.com/mihnita">@mihnita</a> in particular, |
| 33 | +category selection is not always appropriate for selection on a number: |
| 34 | +the number may be representing some completely other quantity, |
| 35 | +such as a four-digit year or the integer value of an enumerator. |
| 36 | + |
| 37 | +Furthermore, as pointed out by <a href="https://github.com/ryzokuken">@ryzokuken</a> |
| 38 | +in <a href="https://github.com/unicode-org/message-format-wg/pull/457#discussion_r1307443288">#457 (comment)</a>, |
| 39 | +ordinal selection works similarly to plural selection, but uses a separate set of rules |
| 40 | +for each locale. |
| 41 | +This is visible in English, for example, where plural rules use only `one` and `other` |
| 42 | +but ordinal rules use `one` (_1st_, _21st_, etc.), `few` (_2nd_, _22nd_, etc.), |
| 43 | +`many` (_3rd_, _23rd_, etc.), and `other` (_4th_, _5th_, etc.). |
| 44 | + |
| 45 | +Additionally, |
| 46 | +MF1 provides `ChoiceFormat` selection based on a complex rule set |
| 47 | +(and which allows determining if a number falls into a specific range). |
| 48 | + |
| 49 | +Both JS and ICU PluralRules implementations provide for determining the plural category |
| 50 | +of a range based on its start and end values. |
| 51 | +Range-based selectors are not initially considered here. |
| 52 | + |
| 53 | +## Use-Cases |
| 54 | + |
| 55 | +As a user, I want to write messages that use the correct plural for |
| 56 | +my locale and enables translation to locales that use different rules. |
| 57 | + |
| 58 | +As a user, I want to write messages that use the correct ordinal for |
| 59 | +my locale and enables translation to locales that use different rules. |
| 60 | + |
| 61 | +As a user, I want to write messages in which the pattern used depends on exactly matching |
| 62 | +a numeric value. |
| 63 | + |
| 64 | +As a user, I want to write messages that mix exact matching and |
| 65 | +either plural or ordinal selection in a single message. |
| 66 | +> For example: |
| 67 | +>``` |
| 68 | +>.match {$numRemaining} |
| 69 | +>0 {{You have no more chances remaining (exact match)}} |
| 70 | +>1 {{You have one more chance remaining (exact match)}} |
| 71 | +>one {{You have {$numRemaining} chance remaining (plural)}} |
| 72 | +> * {{You have {$numRemaining} chances remaining (plural)}} |
| 73 | +>``` |
| 74 | +
|
| 75 | +
|
| 76 | +## Requirements |
| 77 | +
|
| 78 | +- Enable cardinal plural selection. |
| 79 | +- Enable ordinal number selection. |
| 80 | +- Enable exact match selection. |
| 81 | +- Enable simultaneous "exact match" and either plural or ordinal selection. |
| 82 | + > For example, allow variants `[1]` and `[one]` in the same message. |
| 83 | +- Selection must support relevant formatting options, such as `minimumFractionDigits`. |
| 84 | + > For example, in English the value `1` matches plural rule `one` while the value `1.0` |
| 85 | + > matches the plural rule `other` (`*`) |
| 86 | +- Encourage developers to provide the formatting options used in patterns to the selector |
| 87 | + so that proper selection can be done. |
| 88 | +
|
| 89 | +## Constraints |
| 90 | +
|
| 91 | +ICU MF1 messages using `plural` and `selectordinal` should be representable in MF2. |
| 92 | +
|
| 93 | +## Proposed Design |
| 94 | +
|
| 95 | +Given that we already have a `:number`, |
| 96 | +it makes sense to add a `<matchSignature>` to it with an option |
| 97 | +
|
| 98 | +```xml |
| 99 | +<option name="select" values="plural ordinal exact" default="plural" /> |
| 100 | +``` |
| 101 | +
|
| 102 | +The default `plural` value is presumed to be the most common use case, |
| 103 | +and it affords the least bad fallback when used incorrectly: |
| 104 | +Using "plural" for "exact" still selects exactly matching cases, |
| 105 | +whereas using "exact" for "plural" will not select LDML category matches. |
| 106 | +This might not be noticeable in the source language, |
| 107 | +but can cause problems in target locales that the original developer is not considering. |
| 108 | + |
| 109 | +> For example, a naive developer might use a special message for the value `1` without |
| 110 | +> considering other locale's need for a `one` plural: |
| 111 | +> |
| 112 | +> ``` |
| 113 | +> .match {$var} |
| 114 | +> [1] {{You have one last chance}} |
| 115 | +> [one] {{You have {$var} chance remaining}} // needed by languages such as Polish or Russian |
| 116 | +> [*] {{You have {$var} chances remaining}} |
| 117 | +> ``` |
| 118 | +
|
| 119 | +Additional options such as `minimumFractionDigits` and others already supported by `:number` |
| 120 | +should also be supported. |
| 121 | +
|
| 122 | +If PR [#532](https://github.com/unicode-org/message-format-wg/pull/532) is accepted, |
| 123 | +also add the following `<alias>` definitions to `<function name="number">`: |
| 124 | +
|
| 125 | +```xml |
| 126 | +<alias name="plural" supports="match"> |
| 127 | + <setOption name="select" value="plural"/> |
| 128 | +</alias> |
| 129 | +<alias name="ordinal" supports="match"> |
| 130 | + <setOption name="select" value="ordinal"/> |
| 131 | +</alias> |
| 132 | +``` |
| 133 | +
|
| 134 | +## Alternatives Considered |
| 135 | + |
| 136 | +### Completely Separate Functions |
| 137 | + |
| 138 | +An alternative approach to this problem could be to leave the `:number` `<matchSignature>` undefined, |
| 139 | +and to define three further functions, each with a `<matchSignature>`: |
| 140 | + |
| 141 | +- `:plural` |
| 142 | +- `:ordinal` |
| 143 | +- `:exact` (actual name TBD, pending the resolution of [#433](https://github.com/unicode-org/message-format-wg/issues/433) |
| 144 | + |
| 145 | +which would each need the same set of options as `:number`, except for `type`. |
| 146 | + |
| 147 | +This approach would also mostly work, but it introduces new failure modes: |
| 148 | + |
| 149 | +- If a `:number` is used directly as a selector, this should produce a runtime error. |
| 150 | +- If a `:plural`/`:ordinal`/`:exact` is used as a formatter, this should produce a runtime error. |
| 151 | +- Developers are less encouraged to use the same formatting and selection options. |
| 152 | + |
| 153 | +To expand on the last of these, |
| 154 | +consider this message: |
| 155 | + |
| 156 | +``` |
| 157 | +.match {$count :plural minimumFractionDigits=1} |
| 158 | +0 {{You have no apples}} |
| 159 | +1 {{You have exactly one apple}} |
| 160 | +* {{You have {$count :number minimumFractionDigits=1} apples}} |
| 161 | +``` |
| 162 | + |
| 163 | +Here, because selection on `:number` is not allowed, |
| 164 | +it's easy to duplicate the options because _some_ annotation is required on the selector. |
| 165 | +It would also be relatively easy to leave out the `minimumFractionDigits=1` option from the selector, |
| 166 | +as it's not required for the English source. |
| 167 | + |
| 168 | +With the proposed design, this message would much more naturally be written as: |
| 169 | + |
| 170 | +``` |
| 171 | +.input {$count :number minimumFractionDigits=1} |
| 172 | +.match {$count} |
| 173 | +0 {{You have no apples}} |
| 174 | +1 {{You have exactly one apple}} |
| 175 | +one {{You have {$count} apple}} |
| 176 | +* {{You have {$count} apples}} |
| 177 | +``` |
| 178 | + |
| 179 | +#### Pros |
| 180 | + |
| 181 | +- None? |
| 182 | + |
| 183 | +#### Cons |
| 184 | + |
| 185 | +- Naïve selection on `:number` will fail, leading to user confusion and annoyance. |
| 186 | +- No encouragement to use the same options for selection and formatting. |
| 187 | + |
| 188 | +### Do Not Standardize Number Selection |
| 189 | + |
| 190 | +We could leave number selection undefined in the spec, making it an implementation concern. |
| 191 | +Each implementation could/would then provide their own selectors, |
| 192 | +and they _might_ converge on some overlap that users could safely use across platforms. |
| 193 | + |
| 194 | +#### Pros |
| 195 | + |
| 196 | +- The spec is a little bit lighter, as we've left out this part. |
| 197 | + |
| 198 | +#### Cons |
| 199 | + |
| 200 | +- No guarantees about interoperability for a relatively core feature. |
0 commit comments