1 | # ![format-message][logo]
|
2 |
|
3 | > Write i18n messages inline. Transpile translations.
|
4 |
|
5 | [![npm Version][npm-image]][npm]
|
6 | [![Dependency Status][deps-image]][deps]
|
7 | [![Dev Dependency Status][dev-deps-image]][dev-deps]
|
8 | [![Build Status][build-image]][build]
|
9 |
|
10 | [![JS Standard Style][style-image]][style]
|
11 | [![MIT License][license-image]][LICENSE]
|
12 |
|
13 |
|
14 | Quick Start
|
15 | -----------
|
16 |
|
17 | `npm install format-message --save` adds the library to `node_modules`. You can then use it as follows:
|
18 |
|
19 | ```js
|
20 | var formatMessage = require('format-message');
|
21 |
|
22 | var message = formatMessage('Hello { place }!', { place:'World' });
|
23 | ```
|
24 |
|
25 | You can configure your translations at runtime (typical for server-side use), or transpile your code for better performance in repeated use on the client.
|
26 |
|
27 | `format-message` relies on the ECMAScript Internationalization API 1.0 (`Intl`) for formatting `number`, `date`, and `time` arguments. If you are in an environment missing these ([like node <= 0.12, IE < 11, or Safari][caniuse-intl]) you'll want to use a [polyfill][intl]. Otherwise `format-message` falls back on `toLocaleString` methods, which are most likely just aliases for `toString`.
|
28 |
|
29 |
|
30 | Format Overview
|
31 | ---------------
|
32 |
|
33 | The [ICU Message Format][icu-message] is a great format for user-visible strings, and includes simple placeholders, number and date placeholders, and selecting among submessages for gender and plural arguments. The format is used in apis in [C++][icu-cpp], [PHP][icu-php], and [Java][icu-java].
|
34 |
|
35 | `format-message` provides a way to write your default (often English) messages as literals in your source, and then scrape out the default patterns and transpile your source with fast inline code for formatting the translated message patterns.
|
36 |
|
37 | This relies on [message-format][message-format] for parsing and formatting ICU messages, and [babel][babel] for transpiling the source code.
|
38 |
|
39 | ### Supported ICU Formats
|
40 |
|
41 | See [message-format][message-format] for supported ICU formats.
|
42 |
|
43 | ### Quoting escaping rules
|
44 |
|
45 | See the [ICU site][icu-message] and [message-format][message-format] for details on how to escape special characters in your messages.
|
46 |
|
47 | ### Loading locale data
|
48 |
|
49 | `format-message` supports plurals for all CLDR languages. Locale-aware formatting of number, date, and time are delegated to the `Intl` apis, and select is the same across all locales. You don't need to load any extra files for particular locales for `format-message` itself.
|
50 |
|
51 |
|
52 | API
|
53 | ---
|
54 |
|
55 | ### `formatMessage`
|
56 |
|
57 | ```js
|
58 | var formatMessage = require('format-message')
|
59 | // or
|
60 | import formatMessage from 'format-message'
|
61 |
|
62 | formatMessage(pattern[, args[, locales]])
|
63 | ```
|
64 |
|
65 | Translate and format the message with the given pattern and arguments.
|
66 |
|
67 | Parameters
|
68 |
|
69 | - `pattern` is a properly formatted ICU Message Format pattern. A poorly formatted pattern will cause an `Error` to be thrown.
|
70 | - The pattern is used as a key into the `translate` function you provide in configuration, and is also used as the fallback if no translation is returned, or `translate` has not been configured
|
71 | - If `pattern` is not a string literal, the function cannot be transpiled at build time.
|
72 | - `args` is an object containing the values to replace placeholders with. Required if the pattern contains placeholders.
|
73 | - `locales` is an optional string with a BCP 47 language tag, or an array of such strings.
|
74 | - The locales are also passed into the `translate` function and indicate the desired destination language.
|
75 | - If `locales` is not a string literal, the function cannot be transpiled at build time.
|
76 |
|
77 | ### `formatMessage.setup`
|
78 |
|
79 | ```js
|
80 | formatMessage.setup(options)
|
81 | ```
|
82 |
|
83 | Configure `formatMessage` behavior for subsequent calls. This should be called before any code that uses `formatMessage`.
|
84 |
|
85 | Parameters
|
86 |
|
87 | - `options` is an object containing the following config values:
|
88 | - `cache` is whether message, number, and date formatters are cached. Defaults to `true`
|
89 | - `locale` is the default locale to use when no locale is passed to `formatMessage`. Defaults to `"en"`.
|
90 | - `translate(pattern, locales)` is a function to translate messages. It should return the pattern translated for the specified locale.
|
91 | - `pattern` is the message pattern to translate.
|
92 | - `locale` is a string with a BCP 47 language tag, or an array of such strings.
|
93 | - `missingReplacement` is a string that will be used when a message translation isn't found. By default the source message is used.
|
94 | - `missingTranslation` is one of `"ignore"`, `"warning"`, `"error"`. By default it is `"warning"`, and missing translations cause a console warning. If `"error"`, an error is thrown.
|
95 | - `formats` is an object containing objects that define placeholder styles `{ name, type, style }`:
|
96 | - `number` is an object containing number format styles to add. Each property name can be used afterwards as a style name for a number placeholder. The value of each property is an object that will be passed to an [`Intl.NumberFormat`][mdn-intl-numberformat] constructor as the seconds argument.
|
97 | - `date` is an object containing date format styles to add. Each property name can be used afterwards as a style name for a date placeholder. The value of each property is an object that will be passed to an [`Intl.DateTimeFormat`][mdn-intl-datetimeformat] constructor as the seconds argument.
|
98 | - `time` is an object containing time format styles to add. Each property name can be used afterwards as a style name for a time placeholder. The value of each property is an object that will be passed to an [`Intl.DateTimeFormat`][mdn-intl-datetimeformat] constructor as the seconds argument.
|
99 |
|
100 | ### `formatMessage.translate`
|
101 |
|
102 | ```js
|
103 | formatMessage.translate(pattern[, locales])
|
104 | ```
|
105 |
|
106 | Use the currently configured `translate` to get the locale-specific pattern. Note that this can also be linted, extracted, and inlined if the `pattern` is a literal.
|
107 |
|
108 | Parameters
|
109 |
|
110 | - `pattern` is a properly formatted ICU Message Format pattern.
|
111 | - `locales` is an optional string with a BCP 47 language tag, or an array of such strings.
|
112 | - If not specified, the currently configured `locale` will be used.
|
113 |
|
114 | ### internal apis
|
115 |
|
116 | `formatMessage.number`, `formatMessage.date`, and `formatMessage.time` are used internally and are not intended for external use. Because these appear in the transpiled code, transpiling does not remove the need to properly define `formatMessage` through `require` or `import`.
|
117 |
|
118 |
|
119 | Transpiled Messages
|
120 | --------
|
121 |
|
122 | The examples provide sample transpiler output. This output is not meant to be 100% exact, but to give a general idea of what the transpiler does.
|
123 |
|
124 | ### Simple messages with no placeholders
|
125 |
|
126 | ```js
|
127 | formatMessage('My Collections')
|
128 |
|
129 | // transpiles to translated literal
|
130 | "Minhas Coleções"
|
131 | ```
|
132 |
|
133 | ### Simple string placeholders
|
134 |
|
135 | ```js
|
136 | formatMessage('Welcome, {name}!', { name: userName });
|
137 |
|
138 | // messages with simple placeholders transpiles to concatenated strings
|
139 | "Bem Vindo, " + userName + "!" // Bem Vindo, Bob!
|
140 | ```
|
141 |
|
142 | ### Complex number, date, and time placeholders
|
143 |
|
144 | ```js
|
145 | formatMessage('{ n, number, percent }', { n:0.1 });
|
146 |
|
147 | // transpiles to just the number call
|
148 | formatMessage.number("en", 0.1, "percent") // "10%"
|
149 |
|
150 |
|
151 | formatMessage('{ shorty, date, short }', { shorty:new Date() });
|
152 |
|
153 | // transpiles to just the date call
|
154 | formatMessage.date("en", new Date(), "short") // "1/1/15"
|
155 |
|
156 |
|
157 | formatMessage('You took {n,number} pictures since {d,date} {d,time}', { n:4000, d:new Date() });
|
158 |
|
159 | // transpiles to a function call, with the function defined at the top level
|
160 | $$_you_took_n_number_pictures_123456({ n:4000, d:new Date() })
|
161 | ...
|
162 | function $$_you_took_n_number_pictures_123456(args) {
|
163 | return "You took " + formatMessage.number("en", args["n"]) + " pictures since " + formatMessage.date("en", args["d"]) + " " + formatMessage.time("en", args["d"])
|
164 | } // "You took 4,000 pictures since Jan 1, 2015 9:33:04 AM"
|
165 | ```
|
166 |
|
167 | ### Complex string with select and plural in ES6
|
168 |
|
169 | ```js
|
170 | import formatMessage from 'format-message'
|
171 |
|
172 | // using a template string for multiline, no interpolation
|
173 | let formatMessage(`On { date, date, short } {name} ate {
|
174 | numBananas, plural,
|
175 | =0 {no bananas}
|
176 | =1 {a banana}
|
177 | =2 {a pair of bananas}
|
178 | other {# bananas}
|
179 | } {
|
180 | gender, select,
|
181 | male {at his house.}
|
182 | female {at her house.}
|
183 | other {at their house.}
|
184 | }`, {
|
185 | date: new Date(),
|
186 | name: 'Curious George',
|
187 | gender: 'male',
|
188 | numBananas: 27
|
189 | })
|
190 |
|
191 | // transpiles to a function call, with the function defined at the top level
|
192 | $$_on_date_date_short_name_ate_123456({ n:4000, d:new Date() })
|
193 | ...
|
194 | function $$_on_date_date_short_name_ate_123456(args) {
|
195 | return ...
|
196 | }
|
197 | // en-US: "On 1/1/15 Curious George ate 27 bananas at his house."
|
198 | ```
|
199 |
|
200 | ### Current Optimizations
|
201 |
|
202 | * Calls with no placeholders in the message become string literals.
|
203 | * Calls with no `plural`, `select`, or `selectordinal` in the message, and an object literal with variables or literals for property values become concatentated strings and variables.
|
204 |
|
205 | All other cases result in a function call, with the function declaration somewhere at the top level of the file.
|
206 |
|
207 |
|
208 | CLI Tools
|
209 | ---------
|
210 |
|
211 | All of the command line tools will look for `require`ing or `import`ing `format-message` in your source files to determine the local name of the `formatMessage` function. Then they will either check for problems, extract the original message patterns, or replace the call as follows:
|
212 |
|
213 | ### format-message lint
|
214 |
|
215 | #### Usage: `format-message lint [options] [files...]`
|
216 |
|
217 | find message patterns in files and verify there are no obvious problems
|
218 |
|
219 | #### Options:
|
220 |
|
221 | -h, --help output usage information
|
222 | -n, --function-name [name] find function calls with this name [formatMessage]
|
223 | --no-auto disables auto-detecting the function name from import or require calls
|
224 | -k, --key-type [type] derived key from source pattern literal|normalized|underscored|underscored_crc32 [underscored_crc32]
|
225 | -t, --translations [path] location of the JSON file with message translations, if specified, translations are also checked for errors
|
226 | -f, --filename [filename] filename to use when reading from stdin - this will be used in source-maps, errors etc [stdin]
|
227 |
|
228 | #### Examples:
|
229 |
|
230 | lint the src js files, with `__` as the function name used instead of `formatMessage`
|
231 |
|
232 | format-message lint -n __ src/**/*.js
|
233 |
|
234 | lint the src js files and translations
|
235 |
|
236 | format-message lint -t i18n/pt-BR.json src/**/*.js
|
237 |
|
238 |
|
239 | ### format-message extract
|
240 |
|
241 | #### Usage: `format-message extract [options] [files...]`
|
242 |
|
243 | find and list all message patterns in files
|
244 |
|
245 | #### Options:
|
246 |
|
247 | -h, --help output usage information
|
248 | -n, --function-name [name] find function calls with this name [formatMessage]
|
249 | --no-auto disables auto-detecting the function name from import or require calls
|
250 | -k, --key-type [type] derived key from source pattern (literal | normalized | underscored | underscored_crc32) [underscored_crc32]
|
251 | -l, --locale [locale] BCP 47 language tags specifying the source default locale [en]
|
252 | -o, --out-file [out] write messages JSON object to this file instead of to stdout
|
253 |
|
254 | #### Examples:
|
255 |
|
256 | extract patterns from src js files, dump json to `stdout`. This can be helpful to get familiar with how `--key-type` and `--locale` change the json output.
|
257 |
|
258 | format-message extract src/**/*.js
|
259 |
|
260 | extract patterns from `stdin`, dump to file.
|
261 |
|
262 | someTranspiler src/*.js | format-message extract -o locales/en.json
|
263 |
|
264 |
|
265 | ### format-message inline
|
266 |
|
267 | #### Usage: `format-message inline [options] [files...]`
|
268 |
|
269 | find and replace message pattern calls in files with translations
|
270 |
|
271 | #### Options:
|
272 |
|
273 | -h, --help output usage information
|
274 | -n, --function-name [name] find function calls with this name [formatMessage]
|
275 | --no-auto disables auto-detecting the function name from import or require calls
|
276 | -k, --key-type [type] derived key from source pattern (literal | normalized | underscored | underscored_crc32) [underscored_crc32]
|
277 | -l, --locale [locale] BCP 47 language tags specifying the target locale [en]
|
278 | -t, --translations [path] location of the JSON file with message translations
|
279 | -e, --missing-translation [behavior] behavior when --translations is specified, but a translated pattern is missing (error | warning | ignore) [error]
|
280 | -m, --missing-replacement [pattern] pattern to inline when a translated pattern is missing, defaults to the source pattern
|
281 | -i, --source-maps-inline append sourceMappingURL comment to bottom of code
|
282 | -s, --source-maps save source map alongside the compiled code
|
283 | -f, --filename [filename] filename to use when reading from stdin - this will be used in source-maps, errors etc [stdin]
|
284 | -o, --out-file [out] compile all input files into a single file
|
285 | -d, --out-dir [out] compile an input directory of modules into an output directory
|
286 | -r, --root [path] remove root path for source filename in output directory [cwd]
|
287 |
|
288 | #### Examples:
|
289 |
|
290 | create locale-specific client bundles with source maps
|
291 |
|
292 | format-message inline src/**/*.js -s -l de -t translations.json -o dist/bundle.de.js
|
293 | format-message inline src/**/*.js -s -l en -t translations.json -o dist/bundle.en.js
|
294 | format-message inline src/**/*.js -s -l es -t translations.json -o dist/bundle.es.js
|
295 | format-message inline src/**/*.js -s -l pt -t translations.json -o dist/bundle.pt.js
|
296 | ...
|
297 |
|
298 | inline without translating multiple files that used `var __ = require('format-message')`
|
299 |
|
300 | format-message inline -d dist -r src -n __ src/*.js lib/*.js component/**/*.js
|
301 |
|
302 |
|
303 | License
|
304 | -------
|
305 |
|
306 | This software is free to use under the MIT license. See the [LICENSE-MIT file][LICENSE] for license text and copyright information.
|
307 |
|
308 |
|
309 | [logo]: https://cdn.rawgit.com/format-message/format-message/446d303/src/logo/format-message.svg
|
310 | [npm]: https://www.npmjs.org/package/format-message
|
311 | [npm-image]: https://img.shields.io/npm/v/format-message.svg
|
312 | [deps]: https://david-dm.org/format-message/format-message
|
313 | [deps-image]: https://img.shields.io/david/format-message/format-message.svg
|
314 | [dev-deps]: https://david-dm.org/format-message/format-message#info=devDependencies
|
315 | [dev-deps-image]: https://img.shields.io/david/dev/format-message/format-message.svg
|
316 | [build]: https://travis-ci.org/format-message/format-message
|
317 | [build-image]: https://img.shields.io/travis/format-message/format-message.svg
|
318 | [style]: https://github.com/feross/standard
|
319 | [style-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg
|
320 | [license-image]: https://img.shields.io/npm/l/format-message.svg
|
321 | [caniuse-intl]: http://caniuse.com/#feat=internationalization
|
322 | [icu-message]: http://userguide.icu-project.org/formatparse/messages
|
323 | [icu-cpp]: http://icu-project.org/apiref/icu4c/classicu_1_1MessageFormat.html
|
324 | [icu-php]: http://php.net/manual/en/class.messageformatter.php
|
325 | [icu-java]: http://icu-project.org/apiref/icu4j/
|
326 | [intl]: https://github.com/andyearnshaw/Intl.js
|
327 | [message-format]: https://github.com/format-message/message-format
|
328 | [babel]: https://github.com/babel/babel
|
329 | [mdn-intl-datetimeformat]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
330 | [mdn-intl-numberformat]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
|
331 | [LICENSE]: https://github.com/format-message/format-message/blob/master/LICENSE-MIT
|