Skip to content

Commit 88183fa

Browse files
committed
Update guide
1 parent 29f6adf commit 88183fa

1 file changed

Lines changed: 74 additions & 158 deletions

File tree

guide.md

Lines changed: 74 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -3,238 +3,154 @@ layout: page
33
title: Format Guide
44
---
55

6-
## No Frills
6+
## Contents
7+
* [Variables](#variables)
8+
* [SelectFormat](#selectFormat)
9+
* [PluralFormat](#pluralFormat)
10+
* [Nesting](#nesting)
11+
* [Escaping](#escaping)
712

8-
The most simple case of MessageFormat would involve no formatting. Just a string passthrough. This sounds silly, but often it's nice to always use the same i18n system when doing translations, and not everything takes variables.
13+
14+
The simplest case of MessageFormat involves no formatting, just a string passthrough. This may sound silly, but often it's nice to always use the same message formatting system when doing translations, and not everything requires variables.
915

1016
```javascript
11-
// Insantiate a MessageFormat object on your locale
1217
var mf = new MessageFormat('en');
18+
var message = mf.compile('This is a message.');
1319

14-
// Compile a message
15-
var message = mf.compile( 'This is a message.' ); // returns a function
16-
17-
// You can call the function to get data out
18-
> message();
19-
"This is a message."
20+
message();
21+
// "This is a message."
22+
```
2023

21-
// NOTE:: if a message _does_ require data to be passed in, an error is thrown if you do not.
24+
NOTE: if a message _does_ require data to be passed in, an error is thrown if you do not.
2225

23-
```
2426

25-
## Simple Variable Replacement
27+
## Variables
2628

27-
The second most simple way to use MessageFormat is for simple variable replacement. MessageFormat looks odd at first, but it's actually fairly simple. One way to think about the `{` and `}` is that every level of them bring you into and out-of `literal` and `code` mode.
29+
The second most simple way to use MessageFormat is for simple variable replacement. MessageFormat may look odd at first, but it's actually fairly simple. One way to think about the `{` and `}` is that every level of them bring you into and out-of `literal` and `code` mode.
2830

2931
By default (like in the previous example), you are just writing a literal. Then the first level of brackets brings you into one of several data-driven situations. The most simple is variable replacement.
3032

3133
Simply putting a variable name in between `{` and `}` will place that variable there in the output.
3234

3335
```javascript
34-
// Instantiate new MessageFormat object for your locale
3536
var mf = new MessageFormat('en');
37+
var varMessage = mf.compile('His name is {NAME}.');
3638

37-
// Compile a message
38-
var message = mf.compile('His name is {NAME}.');
39-
40-
// Then send that data into the function
41-
> message({ "NAME" : "Jed" });
42-
"His name is Jed."
43-
44-
// NOTE:: it's best to try and stick to keys that would be natively
45-
// tolerant in your JS runtimes (think valid JS variable names).
39+
varMessage({ NAME : "Jed" });
40+
// "His name is Jed."
4641
```
4742

48-
## SelectFormat
49-
50-
`SelectFormat` is a lot like a switch statement for your messages. Most often it's used to select gender in a string. Here's an example:
51-
52-
```javascript
53-
// Insantiate an instance with your language settings
54-
var mf = new MesssageFormat('en');
55-
// Compile a message - returns a function
56-
var message = mf.compile('{GENDER, select, male{He} female{She} other{They}} liked this.');
57-
58-
// Run your message function with your data
59-
> message({"GENDER" : "male"});
60-
"He liked this."
61-
62-
> message({"GENDER" : "female"});
63-
"She liked this."
6443

65-
// The 'other' key is **required** and in the case of GENDER
66-
// it should be phrased as if you are too far away to tell the gender of the subject.
67-
> message({});
68-
"They liked this."
69-
70-
```
44+
## SelectFormat
7145

72-
## PluralFormat
46+
`SelectFormat` is a lot like a switch statement for your messages. Often it's used to select gender in a string. The format of the statement is `{varname, select, thisvalue{...} thatvalue{...} other{...}}`, where `varname` matches a key in the data you give to the resulting function, and `'thisvalue'` & `'thatvalue'` are some of the string-equivalent values that it may have. The `other` key is required, and is selected if no other case matches.
7347

74-
`PluralFormat` is a similar mechanism to `SelectFormat` (especially syntax wise), but it's specific to numbers, and the key that is chosen is generated by a _Plural Function_.
48+
Note that comparison is made using the JavaScript `==` operator, so if a key is left out of the input data, the case `undefined{...}` would match that.
7549

7650
```javascript
77-
// Insantiate a new MessageFormat object
78-
var mf = new MessageFormat('en');
79-
80-
// You can use the provided locales in the `/locale` folder
81-
// (include the file directly after including messageformat.js
82-
var mf = new MessageFormat( 'sl' );
83-
84-
// OR - you can pass a custom plural function to the MessageFormat constructor function.
85-
var mf = new Message( 'requiredCustomName', function (n) {
86-
if ( n === 42 ) {
87-
return 'many';
88-
}
89-
return 'other';
90-
});
91-
92-
// Then the numbers that are passed into a compiled message will run through this function to select
93-
// the keys. This is for the 'en' locale:
94-
var message = mf.compile('There {NUM_RESULTS, plural, one{is one result} other{are # results}}.');
95-
96-
// Then the data causes the function to output:
97-
98-
> message({"NUM_RESULTS" : 0});
99-
"There are 0 results."
51+
var mf = new MesssageFormat('en');
52+
var selectMessage = mf.compile(
53+
'{GENDER, select, male{He} female{She} other{They}} liked this.'
54+
);
10055

101-
> message({"NUM_RESULTS" : 1});
102-
"There is one result."
56+
selectMessage({ GENDER: 'male' });
57+
// "He liked this."
10358

104-
> message({"NUM_RESULTS" : 100});
105-
"There are 100 results."
59+
selectMessage({ GENDER: 'female' });
60+
// "She liked this."
10661

62+
selectMessage({});
63+
// "They liked this."
10764
```
10865

109-
### Named Keys
11066

111-
ICU declares the 6 named keys that CLDR defines for their plural form data. Those are:
112-
113-
* zero
114-
* one
115-
* two
116-
* few
117-
* many
118-
* other (**required**)
119-
120-
All of them are fairly straight-forward, but do remember, that for some languages, they are more loose "guidelines" than they are exact.
121-
122-
The only **required** key is `other`. Your compilation will throw an error if you forget this. In english, and many other languages, the logic is simple:
67+
## PluralFormat
12368

124-
`If N equals 1, then ONE, otherwise OTHER`
69+
`PluralFormat` is a similar mechanism to `SelectFormat`, but specific to numerical values. The key that is chosen is generated from the specified input variable by a locale-specific _plural function_.
12570

126-
Other languages (take a peak at `ar.js` or `sl.js`) can get much more complicated.
71+
The numeric input is mapped to a plural category, some subset of `zero`, `one`, `two`, `few`, `many`, and `other` depending on the locale and the type of plural. English, for instance, uses `one` and `other` for cardinal plurals (one result, many results) and `one`, `two`, `few`, and `other` for ordinal plurals (1st result, 2nd result, etc). For information on which keys are used by your locale, please refer to the [CLDR table of plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html).
12772

128-
**Note:** English only uses `one` and `other` for cardinal plurals, so including `zero` will never get called, even when the number is 0
73+
Matches for exact values are available with the `=` prefix.
12974

130-
The most simple (to pluralize) languages have no pluralization rules an rely solely on the `other` named key.
75+
The keyword for cardinal plurals is `plural`, and for ordinal plurals is `selectordinal`.
13176

132-
```
133-
{NUM, plural,
134-
zero {There are zero - in a lang that needs it.}
135-
one {There is one - in a lang that has it.}
136-
two {There is two - in a lang that has it.}
137-
few {There are a few - in a lang that has it.}
138-
many {There are many - in a lang that has it.}
139-
other {There is a different amount than all the other stuff above.}
140-
}
141-
```
77+
Within a plural statement, `#` will be replaced by the variable value.
14278

143-
### Literal Numeric Keys
79+
```javascript
80+
var mf = new MessageFormat('en');
81+
var pluralMessage = mf.compile(
82+
'There {NUM_RESULTS, plural, =0{are no results} one{is one result} other{are # results}}.'
83+
);
14484

145-
There also exists the capability to put literal numbers as keys in a select statement. These are delimited by prefixing them with the `=` character. These will match single, specific numbers. If there is a match, that branch will immediately run, and the corresponding named key **will not** also run.
85+
pluralMessage({ NUM_RESULTS: 0 });
86+
// "There are no results."
14687

147-
There are plenty of legitimate uses for this, especially when considering base cases and more pleasant language. But if you're a Douglas Adams fan, might use it like so:
88+
pluralMessage({ NUM_RESULTS: 1 });
89+
// "There is one result."
14890

91+
pluralMessage({ NUM_RESULTS: 100 });
92+
// "There are 100 results."
14993
```
150-
You have {NUM_TASKS, plural,
151-
one {one task}
152-
other {# tasks}
153-
=42 {the answer to the life, the universe and everything tasks}
154-
} remaining.
155-
```
156-
157-
When `NUM_TASKS` is 42, this outputs smiles. Remember, these have priority over the named keys.
158-
159-
### PluralFormat - offset extension
16094

161-
ICU provided the ability to extend existing select and plural functionality, and the only official extension (that I could find) is the `offset` extension.
16295

163-
It goes after the `plural` declaration, and is used to generate sentences that break up a number into multiple sections. For instance:
96+
#### Offset extension
16497

165-
> You and 4 others added this to their profiles.
166-
167-
In this case, the total number of people who added 'this' to their profiles is actually 5. We can use the `offset` extension to help us with this.
98+
To generate sentences such as "You and 4 others added this to their profiles.", PluralFormat supports adding an `offset` to the variable value before determining its plural category. Literal/exact matches are tested before applying the offset.
16899

169100
```javascript
170101
var mf = new MessageFormat('en');
171102

172-
// For simplicity's sake, let's assume the base case here isn't silly.
173-
// The test suite has a bigger offset example at the bottom
174-
// Let's also assume neutral gender for the same reason
175-
176-
// Set the offset to 1
177-
var message = mf.compile(
103+
var offsetMessage = mf.compile(
178104
'You {NUM_ADDS, plural, offset:1' +
179-
'=0{didnt add this to your profile}' + // Number literals, with a `=` do **NOT** use
180-
'=1{added this to your profile}' + // the offset value
181-
'one{and one other person added this to their profile}' +
182-
'other{and # others added this to their profiles}' +
183-
'}.'
105+
'=0{did not add this}' +
106+
'=1{added this}' +
107+
'one{and one other person added this}' +
108+
'other{and # others added this}' +
109+
'}.'
184110
);
185111

186-
// Tip: I like to consider the `=` prefixed number literals as more of an "inductive step"
187-
// e.g. in this case, since (0 - 1) is _negative_ 1, we want to handle that base case.
188-
189-
> message({"NUM_ADDS" : 0 });
190-
"You didnt add this to your profile."
191-
192-
> message({"NUM_ADDS" : 1 });
193-
"You added this to your profile."
112+
offsetMessage({ NUM_ADDS: 0 });
113+
// "You did not add this."
194114

195-
> message({"NUM_ADDS" : 2 });
196-
"You and one other person added this to their profile."
115+
offsetMessage({ NUM_ADDS: 1 });
116+
// "You added this."
197117

198-
> message({"NUM_ADDS" : 3 });
199-
"You and 2 others added this to their profile."
118+
offsetMessage({ NUM_ADDS: 2 });
119+
// "You and one other person added this."
200120

121+
offsetMessage({ NUM_ADDS: 3 });
122+
// "You and 2 others added this."
201123
```
202124

125+
203126
## Nesting
204127

205-
Very simply, you can nest both `SelectFormat` blocks into `PluralFormat` blocks, and visa-versa, as deeply as you'd like. Simply start the new block directly inside:
128+
All types of messageformat statements may be nested within each other, to unlimited depth:
206129

207-
```
130+
```text
208131
{SEL1, select,
209132
other {
210133
{PLUR1, plural,
211134
one {1}
212135
other {
213136
{SEL2, select,
214-
other {deep in the heart.}
137+
other {Deep in the heart.}
215138
}
216139
}
217140
}
218141
}
219142
}
220143
```
221144

222-
## Escaping
223145

224-
messageformat.js tries to a good job of being tolerant of as much as possible, but some characters, like the ones used the actual MessageFormat spec itself, must be escaped to be a part of your string.
146+
## Escaping
225147

226-
For `{`, `}` and `#` (only inside of a select value) literals, just escape them with a backslash. (If you are in a JS string, you'll need to escape the escape backslash so it'll look like two).
148+
The characters `{` and `}` must be escaped with a `\` to be included in the output as literal characters. Within plural statements, `#` must also be similarly escaped. Keep in mind that you'll need to double-escape with `\\` within e.g. JavaScript and JSON strings.
227149

228150
```javascript
229-
// Technically, it's just:
230-
231-
\{\}\#
232-
233-
// But in practice, since you're often dealing with string literals, it looks more like
234-
235-
var msg = mf.compile("\\{ {S, select, other{# is a \\#}} \\}");
151+
var mf = new MessageFormat('en');
152+
var escMessage = mf.compile('\\{ {S, plural, other{# is a \\#}} \\}');
236153

237-
> msg({S:5});
238-
"{ 5 is a # }"
154+
escMessage({ S: 5 });
155+
// "{ 5 is a # }"
239156
```
240-

0 commit comments

Comments
 (0)