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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 | 1×
1×
1×
22×
22×
22×
22×
1×
1×
21×
30×
30×
30×
21×
18×
3×
22×
1×
30×
30×
30×
30×
2×
2×
28×
18×
2×
18×
18×
10×
10×
9×
1×
30×
1×
11×
11×
11×
1×
1×
1×
6×
1×
14×
14×
14×
3988×
3960×
13×
13×
1×
13×
13×
1×
12×
10×
2×
1×
1×
11×
11×
10×
10×
2×
8×
1×
7×
1×
10×
6×
10×
1×
1×
1×
1×
10×
7×
7×
7×
3×
11×
1×
| var cldrData = require('cldr-data'),
fs = require('fs'),
globalize = require('globalize'),
kew = require('kew'),
path = require('path');
var globalizeExpress,
loadMessages;
/**
* Load locale message into globalize
* @param {String} dir The directory from where we load in the locale files
* @param {Boolean} devMode Is the env in development.
* @return {Promise} A promise that the locale files will be loaded
*/
function loadLocaleFiles (dir, devMode) {
'use strict';
var readDirPromise = kew.defer();
// Read all files in the locale directory
fs.readdir(dir, function (err, files) {
var filePromises = [];
// If reading the files failed.
if (err) {
// Reject the promise if there was an error reading the dir
readDirPromise.reject(err);
return;
}
files.forEach(function (file) {
var filePromise,
filename = path.join(dir, file);
filePromise = loadMessages(filename, devMode);
filePromises.push(filePromise);
});
kew.all(filePromises)
.then(function () {
readDirPromise.resolve();
}).fail(function (error) {
readDirPromise.reject(error);
});
});
return readDirPromise.promise;
}
loadMessages = function (filename, devMode) {
'use strict';
var filePromise = kew.defer();
fs.stat(filename, function (err, stat) {
var subDirPromise;
if (err) {
filePromise.reject(err);
return;
}
// If the file is a file and not a directory, then load it in
if (stat.isFile()) {
// If we are in development env, then unload the existing locale
// files from the requires cache.
if (devMode) {
delete require.cache[filename];
}
// Load the locale files one by one
globalize.loadMessages(require(filename));
filePromise.resolve();
// Else if the file is a directory, then read all the files in it
} else {
subDirPromise = loadLocaleFiles(filename, devMode);
subDirPromise
.then(function () {
filePromise.resolve();
}).fail(function (error) {
filePromise.reject(error);
});
}
});
return filePromise.promise;
};
/**
* Load in gloabalize locale data
* @param {Array} dataList List of all the locale data to load in
*/
function loadLocaleData (dataList) {
'use strict';
var i;
for (i = 0; i < dataList.length; i++) {
globalize.load(require(dataList[i]));
}
}
/**
* Load default supplemental and locale data
* @param {String[]} locales Array of all the locale data to load
*/
function loadDefaultLocaleData (locales) {
'use strict';
// Load all the supplemental data
globalize.load(cldrData.entireSupplemental());
// Load all the cldr-data for each individual locale
locales.forEach(function (locale) {
globalize.load(cldrData.entireMainFor(locale));
});
}
/**
* Unload the module from require's cache and all the modules
* that depend on it
* @param {String} moduleName The name of the module to delete
*/
function unloadModule (moduleName) {
'use strict';
var key,
modulePath = require.resolve(moduleName);
// Delete the module from require's cache
delete require.cache[modulePath];
// Check all other keys in the cache if they were required by
// this module. If they were, unload them too
for (key in require.cache) {
if (require.cache[key].parent) {
// If the parent module is the same module we are unloading
if (modulePath === require.cache[key].parent.id) {
unloadModule(require.cache[key].id);
delete require.cache[key];
}
}
}
}
/**
* Method to initialize the globalize object
* @param {Object} opts Options for setting up localization
* @param {String[]} opts.locales An array of available locales (e.g ["en", "ch"])
* @param {String} opts.defaultLocale The default locale to fallback to
* @param {String} opts.cookieName The name of the cookie that stores locale info on the client
* @param {String} opts.messages The directory that contains all the locale files
* @param {Boolean} opts.devMode Is the webapp running in development mode or not
* @return {Function} An express compatible middleware method
*/
globalizeExpress = function (opts) {
'use strict';
var globalizeMiddleware,
loadLocaleFilesPromise;
if (!opts.messages && opts.directory) {
throw new Error('Please change the option "directory" to "messages" in your config file \n'
+ '(see https://github.com/devangnegandhi/globalize-express/issues/2 for more info)');
}
// If opts.localeData provided, then load the specified locale data from disk
if (opts.localeData) {
loadLocaleData(opts.localeData);
// Else if opts.locales provided, load default locale data
} else if (opts.locales) {
loadDefaultLocaleData(opts.locales);
// Else throw an error
} else {
throw new Error('Please specify either localeData or locales properties in the config');
}
// Load the locales from disk
loadLocaleFilesPromise = loadLocaleFiles(opts.messages);
/**
* The middleware to setup localization
* @param {Object} req The express request object
* @param {Object} res The express response object
* @param {Function} next The express next method
*/
globalizeMiddleware = function (req, res, next) {
var locale = '';
// If lang param is specified in the URL as a query, use that
if (req.query && req.query.lang) {
locale = req.query.lang;
// Else if locale specified in the client cookie, use that
} else if (req.cookies && opts.cookieName && req.cookies[opts.cookieName]) {
locale = req.cookies[opts.cookieName];
// Else if locale specified in the browser header, use that
} else if (req.headers && req.headers['accept-language']) {
locale = req.headers['accept-language'].split(',')[0];
}
// If the locale found is not in the list of available locales,
// then fallback to the default locale
if (opts.locales.indexOf(locale) === -1) {
locale = opts.defaultLocale;
}
// If we are in the development mode, then reload all the messages
// from the disk
if (opts.devMode) {
unloadModule('globalize');
globalize = require('globalize');
loadLocaleData(opts.localeData);
loadLocaleFilesPromise = loadLocaleFiles(opts.messages, opts.devMode);
}
loadLocaleFilesPromise
.then(function () {
// Assign globalize objects to the req object
req.Globalize = globalize(locale);
req.locale = locale;
next();
}).fail(function (err) {
next(err);
});
};
return globalizeMiddleware;
};
module.exports = globalizeExpress;
|