[483] | 1 | i18nUtil = {}; |
---|
| 2 | |
---|
| 3 | i18nUtil.setup = function(/*Object*/kwArgs){ |
---|
| 4 | // summary: |
---|
| 5 | // loads dojo so we can use it for i18n bundle flattening. |
---|
| 6 | |
---|
| 7 | //Do the setup only if it has not already been done before. |
---|
| 8 | if(typeof djConfig == "undefined" || !(typeof dojo != "undefined" && dojo["i18n"])){ |
---|
| 9 | djConfig={ |
---|
| 10 | locale: 'xx', |
---|
| 11 | extraLocale: kwArgs.localeList, |
---|
| 12 | baseUrl: buildScriptsPath + "../../dojo/" |
---|
| 13 | }; |
---|
| 14 | |
---|
| 15 | load(buildScriptsPath + '../../dojo/dojo.js'); |
---|
| 16 | |
---|
| 17 | //Now set baseUrl so it is current directory, since all the prefixes |
---|
| 18 | //will be relative to the release dir from this directory. |
---|
| 19 | dojo.baseUrl = "./"; |
---|
| 20 | |
---|
| 21 | //Also be sure we register the right paths for module prefixes. |
---|
| 22 | buildUtil.configPrefixes(kwArgs.profileProperties.dependencies.prefixes); |
---|
| 23 | |
---|
| 24 | dojo.require("dojo.i18n"); |
---|
| 25 | } |
---|
| 26 | } |
---|
| 27 | |
---|
| 28 | i18nUtil.flattenLayerFileBundles = function(/*String*/fileName, /*String*/fileContents, /*Object*/kwArgs){ |
---|
| 29 | // summary: |
---|
| 30 | // This little utility is invoked by the build to flatten all of the JSON resource bundles used |
---|
| 31 | // by dojo.requireLocalization(), much like the main build itself, to optimize so that multiple |
---|
| 32 | // web hits will not be necessary to load these resources. Normally, a request for a particular |
---|
| 33 | // bundle in a locale like "en-us" would result in three web hits: one looking for en_us/ another |
---|
| 34 | // for en/ and another for ROOT/. All of this multiplied by the number of bundles used can result |
---|
| 35 | // in a lot of web hits and latency. This script uses Dojo to actually load the resources into |
---|
| 36 | // memory, then flatten the object and spit it out using dojo.toJson. The bootstrap |
---|
| 37 | // will be modified to download exactly one of these files, whichever is closest to the user's |
---|
| 38 | // locale. |
---|
| 39 | // fileName: |
---|
| 40 | // The name of the file to process (like dojo.js). This function will use |
---|
| 41 | // it to determine the best resource name to give the flattened bundle. |
---|
| 42 | // fileContents: |
---|
| 43 | // The contents of the file to process (like dojo.js). This function will look in |
---|
| 44 | // the contents for dojo.requireLocation() calls. |
---|
| 45 | // kwArgs: |
---|
| 46 | // The build's kwArgs. |
---|
| 47 | |
---|
| 48 | var destDirName = fileName.replace(/\/[^\/]+$/, "/") + "nls"; |
---|
| 49 | var nlsNamePrefix = fileName.replace(/\.js$/, ""); |
---|
| 50 | nlsNamePrefix = nlsNamePrefix.substring(nlsNamePrefix.lastIndexOf("/") + 1, nlsNamePrefix.length); |
---|
| 51 | |
---|
| 52 | i18nUtil.setup(kwArgs); |
---|
| 53 | var djLoadedBundles = []; |
---|
| 54 | |
---|
| 55 | //TODO: register plain function handler (output source) in jsonRegistry? |
---|
| 56 | var drl = dojo.requireLocalization; |
---|
| 57 | var dupes = {}; |
---|
| 58 | dojo.requireLocalization = function(modulename, bundlename, locale){ |
---|
| 59 | var dupName = [modulename, bundlename, locale].join(":"); |
---|
| 60 | if(!dupes[dupName]){ |
---|
| 61 | drl(modulename, bundlename, locale); |
---|
| 62 | djLoadedBundles.push({modulename: modulename, module: eval(modulename), bundlename: bundlename}); |
---|
| 63 | dupes[dupName] = 1; |
---|
| 64 | } |
---|
| 65 | }; |
---|
| 66 | |
---|
| 67 | var requireStatements = fileContents.match(/dojo\.requireLocalization\(.*\)\;/g); |
---|
| 68 | if(requireStatements){ |
---|
| 69 | eval(requireStatements.join(";")); |
---|
| 70 | |
---|
| 71 | //print("loaded bundles: "+djLoadedBundles.length); |
---|
| 72 | |
---|
| 73 | var djBundlesByLocale = {}; |
---|
| 74 | var jsLocale, entry, bundle; |
---|
| 75 | |
---|
| 76 | for (var i = 0; i < djLoadedBundles.length; i++){ |
---|
| 77 | entry = djLoadedBundles[i]; |
---|
| 78 | bundle = entry.module.nls[entry.bundlename]; |
---|
| 79 | for (jsLocale in bundle){ |
---|
| 80 | if (!djBundlesByLocale[jsLocale]){djBundlesByLocale[jsLocale]=[];} |
---|
| 81 | djBundlesByLocale[jsLocale].push(entry); |
---|
| 82 | } |
---|
| 83 | } |
---|
| 84 | |
---|
| 85 | localeList = []; |
---|
| 86 | |
---|
| 87 | //Save flattened bundles used by dojo.js. |
---|
| 88 | var mkdir = false; |
---|
| 89 | var dir = new java.io.File(destDirName); |
---|
| 90 | var modulePrefix = buildUtil.mapPathToResourceName(fileName, kwArgs.profileProperties.dependencies.prefixes); |
---|
| 91 | |
---|
| 92 | //Adjust modulePrefix to include the nls part before the last segment. |
---|
| 93 | var lastDot = modulePrefix.lastIndexOf("."); |
---|
| 94 | if(lastDot != -1){ |
---|
| 95 | modulePrefix = modulePrefix.substring(0, lastDot + 1) + "nls." + modulePrefix.substring(lastDot + 1, modulePrefix.length); |
---|
| 96 | }else{ |
---|
| 97 | throw "Invalid module prefix for flattened bundle: " + modulePrefix; |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | for (jsLocale in djBundlesByLocale){ |
---|
| 101 | var locale = jsLocale.replace(/\_/g, '-'); |
---|
| 102 | if(!mkdir){ dir.mkdir(); mkdir = true; } |
---|
| 103 | |
---|
| 104 | var outFile = new java.io.File(dir, nlsNamePrefix + "_" + locale + ".js"); |
---|
| 105 | //Make sure we can create the final file. |
---|
| 106 | var parentDir = outFile.getParentFile(); |
---|
| 107 | if(!parentDir.exists()){ |
---|
| 108 | if(!parentDir.mkdirs()){ |
---|
| 109 | throw "Could not create directory: " + parentDir.getAbsolutePath(); |
---|
| 110 | } |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | var os = new java.io.BufferedWriter( |
---|
| 114 | new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), "utf-8")); |
---|
| 115 | try{ |
---|
| 116 | os.write("dojo.provide(\""+modulePrefix+"_"+locale+"\");"); |
---|
| 117 | for (var j = 0; j < djLoadedBundles.length; j++){ |
---|
| 118 | entry = djLoadedBundles[j]; |
---|
| 119 | var bundlePkg = [entry.modulename,"nls",entry.bundlename].join("."); |
---|
| 120 | var translationPkg = [bundlePkg,jsLocale].join("."); |
---|
| 121 | bundle = entry.module.nls[entry.bundlename]; |
---|
| 122 | if(bundle[jsLocale]){ //FIXME:redundant check? |
---|
| 123 | os.write("dojo.provide(\""+bundlePkg+"\");"); |
---|
| 124 | os.write(bundlePkg+"._built=true;"); |
---|
| 125 | os.write("dojo.provide(\""+translationPkg+"\");"); |
---|
| 126 | os.write(translationPkg+"="+dojo.toJson(bundle[jsLocale])+";"); |
---|
| 127 | } |
---|
| 128 | } |
---|
| 129 | }finally{ |
---|
| 130 | os.close(); |
---|
| 131 | } |
---|
| 132 | localeList.push(locale); |
---|
| 133 | } |
---|
| 134 | |
---|
| 135 | //Remove dojo.requireLocalization calls from the file. |
---|
| 136 | fileContents = fileContents.replace(/dojo\.requireLocalization\(.*\)\;/g, ""); |
---|
| 137 | |
---|
| 138 | |
---|
| 139 | var preloadCall = '\ndojo.i18n._preloadLocalizations("' + modulePrefix + '", ' + dojo.toJson(localeList.sort()) + ');\n'; |
---|
| 140 | //Inject the dojo._preloadLocalizations call into the file. |
---|
| 141 | //Do this at the end of the file, since we need to make sure dojo.i18n has been loaded. |
---|
| 142 | //The assumption is that if dojo.i18n is not in this layer file, dojo.i18n is |
---|
| 143 | //in one of the layer files this layer file depends on. |
---|
| 144 | //Allow call to be inserted in the dojo.js closure, if that is in play. |
---|
| 145 | i18nUtil.preloadInsertionRegExp.lastIndex = 0; |
---|
| 146 | if(fileContents.match(i18nUtil.preloadInsertionRegExp)){ |
---|
| 147 | i18nUtil.preloadInsertionRegExp.lastIndex = 0; |
---|
| 148 | fileContents = fileContents.replace(i18nUtil.preloadInsertionRegExp, preloadCall); |
---|
| 149 | }else{ |
---|
| 150 | fileContents += preloadCall; |
---|
| 151 | } |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | return fileContents; //String |
---|
| 155 | } |
---|
| 156 | |
---|
| 157 | i18nUtil.preloadInsertionRegExp = /\/\/INSERT dojo.i18n._preloadLocalizations HERE/; |
---|
| 158 | |
---|
| 159 | i18nUtil.flattenDirBundles = function(/*String*/prefixName, /*String*/prefixDir, /*Object*/kwArgs, /*RegExp*/nlsIgnoreRegExp){ |
---|
| 160 | // summary: |
---|
| 161 | // Flattens the i18n bundles inside a directory so that only request |
---|
| 162 | // is needed per bundle. Does not handle resource flattening for dojo.js or |
---|
| 163 | // layered build files. |
---|
| 164 | |
---|
| 165 | i18nUtil.setup(kwArgs); |
---|
| 166 | var fileList = fileUtil.getFilteredFileList(prefixDir, /\.js$/, true); |
---|
| 167 | var prefixes = kwArgs.profileProperties.dependencies.prefixes; |
---|
| 168 | for(var i= 0; i < fileList.length; i++){ |
---|
| 169 | //Use new String so we get a JS string and not a Java string. |
---|
| 170 | var jsFileName = String(fileList[i]); |
---|
| 171 | var fileContents = null; |
---|
| 172 | |
---|
| 173 | //Files in nls directories, except for layer bundles that already have been processed. |
---|
| 174 | if(jsFileName.match(/\/nls\//) && !jsFileName.match(nlsIgnoreRegExp)){ |
---|
| 175 | fileContents = "(" + i18nUtil.makeFlatBundleContents(prefixName, prefixDir, jsFileName) + ")"; |
---|
| 176 | }else{ |
---|
| 177 | fileContents = i18nUtil.modifyRequireLocalization(readText(jsFileName), prefixes); |
---|
| 178 | } |
---|
| 179 | |
---|
| 180 | if(fileContents){ |
---|
| 181 | fileUtil.saveUtf8File(jsFileName, fileContents); |
---|
| 182 | } |
---|
| 183 | } |
---|
| 184 | } |
---|
| 185 | |
---|
| 186 | i18nUtil.modifyRequireLocalization = function(/*String*/fileContents, /*Array*/prefixes){ |
---|
| 187 | // summary: |
---|
| 188 | // Modifies any dojo.requireLocalization calls in the fileContents to have the |
---|
| 189 | // list of supported locales as part of the call. This allows the i18n loading functions |
---|
| 190 | // to only make request(s) for locales that actually exist on disk. |
---|
| 191 | var dependencies = []; |
---|
| 192 | |
---|
| 193 | //Make sure we have a JS string, and not a Java string. |
---|
| 194 | fileContents = String(fileContents); |
---|
| 195 | |
---|
| 196 | var modifiedContents = fileContents; |
---|
| 197 | |
---|
| 198 | if(fileContents.match(buildUtil.globalRequireLocalizationRegExp)){ |
---|
| 199 | modifiedContents = fileContents.replace(buildUtil.globalRequireLocalizationRegExp, function(matchString){ |
---|
| 200 | var replacement = matchString; |
---|
| 201 | var partMatches = matchString.match(buildUtil.requireLocalizationRegExp); |
---|
| 202 | var depCall = partMatches[1]; |
---|
| 203 | var depArgs = partMatches[2]; |
---|
| 204 | |
---|
| 205 | if(depCall == "requireLocalization"){ |
---|
| 206 | //Need to find out what locales are available so the dojo loader |
---|
| 207 | //only has to do one script request for the closest matching locale. |
---|
| 208 | var reqArgs = i18nUtil.getRequireLocalizationArgsFromString(depArgs); |
---|
| 209 | if(reqArgs.moduleName){ |
---|
| 210 | //Find the list of locales supported by looking at the path names. |
---|
| 211 | var locales = i18nUtil.getLocalesForBundle(reqArgs.moduleName, reqArgs.bundleName, prefixes); |
---|
| 212 | |
---|
| 213 | //Add the supported locales to the requireLocalization arguments. |
---|
| 214 | if(!reqArgs.localeName){ |
---|
| 215 | depArgs += ", null"; |
---|
| 216 | } |
---|
| 217 | |
---|
| 218 | depArgs += ', "' + locales.join(",") + '"'; |
---|
| 219 | |
---|
| 220 | replacement = "dojo." + depCall + "(" + depArgs + ")"; |
---|
| 221 | } |
---|
| 222 | } |
---|
| 223 | return replacement; |
---|
| 224 | }); |
---|
| 225 | } |
---|
| 226 | return modifiedContents; |
---|
| 227 | } |
---|
| 228 | |
---|
| 229 | i18nUtil.makeFlatBundleContents = function(prefix, prefixPath, srcFileName){ |
---|
| 230 | // summary: |
---|
| 231 | // Given a nls file name, flatten the bundles from parent locales into the nls bundle. |
---|
| 232 | var bundleParts = i18nUtil.getBundlePartsFromFileName(prefix, prefixPath, srcFileName); |
---|
| 233 | if(!bundleParts){ |
---|
| 234 | return null; |
---|
| 235 | } |
---|
| 236 | var moduleName = bundleParts.moduleName; |
---|
| 237 | var bundleName = bundleParts.bundleName; |
---|
| 238 | var localeName = bundleParts.localeName; |
---|
| 239 | |
---|
| 240 | dojo.requireLocalization(moduleName, bundleName, localeName); |
---|
| 241 | |
---|
| 242 | //Get the generated, flattened bundle. |
---|
| 243 | var module = dojo.getObject(moduleName); |
---|
| 244 | var bundleLocale = localeName ? localeName.replace(/-/g, "_") : "ROOT"; |
---|
| 245 | var flattenedBundle = module.nls[bundleName][bundleLocale]; |
---|
| 246 | |
---|
| 247 | if(!flattenedBundle){ |
---|
| 248 | throw "Cannot create flattened bundle for src file: " + srcFileName; |
---|
| 249 | } |
---|
| 250 | |
---|
| 251 | return dojo.toJson(flattenedBundle); |
---|
| 252 | } |
---|
| 253 | |
---|
| 254 | //Given a module and bundle name, find all the supported locales. |
---|
| 255 | i18nUtil.getLocalesForBundle = function(moduleName, bundleName, prefixes){ |
---|
| 256 | //Build a path to the bundle directory and ask for all files that match |
---|
| 257 | //the bundle name. |
---|
| 258 | var filePath = buildUtil.mapResourceToPath(moduleName, prefixes); |
---|
| 259 | |
---|
| 260 | var bundleRegExp = new RegExp("nls[/]?([\\w\\-]*)/" + bundleName + ".js$"); |
---|
| 261 | var bundleFiles = fileUtil.getFilteredFileList(filePath + "nls/", bundleRegExp, true); |
---|
| 262 | |
---|
| 263 | //Find the list of locales supported by looking at the path names. |
---|
| 264 | var locales = []; |
---|
| 265 | for(var j = 0; j < bundleFiles.length; j++){ |
---|
| 266 | var bundleParts = bundleFiles[j].match(bundleRegExp); |
---|
| 267 | if(bundleParts && bundleParts[1]){ |
---|
| 268 | locales.push(bundleParts[1]); |
---|
| 269 | }else{ |
---|
| 270 | locales.push("ROOT"); |
---|
| 271 | } |
---|
| 272 | } |
---|
| 273 | |
---|
| 274 | return locales.sort(); |
---|
| 275 | } |
---|
| 276 | |
---|
| 277 | i18nUtil.getRequireLocalizationArgsFromString = function(argString){ |
---|
| 278 | // summary: |
---|
| 279 | // Given a string of the arguments to a dojo.requireLocalization |
---|
| 280 | // call, separate the string into individual arguments. |
---|
| 281 | var argResult = { |
---|
| 282 | moduleName: null, |
---|
| 283 | bundleName: null, |
---|
| 284 | localeName: null |
---|
| 285 | }; |
---|
| 286 | |
---|
| 287 | var l10nMatches = argString.split(/\,\s*/); |
---|
| 288 | if(l10nMatches && l10nMatches.length > 1){ |
---|
| 289 | argResult.moduleName = l10nMatches[0] ? l10nMatches[0].replace(/\"/g, "") : null; |
---|
| 290 | argResult.bundleName = l10nMatches[1] ? l10nMatches[1].replace(/\"/g, "") : null; |
---|
| 291 | argResult.localeName = l10nMatches[2]; |
---|
| 292 | } |
---|
| 293 | return argResult; |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | i18nUtil.getBundlePartsFromFileName = function(prefix, prefixPath, srcFileName){ |
---|
| 297 | //Pull off any ../ values from prefix path to make matching easier. |
---|
| 298 | var prefixPath = prefixPath.replace(/\.\.\//g, ""); |
---|
| 299 | |
---|
| 300 | //Strip off the prefix path so we can find the real resource and bundle names. |
---|
| 301 | var prefixStartIndex = srcFileName.lastIndexOf(prefixPath); |
---|
| 302 | if(prefixStartIndex != -1){ |
---|
| 303 | var startIndex = prefixStartIndex + prefixPath.length; |
---|
| 304 | |
---|
| 305 | //Need to add one if the prefiPath does not include an ending /. Otherwise, |
---|
| 306 | //We'll get extra dots in our bundleName. |
---|
| 307 | if(prefixPath.charAt(prefixPath.length) != "/"){ |
---|
| 308 | startIndex += 1; |
---|
| 309 | } |
---|
| 310 | srcFileName = srcFileName.substring(startIndex, srcFileName.length); |
---|
| 311 | } |
---|
| 312 | |
---|
| 313 | //var srcIndex = srcFileName.indexOf("src/"); |
---|
| 314 | //srcFileName = srcFileName.substring(srcIndex + 4, srcFileName.length); |
---|
| 315 | var parts = srcFileName.split("/"); |
---|
| 316 | |
---|
| 317 | //Split up the srcFileName into arguments that can be used for dojo.requireLocalization() |
---|
| 318 | var moduleParts = [prefix]; |
---|
| 319 | for(var i = 0; parts[i] != "nls"; i++){ |
---|
| 320 | moduleParts.push(parts[i]); |
---|
| 321 | } |
---|
| 322 | var moduleName = moduleParts.join("."); |
---|
| 323 | if(parts[i+1].match(/\.js$/)){ |
---|
| 324 | var localeName = ""; |
---|
| 325 | var bundleName = parts[i+1]; |
---|
| 326 | }else{ |
---|
| 327 | var localeName = parts[i+1]; |
---|
| 328 | var bundleName = parts[i+2]; |
---|
| 329 | } |
---|
| 330 | |
---|
| 331 | if(!bundleName || bundleName.indexOf(".js") == -1){ |
---|
| 332 | //Not a valid bundle. Could be something like a README file. |
---|
| 333 | return null; |
---|
| 334 | }else{ |
---|
| 335 | bundleName = bundleName.replace(/\.js/, ""); |
---|
| 336 | } |
---|
| 337 | |
---|
| 338 | return {moduleName: moduleName, bundleName: bundleName, localeName: localeName}; |
---|
| 339 | } |
---|