15
15
1 . [ Complex Messages] ( #complex-messages )
16
16
1 . [ Productions] ( #productions )
17
17
1 . [ Message] ( #message )
18
- 1 . [ Plain ] ( #plain )
19
- 1 . [ Preamble ] ( #preamble )
18
+ 1 . [ Variable Declarations ] ( #variable-declarations )
19
+ 1 . [ Selectors ] ( #selectors )
20
20
1 . [ Variants] ( #variants )
21
21
1 . [ Patterns] ( #patterns )
22
22
1 . [ Placeholders] ( #placeholders )
@@ -66,9 +66,6 @@ The design goals of the syntax specification are as follows:
66
66
` .properties ` , YAML, XML, inlined as string literals in programming languages, etc.
67
67
This includes a future _ MessageResource_ specification.
68
68
69
- 1 . Simple messages that do not use any placeholders or selectors should (as far as possible)
70
- be represented in the syntax with no additional characters than their actual contents.
71
-
72
69
### Design Restrictions
73
70
74
71
The syntax specification takes into account the following design restrictions:
@@ -77,52 +74,36 @@ The syntax specification takes into account the following design restrictions:
77
74
It should be possible to define a message entirely on a single line with no ambiguity,
78
75
as well as to format it over multiple lines for clarity.
79
76
80
- 1 . The syntax should not use nor reserve any keywords in any natural language,
81
- such as ` if ` , ` match ` , or ` let ` .
82
-
83
77
1 . The syntax should define as few special characters and sigils as possible.
84
78
85
79
## Overview & Examples
86
80
87
81
### Simple Messages
88
82
89
- A simple message without any variables does not need any syntax :
83
+ All messages, including simple ones, need ` […] ` delimiters :
90
84
91
- Hello, world!
85
+ [ Hello, world!]
92
86
93
87
The same message defined in a ` .properties ` file:
94
88
95
89
``` properties
96
- app.greetings.hello = Hello, world!
90
+ app.greetings.hello = [ Hello, world!]
97
91
```
98
92
99
93
The same message defined inline in JavaScript:
100
94
101
95
``` js
102
- let hello = new MessageFormat (' Hello, world!' )
96
+ let hello = new MessageFormat (' [ Hello, world!] ' )
103
97
hello .format ()
104
98
```
105
99
106
100
### Simple Placeholders
107
101
108
- A message with an interpolated variable needs to be interpreted as a pattern ,
109
- which uses ` […] ` delimiters :
102
+ Messages may contain placeholders within ` {…} ` delimiters ,
103
+ such as variables that are expected to be passed in as format paramters :
110
104
111
105
[Hello, {$userName}!]
112
106
113
- The same message defined in a ` .properties ` file:
114
-
115
- ``` properties
116
- app.greetings.hello = [Hello, {$userName}!]
117
- ```
118
-
119
- The same message defined inline in JavaScript:
120
-
121
- ``` js
122
- let hello = new MessageFormat (' [Hello, {$userName}!]' )
123
- hello .format ({ userName: ' Anne' })
124
- ```
125
-
126
107
### Formatting Functions
127
108
128
109
A message with an interpolated ` $date ` variable formatted with the ` :datetime ` function:
@@ -152,73 +133,73 @@ which the runtime can use to construct a document tree structure for a UI framew
152
133
153
134
A message with a single selector:
154
135
155
- {$count :number}
156
- 1 [You have one notification.]
157
- * [You have {$count} notifications.]
136
+ match {$count :number}
137
+ when 1 [You have one notification.]
138
+ when * [You have {$count} notifications.]
158
139
159
140
A message with a single selector which is an invocation of
160
141
a custom function ` :platform ` , formatted on a single line:
161
142
162
- {:platform} windows [Settings] * [Preferences]
143
+ match {:platform} when windows [Settings] when * [Preferences]
163
144
164
145
A message with a single selector and a custom ` :hasCase ` function
165
146
which allows the message to query for presence of grammatical cases required for each variant:
166
147
167
- {$userName :hasCase}
168
- vocative [Hello, {$userName :person case=vocative}!]
169
- accusative [Please welcome {$userName :person case=accusative}!]
170
- * [Hello!]
148
+ match {$userName :hasCase}
149
+ when vocative [Hello, {$userName :person case=vocative}!]
150
+ when accusative [Please welcome {$userName :person case=accusative}!]
151
+ when * [Hello!]
171
152
172
153
A message with 2 selectors:
173
154
174
- {$photoCount :number} {$userGender :equals}
175
- 1 masculine [{$userName} added a new photo to his album.]
176
- 1 feminine [{$userName} added a new photo to her album.]
177
- 1 * [{$userName} added a new photo to their album.]
178
- * masculine [{$userName} added {$photoCount} photos to his album.]
179
- * feminine [{$userName} added {$photoCount} photos to her album.]
180
- * * [{$userName} added {$photoCount} photos to their album.]
155
+ match {$photoCount :number} {$userGender :equals}
156
+ when 1 masculine [{$userName} added a new photo to his album.]
157
+ when 1 feminine [{$userName} added a new photo to her album.]
158
+ when 1 * [{$userName} added a new photo to their album.]
159
+ when * masculine [{$userName} added {$photoCount} photos to his album.]
160
+ when * feminine [{$userName} added {$photoCount} photos to her album.]
161
+ when * * [{$userName} added {$photoCount} photos to their album.]
181
162
182
163
### Local Variables
183
164
184
165
A message defining a local variable ` $whom ` which is then used twice inside the pattern:
185
166
186
- $whom = {$monster :noun case=accusative}
167
+ let $whom = {$monster :noun case=accusative}
187
168
[You see {$quality :adjective article=indefinite accord=$whom} {$whom}!]
188
169
189
170
A message defining two local variables:
190
171
` $itemAcc ` and ` $countInt ` , and using ` $countInt ` as a selector:
191
172
192
- $countInt = {$count :number maximumFractionDigits=0}
193
- $itemAcc = {$item :noun count=$count case=accusative}
194
- one [You bought {$color :adjective article=indefinite accord=$itemAcc} {$itemAcc}.]
195
- * [You bought {$countInt} {$color :adjective accord=$itemAcc} {$itemAcc}.]
173
+ let $countInt = {$count :number maximumFractionDigits=0}
174
+ let $itemAcc = {$item :noun count=$count case=accusative}
175
+ match {$countInt}
176
+ when one [You bought {$color :adjective article=indefinite accord=$itemAcc} {$itemAcc}.]
177
+ when * [You bought {$countInt} {$color :adjective accord=$itemAcc} {$itemAcc}.]
196
178
197
179
### Complex Messages
198
180
199
181
A complex message with 2 selectors and 3 local variable definitions:
200
182
201
- {$host :gender}
202
- {$guestOther :number}
183
+ let $hostName = {$host :person firstName=long}
184
+ let $guestName = {$guest :person firstName=long}
185
+ let $guestsOther = {$guestCount :number offset=1}
203
186
204
- $hostName = {$host :person firstName=long}
205
- $guestName = {$guest :person firstName=long}
206
- $guestsOther = {$guestCount :number offset=1}
187
+ match {$host :gender} {$guestOther :number}
207
188
208
- female 0 [{$hostName} does not give a party.]
209
- female 1 [{$hostName} invites {$guestName} to her party.]
210
- female 2 [{$hostName} invites {$guestName} and one other person to her party.]
211
- female * [{$hostName} invites {$guestName} and {$guestsOther} other people to her party.]
189
+ when female 0 [{$hostName} does not give a party.]
190
+ when female 1 [{$hostName} invites {$guestName} to her party.]
191
+ when female 2 [{$hostName} invites {$guestName} and one other person to her party.]
192
+ when female * [{$hostName} invites {$guestName} and {$guestsOther} other people to her party.]
212
193
213
- male 0 [{$hostName} does not give a party.]
214
- male 1 [{$hostName} invites {$guestName} to his party.]
215
- male 2 [{$hostName} invites {$guestName} and one other person to his party.]
216
- male * [{$hostName} invites {$guestName} and {$guestsOther} other people to his party.]
194
+ when male 0 [{$hostName} does not give a party.]
195
+ when male 1 [{$hostName} invites {$guestName} to his party.]
196
+ when male 2 [{$hostName} invites {$guestName} and one other person to his party.]
197
+ when male * [{$hostName} invites {$guestName} and {$guestsOther} other people to his party.]
217
198
218
- * 0 [{$hostName} does not give a party.]
219
- * 1 [{$hostName} invites {$guestName} to their party.]
220
- * 2 [{$hostName} invites {$guestName} and one other person to their party.]
221
- * * [{$hostName} invites {$guestName} and {$guestsOther} other people to their party.]
199
+ when * 0 [{$hostName} does not give a party.]
200
+ when * 1 [{$hostName} invites {$guestName} to their party.]
201
+ when * 2 [{$hostName} invites {$guestName} and one other person to their party.]
202
+ when * * [{$hostName} invites {$guestName} and {$guestsOther} other people to their party.]
222
203
223
204
## Productions
224
205
@@ -229,63 +210,61 @@ if it meets additional semantic requirements about its structure, defined below.
229
210
230
211
### Message
231
212
232
- A single message is either a plain message, a single pattern, or has a preamble
213
+ A single message is either a single pattern, or has a ` match ` statement
233
214
followed by one or more variants which represent the translatable body of the message.
234
215
235
216
``` ebnf
236
- Message ::= Plain | Pattern | Preamble Variant+
217
+ Message ::= Declaration* ( Pattern | Selector Variant+ )
237
218
```
238
219
239
- ### Plain
220
+ ### Variable Declarations
240
221
241
- A plain message only contains translatable content;
242
- placeholders or their delimiters are not allowed inside a plain message.
243
- Plain messages must not start with one of the syntax characters ` [ ` , ` { ` or ` $ ` ,
244
- as those would indicate that the message has a more complex structure.
245
- Any whitespace at the beginning or end of a plain message is ignored.
246
- A plain message cannot represent an empty string;
247
- for that, use an empty pattern ` [] ` instead.
222
+ A variable declaration is an expression binding a variable identifier
223
+ within the scope of the message to the value of an expression.
224
+ This local variable may then be used in other expressions within the same message.
248
225
249
226
``` ebnf
250
- Plain ::= PlainStart (PlainChar* PlainEnd)? /* ws: explicit */
251
- PlainChar ::= AnyChar - ('{' | '}')
252
- PlainStart ::= PlainChar - ('[' | '$' | WhiteSpace)
253
- PlainEnd ::= PlainChar - WhiteSpace
227
+ Declaration ::= 'let' WhiteSpace Variable '=' '{' Expression '}'
254
228
```
255
229
256
- ### Preamble
230
+ ### Selectors
257
231
258
- The preamble is where selectors and local variables can be defined.
259
- A selector is an expression which will be used to choose one of the variants during formatting.
260
- A selector can be optionally bound to a local variable, which may then be used in other expressions.
232
+ A selector is a statement containing one or more expressions
233
+ which will be used to choose one of the variants during formatting.
261
234
262
235
``` ebnf
263
- Preamble ::= Selector+
264
- Selector ::= (Variable '=')? '{' Expression '}'
236
+ Selector ::= 'match' ( '{' Expression '}' )+
265
237
```
266
238
267
239
Examples:
268
240
269
241
```
270
- $frac = {$count: number minFractionDigits=2}
271
- 1 [One apple]
272
- * [{$frac} apples]
242
+ match {$count :plural}
243
+ when 1 [One apple]
244
+ when * [{$count} apples]
245
+ ```
246
+
247
+ ```
248
+ let $frac = {$count: number minFractionDigits=2}
249
+ match {$frac}
250
+ when 1 [One apple]
251
+ when * [{$frac} apples]
273
252
```
274
253
275
254
### Variants
276
255
277
256
A variant is a keyed pattern.
278
- The keys are used to match against the selectors defined in the preamble .
257
+ The keys are used to match against the selectors defined in the ` match ` statement .
279
258
The key ` * ` is a "catch-all" key, matching all selector values.
280
259
281
260
``` ebnf
282
- Variant ::= VariantKey* Pattern
261
+ Variant ::= 'when' ( WhiteSpace VariantKey )+ Pattern
283
262
VariantKey ::= Literal | Nmtoken | '*'
284
263
```
285
264
286
265
A well-formed message is considered valid if the following requirements are satisfied:
287
266
288
- - The number of keys on each variant must be fewer or equal to the number of selectors defined in the preamble .
267
+ - The number of keys on each variant must be equal to the number of selectors.
289
268
- At least one variant's keys must all be equal to the catch-all key (` * ` ).
290
269
291
270
### Patterns
0 commit comments