1515 1 . [ Complex Messages] ( #complex-messages )
16161 . [ Productions] ( #productions )
1717 1 . [ Message] ( #message )
18- 1 . [ Plain ] ( #plain )
19- 1 . [ Preamble ] ( #preamble )
18+ 1 . [ Variable Declarations ] ( #variable-declarations )
19+ 1 . [ Selectors ] ( #selectors )
2020 1 . [ Variants] ( #variants )
2121 1 . [ Patterns] ( #patterns )
2222 1 . [ Placeholders] ( #placeholders )
@@ -66,9 +66,6 @@ The design goals of the syntax specification are as follows:
6666 ` .properties ` , YAML, XML, inlined as string literals in programming languages, etc.
6767 This includes a future _ MessageResource_ specification.
6868
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-
7269### Design Restrictions
7370
7471The syntax specification takes into account the following design restrictions:
@@ -77,52 +74,36 @@ The syntax specification takes into account the following design restrictions:
7774 It should be possible to define a message entirely on a single line with no ambiguity,
7875 as well as to format it over multiple lines for clarity.
7976
80- 1 . The syntax should not use nor reserve any keywords in any natural language,
81- such as ` if ` , ` match ` , or ` let ` .
82-
83771 . The syntax should define as few special characters and sigils as possible.
8478
8579## Overview & Examples
8680
8781### Simple Messages
8882
89- A simple message without any variables does not need any syntax :
83+ All messages, including simple ones, need ` […] ` delimiters :
9084
91- Hello, world!
85+ [ Hello, world!]
9286
9387The same message defined in a ` .properties ` file:
9488
9589``` properties
96- app.greetings.hello = Hello, world!
90+ app.greetings.hello = [ Hello, world!]
9791```
9892
9993The same message defined inline in JavaScript:
10094
10195``` js
102- let hello = new MessageFormat (' Hello, world!' )
96+ let hello = new MessageFormat (' [ Hello, world!] ' )
10397hello .format ()
10498```
10599
106100### Simple Placeholders
107101
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 :
110104
111105 [Hello, {$userName}!]
112106
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-
126107### Formatting Functions
127108
128109A 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
152133
153134A message with a single selector:
154135
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.]
158139
159140A message with a single selector which is an invocation of
160141a custom function ` :platform ` , formatted on a single line:
161142
162- {:platform} windows [Settings] * [Preferences]
143+ match {:platform} when windows [Settings] when * [Preferences]
163144
164145A message with a single selector and a custom ` :hasCase ` function
165146which allows the message to query for presence of grammatical cases required for each variant:
166147
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!]
171152
172153A message with 2 selectors:
173154
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.]
181162
182163### Local Variables
183164
184165A message defining a local variable ` $whom ` which is then used twice inside the pattern:
185166
186- $whom = {$monster :noun case=accusative}
167+ let $whom = {$monster :noun case=accusative}
187168 [You see {$quality :adjective article=indefinite accord=$whom} {$whom}!]
188169
189170A message defining two local variables:
190171` $itemAcc ` and ` $countInt ` , and using ` $countInt ` as a selector:
191172
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}.]
196178
197179### Complex Messages
198180
199181A complex message with 2 selectors and 3 local variable definitions:
200182
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}
203186
204- $hostName = {$host :person firstName=long}
205- $guestName = {$guest :person firstName=long}
206- $guestsOther = {$guestCount :number offset=1}
187+ match {$host :gender} {$guestOther :number}
207188
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.]
212193
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.]
217198
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.]
222203
223204## Productions
224205
@@ -229,63 +210,61 @@ if it meets additional semantic requirements about its structure, defined below.
229210
230211### Message
231212
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
233214followed by one or more variants which represent the translatable body of the message.
234215
235216``` ebnf
236- Message ::= Plain | Pattern | Preamble Variant+
217+ Message ::= Declaration* ( Pattern | Selector Variant+ )
237218```
238219
239- ### Plain
220+ ### Variable Declarations
240221
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.
248225
249226``` 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 '}'
254228```
255229
256- ### Preamble
230+ ### Selectors
257231
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.
261234
262235``` ebnf
263- Preamble ::= Selector+
264- Selector ::= (Variable '=')? '{' Expression '}'
236+ Selector ::= 'match' ( '{' Expression '}' )+
265237```
266238
267239Examples:
268240
269241```
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]
273252```
274253
275254### Variants
276255
277256A 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 .
279258The key ` * ` is a "catch-all" key, matching all selector values.
280259
281260``` ebnf
282- Variant ::= VariantKey* Pattern
261+ Variant ::= 'when' ( WhiteSpace VariantKey )+ Pattern
283262VariantKey ::= Literal | Nmtoken | '*'
284263```
285264
286265A well-formed message is considered valid if the following requirements are satisfied:
287266
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.
289268- At least one variant's keys must all be equal to the catch-all key (` * ` ).
290269
291270### Patterns
0 commit comments