forked from messageformat/messageformat
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmessageformat.js
More file actions
executable file
·191 lines (167 loc) · 5.85 KB
/
messageformat.js
File metadata and controls
executable file
·191 lines (167 loc) · 5.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/env node
var nopt = require("nopt")
fs = require('fs'),
vm = require('vm'),
coffee = require('coffee-script'), /* only for watchr */
watch = require('watchr').watch,
Path = require('path'),
join = Path.join,
glob = require("glob"),
async = require('async'),
MessageFormat = require('../'),
_ = require('underscore'),
knownOpts = {
"locale" : String,
"inputdir" : Path,
"output" : Path,
"watch" : Boolean,
"namespace" : String,
"include" : String,
"stdout" : Boolean,
"verbose" : Boolean
},
description = {
"locale" : "locale to use [mandatory]",
"inputdir" : "directory containings messageformat files to compile",
"output" : "output where messageformat will be compiled",
"watch" : "watch `inputdir` for change",
"namespace" : "object in the browser containing the templates",
"include" : "Glob patterns for files to include in `inputdir`",
"stdout" : "Print the result in stdout instead of writing in a file",
"verbose" : "Print logs for debug"
},
defaults = {
"inputdir" : process.cwd(),
"output" : process.cwd(),
"watch" : false,
"namespace" : 'window.i18n',
"include" : '**/*.json',
"stdout" : false,
"verbose" : false
},
shortHands = {
"l" : "--locale",
"i" : "--inputdir",
"o" : "--output",
"w" : "--watch",
"ns" : "--namespace",
"I" : "--include",
"s" : "--stdout",
"v" : "--verbose"
},
options = nopt(knownOpts, shortHands, process.argv, 2),
argvRemain = options.argv.remain,
inputdir;
// defaults value
_(defaults).forEach(function(value, key){
options[key] = options[key] || value;
})
if(argvRemain && argvRemain.length >=1 ) options.inputdir = argvRemain[0];
if(argvRemain && argvRemain.length >=2 ) options.output = argvRemain[1];
if(!options.locale) {
console.error('Usage: messageformat -l [locale] [INPUT_DIR] [OUTPUT_DIR]')
console.error('')
console.error(nopt.usage(knownOpts, shortHands, description, defaults));
process.exit(-1);
}
var inputdir = options.inputdir;
compile();
if(options.watch){
return watch(options.inputdir, _.debounce(compile, 100));
}
function handleError( err, data ){
if(err){
err = err.message ? err.message : err;
return console.error('--->\t'+ err);
}
}
function compile(){
build(inputdir, options, function(err, data){
if( err ) return handleError( err );
write(data, function(err, output){
if( err ) return handleError( err );
if( options.verbose ) console.log(output + " written.");
})
});
}
function write( data, callback ){
data = data.join('\n');
if(options.stdout) {
return console.log(data);
}
var output = options.output;
fs.stat(output, function(err, stat){
if(err){
// do nothing
}else if(stat.isFile()){
// do nothing
}else if(stat.isDirectory()){
// if `output` is a directory, create a new file called `i18n.js` in this directory.
output = join(output, 'i18n.js');
}else{
return engines.handleError(ouput, 'is not a file nor a directory');
}
fs.writeFile( output, data, 'utf8', function( err ){
if( typeof callback == "function" ) callback(err, output);
});
});
};
function build(inputdir, options, callback){
// arrays of compiled templates
var compiledMessageFormat = [];
// read locale file
var localeFile = join(__dirname, '..', 'locale', options.locale + '.js');
if(options.verbose) console.log('Load locale file: ' + localeFile);
fs.readFile(localeFile, function(err, localeStr){
if(err) handleError(new Error('locale ' + options.locale + ' not supported.' ));
var script = vm.createScript(localeStr);
// needed for runInThisContext
global.MessageFormat = MessageFormat;
script.runInThisContext();
if( options.verbose ) { console.log('Read dir: ' + inputdir); }
// list each file in inputdir folder and subfolders
glob(options.include, {cwd: inputdir}, function(err, files){
files = files.map(function(file){
// normalize the file name
return file.replace(inputdir, '').replace(/^\//, '');
})
async.forEach(files, readFile, function(err){
// errors are logged in readFile. No need to print them here.
var fileData = [
'(function(){ ' + options.namespace + ' || (' + options.namespace + ' = {}) ',
'var MessageFormat = { locale: {} };',
localeStr
].concat(compiledMessageFormat)
.concat(['})();']);
return callback(null, _.flatten(fileData));
});
// Read each file, compile them, and append the result in the `compiledI18n` array
function readFile(file, cb){
var path = join(inputdir, file);
fs.stat(path, function(err, stat){
if(err) { handleError(err); return cb(); }
if(!stat.isFile()) {
if( options.verbose ) { handleError('Skip ' + file); }
return cb();
}
fs.readFile(path, 'utf8', function(err, text){
if(err) { handleError(err); return cb() }
var nm = join(file).split('.')[0].replace(/\\/g, '/'); // windows users should have the same key.
if( options.verbose ) console.log('Building ' + options.namespace + '["' + nm + '"]');
compiledMessageFormat.push(compiler( options, nm, JSON.parse(text) ));
cb();
});
});
}
});
});
}
function compiler(options, nm, obj){
var mf = new MessageFormat(options.locale),
compiledMessageFormat = [options.namespace + '["' + nm + '"] = {}'];
_(obj).forEach(function(value, key){
var str = mf.precompile( mf.parse(value) );
compiledMessageFormat.push(options.namespace + '["' + nm + '"]["' + key + '"] = ' + str);
});
return compiledMessageFormat;
}