i18n.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /**
  2. * @license RequireJS i18n 2.0.4 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
  3. * Available via the MIT or new BSD license.
  4. * see: http://github.com/requirejs/i18n for details
  5. */
  6. /*jslint regexp: true */
  7. /*global require: false, navigator: false, define: false */
  8. /**
  9. * This plugin handles i18n! prefixed modules. It does the following:
  10. *
  11. * 1) A regular module can have a dependency on an i18n bundle, but the regular
  12. * module does not want to specify what locale to load. So it just specifies
  13. * the top-level bundle, like "i18n!nls/colors".
  14. *
  15. * This plugin will load the i18n bundle at nls/colors, see that it is a root/master
  16. * bundle since it does not have a locale in its name. It will then try to find
  17. * the best match locale available in that master bundle, then request all the
  18. * locale pieces for that best match locale. For instance, if the locale is "en-us",
  19. * then the plugin will ask for the "en-us", "en" and "root" bundles to be loaded
  20. * (but only if they are specified on the master bundle).
  21. *
  22. * Once all the bundles for the locale pieces load, then it mixes in all those
  23. * locale pieces into each other, then finally sets the context.defined value
  24. * for the nls/colors bundle to be that mixed in locale.
  25. *
  26. * 2) A regular module specifies a specific locale to load. For instance,
  27. * i18n!nls/fr-fr/colors. In this case, the plugin needs to load the master bundle
  28. * first, at nls/colors, then figure out what the best match locale is for fr-fr,
  29. * since maybe only fr or just root is defined for that locale. Once that best
  30. * fit is found, all of its locale pieces need to have their bundles loaded.
  31. *
  32. * Once all the bundles for the locale pieces load, then it mixes in all those
  33. * locale pieces into each other, then finally sets the context.defined value
  34. * for the nls/fr-fr/colors bundle to be that mixed in locale.
  35. */
  36. (function () {
  37. 'use strict';
  38. //regexp for reconstructing the master bundle name from parts of the regexp match
  39. //nlsRegExp.exec("foo/bar/baz/nls/en-ca/foo") gives:
  40. //["foo/bar/baz/nls/en-ca/foo", "foo/bar/baz/nls/", "/", "/", "en-ca", "foo"]
  41. //nlsRegExp.exec("foo/bar/baz/nls/foo") gives:
  42. //["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""]
  43. //so, if match[5] is blank, it means this is the top bundle definition.
  44. var nlsRegExp = /(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/;
  45. //Helper function to avoid repeating code. Lots of arguments in the
  46. //desire to stay functional and support RequireJS contexts without having
  47. //to know about the RequireJS contexts.
  48. function addPart(locale, master, needed, toLoad, prefix, suffix) {
  49. if (master[locale]) {
  50. needed.push(locale);
  51. if (master[locale] === true || master[locale] === 1) {
  52. toLoad.push(prefix + locale + '/' + suffix);
  53. }
  54. }
  55. }
  56. function addIfExists(req, locale, toLoad, prefix, suffix) {
  57. var fullName = prefix + locale + '/' + suffix;
  58. if (require._fileExists(req.toUrl(fullName + '.js'))) {
  59. toLoad.push(fullName);
  60. }
  61. }
  62. /**
  63. * Simple function to mix in properties from source into target,
  64. * but only if target does not already have a property of the same name.
  65. * This is not robust in IE for transferring methods that match
  66. * Object.prototype names, but the uses of mixin here seem unlikely to
  67. * trigger a problem related to that.
  68. */
  69. function mixin(target, source, force) {
  70. var prop;
  71. for (prop in source) {
  72. if (source.hasOwnProperty(prop) && (!target.hasOwnProperty(prop) || force)) {
  73. target[prop] = source[prop];
  74. } else if (typeof source[prop] === 'object') {
  75. if (!target[prop] && source[prop]) {
  76. target[prop] = {};
  77. }
  78. mixin(target[prop], source[prop], force);
  79. }
  80. }
  81. }
  82. define(['module'], function (module) {
  83. var masterConfig = module.config ? module.config() : {};
  84. return {
  85. version: '2.0.4',
  86. /**
  87. * Called when a dependency needs to be loaded.
  88. */
  89. load: function (name, req, onLoad, config) {
  90. config = config || {};
  91. if (config.locale) {
  92. masterConfig.locale = config.locale;
  93. }
  94. var masterName,
  95. match = nlsRegExp.exec(name),
  96. prefix = match[1],
  97. locale = match[4],
  98. suffix = match[5],
  99. parts = locale.split("-"),
  100. toLoad = [],
  101. value = {},
  102. i, part, current = "";
  103. //If match[5] is blank, it means this is the top bundle definition,
  104. //so it does not have to be handled. Locale-specific requests
  105. //will have a match[4] value but no match[5]
  106. if (match[5]) {
  107. //locale-specific bundle
  108. prefix = match[1];
  109. masterName = prefix + suffix;
  110. } else {
  111. //Top-level bundle.
  112. masterName = name;
  113. suffix = match[4];
  114. locale = masterConfig.locale;
  115. if (!locale) {
  116. locale = masterConfig.locale =
  117. typeof navigator === "undefined" ? "root" :
  118. (navigator.language ||
  119. navigator.userLanguage || "root").toLowerCase();
  120. }
  121. parts = locale.split("-");
  122. }
  123. if (config.isBuild) {
  124. //Check for existence of all locale possible files and
  125. //require them if exist.
  126. toLoad.push(masterName);
  127. addIfExists(req, "root", toLoad, prefix, suffix);
  128. for (i = 0; i < parts.length; i++) {
  129. part = parts[i];
  130. current += (current ? "-" : "") + part;
  131. addIfExists(req, current, toLoad, prefix, suffix);
  132. }
  133. req(toLoad, function () {
  134. onLoad();
  135. });
  136. } else {
  137. //First, fetch the master bundle, it knows what locales are available.
  138. req([masterName], function (master) {
  139. //Figure out the best fit
  140. var needed = [],
  141. part;
  142. //Always allow for root, then do the rest of the locale parts.
  143. addPart("root", master, needed, toLoad, prefix, suffix);
  144. for (i = 0; i < parts.length; i++) {
  145. part = parts[i];
  146. current += (current ? "-" : "") + part;
  147. addPart(current, master, needed, toLoad, prefix, suffix);
  148. }
  149. //Load all the parts missing.
  150. req(toLoad, function () {
  151. var i, partBundle, part;
  152. for (i = needed.length - 1; i > -1 && needed[i]; i--) {
  153. part = needed[i];
  154. partBundle = master[part];
  155. if (partBundle === true || partBundle === 1) {
  156. partBundle = req(prefix + part + '/' + suffix);
  157. }
  158. mixin(value, partBundle);
  159. }
  160. //All done, notify the loader.
  161. onLoad(value);
  162. });
  163. });
  164. }
  165. }
  166. };
  167. });
  168. }());