Skip to content

Commit 8f424cc

Browse files
committed
Use curly braces to delimit patterns
Closes unicode-org#255.
1 parent cb02ef0 commit 8f424cc

File tree

2 files changed

+53
-54
lines changed

2 files changed

+53
-54
lines changed

spec/message.ebnf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Selector ::= 'match' ( '{' Expression '}' )+
77
/* Variants and Patterns */
88
Variant ::= 'when' ( WhiteSpace VariantKey )+ Pattern
99
VariantKey ::= Literal | Nmtoken | '*'
10-
Pattern ::= '[' (Text | Placeholder)* ']' /* ws: explicit */
10+
Pattern ::= '{' (Text | Placeholder)* '}' /* ws: explicit */
1111

1212
/* Placeholders */
1313
Placeholder ::= '{' (Expression | Markup | MarkupEnd)? '}'
@@ -25,7 +25,7 @@ Markup ::= MarkupStart Option*
2525

2626
/* Text */
2727
Text ::= (TextChar | TextEscape)+
28-
TextChar ::= AnyChar - ('[' | ']' | '{' | '}' | Esc)
28+
TextChar ::= AnyChar - ('{' | '}' | Esc)
2929
AnyChar ::= [#x0-#x10FFFF]
3030

3131
/* Names */
@@ -49,7 +49,7 @@ LiteralChar ::= AnyChar - ('(' | ')' | Esc)
4949

5050
/* Escape sequences */
5151
Esc ::= '\'
52-
TextEscape ::= Esc Esc | Esc '[' | Esc ']' | Esc '{' | Esc '}'
52+
TextEscape ::= Esc Esc | Esc '{' | Esc '}'
5353
LiteralEscape ::= Esc Esc | Esc '(' | Esc ')'
5454

5555
/* WhiteSpace */

spec/syntax.md

Lines changed: 50 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -80,101 +80,101 @@ The syntax specification takes into account the following design restrictions:
8080

8181
### Simple Messages
8282

83-
All messages, including simple ones, need `[…]` delimiters:
83+
All messages, including simple ones, need `{…}` delimiters:
8484

85-
[Hello, world!]
85+
{Hello, world!}
8686

8787
The same message defined in a `.properties` file:
8888

8989
```properties
90-
app.greetings.hello = [Hello, world!]
90+
app.greetings.hello = {Hello, world!}
9191
```
9292

9393
The same message defined inline in JavaScript:
9494

9595
```js
96-
let hello = new MessageFormat('[Hello, world!]')
96+
let hello = new MessageFormat('{Hello, world!}')
9797
hello.format()
9898
```
9999

100100
### Simple Placeholders
101101

102-
Messages may contain placeholders within `{…}` delimiters,
102+
Messages may contain placeholders within nested `{…}` delimiters,
103103
such as variables that are expected to be passed in as format paramters:
104104

105-
[Hello, {$userName}!]
105+
{Hello, {$userName}!}
106106

107107
### Formatting Functions
108108

109109
A message with an interpolated `$date` variable formatted with the `:datetime` function:
110110

111-
[Today is {$date :datetime weekday=long}.]
111+
{Today is {$date :datetime weekday=long}.}
112112

113113
A message with an interpolated `$userName` variable formatted with
114114
the custom `:person` function capable of
115115
declension (using either a fixed dictionary, algorithmic declension, ML, etc.):
116116

117-
[Hello, {$userName :person case=vocative}!]
117+
{Hello, {$userName :person case=vocative}!}
118118

119119
A message with an interpolated `$userObj` variable formatted with
120120
the custom `:person` function capable of
121121
plucking the first name from the object representing a person:
122122

123-
[Hello, {$userObj :person firstName=long}!]
123+
{Hello, {$userObj :person firstName=long}!}
124124

125125
### Markup Elements
126126

127127
A message with two markup-like element placeholders, `button` and `link`,
128128
which the runtime can use to construct a document tree structure for a UI framework.
129129

130-
[{+button}Submit{-button} or {+link}cancel{-link}.]
130+
{{+button}Submit{-button} or {+link}cancel{-link}.}
131131

132132
### Selection
133133

134134
A message with a single selector:
135135

136136
match {$count :number}
137-
when 1 [You have one notification.]
138-
when * [You have {$count} notifications.]
137+
when 1 {You have one notification.}
138+
when * {You have {$count} notifications.}
139139

140140
A message with a single selector which is an invocation of
141141
a custom function `:platform`, formatted on a single line:
142142

143-
match {:platform} when windows [Settings] when * [Preferences]
143+
match {:platform} when windows {Settings} when * {Preferences}
144144

145145
A message with a single selector and a custom `:hasCase` function
146146
which allows the message to query for presence of grammatical cases required for each variant:
147147

148148
match {$userName :hasCase}
149-
when vocative [Hello, {$userName :person case=vocative}!]
150-
when accusative [Please welcome {$userName :person case=accusative}!]
151-
when * [Hello!]
149+
when vocative {Hello, {$userName :person case=vocative}!}
150+
when accusative {Please welcome {$userName :person case=accusative}!}
151+
when * {Hello!}
152152

153153
A message with 2 selectors:
154154

155155
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.]
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.}
162162

163163
### Local Variables
164164

165165
A message defining a local variable `$whom` which is then used twice inside the pattern:
166166

167167
let $whom = {$monster :noun case=accusative}
168-
[You see {$quality :adjective article=indefinite accord=$whom} {$whom}!]
168+
{You see {$quality :adjective article=indefinite accord=$whom} {$whom}!}
169169

170170
A message defining two local variables:
171171
`$itemAcc` and `$countInt`, and using `$countInt` as a selector:
172172

173173
let $countInt = {$count :number maximumFractionDigits=0}
174174
let $itemAcc = {$item :noun count=$count case=accusative}
175175
match {$countInt}
176-
when one [You bought {$color :adjective article=indefinite accord=$itemAcc} {$itemAcc}.]
177-
when * [You bought {$countInt} {$color :adjective accord=$itemAcc} {$itemAcc}.]
176+
when one {You bought {$color :adjective article=indefinite accord=$itemAcc} {$itemAcc}.}
177+
when * {You bought {$countInt} {$color :adjective accord=$itemAcc} {$itemAcc}.}
178178

179179
### Complex Messages
180180

@@ -186,20 +186,20 @@ A complex message with 2 selectors and 3 local variable definitions:
186186

187187
match {$host :gender} {$guestOther :number}
188188

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.]
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.}
193193

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.]
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.}
198198

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.]
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.}
203203

204204
## Productions
205205

@@ -240,15 +240,15 @@ Examples:
240240

241241
```
242242
match {$count :plural}
243-
when 1 [One apple]
244-
when * [{$count} apples]
243+
when 1 {One apple}
244+
when * {{$count} apples}
245245
```
246246

247247
```
248248
let $frac = {$count: number minFractionDigits=2}
249249
match {$frac}
250-
when 1 [One apple]
251-
when * [{$frac} apples]
250+
when 1 {One apple}
251+
when * {{$frac} apples}
252252
```
253253

254254
### Variants
@@ -270,13 +270,13 @@ A well-formed message is considered valid if the following requirements are sati
270270
### Patterns
271271

272272
A pattern is a sequence of translatable elements.
273-
Patterns are always delimited with `[` at the start, and `]` at the end.
273+
Patterns are always delimited with `{` at the start, and `}` at the end.
274274
This serves 3 purposes:
275275

276276
- The message should be unambiguously embeddable in various container formats
277277
regardless of the container's whitespace trimming rules.
278278
E.g. in Java `.properties` files,
279-
`hello = [Hello]` will unambiguously define the `Hello` message without the space in front of it.
279+
`hello = {Hello}` will unambiguously define the `Hello` message without the space in front of it.
280280
- The message should be conveniently embeddable in various programming languages
281281
without the need to escape characters commonly related to strings, e.g. `"` and `'`.
282282
Such need may still occur when a single or double quote is
@@ -285,13 +285,13 @@ This serves 3 purposes:
285285
are translatable and which ones are part of the formatting logic definition.
286286

287287
```ebnf
288-
Pattern ::= '[' (Text | Placeholder)* ']' /* ws: explicit */
288+
Pattern ::= '{' (Text | Placeholder)* '}' /* ws: explicit */
289289
```
290290

291291
Examples:
292292

293293
```
294-
[Hello, world!]
294+
{Hello, world!}
295295
```
296296

297297
### Placeholders
@@ -366,11 +366,11 @@ MarkupEnd ::= '-' Name /* ws: explicit */
366366
Examples:
367367

368368
```
369-
[This is {+b}bold{-b}.]
369+
{This is {+b}bold{-b}.}
370370
```
371371

372372
```
373-
[{+h1 name=(above-and-beyond)}Above And Beyond{-h1}]
373+
{{+h1 name=(above-and-beyond)}Above And Beyond{-h1}}
374374
```
375375

376376
## Tokens
@@ -381,13 +381,12 @@ The grammar defines the following tokens for the purpose of the lexical analysis
381381

382382
Text is the translatable content of a _pattern_.
383383
Any Unicode codepoint is allowed in text, with the exception of
384-
`[` and `]` (which delimit patterns),
385-
`{` and `}` (which delimit placeholders),
384+
`{` and `}` (which delimit patterns and placeholders),
386385
and `\` (which starts an escape sequence).
387386

388387
```ebnf
389388
Text ::= (TextChar | TextEscape)+ /* ws: explicit */
390-
TextChar ::= AnyChar - ('[' | ']' | '{' | '}' | Esc)
389+
TextChar ::= AnyChar - ('{' | '}' | Esc)
391390
AnyChar ::= [#x0-#x10FFFF]
392391
```
393392

@@ -449,7 +448,7 @@ They are allowed in translatable text as well as in literals.
449448

450449
```ebnf
451450
Esc ::= '\'
452-
TextEscape ::= Esc Esc | Esc '[' | Esc ']' | Esc '{' | Esc '}'
451+
TextEscape ::= Esc Esc | Esc '{' | Esc '}'
453452
LiteralEscape ::= Esc Esc | Esc '(' | Esc ')'
454453
```
455454

0 commit comments

Comments
 (0)