i18n.js 25 KB

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