Skip to content

Commit c9c68a1

Browse files
eemeliaphillips
andauthored
Add @attributes as reserved (#592)
* Add @attributes as reserved * Apply suggestions from code review Co-authored-by: Addison Phillips <[email protected]> * Apply suggestions from code review * Relax formatting restriction from MUST to SHOULD Co-authored-by: Addison Phillips <[email protected]> --------- Co-authored-by: Addison Phillips <[email protected]>
1 parent 715e99e commit c9c68a1

File tree

6 files changed

+117
-30
lines changed

6 files changed

+117
-30
lines changed

spec/data-model/README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,24 +136,33 @@ interface LiteralExpression {
136136
type: "expression";
137137
arg: Literal;
138138
annotation?: FunctionAnnotation | UnsupportedAnnotation;
139+
attributes?: Attribute[];
139140
}
140141

141142
interface VariableExpression {
142143
type: "expression";
143144
arg: VariableRef;
144145
annotation?: FunctionAnnotation | UnsupportedAnnotation;
146+
attributes?: Attribute[];
145147
}
146148

147149
interface FunctionExpression {
148150
type: "expression";
149151
arg?: never;
150152
annotation: FunctionAnnotation;
153+
attributes?: Attribute[];
151154
}
152155

153156
interface UnsupportedExpression {
154157
type: "expression";
155158
arg?: never;
156159
annotation: UnsupportedAnnotation;
160+
attributes?: Attribute[];
161+
}
162+
163+
interface Attribute {
164+
name: string;
165+
value?: Literal | VariableRef;
157166
}
158167
```
159168

@@ -220,7 +229,7 @@ that the implementation attaches to that _annotation_.
220229
```ts
221230
interface UnsupportedAnnotation {
222231
type: "unsupported-annotation";
223-
sigil: "!" | "@" | "%" | "^" | "&" | "*" | "+" | "<" | ">" | "?" | "~";
232+
sigil: "!" | "%" | "^" | "&" | "*" | "+" | "<" | ">" | "?" | "~";
224233
source: string;
225234
}
226235
```
@@ -242,19 +251,22 @@ interface MarkupOpen {
242251
kind: "open";
243252
name: string;
244253
options?: Option[];
254+
attributes?: Attribute[];
245255
}
246256

247257
interface MarkupStandalone {
248258
type: "markup";
249259
kind: "standalone";
250260
name: string;
251261
options?: Option[];
262+
attributes?: Attribute[];
252263
}
253264

254265
interface MarkupClose {
255266
type: "markup";
256267
kind: "close";
257268
name: string;
269+
attributes?: Attribute[];
258270
}
259271
```
260272

spec/data-model/message.dtd

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
<!ELEMENT pattern (#PCDATA | expression | markup)*>
2525

2626
<!ELEMENT expression (
27-
((literal | variable), (functionAnnotation | unsupportedAnnotation)?) |
28-
functionAnnotation | unsupportedAnnotation
27+
((literal | variable), (functionAnnotation | unsupportedAnnotation)?, attribute*) |
28+
((functionAnnotation | unsupportedAnnotation), attribute*)
2929
)>
3030

3131
<!ELEMENT literal (#PCDATA)>
@@ -43,8 +43,11 @@
4343
<!ELEMENT unsupportedAnnotation (#PCDATA)>
4444
<!ATTLIST unsupportedAnnotation sigil CDATA #REQUIRED>
4545

46+
<!ELEMENT attribute (literal | variable)?>
47+
<!ATTLIST attribute name NMTOKEN #REQUIRED>
48+
4649
<!-- A <markup kind="close"> MUST NOT contain any <option> elements -->
47-
<!ELEMENT markup (option)*>
50+
<!ELEMENT markup (option*, attribute*)>
4851
<!ATTLIST markup
4952
kind (open | standalone | close) #REQUIRED
5053
name NMTOKEN #REQUIRED

spec/data-model/message.json

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@
3838
"required": ["name", "value"]
3939
}
4040
},
41+
"attributes": {
42+
"type": "array",
43+
"items": {
44+
"type": "object",
45+
"properties": {
46+
"name": { "type": "string" },
47+
"value": {
48+
"oneOf": [
49+
{ "$ref": "#/$defs/literal" },
50+
{ "$ref": "#/$defs/variable" }
51+
]
52+
}
53+
},
54+
"required": ["name"]
55+
}
56+
},
4157

4258
"function-annotation": {
4359
"type": "object",
@@ -53,7 +69,7 @@
5369
"properties": {
5470
"type": { "const": "unsupported-annotation" },
5571
"sigil": {
56-
"enum": ["!", "@", "#", "%", "^", "&", "*", "<", ">", "/", "?", "~"]
72+
"enum": ["!", "#", "%", "^", "&", "*", "<", ">", "/", "?", "~"]
5773
},
5874
"source": { "type": "string" }
5975
},
@@ -71,7 +87,8 @@
7187
"properties": {
7288
"type": { "const": "expression" },
7389
"arg": { "$ref": "#/$defs/literal" },
74-
"annotation": { "$ref": "#/$defs/annotation" }
90+
"annotation": { "$ref": "#/$defs/annotation" },
91+
"attributes": { "$ref": "#/$defs/attributes" }
7592
},
7693
"required": ["type", "arg"]
7794
},
@@ -80,23 +97,26 @@
8097
"properties": {
8198
"type": { "const": "expression" },
8299
"arg": { "$ref": "#/$defs/variable" },
83-
"annotation": { "$ref": "#/$defs/annotation" }
100+
"annotation": { "$ref": "#/$defs/annotation" },
101+
"attributes": { "$ref": "#/$defs/attributes" }
84102
},
85103
"required": ["type", "arg"]
86104
},
87105
"function-expression": {
88106
"type": "object",
89107
"properties": {
90108
"type": { "const": "expression" },
91-
"annotation": { "$ref": "#/$defs/function-annotation" }
109+
"annotation": { "$ref": "#/$defs/function-annotation" },
110+
"attributes": { "$ref": "#/$defs/attributes" }
92111
},
93112
"required": ["type", "annotation"]
94113
},
95114
"unsupported-expression": {
96115
"type": "object",
97116
"properties": {
98117
"type": { "const": "expression" },
99-
"annotation": { "$ref": "#/$defs/unsupported-annotation" }
118+
"annotation": { "$ref": "#/$defs/unsupported-annotation" },
119+
"attributes": { "$ref": "#/$defs/attributes" }
100120
},
101121
"required": ["type", "annotation"]
102122
},
@@ -115,7 +135,8 @@
115135
"type": { "const": "markup" },
116136
"kind": { "const": "open" },
117137
"name": { "type": "string" },
118-
"options": { "$ref": "#/$defs/options" }
138+
"options": { "$ref": "#/$defs/options" },
139+
"attributes": { "$ref": "#/$defs/attributes" }
119140
},
120141
"required": ["type", "kind", "name"]
121142
},
@@ -125,7 +146,8 @@
125146
"type": { "const": "markup" },
126147
"kind": { "const": "standalone" },
127148
"name": { "type": "string" },
128-
"options": { "$ref": "#/$defs/options" }
149+
"options": { "$ref": "#/$defs/options" },
150+
"attributes": { "$ref": "#/$defs/attributes" }
129151
},
130152
"required": ["type", "kind", "name"]
131153
},
@@ -134,7 +156,8 @@
134156
"properties": {
135157
"type": { "const": "markup" },
136158
"kind": { "const": "close" },
137-
"name": { "type": "string" }
159+
"name": { "type": "string" },
160+
"attributes": { "$ref": "#/$defs/attributes" }
138161
},
139162
"required": ["type", "kind", "name"]
140163
},

spec/formatting.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,10 @@ MUST be an empty string.
652652
Implementations MAY offer functionality for customizing this,
653653
such as by emitting XML-ish tags for each _markup_.
654654
655+
_Attributes_ are reserved for future standardization.
656+
Other than checking for valid syntax, they SHOULD NOT
657+
affect the processing or output of a _message_.
658+
655659
### Examples
656660
657661
_This section is non-normative._

spec/message.abnf

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,26 @@ selector = expression
1919
variant = key *(s key) [s] quoted-pattern
2020
key = literal / "*"
2121

22-
expression = literal-expression / variable-expression / annotation-expression
23-
literal-expression = "{" [s] literal [s annotation] [s] "}"
24-
variable-expression = "{" [s] variable [s annotation] [s] "}"
25-
annotation-expression = "{" [s] annotation [s] "}"
22+
expression = literal-expression
23+
/ variable-expression
24+
/ annotation-expression
25+
literal-expression = "{" [s] literal [s annotation] *(s attribute) [s] "}"
26+
variable-expression = "{" [s] variable [s annotation] *(s attribute) [s] "}"
27+
annotation-expression = "{" [s] annotation *(s attribute) [s] "}"
2628
annotation = function
2729
/ private-use-annotation
2830
/ reserved-annotation
2931

30-
markup = "{" [s] markup-open [s] ["/"] "}"
31-
/ "{" [s] markup-close [s] "}"
32+
markup = "{" [s] markup-open *(s attribute) [s] ["/"] "}"
33+
/ "{" [s] markup-close *(s attribute) [s] "}"
3234
markup-open = "#" identifier *(s option)
3335
markup-close = "/" identifier
3436

3537
literal = quoted / unquoted
3638
variable = "$" name
3739
function = ":" identifier *(s option)
3840
option = identifier [s] "=" [s] (literal / variable)
41+
attribute = "@" identifier [[s] "=" [s] (literal / variable)]
3942

4043
input = %s".input"
4144
local = %s".local"
@@ -70,14 +73,14 @@ reserved-keyword = "." name
7073

7174
; Reserve additional sigils for use by future versions of this specification.
7275
reserved-annotation = reserved-annotation-start reserved-body
73-
reserved-annotation-start = "!" / "@" / "%" / "*" / "+"
74-
/ "<" / ">" / "?" / "~"
76+
reserved-annotation-start = "!" / "%" / "*" / "+" / "<" / ">" / "?" / "~"
7577

7678
reserved-body = *([s] 1*(reserved-char / reserved-escape / quoted))
7779
reserved-char = %x00-08 ; omit HTAB and LF
7880
/ %x0B-0C ; omit CR
7981
/ %x0E-19 ; omit SP
80-
/ %x21-5B ; omit \
82+
/ %x21-3F ; omit @
83+
/ %x41-5B ; omit \
8184
/ %x5D-7A ; omit { | }
8285
/ %x7E-2FFF ; omit IDEOGRAPHIC SPACE
8386
/ %x3001-D7FF ; omit surrogates

spec/syntax.md

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ An _expression_ MUST begin with U+007B LEFT CURLY BRACKET `{`
427427
and end with U+007D RIGHT CURLY BRACKET `}`.
428428
An _expression_ MUST NOT be empty.
429429
An _expression_ cannot contain another _expression_.
430+
An _expression_ MAY contain one more _attributes_.
430431

431432
A **_<dfn>literal-expression</dfn>_** contains a _literal_,
432433
optionally followed by an _annotation_.
@@ -438,9 +439,9 @@ An **_<dfn>annotation-expression</dfn>_** contains an _annotation_ without an _o
438439

439440
```abnf
440441
expression = literal-expression / variable-expression / annotation-expression
441-
literal-expression = "{" [s] literal [s annotation] [s] "}"
442-
variable-expression = "{" [s] variable [s annotation] [s] "}"
443-
annotation-expression = "{" [s] annotation [s] "}"
442+
literal-expression = "{" [s] literal [s annotation] *(s attribute) [s] "}"
443+
variable-expression = "{" [s] variable [s annotation] *(s attribute) [s] "}"
444+
annotation-expression = "{" [s] annotation *(s attribute) [s] "}"
444445
```
445446

446447
There are several types of _expression_ that can appear in a _message_.
@@ -638,14 +639,14 @@ unrecognized _reserved-annotations_ or _private-use-annotations_ have no meaning
638639
639640
```abnf
640641
reserved-annotation = reserved-annotation-start reserved-body
641-
reserved-annotation-start = "!" / "@" / "%" / "*" / "+"
642-
/ "<" / ">" / "?" / "~"
642+
reserved-annotation-start = "!" / "%" / "*" / "+" / "<" / ">" / "?" / "~"
643643
644644
reserved-body = *([s] 1*(reserved-char / reserved-escape / quoted))
645645
reserved-char = %x00-08 ; omit HTAB and LF
646646
/ %x0B-0C ; omit CR
647647
/ %x0E-19 ; omit SP
648-
/ %x21-5B ; omit \
648+
/ %x21-3F ; omit @
649+
/ %x41-5B ; omit \
649650
/ %x5D-7A ; omit { | }
650651
/ %x7E-D7FF ; omit surrogates
651652
/ %xE000-10FFFF
@@ -656,7 +657,12 @@ reserved-char = %x00-08 ; omit HTAB and LF
656657
**_<dfn>Markup</dfn>_** _placeholders_ are _pattern_ parts
657658
that can be used to represent non-language parts of a _message_,
658659
such as inline elements or styling that should apply to a span of parts.
659-
Markup comes in three forms:
660+
661+
_Markup_ MUST begin with U+007B LEFT CURLY BRACKET `{`
662+
and end with U+007D RIGHT CURLY BRACKET `}`.
663+
_Markup_ MAY contain one more _attributes_.
664+
665+
_Markup_ comes in three forms:
660666

661667
**_<dfn>Markup-open</dfn>_** starts with U+0023 NUMBER SIGN `#` and
662668
represents an opening element within the _message_,
@@ -673,8 +679,8 @@ is a _pattern_ part ending a span.
673679
Unlike the other forms, it does not include _options_.
674680

675681
```abnf
676-
markup = "{" [s] markup-open [s] ["/"] "}"
677-
/ "{" [s] markup-close [s] "}"
682+
markup = "{" [s] markup-open *(s attribute) [s] ["/"] "}"
683+
/ "{" [s] markup-close *(s attribute) [s] "}"
678684
markup-open = "#" identifier *(s option)
679685
markup-close = "/" identifier
680686
```
@@ -691,6 +697,42 @@ _Markup_ _placeholders_ can appear in any order without making the _message_ inv
691697
However, specifications or implementations defining _markup_ might impose requirements
692698
on the pairing, ordering, or contents of _markup_ during _formatting_.
693699
700+
## Attributes
701+
702+
**_Attributes_ are reserved for standardization by future versions of this specification.**
703+
Examples in this section are meant to be illustrative and
704+
might not match future requirements or usage.
705+
706+
An **_<dfn>attribute</dfn>_** is an _identifier_ with an optional value
707+
that appears in an _expression_ or in _markup_.
708+
709+
_Attributes_ are prefixed by a U+0040 COMMERCIAL AT `@` sign,
710+
followed by an _identifier_.
711+
An _attribute_ MAY have a _value_ which is separated from the _identifier_
712+
by an U+003D EQUALS SIGN `=` along with optional whitespace.
713+
The _value_ of an _attribute_ can be either a _literal_ or a _variable_.
714+
715+
Multiple _attributes_ are permitted in an _expression_ or _markup_.
716+
Each _attribute_ is separated by whitespace.
717+
718+
```abnf
719+
attribute = "@" identifier [[s] "=" [s] (literal / variable)]
720+
```
721+
722+
> Examples of _expressions_ and _markup_ with _attributes_:
723+
>
724+
> A _message_ including a _literal_ that should not be translated:
725+
>
726+
> ```
727+
> In French, "{|bonjour| @translate=no}" is a greeting
728+
> ```
729+
>
730+
> A _message_ with _markup_ that should not be copied:
731+
>
732+
> ```
733+
> Have a {+span @can-copy}great and wonderful{-span @can-copy} birthday!
734+
> ```
735+
694736
## Other Syntax Elements
695737
696738
This section defines common elements used to construct _messages_.

0 commit comments

Comments
 (0)