|
| 1 | +/** |
| 2 | + * Plugin based on requirejs i18n |
| 3 | + * see: http://github.com/requirejs/i18n for details |
| 4 | + */ |
| 5 | +define(['./i18n/common', "module"], function (common, module) { |
| 6 | + |
| 7 | + // regexp for reconstructing the master bundle name from parts of the regexp match |
| 8 | + // nlsRegExp.exec("foo/bar/baz/nls/en-ca/foo") gives: |
| 9 | + // ["foo/bar/baz/nls/en-ca/foo", "foo/bar/baz/nls/", "/", "/", "en-ca", "foo"] |
| 10 | + // nlsRegExp.exec("foo/bar/baz/nls/foo") gives: |
| 11 | + // ["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""] |
| 12 | + // so, if match[5] is blank, it means this is the top bundle definition. |
| 13 | + var nlsRegExp = /(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/, |
| 14 | + |
| 15 | + |
| 16 | + // Simple function to mix in properties from source into target, |
| 17 | + // but only if target does not already have a property of the same name. |
| 18 | + // This is not robust in IE for transferring methods that match |
| 19 | + // Object.prototype names, but the uses of mixin here seem unlikely to |
| 20 | + // trigger a problem related to that. |
| 21 | + mixin = function (target, source, force) { |
| 22 | + var prop; |
| 23 | + for (prop in source) { |
| 24 | + if (source.hasOwnProperty(prop) && (!target.hasOwnProperty(prop) || force)) { |
| 25 | + target[prop] = source[prop]; |
| 26 | + } else if (typeof source[prop] === 'object') { |
| 27 | + if (!target[prop] && source[prop]) { |
| 28 | + target[prop] = {}; |
| 29 | + } |
| 30 | + mixin(target[prop], source[prop], force); |
| 31 | + } |
| 32 | + } |
| 33 | + }, |
| 34 | + |
| 35 | + // Use nlsRegExp to parse the resource mid and return a usable object. |
| 36 | + parseName = function (name) { |
| 37 | + var match = nlsRegExp.exec(name); |
| 38 | + |
| 39 | + // If match[5] is blank, it means this is the top bundle definition, |
| 40 | + // hence suffix is match[4] and locale is null. |
| 41 | + return { |
| 42 | + prefix: match[1], |
| 43 | + masterLocale: "root", |
| 44 | + requestedLocale: match[5] ? match[4] : null, |
| 45 | + suffix: match[5] || match[4] |
| 46 | + }; |
| 47 | + }, |
| 48 | + |
| 49 | + getMasterMid = function (name) { |
| 50 | + return name.masterLocale === "root" ? name.prefix + name.suffix : |
| 51 | + name.prefix + name.masterLocale + "/" + name.suffix; |
| 52 | + }, |
| 53 | + |
| 54 | + |
| 55 | + // Transform a bundle from a language layer to a root bundle. |
| 56 | + rootify = function (bundle, locale) { |
| 57 | + var result = {}; |
| 58 | + if (bundle._pseudoRoot) { |
| 59 | + result[locale] = {}; |
| 60 | + mixin(result, bundle._pseudoRoot); |
| 61 | + delete bundle._pseudoRoot; |
| 62 | + mixin(result[locale], bundle); |
| 63 | + bundle = result; |
| 64 | + } |
| 65 | + return bundle; |
| 66 | + }, |
| 67 | + |
| 68 | + // Construct the best language bundle by merging from most specific locale to less specific locale. |
| 69 | + resolveAMD = function (name, req, onLoad) { |
| 70 | + var masterMid = getMasterMid(name); |
| 71 | + |
| 72 | + //First, fetch the master bundle, it knows what locales are available. |
| 73 | + req([masterMid], function (master) { |
| 74 | + var getBundleAndMixin = function (prefix, suffix, locale, value) { |
| 75 | + var mixBundle = function (bundle) { |
| 76 | + mixin(value, bundle); |
| 77 | + locale = common.getParentLocale(locale); |
| 78 | + if (!bundle._flattened && locale) { |
| 79 | + getBundleAndMixin(prefix, suffix, locale, value); |
| 80 | + } else { |
| 81 | + value._flattened = true; |
| 82 | + onLoad(value); |
| 83 | + } |
| 84 | + }; |
| 85 | + |
| 86 | + if (master[locale] === true || master[locale] === 1) { |
| 87 | + req([prefix + locale + '/' + suffix], mixBundle); |
| 88 | + } else { |
| 89 | + // locale is on the master bundle or locale is unexisting |
| 90 | + mixBundle(master[locale] || {}); |
| 91 | + } |
| 92 | + }; |
| 93 | + |
| 94 | + master = rootify(master, name.masterLocale); |
| 95 | + getBundleAndMixin(name.prefix, name.suffix, name.requestedLocale, {}); |
| 96 | + }); |
| 97 | + }, |
| 98 | + |
| 99 | + getLayer = function (name, layer, moduleConfig, getParentLocale, req, onLoad) { |
| 100 | + var locale = name.requestedLocale, |
| 101 | + localesMap = moduleConfig.localesMap[layer]; |
| 102 | + |
| 103 | + while (locale && !localesMap[locale]) { |
| 104 | + locale = getParentLocale(locale); |
| 105 | + } |
| 106 | + |
| 107 | + if (locale) { |
| 108 | + name.masterLocale = locale; |
| 109 | + |
| 110 | + req([layer + "_" + locale], function () { |
| 111 | + pickFromLayer(name, moduleConfig, req, onLoad); |
| 112 | + }); |
| 113 | + } else { |
| 114 | + console.log("i18n: no relevant layer " + layer + " found for locale " + name.requestedLocale + "."); |
| 115 | + onLoad(); |
| 116 | + } |
| 117 | + }, |
| 118 | + |
| 119 | + |
| 120 | + tryLayer = function (name, layer, moduleConfig, getParentLocale, req, onLoad) { |
| 121 | + var helper = function (locale) { |
| 122 | + if (locale) { |
| 123 | + req(["maybe!" + layer + "_" + locale], function (bundle) { |
| 124 | + if (bundle) { |
| 125 | + name.masterLocale = locale; |
| 126 | + pickFromLayer(name, moduleConfig, req, onLoad); |
| 127 | + } else { |
| 128 | + helper(getParentLocale(locale)); |
| 129 | + } |
| 130 | + }); |
| 131 | + } else { |
| 132 | + console.log("i18n: no relevant layer " + layer + " found for locale " + name.requestedLocale + "."); |
| 133 | + onLoad(); |
| 134 | + } |
| 135 | + }; |
| 136 | + |
| 137 | + helper(name.requestedLocale); |
| 138 | + }, |
| 139 | + |
| 140 | + pickFromLayer = function (name, moduleConfig, req, onLoad) { |
| 141 | + var masterMid = getMasterMid(name); |
| 142 | + |
| 143 | + if (name.requestedLocale === name.masterLocale || moduleConfig.layerOnly || !moduleConfig.enhanceLayer) { |
| 144 | + req([masterMid], function (bundle) { |
| 145 | + if (bundle.root) { |
| 146 | + bundle = bundle.root; |
| 147 | + } |
| 148 | + onLoad(bundle); |
| 149 | + }); |
| 150 | + } else { |
| 151 | + resolveAMD(name, req, onLoad); |
| 152 | + } |
| 153 | + }; |
| 154 | + |
| 155 | + return { |
| 156 | + load: function (name, req, onLoad, config) { |
| 157 | + config = config || {}; |
| 158 | + |
| 159 | + var moduleConfig = module.config(), |
| 160 | + masterMid, |
| 161 | + layer; |
| 162 | + |
| 163 | + // Parse name and set the locale if a top level bundle is required |
| 164 | + name = parseName(name); |
| 165 | + name.requestedLocale = name.requestedLocale || common.getLocale(config); |
| 166 | + masterMid = getMasterMid(name); |
| 167 | + |
| 168 | + // If there is no layer, classic AMD mode |
| 169 | + if (!moduleConfig.bundlesMap) { |
| 170 | + resolveAMD(name, req, onLoad); |
| 171 | + return; |
| 172 | + } |
| 173 | + |
| 174 | + // From now on there is at least one layer available |
| 175 | + |
| 176 | + // Check if requested module is in a layer |
| 177 | + layer = moduleConfig.bundlesMap[masterMid]; |
| 178 | + if (!layer && moduleConfig.layerOnly) { |
| 179 | + console.log("i18n: module " + masterMid + " not found in layer."); |
| 180 | + onLoad(); |
| 181 | + return; |
| 182 | + } else if (!layer) { |
| 183 | + resolveAMD(name, req, onLoad); |
| 184 | + return; |
| 185 | + } |
| 186 | + |
| 187 | + // The module is in a layer |
| 188 | + |
| 189 | + if (moduleConfig.languagePack) { |
| 190 | + // Drop language pack mode, hence need to try every possible layer |
| 191 | + tryLayer(name, layer, moduleConfig, common.getParentLocale, req, onLoad); |
| 192 | + return; |
| 193 | + } else { |
| 194 | + // There is a locale list for the layer |
| 195 | + getLayer(name, layer, moduleConfig, common.getParentLocale, req, onLoad); |
| 196 | + return; |
| 197 | + } |
| 198 | + } |
| 199 | + }; |
| 200 | +}); |
0 commit comments