SlexAxton/messageformat.js — pull request #54 by eemeli (2014-06-10 11:56:11+00:00)
Title: CLI: refactor, add support for multiple locales, revert #18

This adds support for compiling a single file with multiple locales to `bin/messageformat.js`, as well as pretty much completely refactoring that file. Also, the option `--help` has been added, `--watch` fixed, and `--combine` reverted, as it never actually worked in the first place.

The function that used to be `compiler()` in `bin/messageformat.js` has been refactored as `MessageFormat.prototype.precompileObject()`, which takes in a JavaScript object of the form
```js
{key0: "messageformat {STRING}", key1: ...}
```
and returns a string representation of a similar object formed of executable JavaScript functions:
```js
'{"key0":function(d){return "messageformat "+i18n.v(d,"STRING")}}, "key1":...}'
```
With a little bit of wrapping and the inclusion of the output of `MessageFormat.prototype.functions()`, that string may then be later executed as JavaScript to define the compiled localization functions. Which is pretty much exactly what `bin/messageformat.js` does.

Feature-wise, the following now work:

```
messageformat.js/example$ messageformat
Usage: messageformat -l [locale] [OPTIONS] [INPUT_DIR] [OUTPUT_DIR]
Try 'messageformat --help' for more information.

messageformat.js/example$ messageformat -?
Usage: messageformat -l [locale] [OPTIONS] [INPUT_DIR] [OUTPUT_DIR]

Available options:
-l,	--locale	locale(s) to use [mandatory]
-i,	--inputdir	directory containing messageformat files to compile
-o,	--output	output where messageformat will be compiled
-ns,	--namespace	global object in the output containing the templates
-I,	--include	glob patterns for files to include from `inputdir`
-s,	--stdout	print the result in stdout instead of writing in a file
-w,	--watch	watch `inputdir` for changes
-v,	--verbose	print logs for debug

messageformat.js/example$ messageformat -v --locale en,fr . .
Input dir: .
Included locales: en, fr
Building i18n["en/colors"] from `en/colors.json` with locale "en"
Building i18n["en/sub/folder/plural"] from `en/sub/folder/plural.json` with locale "en"
Building i18n["fr/colors"] from `fr/colors.json` with locale "fr"
Building i18n["fr/sub/folder/plural"] from `fr/sub/folder/plural.json` with locale "fr"
i18n.js written.
```

Which results in the following contents for `example/i18n.js`:

```js
(function(G){G['i18n']={lc:{"en":function(n){return n===1?"one":"other"},"fr":function(n){return n===0||n==1?"one":"other"}},
c:function(d,k){if(!d)throw new Error("MessageFormat: Data required for '"+k+"'.")},
n:function(d,k,o){if(isNaN(d[k]))throw new Error("MessageFormat: '"+k+"' isn't a number.");return d[k]-(o||0)},
v:function(d,k){i18n.c(d,k);return d[k]},
p:function(d,k,o,l,p){i18n.c(d,k);return d[k] in p?p[d[k]]:(k=i18n.lc[l](d[k]-o),k in p?p[k]:p.other)},
s:function(d,k,p){i18n.c(d,k);return d[k] in p?p[d[k]]:p.other}}
i18n["en/colors"]={
"red":function(d){return "red"},
"blue":function(d){return "blue"},
"green":function(d){return "green"}}
i18n["en/sub/folder/plural"]={
"test":function(d){return "Your "+i18n.p(d,"NUM",0,"en",{"one":"message","other":"messages"})+" go here."}}
i18n["fr/colors"]={
"red":function(d){return "rouge"},
"blue":function(d){return "bleu"},
"green":function(d){return "vert"}}
i18n["fr/sub/folder/plural"]={
"test":function(d){return i18n.p(d,"NUM",0,"fr",{"one":"Votre message se trouve","other":"Vos messages se trouvent"})+" ici."}}
})(this);
```

Note in particular that the file paths are parsed for a match to the defined locales, and those are used appropriately in the resulting JavaScript output. If no match is found, the first-defined locale is taken as the default one.