1 | define(["./_base/kernel", "require", "./has", "./_base/array", "./_base/config", "./_base/lang", "./has!host-browser?./_base/xhr", "./json", "module"], |
---|
2 | function(dojo, require, has, array, config, lang, xhr, json, module){ |
---|
3 | |
---|
4 | // module: |
---|
5 | // dojo/i18n |
---|
6 | |
---|
7 | has.add("dojo-preload-i18n-Api", |
---|
8 | // if true, define the preload localizations machinery |
---|
9 | 1 |
---|
10 | ); |
---|
11 | |
---|
12 | has.add("dojo-v1x-i18n-Api", |
---|
13 | // if true, define the v1.x i18n functions |
---|
14 | 1 |
---|
15 | ); |
---|
16 | |
---|
17 | var |
---|
18 | thisModule = dojo.i18n = |
---|
19 | { |
---|
20 | // summary: |
---|
21 | // This module implements the dojo/i18n! plugin and the v1.6- i18n API |
---|
22 | // description: |
---|
23 | // We choose to include our own plugin to leverage functionality already contained in dojo |
---|
24 | // and thereby reduce the size of the plugin compared to various loader implementations. Also, this |
---|
25 | // allows foreign AMD loaders to be used without their plugins. |
---|
26 | }, |
---|
27 | |
---|
28 | nlsRe = |
---|
29 | // regexp for reconstructing the master bundle name from parts of the regexp match |
---|
30 | // nlsRe.exec("foo/bar/baz/nls/en-ca/foo") gives: |
---|
31 | // ["foo/bar/baz/nls/en-ca/foo", "foo/bar/baz/nls/", "/", "/", "en-ca", "foo"] |
---|
32 | // nlsRe.exec("foo/bar/baz/nls/foo") gives: |
---|
33 | // ["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""] |
---|
34 | // so, if match[5] is blank, it means this is the top bundle definition. |
---|
35 | // courtesy of http://requirejs.org |
---|
36 | /(^.*(^|\/)nls)(\/|$)([^\/]*)\/?([^\/]*)/, |
---|
37 | |
---|
38 | getAvailableLocales = function( |
---|
39 | root, |
---|
40 | locale, |
---|
41 | bundlePath, |
---|
42 | bundleName |
---|
43 | ){ |
---|
44 | // summary: |
---|
45 | // return a vector of module ids containing all available locales with respect to the target locale |
---|
46 | // For example, assuming: |
---|
47 | // |
---|
48 | // - the root bundle indicates specific bundles for "fr" and "fr-ca", |
---|
49 | // - bundlePath is "myPackage/nls" |
---|
50 | // - bundleName is "myBundle" |
---|
51 | // |
---|
52 | // Then a locale argument of "fr-ca" would return |
---|
53 | // |
---|
54 | // ["myPackage/nls/myBundle", "myPackage/nls/fr/myBundle", "myPackage/nls/fr-ca/myBundle"] |
---|
55 | // |
---|
56 | // Notice that bundles are returned least-specific to most-specific, starting with the root. |
---|
57 | // |
---|
58 | // If root===false indicates we're working with a pre-AMD i18n bundle that doesn't tell about the available locales; |
---|
59 | // therefore, assume everything is available and get 404 errors that indicate a particular localization is not available |
---|
60 | |
---|
61 | for(var result = [bundlePath + bundleName], localeParts = locale.split("-"), current = "", i = 0; i<localeParts.length; i++){ |
---|
62 | current += (current ? "-" : "") + localeParts[i]; |
---|
63 | if(!root || root[current]){ |
---|
64 | result.push(bundlePath + current + "/" + bundleName); |
---|
65 | result.specificity = current; |
---|
66 | } |
---|
67 | } |
---|
68 | return result; |
---|
69 | }, |
---|
70 | |
---|
71 | cache = {}, |
---|
72 | |
---|
73 | getBundleName = function(moduleName, bundleName, locale){ |
---|
74 | locale = locale ? locale.toLowerCase() : dojo.locale; |
---|
75 | moduleName = moduleName.replace(/\./g, "/"); |
---|
76 | bundleName = bundleName.replace(/\./g, "/"); |
---|
77 | return (/root/i.test(locale)) ? |
---|
78 | (moduleName + "/nls/" + bundleName) : |
---|
79 | (moduleName + "/nls/" + locale + "/" + bundleName); |
---|
80 | }, |
---|
81 | |
---|
82 | getL10nName = dojo.getL10nName = function(moduleName, bundleName, locale){ |
---|
83 | return moduleName = module.id + "!" + getBundleName(moduleName, bundleName, locale); |
---|
84 | }, |
---|
85 | |
---|
86 | doLoad = function(require, bundlePathAndName, bundlePath, bundleName, locale, load){ |
---|
87 | // summary: |
---|
88 | // get the root bundle which instructs which other bundles are required to construct the localized bundle |
---|
89 | require([bundlePathAndName], function(root){ |
---|
90 | var current = lang.clone(root.root || root.ROOT),// 1.6 built bundle defined ROOT |
---|
91 | availableLocales = getAvailableLocales(!root._v1x && root, locale, bundlePath, bundleName); |
---|
92 | require(availableLocales, function(){ |
---|
93 | for (var i = 1; i<availableLocales.length; i++){ |
---|
94 | current = lang.mixin(lang.clone(current), arguments[i]); |
---|
95 | } |
---|
96 | // target may not have been resolve (e.g., maybe only "fr" exists when "fr-ca" was requested) |
---|
97 | var target = bundlePathAndName + "/" + locale; |
---|
98 | cache[target] = current; |
---|
99 | current.$locale = availableLocales.specificity; |
---|
100 | load(); |
---|
101 | }); |
---|
102 | }); |
---|
103 | }, |
---|
104 | |
---|
105 | normalize = function(id, toAbsMid){ |
---|
106 | // summary: |
---|
107 | // id may be relative. |
---|
108 | // preload has form `*preload*<path>/nls/<module>*<flattened locales>` and |
---|
109 | // therefore never looks like a relative |
---|
110 | return /^\./.test(id) ? toAbsMid(id) : id; |
---|
111 | }, |
---|
112 | |
---|
113 | getLocalesToLoad = function(targetLocale){ |
---|
114 | var list = config.extraLocale || []; |
---|
115 | list = lang.isArray(list) ? list : [list]; |
---|
116 | list.push(targetLocale); |
---|
117 | return list; |
---|
118 | }, |
---|
119 | |
---|
120 | load = function(id, require, load){ |
---|
121 | // summary: |
---|
122 | // id is in one of the following formats |
---|
123 | // |
---|
124 | // 1. <path>/nls/<bundle> |
---|
125 | // => load the bundle, localized to config.locale; load all bundles localized to |
---|
126 | // config.extraLocale (if any); return the loaded bundle localized to config.locale. |
---|
127 | // |
---|
128 | // 2. <path>/nls/<locale>/<bundle> |
---|
129 | // => load then return the bundle localized to <locale> |
---|
130 | // |
---|
131 | // 3. *preload*<path>/nls/<module>*<JSON array of available locales> |
---|
132 | // => for config.locale and all config.extraLocale, load all bundles found |
---|
133 | // in the best-matching bundle rollup. A value of 1 is returned, which |
---|
134 | // is meaningless other than to say the plugin is executing the requested |
---|
135 | // preloads |
---|
136 | // |
---|
137 | // In cases 1 and 2, <path> is always normalized to an absolute module id upon entry; see |
---|
138 | // normalize. In case 3, it <path> is assumed to be absolute; this is arranged by the builder. |
---|
139 | // |
---|
140 | // To load a bundle means to insert the bundle into the plugin's cache and publish the bundle |
---|
141 | // value to the loader. Given <path>, <bundle>, and a particular <locale>, the cache key |
---|
142 | // |
---|
143 | // <path>/nls/<bundle>/<locale> |
---|
144 | // |
---|
145 | // will hold the value. Similarly, then plugin will publish this value to the loader by |
---|
146 | // |
---|
147 | // define("<path>/nls/<bundle>/<locale>", <bundle-value>); |
---|
148 | // |
---|
149 | // Given this algorithm, other machinery can provide fast load paths be preplacing |
---|
150 | // values in the plugin's cache, which is public. When a load is demanded the |
---|
151 | // cache is inspected before starting any loading. Explicitly placing values in the plugin |
---|
152 | // cache is an advanced/experimental feature that should not be needed; use at your own risk. |
---|
153 | // |
---|
154 | // For the normal AMD algorithm, the root bundle is loaded first, which instructs the |
---|
155 | // plugin what additional localized bundles are required for a particular locale. These |
---|
156 | // additional locales are loaded and a mix of the root and each progressively-specific |
---|
157 | // locale is returned. For example: |
---|
158 | // |
---|
159 | // 1. The client demands "dojo/i18n!some/path/nls/someBundle |
---|
160 | // |
---|
161 | // 2. The loader demands load(some/path/nls/someBundle) |
---|
162 | // |
---|
163 | // 3. This plugin require's "some/path/nls/someBundle", which is the root bundle. |
---|
164 | // |
---|
165 | // 4. Assuming config.locale is "ab-cd-ef" and the root bundle indicates that localizations |
---|
166 | // are available for "ab" and "ab-cd-ef" (note the missing "ab-cd", then the plugin |
---|
167 | // requires "some/path/nls/ab/someBundle" and "some/path/nls/ab-cd-ef/someBundle" |
---|
168 | // |
---|
169 | // 5. Upon receiving all required bundles, the plugin constructs the value of the bundle |
---|
170 | // ab-cd-ef as... |
---|
171 | // |
---|
172 | // mixin(mixin(mixin({}, require("some/path/nls/someBundle"), |
---|
173 | // require("some/path/nls/ab/someBundle")), |
---|
174 | // require("some/path/nls/ab-cd-ef/someBundle")); |
---|
175 | // |
---|
176 | // This value is inserted into the cache and published to the loader at the |
---|
177 | // key/module-id some/path/nls/someBundle/ab-cd-ef. |
---|
178 | // |
---|
179 | // The special preload signature (case 3) instructs the plugin to stop servicing all normal requests |
---|
180 | // (further preload requests will be serviced) until all ongoing preloading has completed. |
---|
181 | // |
---|
182 | // The preload signature instructs the plugin that a special rollup module is available that contains |
---|
183 | // one or more flattened, localized bundles. The JSON array of available locales indicates which locales |
---|
184 | // are available. Here is an example: |
---|
185 | // |
---|
186 | // *preload*some/path/nls/someModule*["root", "ab", "ab-cd-ef"] |
---|
187 | // |
---|
188 | // This indicates the following rollup modules are available: |
---|
189 | // |
---|
190 | // some/path/nls/someModule_ROOT |
---|
191 | // some/path/nls/someModule_ab |
---|
192 | // some/path/nls/someModule_ab-cd-ef |
---|
193 | // |
---|
194 | // Each of these modules is a normal AMD module that contains one or more flattened bundles in a hash. |
---|
195 | // For example, assume someModule contained the bundles some/bundle/path/someBundle and |
---|
196 | // some/bundle/path/someOtherBundle, then some/path/nls/someModule_ab would be expressed as follows: |
---|
197 | // |
---|
198 | // define({ |
---|
199 | // some/bundle/path/someBundle:<value of someBundle, flattened with respect to locale ab>, |
---|
200 | // some/bundle/path/someOtherBundle:<value of someOtherBundle, flattened with respect to locale ab>, |
---|
201 | // }); |
---|
202 | // |
---|
203 | // E.g., given this design, preloading for locale=="ab" can execute the following algorithm: |
---|
204 | // |
---|
205 | // require(["some/path/nls/someModule_ab"], function(rollup){ |
---|
206 | // for(var p in rollup){ |
---|
207 | // var id = p + "/ab", |
---|
208 | // cache[id] = rollup[p]; |
---|
209 | // define(id, rollup[p]); |
---|
210 | // } |
---|
211 | // }); |
---|
212 | // |
---|
213 | // Similarly, if "ab-cd" is requested, the algorithm can determine that "ab" is the best available and |
---|
214 | // load accordingly. |
---|
215 | // |
---|
216 | // The builder will write such rollups for every layer if a non-empty localeList profile property is |
---|
217 | // provided. Further, the builder will include the following cache entry in the cache associated with |
---|
218 | // any layer. |
---|
219 | // |
---|
220 | // "*now":function(r){r(['dojo/i18n!*preload*<path>/nls/<module>*<JSON array of available locales>']);} |
---|
221 | // |
---|
222 | // The *now special cache module instructs the loader to apply the provided function to context-require |
---|
223 | // with respect to the particular layer being defined. This causes the plugin to hold all normal service |
---|
224 | // requests until all preloading is complete. |
---|
225 | // |
---|
226 | // Notice that this algorithm is rarely better than the standard AMD load algorithm. Consider the normal case |
---|
227 | // where the target locale has a single segment and a layer depends on a single bundle: |
---|
228 | // |
---|
229 | // Without Preloads: |
---|
230 | // |
---|
231 | // 1. Layer loads root bundle. |
---|
232 | // 2. bundle is demanded; plugin loads single localized bundle. |
---|
233 | // |
---|
234 | // With Preloads: |
---|
235 | // |
---|
236 | // 1. Layer causes preloading of target bundle. |
---|
237 | // 2. bundle is demanded; service is delayed until preloading complete; bundle is returned. |
---|
238 | // |
---|
239 | // In each case a single transaction is required to load the target bundle. In cases where multiple bundles |
---|
240 | // are required and/or the locale has multiple segments, preloads still requires a single transaction whereas |
---|
241 | // the normal path requires an additional transaction for each additional bundle/locale-segment. However all |
---|
242 | // of these additional transactions can be done concurrently. Owing to this analysis, the entire preloading |
---|
243 | // algorithm can be discard during a build by setting the has feature dojo-preload-i18n-Api to false. |
---|
244 | |
---|
245 | if(has("dojo-preload-i18n-Api")){ |
---|
246 | var split = id.split("*"), |
---|
247 | preloadDemand = split[1] == "preload"; |
---|
248 | if(preloadDemand){ |
---|
249 | if(!cache[id]){ |
---|
250 | // use cache[id] to prevent multiple preloads of the same preload; this shouldn't happen, but |
---|
251 | // who knows what over-aggressive human optimizers may attempt |
---|
252 | cache[id] = 1; |
---|
253 | preloadL10n(split[2], json.parse(split[3]), 1, require); |
---|
254 | } |
---|
255 | // don't stall the loader! |
---|
256 | load(1); |
---|
257 | } |
---|
258 | if(preloadDemand || waitForPreloads(id, require, load)){ |
---|
259 | return; |
---|
260 | } |
---|
261 | } |
---|
262 | |
---|
263 | var match = nlsRe.exec(id), |
---|
264 | bundlePath = match[1] + "/", |
---|
265 | bundleName = match[5] || match[4], |
---|
266 | bundlePathAndName = bundlePath + bundleName, |
---|
267 | localeSpecified = (match[5] && match[4]), |
---|
268 | targetLocale = localeSpecified || dojo.locale || "", |
---|
269 | loadTarget = bundlePathAndName + "/" + targetLocale, |
---|
270 | loadList = localeSpecified ? [targetLocale] : getLocalesToLoad(targetLocale), |
---|
271 | remaining = loadList.length, |
---|
272 | finish = function(){ |
---|
273 | if(!--remaining){ |
---|
274 | load(lang.delegate(cache[loadTarget])); |
---|
275 | } |
---|
276 | }; |
---|
277 | array.forEach(loadList, function(locale){ |
---|
278 | var target = bundlePathAndName + "/" + locale; |
---|
279 | if(has("dojo-preload-i18n-Api")){ |
---|
280 | checkForLegacyModules(target); |
---|
281 | } |
---|
282 | if(!cache[target]){ |
---|
283 | doLoad(require, bundlePathAndName, bundlePath, bundleName, locale, finish); |
---|
284 | }else{ |
---|
285 | finish(); |
---|
286 | } |
---|
287 | }); |
---|
288 | }; |
---|
289 | |
---|
290 | if(has("dojo-unit-tests")){ |
---|
291 | var unitTests = thisModule.unitTests = []; |
---|
292 | } |
---|
293 | |
---|
294 | if(has("dojo-preload-i18n-Api") || has("dojo-v1x-i18n-Api")){ |
---|
295 | var normalizeLocale = thisModule.normalizeLocale = function(locale){ |
---|
296 | var result = locale ? locale.toLowerCase() : dojo.locale; |
---|
297 | return result == "root" ? "ROOT" : result; |
---|
298 | }, |
---|
299 | |
---|
300 | isXd = function(mid, contextRequire){ |
---|
301 | return (has("dojo-sync-loader") && has("dojo-v1x-i18n-Api")) ? |
---|
302 | contextRequire.isXdUrl(require.toUrl(mid + ".js")) : |
---|
303 | true; |
---|
304 | }, |
---|
305 | |
---|
306 | preloading = 0, |
---|
307 | |
---|
308 | preloadWaitQueue = [], |
---|
309 | |
---|
310 | preloadL10n = thisModule._preloadLocalizations = function(/*String*/bundlePrefix, /*Array*/localesGenerated, /*boolean?*/ guaranteedAmdFormat, /*function?*/ contextRequire){ |
---|
311 | // summary: |
---|
312 | // Load available flattened resource bundles associated with a particular module for dojo/locale and all dojo/config.extraLocale (if any) |
---|
313 | // description: |
---|
314 | // Only called by built layer files. The entire locale hierarchy is loaded. For example, |
---|
315 | // if locale=="ab-cd", then ROOT, "ab", and "ab-cd" are loaded. This is different than v1.6- |
---|
316 | // in that the v1.6- would only load ab-cd...which was *always* flattened. |
---|
317 | // |
---|
318 | // If guaranteedAmdFormat is true, then the module can be loaded with require thereby circumventing the detection algorithm |
---|
319 | // and the extra possible extra transaction. |
---|
320 | |
---|
321 | // If this function is called from legacy code, then guaranteedAmdFormat and contextRequire will be undefined. Since the function |
---|
322 | // needs a require in order to resolve module ids, fall back to the context-require associated with this dojo/i18n module, which |
---|
323 | // itself may have been mapped. |
---|
324 | contextRequire = contextRequire || require; |
---|
325 | |
---|
326 | function doRequire(mid, callback){ |
---|
327 | if(isXd(mid, contextRequire) || guaranteedAmdFormat){ |
---|
328 | contextRequire([mid], callback); |
---|
329 | }else{ |
---|
330 | syncRequire([mid], callback, contextRequire); |
---|
331 | } |
---|
332 | } |
---|
333 | |
---|
334 | function forEachLocale(locale, func){ |
---|
335 | // given locale= "ab-cd-ef", calls func on "ab-cd-ef", "ab-cd", "ab", "ROOT"; stops calling the first time func returns truthy |
---|
336 | var parts = locale.split("-"); |
---|
337 | while(parts.length){ |
---|
338 | if(func(parts.join("-"))){ |
---|
339 | return; |
---|
340 | } |
---|
341 | parts.pop(); |
---|
342 | } |
---|
343 | func("ROOT"); |
---|
344 | } |
---|
345 | |
---|
346 | function preloadingAddLock(){ |
---|
347 | preloading++; |
---|
348 | } |
---|
349 | |
---|
350 | function preloadingRelLock(){ |
---|
351 | --preloading; |
---|
352 | while(!preloading && preloadWaitQueue.length){ |
---|
353 | load.apply(null, preloadWaitQueue.shift()); |
---|
354 | } |
---|
355 | } |
---|
356 | |
---|
357 | function cacheId(path, name, loc, require){ |
---|
358 | // path is assumed to have a trailing "/" |
---|
359 | return require.toAbsMid(path + name + "/" + loc) |
---|
360 | } |
---|
361 | |
---|
362 | function preload(locale){ |
---|
363 | locale = normalizeLocale(locale); |
---|
364 | forEachLocale(locale, function(loc){ |
---|
365 | if(array.indexOf(localesGenerated, loc) >= 0){ |
---|
366 | var mid = bundlePrefix.replace(/\./g, "/") + "_" + loc; |
---|
367 | preloadingAddLock(); |
---|
368 | doRequire(mid, function(rollup){ |
---|
369 | for(var p in rollup){ |
---|
370 | var bundle = rollup[p], |
---|
371 | match = p.match(/(.+)\/([^\/]+)$/), |
---|
372 | bundleName, bundlePath; |
---|
373 | |
---|
374 | // If there is no match, the bundle is not a regular bundle from an AMD layer. |
---|
375 | if (!match){continue;} |
---|
376 | |
---|
377 | bundleName = match[2]; |
---|
378 | bundlePath = match[1] + "/"; |
---|
379 | |
---|
380 | // backcompat |
---|
381 | bundle._localized = bundle._localized || {}; |
---|
382 | |
---|
383 | var localized; |
---|
384 | if(loc === "ROOT"){ |
---|
385 | var root = localized = bundle._localized; |
---|
386 | delete bundle._localized; |
---|
387 | root.root = bundle; |
---|
388 | cache[require.toAbsMid(p)] = root; |
---|
389 | }else{ |
---|
390 | localized = bundle._localized; |
---|
391 | cache[cacheId(bundlePath, bundleName, loc, require)] = bundle; |
---|
392 | } |
---|
393 | |
---|
394 | if(loc !== locale){ |
---|
395 | // capture some locale variables |
---|
396 | function improveBundle(bundlePath, bundleName, bundle, localized){ |
---|
397 | // locale was not flattened and we've fallen back to a less-specific locale that was flattened |
---|
398 | // for example, we had a flattened 'fr', a 'fr-ca' is available for at least this bundle, and |
---|
399 | // locale==='fr-ca'; therefore, we must improve the bundle as retrieved from the rollup by |
---|
400 | // manually loading the fr-ca version of the bundle and mixing this into the already-retrieved 'fr' |
---|
401 | // version of the bundle. |
---|
402 | // |
---|
403 | // Remember, different bundles may have different sets of locales available. |
---|
404 | // |
---|
405 | // we are really falling back on the regular algorithm here, but--hopefully--starting with most |
---|
406 | // of the required bundles already on board as given by the rollup and we need to "manually" load |
---|
407 | // only one locale from a few bundles...or even better...we won't find anything better to load. |
---|
408 | // This algorithm ensures there is nothing better to load even when we can only load a less-specific rollup. |
---|
409 | // |
---|
410 | // note: this feature is only available in async mode |
---|
411 | |
---|
412 | // inspect the loaded bundle that came from the rollup to see if something better is available |
---|
413 | // for any bundle in a rollup, more-specific available locales are given at localized. |
---|
414 | var requiredBundles = [], |
---|
415 | cacheIds = []; |
---|
416 | forEachLocale(locale, function(loc){ |
---|
417 | if(localized[loc]){ |
---|
418 | requiredBundles.push(require.toAbsMid(bundlePath + loc + "/" + bundleName)); |
---|
419 | cacheIds.push(cacheId(bundlePath, bundleName, loc, require)); |
---|
420 | } |
---|
421 | }); |
---|
422 | |
---|
423 | if(requiredBundles.length){ |
---|
424 | preloadingAddLock(); |
---|
425 | contextRequire(requiredBundles, function(){ |
---|
426 | for(var i = 0; i < requiredBundles.length; i++){ |
---|
427 | bundle = lang.mixin(lang.clone(bundle), arguments[i]); |
---|
428 | cache[cacheIds[i]] = bundle; |
---|
429 | } |
---|
430 | // this is the best possible (maybe a perfect match, maybe not), accept it |
---|
431 | cache[cacheId(bundlePath, bundleName, locale, require)] = lang.clone(bundle); |
---|
432 | preloadingRelLock(); |
---|
433 | }); |
---|
434 | }else{ |
---|
435 | // this is the best possible (definitely not a perfect match), accept it |
---|
436 | cache[cacheId(bundlePath, bundleName, locale, require)] = bundle; |
---|
437 | } |
---|
438 | } |
---|
439 | improveBundle(bundlePath, bundleName, bundle, localized); |
---|
440 | } |
---|
441 | } |
---|
442 | preloadingRelLock(); |
---|
443 | }); |
---|
444 | return true; |
---|
445 | } |
---|
446 | return false; |
---|
447 | }); |
---|
448 | } |
---|
449 | |
---|
450 | preload(); |
---|
451 | array.forEach(dojo.config.extraLocale, preload); |
---|
452 | }, |
---|
453 | |
---|
454 | waitForPreloads = function(id, require, load){ |
---|
455 | if(preloading){ |
---|
456 | preloadWaitQueue.push([id, require, load]); |
---|
457 | } |
---|
458 | return preloading; |
---|
459 | }, |
---|
460 | |
---|
461 | checkForLegacyModules = function() |
---|
462 | {}; |
---|
463 | } |
---|
464 | |
---|
465 | if(has("dojo-v1x-i18n-Api")){ |
---|
466 | // this code path assumes the dojo loader and won't work with a standard AMD loader |
---|
467 | var amdValue = {}, |
---|
468 | evalBundle = |
---|
469 | // use the function ctor to keep the minifiers away (also come close to global scope, but this is secondary) |
---|
470 | new Function( |
---|
471 | "__bundle", // the bundle to evalutate |
---|
472 | "__checkForLegacyModules", // a function that checks if __bundle defined __mid in the global space |
---|
473 | "__mid", // the mid that __bundle is intended to define |
---|
474 | "__amdValue", |
---|
475 | |
---|
476 | // returns one of: |
---|
477 | // 1 => the bundle was an AMD bundle |
---|
478 | // a legacy bundle object that is the value of __mid |
---|
479 | // instance of Error => could not figure out how to evaluate bundle |
---|
480 | |
---|
481 | // used to detect when __bundle calls define |
---|
482 | "var define = function(mid, factory){define.called = 1; __amdValue.result = factory || mid;}," |
---|
483 | + " require = function(){define.called = 1;};" |
---|
484 | |
---|
485 | + "try{" |
---|
486 | + "define.called = 0;" |
---|
487 | + "eval(__bundle);" |
---|
488 | + "if(define.called==1)" |
---|
489 | // bundle called define; therefore signal it's an AMD bundle |
---|
490 | + "return __amdValue;" |
---|
491 | |
---|
492 | + "if((__checkForLegacyModules = __checkForLegacyModules(__mid)))" |
---|
493 | // bundle was probably a v1.6- built NLS flattened NLS bundle that defined __mid in the global space |
---|
494 | + "return __checkForLegacyModules;" |
---|
495 | |
---|
496 | + "}catch(e){}" |
---|
497 | // evaulating the bundle was *neither* an AMD *nor* a legacy flattened bundle |
---|
498 | // either way, re-eval *after* surrounding with parentheses |
---|
499 | |
---|
500 | + "try{" |
---|
501 | + "return eval('('+__bundle+')');" |
---|
502 | + "}catch(e){" |
---|
503 | + "return e;" |
---|
504 | + "}" |
---|
505 | ), |
---|
506 | |
---|
507 | syncRequire = function(deps, callback, require){ |
---|
508 | var results = []; |
---|
509 | array.forEach(deps, function(mid){ |
---|
510 | var url = require.toUrl(mid + ".js"); |
---|
511 | |
---|
512 | function load(text){ |
---|
513 | var result = evalBundle(text, checkForLegacyModules, mid, amdValue); |
---|
514 | if(result===amdValue){ |
---|
515 | // the bundle was an AMD module; re-inject it through the normal AMD path |
---|
516 | // we gotta do this since it could be an anonymous module and simply evaluating |
---|
517 | // the text here won't provide the loader with the context to know what |
---|
518 | // module is being defined()'d. With browser caching, this should be free; further |
---|
519 | // this entire code path can be circumvented by using the AMD format to begin with |
---|
520 | results.push(cache[url] = amdValue.result); |
---|
521 | }else{ |
---|
522 | if(result instanceof Error){ |
---|
523 | console.error("failed to evaluate i18n bundle; url=" + url, result); |
---|
524 | result = {}; |
---|
525 | } |
---|
526 | // nls/<locale>/<bundle-name> indicates not the root. |
---|
527 | results.push(cache[url] = (/nls\/[^\/]+\/[^\/]+$/.test(url) ? result : {root:result, _v1x:1})); |
---|
528 | } |
---|
529 | } |
---|
530 | |
---|
531 | if(cache[url]){ |
---|
532 | results.push(cache[url]); |
---|
533 | }else{ |
---|
534 | var bundle = require.syncLoadNls(mid); |
---|
535 | // don't need to check for legacy since syncLoadNls returns a module if the module |
---|
536 | // (1) was already loaded, or (2) was in the cache. In case 1, if syncRequire is called |
---|
537 | // from getLocalization --> load, then load will have called checkForLegacyModules() before |
---|
538 | // calling syncRequire; if syncRequire is called from preloadLocalizations, then we |
---|
539 | // don't care about checkForLegacyModules() because that will be done when a particular |
---|
540 | // bundle is actually demanded. In case 2, checkForLegacyModules() is never relevant |
---|
541 | // because cached modules are always v1.7+ built modules. |
---|
542 | if(bundle){ |
---|
543 | results.push(bundle); |
---|
544 | }else{ |
---|
545 | if(!xhr){ |
---|
546 | try{ |
---|
547 | require.getText(url, true, load); |
---|
548 | }catch(e){ |
---|
549 | results.push(cache[url] = {}); |
---|
550 | } |
---|
551 | }else{ |
---|
552 | xhr.get({ |
---|
553 | url:url, |
---|
554 | sync:true, |
---|
555 | load:load, |
---|
556 | error:function(){ |
---|
557 | results.push(cache[url] = {}); |
---|
558 | } |
---|
559 | }); |
---|
560 | } |
---|
561 | } |
---|
562 | } |
---|
563 | }); |
---|
564 | callback && callback.apply(null, results); |
---|
565 | }; |
---|
566 | |
---|
567 | checkForLegacyModules = function(target){ |
---|
568 | // legacy code may have already loaded [e.g] the raw bundle x/y/z at x.y.z; when true, push into the cache |
---|
569 | for(var result, names = target.split("/"), object = dojo.global[names[0]], i = 1; object && i<names.length-1; object = object[names[i++]]){} |
---|
570 | if(object){ |
---|
571 | result = object[names[i]]; |
---|
572 | if(!result){ |
---|
573 | // fallback for incorrect bundle build of 1.6 |
---|
574 | result = object[names[i].replace(/-/g,"_")]; |
---|
575 | } |
---|
576 | if(result){ |
---|
577 | cache[target] = result; |
---|
578 | } |
---|
579 | } |
---|
580 | return result; |
---|
581 | }; |
---|
582 | |
---|
583 | thisModule.getLocalization = function(moduleName, bundleName, locale){ |
---|
584 | var result, |
---|
585 | l10nName = getBundleName(moduleName, bundleName, locale); |
---|
586 | load( |
---|
587 | l10nName, |
---|
588 | |
---|
589 | // isXd() and syncRequire() need a context-require in order to resolve the mid with respect to a reference module. |
---|
590 | // Since this legacy function does not have the concept of a reference module, resolve with respect to this |
---|
591 | // dojo/i18n module, which, itself may have been mapped. |
---|
592 | (!isXd(l10nName, require) ? function(deps, callback){ syncRequire(deps, callback, require); } : require), |
---|
593 | |
---|
594 | function(result_){ result = result_; } |
---|
595 | ); |
---|
596 | return result; |
---|
597 | }; |
---|
598 | |
---|
599 | if(has("dojo-unit-tests")){ |
---|
600 | unitTests.push(function(doh){ |
---|
601 | doh.register("tests.i18n.unit", function(t){ |
---|
602 | var check; |
---|
603 | |
---|
604 | check = evalBundle("{prop:1}", checkForLegacyModules, "nonsense", amdValue); |
---|
605 | t.is({prop:1}, check); t.is(undefined, check[1]); |
---|
606 | |
---|
607 | check = evalBundle("({prop:1})", checkForLegacyModules, "nonsense", amdValue); |
---|
608 | t.is({prop:1}, check); t.is(undefined, check[1]); |
---|
609 | |
---|
610 | check = evalBundle("{'prop-x':1}", checkForLegacyModules, "nonsense", amdValue); |
---|
611 | t.is({'prop-x':1}, check); t.is(undefined, check[1]); |
---|
612 | |
---|
613 | check = evalBundle("({'prop-x':1})", checkForLegacyModules, "nonsense", amdValue); |
---|
614 | t.is({'prop-x':1}, check); t.is(undefined, check[1]); |
---|
615 | |
---|
616 | check = evalBundle("define({'prop-x':1})", checkForLegacyModules, "nonsense", amdValue); |
---|
617 | t.is(amdValue, check); t.is({'prop-x':1}, amdValue.result); |
---|
618 | |
---|
619 | check = evalBundle("define('some/module', {'prop-x':1})", checkForLegacyModules, "nonsense", amdValue); |
---|
620 | t.is(amdValue, check); t.is({'prop-x':1}, amdValue.result); |
---|
621 | |
---|
622 | check = evalBundle("this is total nonsense and should throw an error", checkForLegacyModules, "nonsense", amdValue); |
---|
623 | t.is(check instanceof Error, true); |
---|
624 | }); |
---|
625 | }); |
---|
626 | } |
---|
627 | } |
---|
628 | |
---|
629 | return lang.mixin(thisModule, { |
---|
630 | dynamic:true, |
---|
631 | normalize:normalize, |
---|
632 | load:load, |
---|
633 | cache:cache, |
---|
634 | getL10nName: getL10nName |
---|
635 | }); |
---|
636 | }); |
---|