@@ -19,6 +19,239 @@ the local variable takes precedence.
19
19
It is an error for a local variable definition to
20
20
refer to a local variable that's defined after it in the message.
21
21
22
+ ## Pattern Selection
23
+
24
+ When formatting a message with one or more _ selectors_ ,
25
+ the _ pattern_ of one of the _ variants_ must be selected for formatting.
26
+
27
+ When a message has a single _ selector_ ,
28
+ an implementation-defined method compares each key to the _ selector_
29
+ and determines which of the keys match, and in what order of preference.
30
+ A catch-all key will always match, but is always the least preferred choice.
31
+ During selection, the _ variant_ with the best-matching key is selected.
32
+
33
+ In a message with more than one _ selector_ ,
34
+ each _ variant_ also has a corresponding number of keys.
35
+ These correspond to _ selectors_ by position.
36
+ The same implementation-defined method as above is used to compare
37
+ the corresponding key of each _ variant_ to its _ selector_ ,
38
+ to determine which of the keys match, and in what order of preference.
39
+ In order to select a single _ variant_ ,
40
+ the full list of _ variants_ will need to be filtered and sorted.
41
+ First, each _ variant_ with a key that does not match its _ selector_ is left out.
42
+ Then, the remaining _ variants_ are sorted lexicographically by key preference,
43
+ with earlier _ selectors_ having higher priority than later ones.
44
+ Finally, the highest-sorted _ variant_ is selected.
45
+
46
+ This selection method is defined in more detail below.
47
+ An implementation MAY use any pattern selection method,
48
+ as long as its observable behaviour matches the results of the method defined here.
49
+
50
+ ### Resolve Selectors
51
+
52
+ First, resolve the values of each _ selector_ :
53
+
54
+ 1 . Let ` res ` be a new empty list of resolved values that support selection.
55
+ 1 . For each _ expression_ ` exp ` of the message's _ selectors_ ,
56
+ 1 . Let ` rv ` be the resolved value of ` exp ` .
57
+ 1 . If selection is supported for ` rv ` :
58
+ 1 . Append ` rv ` as the last element of the list ` res ` .
59
+ 1 . Else:
60
+ 1 . Let ` nomatch ` be a resolved value for which selection always fails.
61
+ 1 . Append ` nomatch ` as the last element of the list ` res ` .
62
+ 1 . Emit a Selection Error.
63
+
64
+ The shape of the resolved values is determined by each implementation,
65
+ along with the manner of determining their support for selection.
66
+
67
+ ### Resolve Preferences
68
+
69
+ Next, using ` res ` , resolve the preferential order for all message keys:
70
+
71
+ 1 . Let ` pref ` be a new empty list of lists of strings.
72
+ 1 . For each index ` i ` in ` res ` :
73
+ 1 . Let ` keys ` be a new empty list of strings.
74
+ 1 . For each _ variant_ ` var ` of the message:
75
+ 1 . Let ` key ` be the ` var ` key at position ` i ` .
76
+ 1 . If ` key ` is not the catch-all key ` '*' ` :
77
+ 1 . Let ` ks ` be the decoded value of ` key ` .
78
+ 1 . Append ` ks ` as the last element of the list ` keys ` .
79
+ 1 . Let ` rv ` be the resolved value at index ` i ` of ` res ` .
80
+ 1 . Let ` matches ` be the result of calling the method MatchSelectorKeys(` rv ` , ` keys ` )
81
+ 1 . Append ` matches ` as the last element of the list ` pref ` .
82
+
83
+ The method MatchSelectorKeys is determined by the implementation.
84
+ It takes as arguments a resolved _ selector_ value ` rv ` and a list of string keys ` keys ` ,
85
+ and returns a list of string keys in preferential order.
86
+ The returned list must only contain unique elements of the input list ` keys ` ,
87
+ and it may be empty.
88
+ The most preferred key is first, with the rest sorted by decreasing preference.
89
+
90
+ ### Filter Variants
91
+
92
+ Then, using the preferential key orders ` pref ` ,
93
+ filter the list of _ variants_ to the ones that match with some preference:
94
+
95
+ 1 . Let ` vars ` be a new empty list of _ variants_ .
96
+ 1 . For each _ variant_ ` var ` of the message:
97
+ 1 . For each index ` i ` in ` pref ` :
98
+ 1 . Let ` key ` be the ` var ` key at position ` i ` .
99
+ 1 . If ` key ` is the catch-all key ` '*' ` :
100
+ 1 . Continue the inner loop on ` pref ` .
101
+ 1 . Let ` ks ` be the decoded value of ` key ` .
102
+ 1 . Let ` matches ` be the list of strings at index ` i ` of ` pref ` .
103
+ 1 . If ` matches ` includes ` ks ` :
104
+ 1 . Continue the inner loop on ` pref ` .
105
+ 1 . Else:
106
+ 1 . Continue the outer loop on message _ variants_ .
107
+ 1 . Append ` var ` as the last element of the list ` vars ` .
108
+
109
+ ### Sort Variants
110
+
111
+ Finally, sort the list of variants ` vars ` and select the _ pattern_ :
112
+
113
+ 1 . Let ` sortable ` be a new empty list of (integer, _ variant_ ) tuples.
114
+ 1 . For each _ variant_ ` var ` of ` vars ` :
115
+ 1 . Let ` tuple ` be a new tuple (-1, ` var ` ).
116
+ 1 . Append ` tuple ` as the last element of the list ` sortable ` .
117
+ 1 . Let ` len ` be the integer count of items in ` pref ` .
118
+ 1 . Let ` i ` be ` len ` - 1.
119
+ 1 . While ` i ` >= 0:
120
+ 1 . Let ` matches ` be the list of strings at index ` i ` of ` pref ` .
121
+ 1 . Let ` minpref ` be the integer count of items in ` matches ` .
122
+ 1 . For each tuple ` tuple ` of ` sortable ` :
123
+ 1 . Let ` matchpref ` be an integer with the value ` minpref ` .
124
+ 1 . Let ` key ` be the ` tuple ` _ variant_ key at position ` i ` .
125
+ 1 . If ` key ` is not the catch-all key ` '*' ` :
126
+ 1 . Let ` ks ` be the decoded value of ` key ` .
127
+ 1 . Let ` matchpref ` be the integer position of ` ks ` in ` matches ` .
128
+ 1 . Set the ` tuple ` integer value as ` matchpref ` .
129
+ 1 . Call the method SortVariants(` sortable ` ).
130
+ 1 . Set ` i ` to be ` i ` - 1.
131
+ 1 . Let ` var ` be the _ variant_ element of the first element of ` sortable ` .
132
+ 1 . Select the _ pattern_ of ` var ` .
133
+
134
+ The method SortVariants is determined by the implementation.
135
+ It takes as an argument a ` sortable ` list of (integer, _ variant_ ) tuples,
136
+ which it modifies in place using some stable sorting algorithm.
137
+ The method does not return anything.
138
+ The list is sorted according to the tuple's first integer element,
139
+ such that a lower number is sorted before a higher one,
140
+ and entries that have the same number retain their order.
141
+
142
+ ### Examples
143
+
144
+ #### Example 1
145
+
146
+ Presuming a minimal implementation which only supports string values
147
+ and matches keys by using string comparison,
148
+ and a formatting context in which
149
+ the variable reference ` $foo ` resolves to the string ` 'foo' ` and
150
+ the variable reference ` $bar ` resolves to the string ` 'bar' ` ,
151
+ pattern selection proceeds as follows for this message:
152
+
153
+ ```
154
+ match {$foo} {$bar}
155
+ when bar bar {All bar}
156
+ when foo foo {All foo}
157
+ when * * {Otherwise}
158
+ ```
159
+
160
+ 1 . For the first selector:<br >
161
+ The value of the selector is resolved to be ` 'foo' ` .<br >
162
+ The available keys « ` 'bar' ` , ` 'foo' ` » are compared to ` 'foo' ` ,<br >
163
+ resulting in a list « ` 'foo' ` » of matching keys.
164
+
165
+ 2 . For the second selector:<br >
166
+ The value of the selector is resolved to be ` 'bar' ` .<br >
167
+ The available keys « ` 'bar' ` , ` 'foo' ` » are compared to ` 'bar' ` ,<br >
168
+ resulting in a list « ` 'bar' ` » of matching keys.
169
+
170
+ 3 . Creating the list ` vars ` of variants matching all keys:<br >
171
+ The first variant ` bar bar ` is discarded as its first key does not match the first selector.<br >
172
+ The second variant ` foo foo ` is discarded as its second key does not match the second selector.<br >
173
+ The catch-all keys of the third variant ` * * ` always match, and this is added to ` vars ` ,<br >
174
+ resulting in a list « ` * * ` » of variants.
175
+
176
+ 4 . As the list ` vars ` only has one entry, it does not need to be sorted.<br >
177
+ The pattern ` {Otherwise} ` of the third variant is selected.
178
+
179
+ #### Example 2
180
+
181
+ Alternatively, with the same implementation and formatting context as in Example 1,
182
+ pattern selection would proceed as follows for this message:
183
+
184
+ ```
185
+ match {$foo} {$bar}
186
+ when * bar {Any and bar}
187
+ when foo * {Foo and any}
188
+ when foo bar {Foo and bar}
189
+ when * * {Otherwise}
190
+ ```
191
+
192
+ 1 . For the first selector:<br >
193
+ The value of the selector is resolved to be ` 'foo' ` .<br >
194
+ The available keys « ` 'foo' ` » are compared to ` 'foo' ` ,<br >
195
+ resulting in a list « ` 'foo' ` » of matching keys.
196
+
197
+ 2 . For the second selector:<br >
198
+ The value of the selector is resolved to be ` 'bar' ` .<br >
199
+ The available keys « ` 'bar' ` » are compared to ` 'bar' ` ,<br >
200
+ resulting in a list « ` 'bar' ` » of matching keys.
201
+
202
+ 3 . Creating the list ` vars ` of variants matching all keys:<br >
203
+ The keys of all variants either match each selector exactly, or via the catch-all key,<br >
204
+ resulting in a list « ` * bar ` , ` foo * ` , ` foo bar ` , ` * * ` » of variants.
205
+
206
+ 4 . Sorting the variants:<br >
207
+ The list ` sortable ` is first set with the variants in their source order
208
+ and scores determined by the second selector:<br >
209
+ « ( 0, ` * bar ` ), ( 1, ` foo * ` ), ( 0, ` foo bar ` ), ( 1, ` * * ` ) »<br >
210
+ This is then sorted as:<br >
211
+ « ( 0, ` * bar ` ), ( 0, ` foo bar ` ), ( 1, ` foo * ` ), ( 1, ` * * ` ) ».<br >
212
+ To sort according to the first selector, the scores are updated to:<br >
213
+ « ( 1, ` * bar ` ), ( 0, ` foo bar ` ), ( 0, ` foo * ` ), ( 1, ` * * ` ) ».<br >
214
+ This is then sorted as:<br >
215
+ « ( 0, ` foo bar ` ), ( 0, ` foo * ` ), ( 1, ` * bar ` ), ( 1, ` * * ` ) ».<br >
216
+
217
+ 5 . The pattern ` {Foo and bar} ` of the most preferred ` foo bar ` variant is selected.
218
+
219
+ #### Example 3
220
+
221
+ Presuming a more powerful implementation which supports selection on numerical values,
222
+ and provides a ` :plural ` function that matches keys by their exact value
223
+ as well as their plural category (preferring the former, if possible),
224
+ and an Enligh-language formatting context in which
225
+ the variable reference ` $count ` resolves to the number ` 1 ` ,
226
+ pattern selection proceeds as follows for this message:
227
+
228
+ ```
229
+ match {$count :plural}
230
+ when one {Category match}
231
+ when 1 {Exact match}
232
+ when * {Other match}
233
+ ```
234
+
235
+ 1 . For the selector:<br >
236
+ The value of the selector is resolved to an implementation-defined value
237
+ that is capable of performing English plural category selection on the value ` 1 ` .<br >
238
+ The available keys « ` 'one' ` , ` '1' ` » are passed to
239
+ the implementation's MatchSelectorKeys method,<br >
240
+ resulting in a list « ` '1' ` , ` 'one' ` » of matching keys.
241
+
242
+ 2 . Creating the list ` vars ` of variants matching all keys:<br >
243
+ The keys of all variants are included in the list of matching keys, or use the catch-all key,<br >
244
+ resulting in a list « ` one ` , ` 1 ` , ` * ` » of variants.
245
+
246
+ 3 . Sorting the variants:<br >
247
+ The list ` sortable ` is first set with the variants in their source order
248
+ and scores determined by the selector key order:<br >
249
+ « ( 1, ` one ` ), ( 0, ` 1 ` ), ( 2, ` * ` ) »<br >
250
+ This is then sorted as:<br >
251
+ « ( 0, ` 1 ` ), ( 1, ` one ` ), ( 2, ` * ` ) »<br >
252
+
253
+ 5 . The pattern ` {Exact match} ` of the most preferred ` 1 ` variant is selected.
254
+
22
255
## Error Handling
23
256
24
257
Errors in messages and their formatting may occur and be detected
0 commit comments