-
Notifications
You must be signed in to change notification settings - Fork 52
/
i18n.js
183 lines (168 loc) · 7.82 KB
/
i18n.js
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
/**
* @license i18n 2.0.6 Copyright jQuery Foundation and other contributors.
* Released under MIT license, http://github.com/requirejs/i18n/LICENSE
*/
/*jslint regexp: true */
/*global require: false, navigator: false, define: false */
/**
* This plugin handles i18n! prefixed modules. It does the following:
*
* 1) A regular module can have a dependency on an i18n bundle, but the regular
* module does not want to specify what locale to load. So it just specifies
* the top-level bundle, like 'i18n!nls/colors'.
*
* This plugin will load the i18n bundle at nls/colors, see that it is a root/master
* bundle since it does not have a locale in its name. It will then try to find
* the best match locale available in that master bundle, then request all the
* locale pieces for that best match locale. For instance, if the locale is 'en-us',
* then the plugin will ask for the 'en-us', 'en' and 'root' bundles to be loaded
* (but only if they are specified on the master bundle).
*
* Once all the bundles for the locale pieces load, then it mixes in all those
* locale pieces into each other, then finally sets the context.defined value
* for the nls/colors bundle to be that mixed in locale.
*
* 2) A regular module specifies a specific locale to load. For instance,
* i18n!nls/fr-fr/colors. In this case, the plugin needs to load the master bundle
* first, at nls/colors, then figure out what the best match locale is for fr-fr,
* since maybe only fr or just root is defined for that locale. Once that best
* fit is found, all of its locale pieces need to have their bundles loaded.
*
* Once all the bundles for the locale pieces load, then it mixes in all those
* locale pieces into each other, then finally sets the context.defined value
* for the nls/fr-fr/colors bundle to be that mixed in locale.
*/
(function () {
'use strict';
//regexp for reconstructing the master bundle name from parts of the regexp match
//nlsRegExp.exec('foo/bar/baz/nls/en-ca/foo') gives:
//['foo/bar/baz/nls/en-ca/foo', 'foo/bar/baz/nls/', '/', '/', 'en-ca', 'foo']
//nlsRegExp.exec('foo/bar/baz/nls/foo') gives:
//['foo/bar/baz/nls/foo', 'foo/bar/baz/nls/', '/', '/', 'foo', '']
//so, if match[5] is blank, it means this is the top bundle definition.
var nlsRegExp = /(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/;
//Helper function to avoid repeating code. Lots of arguments in the
//desire to stay functional and support RequireJS contexts without having
//to know about the RequireJS contexts.
function addPart(locale, master, needed, toLoad, prefix, suffix) {
if (master[locale]) {
needed.push(locale);
if (master[locale] === true || master[locale] === 1) {
toLoad.push(prefix + locale + '/' + suffix);
}
}
}
function addIfExists(req, locale, toLoad, prefix, suffix) {
var fullName = prefix + locale + '/' + suffix;
if (require._fileExists(req.toUrl(fullName + '.js'))) {
toLoad.push(fullName);
}
}
/**
* Simple function to mix in properties from source into target,
* but only if target does not already have a property of the same name.
* This is not robust in IE for transferring methods that match
* Object.prototype names, but the uses of mixin here seem unlikely to
* trigger a problem related to that.
*/
function mixin(target, source, force) {
var prop;
for (prop in source) {
if (source.hasOwnProperty(prop) && (!target.hasOwnProperty(prop) || force)) {
target[prop] = source[prop];
} else if (typeof source[prop] === 'object') {
if (!target[prop] && source[prop]) {
target[prop] = {};
}
mixin(target[prop], source[prop], force);
}
}
}
define(['module'], function (module) {
var masterConfig = module.config ? module.config() : {};
return {
version: '2.0.6',
/**
* Called when a dependency needs to be loaded.
*/
load: function (name, req, onLoad, config) {
config = config || {};
if (config.locale) {
masterConfig.locale = config.locale;
}
var masterName,
match = nlsRegExp.exec(name),
prefix = match[1],
locale = match[4],
suffix = match[5],
parts = locale.split('-'),
toLoad = [],
value = {},
i, part, current = '';
//If match[5] is blank, it means this is the top bundle definition,
//so it does not have to be handled. Locale-specific requests
//will have a match[4] value but no match[5]
if (match[5]) {
//locale-specific bundle
prefix = match[1];
masterName = prefix + suffix;
} else {
//Top-level bundle.
masterName = name;
suffix = match[4];
locale = masterConfig.locale;
if (!locale) {
locale = masterConfig.locale =
typeof navigator === 'undefined' ? 'root' :
((navigator.languages && navigator.languages[0]) ||
navigator.language ||
navigator.userLanguage || 'root').toLowerCase();
}
parts = locale.split('-');
}
if (config.isBuild) {
//Check for existence of all locale possible files and
//require them if exist.
toLoad.push(masterName);
addIfExists(req, 'root', toLoad, prefix, suffix);
for (i = 0; i < parts.length; i++) {
part = parts[i];
current += (current ? '-' : '') + part;
addIfExists(req, current, toLoad, prefix, suffix);
}
req(toLoad, function () {
onLoad();
});
} else {
//First, fetch the master bundle, it knows what locales are available.
req([masterName], function (master) {
//Figure out the best fit
var needed = [],
part;
//Always allow for root, then do the rest of the locale parts.
addPart('root', master, needed, toLoad, prefix, suffix);
for (i = 0; i < parts.length; i++) {
part = parts[i];
current += (current ? '-' : '') + part;
addPart(current, master, needed, toLoad, prefix, suffix);
}
//Load all the parts missing.
req(toLoad, function () {
var i, partBundle, part;
for (i = needed.length - 1; i > -1 && needed[i]; i--) {
part = needed[i];
partBundle = master[part];
if (partBundle === true || partBundle === 1) {
partBundle = req(prefix + part + '/' + suffix);
}
mixin(value, partBundle);
}
//All done, notify the loader.
onLoad(value);
});
});
}
}
};
});
}());