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