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