i18n.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * @license RequireJS i18n 2.0.6 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.6',
  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.languages && navigator.languages[0]) ||
  119. navigator.language ||
  120. navigator.userLanguage || 'root').toLowerCase();
  121. }
  122. parts = locale.split('-');
  123. }
  124. if (config.isBuild) {
  125. //Check for existence of all locale possible files and
  126. //require them if exist.
  127. toLoad.push(masterName);
  128. addIfExists(req, 'root', toLoad, prefix, suffix);
  129. for (i = 0; i < parts.length; i++) {
  130. part = parts[i];
  131. current += (current ? '-' : '') + part;
  132. addIfExists(req, current, toLoad, prefix, suffix);
  133. }
  134. req(toLoad, function () {
  135. onLoad();
  136. });
  137. } else {
  138. //First, fetch the master bundle, it knows what locales are available.
  139. req([masterName], function (master) {
  140. //Figure out the best fit
  141. var needed = [],
  142. part;
  143. //Always allow for root, then do the rest of the locale parts.
  144. addPart('root', master, needed, toLoad, prefix, suffix);
  145. for (i = 0; i < parts.length; i++) {
  146. part = parts[i];
  147. current += (current ? '-' : '') + part;
  148. addPart(current, master, needed, toLoad, prefix, suffix);
  149. }
  150. //Load all the parts missing.
  151. req(toLoad, function () {
  152. var i, partBundle, part;
  153. for (i = needed.length - 1; i > -1 && needed[i]; i--) {
  154. part = needed[i];
  155. partBundle = master[part];
  156. if (partBundle === true || partBundle === 1) {
  157. partBundle = req(prefix + part + '/' + suffix);
  158. }
  159. mixin(value, partBundle);
  160. }
  161. //All done, notify the loader.
  162. onLoad(value);
  163. });
  164. });
  165. }
  166. }
  167. };
  168. });
  169. }());