Skip to content

Commit 45cb43a

Browse files
committed
Require the message body to be indented
Fix #12, #17, #18. With this change, the entire body of a message must be indented. This makes error recovery very easy: finding the next message definition is as simple as finding the next identifier with no indentation. It also opens up a number of opportunities: we can remove the `|` syntax for multiline blocks of text and allow line breaks inside of placeables safely. The change also allows the value to be defined on a new line, making the following examples equivalent: lipsum = Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi pellentesque congue metus, non mattis sem faucibus sit amet. lipsum = Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi pellentesque congue metus, non mattis sem faucibus sit amet. Lastly, quoted patterns are only available inside of placeables, cannot contain aother placeables and cannot be used directly as values. The exact semantics of \ escapes will be defined in #22.
1 parent e5da507 commit 45cb43a

File tree

8 files changed

+76
-68
lines changed

8 files changed

+76
-68
lines changed

guide/builtins.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ emails = You have { $unreadEmails } unread emails.
55
emails2 = You have { NUMBER($unreadEmails) } unread emails.
66
77
last-notice =
8-
| Last checked: { DATETIME($lastChecked, day: "numeric", month: "long") }.
8+
Last checked: { DATETIME($lastChecked, day: "numeric", month: "long") }.
99
```
1010

1111
```json

guide/functions.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,16 @@ the purpose of choosing the correct plural category:
126126

127127
```
128128
liked-count = { $num ->
129-
[0] No likes yet.
130-
[one] One person liked your message
131-
*[other] { $num } people liked your message
132-
}
129+
[0] No likes yet.
130+
[one] One person liked your message
131+
*[other] { $num } people liked your message
132+
}
133133
134134
liked-count2 = { NUMBER($num) ->
135-
[0] No likes yet.
136-
[one] One person liked your message
137-
*[other] { $num } people liked your message
138-
}
135+
[0] No likes yet.
136+
[one] One person liked your message
137+
*[other] { $num } people liked your message
138+
}
139139
```
140140

141141
### `DATETIME`

guide/selectors.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
```
44
emails = { $unreadEmails ->
5-
[one] You have one unread email.
6-
*[other] You have { $unreadEmails } unread emails.
7-
}
5+
[one] You have one unread email.
6+
*[other] You have { $unreadEmails } unread emails.
7+
}
88
```
99

1010
```json
@@ -34,7 +34,7 @@ unformatted number:
3434

3535
```
3636
your-score = { NUMBER($score, minimumFractionDigits: 1) ->
37-
[0.0] You scored zero points. What happened?
38-
*[other] You scored { NUMBER($score, minimumFractionDigits: 1) } points.
39-
}
37+
[0.0] You scored zero points. What happened?
38+
*[other] You scored { NUMBER($score, minimumFractionDigits: 1) } points.
39+
}
4040
```

guide/text.md

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,16 @@
1-
# Working With Text: Multiline and Quotes
1+
# Working With Text
22

33
```
44
about = About Our Software
55
description =
6-
| Loki is a simple micro-blogging
7-
| app written entirely in <i>HTML5</i>.
8-
| It uses FTL to implement localization.
9-
more-info = " Read more about us! "
6+
Loki is a simple micro-blogging
7+
app written entirely in <i>HTML5</i>.
8+
It uses FTL to implement localization.
109
1110
```
1211

13-
The value of an FTL message is usually a simple string.
12+
The value of an FTL message is usually a simple string. It begins after the
13+
`=` and may continue over multiple lines as long as it is indented by at least
14+
one space.
1415

15-
By default, a string begins after a `=` and ends with the end of line. You can
16-
also define easy-to-read, multiline strings with a pipe mark-up, as can be seen
17-
in the `description` message.
18-
19-
FTL ignores leading whitespaces in front of the value allowing localizers to
20-
align their messages for readability. For multiline strings, whitespaces both
21-
before and after the pipe are ignored. In rare cases where leading whitespaces
22-
should be part of the value, FTL allows for special quote delimited strings as
23-
can be seen in the `more-info` message.
16+
Leading and trailing white-space is ignored.

guide/variants.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
```
44
brand-name = {
5-
*[nominative] Aurora
6-
[genitive] Aurore
7-
[dative] Aurori
8-
[accusative] Auroro
9-
[locative] Aurori
10-
[instrumental] Auroro
11-
}
5+
*[nominative] Aurora
6+
[genitive] Aurore
7+
[dative] Aurori
8+
[accusative] Auroro
9+
[locative] Aurori
10+
[instrumental] Auroro
11+
}
1212
1313
about = O { brand-name[locative] }
1414
```

spec/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
## Unreleased
44

5+
- Require the message body to be indented.
6+
7+
Quoted strings are now only valid in placeables and cannot contain other
8+
placeables.
9+
10+
Remove `|` for multiline blocks.
11+
512
- (f176deb) Fix #30. Allow more characters in keys, and trim whitespace
613
around them
714

spec/fluent.asdl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ module Fluent
3232
pat = Pattern(expr* elements, bool quoted)
3333

3434
-- Expressions
35-
expr = Pattern(pat)
36-
| String(string)
35+
expr = String(string)
3736
| Number(number)
3837
| MessageReference(iden id)
3938
| ExternalArgument(iden id)

spec/fluent.ebnf

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,50 @@
1-
body ::= (entry NL)* entry? EOF
1+
body ::= (_* NL)* (entry NL)* entry? EOF
22
entry ::= comment
33
| section
44
| message
55

6-
comment ::= ('//' [^#xA#xD]* NL)+
7-
section ::= '[[' __ word (__ word)* __ ']]'
6+
comment ::= ('//' (char - NL)* )+
7+
section ::= '[[' _? word (_ word)* _? ']]'
88

99
char ::= [https://www.w3.org/TR/REC-xml/#NT-Char]
10-
__ ::= [#x20#x9]* /* space, tab */
11-
NL ::= [#xA#xD]+ /* line feed, carriage return */
10+
11+
/* special chars: { } [ \ ] */
12+
special ::= [#x5b#x5c#x5d#x7b#x7d]
13+
14+
/* line feed, carriage return; space, tab */
15+
line-break ::= [#xA#xD]+
16+
inline-space ::= [#x20#x9]+
17+
18+
/* if you break lines you need to indent afterwards */
19+
break-indent ::= (line-break* inline-space)+
20+
21+
_ ::= inline-space
22+
NL ::= line-break
23+
__ ::= break-indent
1224

1325
identifier ::= [a-zA-Z_?-] [a-zA-Z0-9_?-]*
1426
external ::= '$' identifier
15-
word ::= [^#x20#x9#xA#xD#x5b#x5c#x5d]+ /* exclude: white space, [, \, ] */
27+
word ::= (((char - line-break) - inline-space) - special)+
1628
builtin ::= [A-Z_?-]+
1729
number ::= [0-9]+ ('.' [0-9]+)?
1830

1931
variant-key ::= number | variant-symbol
20-
variant-symbol ::= word (__ word)*
21-
variant ::= '[' variant-key ']' __ pattern NL
22-
default-variant ::= '*' variant
23-
variant-list ::= NL (__ variant)* __ default-variant (__ variant)*
24-
25-
attribute ::= '.' identifier __ '=' __ pattern NL
26-
attribute-list ::= NL (__ attribute)+
27-
28-
message ::= identifier __ '=' __ (pattern attribute-list? | attribute-list)
29-
pattern ::= unquoted-pattern
30-
| quoted-pattern
31-
unquoted-pattern ::= (unquoted-text | placeable | block-text)+
32-
quoted-pattern ::= '"' (quoted-text | placeable)* '"'
33-
unquoted-text ::= ([^{] | '\{')+
34-
quoted-text ::= ([^{"] | '\{' | '\"')+
35-
block-text ::= NL __ '|' unquoted-pattern
36-
37-
placeable ::= '{' __ (expression | select-expression | variant-list) __ '}'
38-
expression ::= quoted-pattern
32+
variant-symbol ::= word (_ word)*
33+
variant ::= NL __ '[' _? variant-key _? ']' __ pattern
34+
default-variant ::= NL __ '*[' _? variant-key _? ']' __ pattern
35+
variant-list ::= variant* default-variant variant*
36+
37+
attribute ::= NL __ '.' identifier value
38+
attribute-list ::= attribute+
39+
40+
message ::= identifier (value attribute-list? | attribute-list)
41+
value ::= _? '=' __? pattern
42+
pattern ::= (text | placeable)+
43+
text ::= ((char - line-break) - special | break-indent | '\' special)+
44+
quoted-text ::= '"' (text | '\"')+ '"'
45+
46+
placeable ::= '{' __? (expression | select-expression | variant-list) __? '}'
47+
expression ::= quoted-text
3948
| number
4049
| identifier
4150
| external
@@ -44,10 +53,10 @@ expression ::= quoted-pattern
4453
| call-expression
4554
| placeable
4655

47-
select-expression ::= expression __ ' ->' __ variant-list
56+
select-expression ::= expression __ '->' __ variant-list
4857
attribute-expression ::= identifier '.' identifier
49-
variant-expression ::= identifier '[' __ variant-key __ ']'
50-
call-expression ::= builtin '(' __ (argument ( __ ',' __ argument)*)? __ ')'
58+
variant-expression ::= identifier '[' _? variant-key _? ']'
59+
call-expression ::= builtin '(' __? (argument ( __? ',' __? argument)*)? __? ')'
5160
argument ::= expression
5261
| named-argument
53-
named-argument ::= identifier __ ':' __ ('"' quoted-text? '"' | number)
62+
named-argument ::= identifier __? ':' __? (quoted-text | number)

0 commit comments

Comments
 (0)