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 | } |
---|