]>
git.wh0rd.org - tt-rss.git/blob - 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
) {
6 // This module implements the !dojo/i18n plugin and the v1.6- i18n API
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.
13 has
.add("dojo-preload-i18n-Api",
14 // if true, define the preload localizations machinery
18 true || has
.add("dojo-v1x-i18n-Api",
19 // if true, define the v1.x i18n functions
24 thisModule
= dojo
.i18n
=
25 // the dojo.i18n module
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)(\/|$)([^\/]*)\/?([^\/]*)/,
38 getAvailableLocales= function(
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.
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
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
);
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);
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]);
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;
94 normalize = function(id, toAbsMid){
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;
101 getLocalesToLoad = function(targetLocale){
102 var list = config.extraLocale || [];
103 list = lang.isArray(list) ? list : [list];
104 list.push(targetLocale);
108 load = function(id, require, load){
110 // id is in one of the following formats
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.
116 // 2. <path>/nls/<locale>/<bundle>
117 // => load then return the bundle localized to <locale>
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
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.
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
131 // <path>/nls/<bundle>/<locale>
133 // will hold the value. Similarly, then plugin will publish this value to the loader by
135 // define("<path
>/nls/<bundle
>/<locale
>", <bundle-value>);
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.
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:
147 // 1. The client demands "dojo
/i18n!some/path/nls/someBundle
149 // 2. The loader demands load(some/path/nls/someBundle)
151 // 3. This plugin require's "some/path/nls/someBundle", which is the root bundle.
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"
157 // 5. Upon receiving all required bundles, the plugin constructs the value of the bundle
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"));
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.
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.
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:
174 // *preload*some/path/nls/someModule*["root", "ab", "ab-cd-ef"]
176 // This indicates the following rollup modules are available:
178 // some/path/nls/someModule_ROOT
179 // some/path/nls/someModule_ab
180 // some/path/nls/someModule_ab-cd-ef
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:
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>,
191 // E.g., given this design, preloading for locale=="ab" can execute the following algorithm:
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]);
201 // Similarly, if "ab-cd" is requested, the algorithm can determine that "ab" is the best available and
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
208 // "*now":function(r){r(['dojo/i18n!*preload*<path>/nls/<module>*<JSON array of available locales>']);}
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.
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:
219 // 1. Layer loads root bundle.
220 // 2. bundle is demanded; plugin loads single localized bundle.
224 // 1. Layer causes preloading of target bundle.
225 // 2. bundle is demanded; service is delayed until preloading complete; bundle is returned.
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.
233 if(has("dojo-preload-i18n-Api")){
234 var split
= id
.split("*"),
235 preloadDemand
= split
[1]=="preload";
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
241 preloadL10n(split
[2], json
.parse(split
[3]), 1);
243 // don't stall the loader!
246 if(preloadDemand
|| waitForPreloads(id
, require
, load
)){
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
,
262 load(lang
.delegate(cache
[loadTarget
]));
265 array
.forEach(loadList
, function(locale
){
266 var target
= bundlePathAndName
+ "/" + locale
;
267 if(has("dojo-preload-i18n-Api")){
268 checkForLegacyModules(target
);
271 doLoad(require
, bundlePathAndName
, bundlePath
, bundleName
, locale
, finish
);
278 if(has("dojo-unit-tests")){
279 var unitTests
= thisModule
.unitTests
= [];
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
;
288 isXd = function(mid
){
290 require
.isXdUrl(require
.toUrl(mid
+ ".js")) :
296 preloadWaitQueue
= [],
298 preloadL10n
= thisModule
._preloadLocalizations = function(/*String*/bundlePrefix
, /*Array*/localesGenerated
, /*boolean*/ guaranteedAmdFormat
){
300 // Load available flattened resource bundles associated with a particular module for dojo.locale and all dojo.config.extraLocale (if any)
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.
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.
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("-");
315 if(func(parts
.join("-"))){
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
;
329 (isXd(mid
) || guaranteedAmdFormat
? require
: syncRequire
)([mid
], function(rollup
){
330 for(var p
in rollup
){
331 cache
[p
+ "/" + locale
] = rollup
[p
];
334 while(!preloading
&& preloadWaitQueue
.length
){
335 load
.apply(null, preloadWaitQueue
.shift());
345 array
.forEach(dojo
.config
.extraLocale
, preload
);
348 waitForPreloads = function(id
, require
, load
){
350 preloadWaitQueue
.push([id
, require
, load
]);
357 // this code path assumes the dojo loader and won't work with a standard AMD loader
359 // use the function ctor to keep the minifiers away (also come close to global scope, but this is secondary)
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
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
370 // used to detect when __bundle calls define
371 "var define = function(){define.called = 1;},"
372 + " require = function(){define.called = 1;};"
375 + "define.called = 0;"
377 + "if(define.called==1)"
378 // bundle called define; therefore signal it's an AMD bundle
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;"
386 // evaulating the bundle was *neither* an AMD *nor* a legacy flattened bundle
387 // either way, re-eval *after* surrounding with parentheses
390 + "return eval('('+__bundle+')');"
396 syncRequire= function(deps
, callback
){
398 array
.forEach(deps
, function(mid
){
399 var url
= require
.toUrl(mid
+ ".js");
402 var result
= evalBundle(text
, checkForLegacyModules
, mid
);
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
);
413 if(result
instanceof Error
){
414 console
.error("failed to evaluate i18n bundle; url=" + url
, result
);
417 // nls/<locale>/<bundle-name> indicates not the root.
418 results
.push(cache
[url
] = (/nls\/[^\/]+\/[^\/]+$/.test(url
) ? result
: {root
:result
, _v1x
:1}));
423 results
.push(cache
[url
]);
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.
434 results
.push(bundle
);
438 require
.getText(url
, true, load
);
440 results
.push(cache
[url
]= {});
448 results
.push(cache
[url
]= {});
455 callback
&& callback
.apply(null, results
);
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
++]]){}
462 result
= object
[names
[i
]];
464 // fallback for incorrect bundle build of 1.6
465 result
= object
[names
[i
].replace(/-/g
,"_")];
468 cache
[target
] = result
;
474 thisModule
.getLocalization= function(moduleName
, bundleName
, locale
){
476 l10nName
= getL10nName(moduleName
, bundleName
, locale
).substring(10);
477 load(l10nName
, (!isXd(l10nName
) ? syncRequire
: require
), function(result_
){ result
= result_
; });
481 if(has("dojo-unit-tests")){
482 unitTests
.push(function(doh
){
483 doh
.register("tests.i18n.unit", function(t
){
486 check
= evalBundle("{prop:1}");
487 t
.is({prop
:1}, check
); t
.is(undefined, check
[1]);
489 check
= evalBundle("({prop:1})");
490 t
.is({prop
:1}, check
); t
.is(undefined, check
[1]);
492 check
= evalBundle("{'prop-x':1}");
493 t
.is({'prop-x':1}, check
); t
.is(undefined, check
[1]);
495 check
= evalBundle("({'prop-x':1})");
496 t
.is({'prop-x':1}, check
); t
.is(undefined, check
[1]);
498 check
= evalBundle("define({'prop-x':1})");
501 check
= evalBundle("this is total nonsense and should throw an error");
502 t
.is(check
instanceof Error
, true);
508 return lang
.mixin(thisModule
, {