331 lines
12 KiB
JavaScript
331 lines
12 KiB
JavaScript
|
i18nUtil = {};
|
||
|
|
||
|
i18nUtil.setup = function(/*Object*/kwArgs){
|
||
|
//summary: loads dojo so we can use it for i18n bundle flattening.
|
||
|
|
||
|
//Do the setup only if it has not already been done before.
|
||
|
if(typeof djConfig == "undefined" || !(typeof dojo != "undefined" && dojo["i18n"])){
|
||
|
djConfig={
|
||
|
locale: 'xx',
|
||
|
extraLocale: kwArgs.localeList,
|
||
|
baseUrl: "../../dojo/"
|
||
|
};
|
||
|
|
||
|
load('../../dojo/dojo.js');
|
||
|
|
||
|
//Now set baseUrl so it is current directory, since all the prefixes
|
||
|
//will be relative to the release dir from this directory.
|
||
|
dojo.baseUrl = "./";
|
||
|
|
||
|
//Also be sure we register the right paths for module prefixes.
|
||
|
buildUtil.configPrefixes(kwArgs.profileProperties.dependencies.prefixes);
|
||
|
|
||
|
dojo.require("dojo.i18n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i18nUtil.flattenLayerFileBundles = function(/*String*/fileName, /*String*/fileContents, /*Object*/kwArgs){
|
||
|
//summary:
|
||
|
// This little utility is invoked by the build to flatten all of the JSON resource bundles used
|
||
|
// by dojo.requireLocalization(), much like the main build itself, to optimize so that multiple
|
||
|
// web hits will not be necessary to load these resources. Normally, a request for a particular
|
||
|
// bundle in a locale like "en-us" would result in three web hits: one looking for en_us/ another
|
||
|
// for en/ and another for ROOT/. All of this multiplied by the number of bundles used can result
|
||
|
// in a lot of web hits and latency. This script uses Dojo to actually load the resources into
|
||
|
// memory, then flatten the object and spit it out using dojo.toJson. The bootstrap
|
||
|
// will be modified to download exactly one of these files, whichever is closest to the user's
|
||
|
// locale.
|
||
|
//fileName:
|
||
|
// The name of the file to process (like dojo.js). This function will use
|
||
|
// it to determine the best resource name to give the flattened bundle.
|
||
|
//fileContents:
|
||
|
// The contents of the file to process (like dojo.js). This function will look in
|
||
|
// the contents for dojo.requireLocation() calls.
|
||
|
//kwArgs:
|
||
|
// The build's kwArgs.
|
||
|
|
||
|
var destDirName = fileName.replace(/\/[^\/]+$/, "/") + "nls";
|
||
|
var nlsNamePrefix = fileName.replace(/\.js$/, "");
|
||
|
nlsNamePrefix = nlsNamePrefix.substring(nlsNamePrefix.lastIndexOf("/") + 1, nlsNamePrefix.length);
|
||
|
|
||
|
i18nUtil.setup(kwArgs);
|
||
|
var djLoadedBundles = [];
|
||
|
|
||
|
//TODO: register plain function handler (output source) in jsonRegistry?
|
||
|
var drl = dojo.requireLocalization;
|
||
|
dojo.requireLocalization = function(modulename, bundlename, locale){
|
||
|
drl(modulename, bundlename, locale);
|
||
|
//TODO: avoid dups?
|
||
|
djLoadedBundles.push({modulename: modulename, module: eval(modulename), bundlename: bundlename});
|
||
|
};
|
||
|
|
||
|
var requireStatements = fileContents.match(/dojo\.requireLocalization\(.*\)\;/g);
|
||
|
if(requireStatements){
|
||
|
eval(requireStatements.join(";"));
|
||
|
|
||
|
//print("loaded bundles: "+djLoadedBundles.length);
|
||
|
|
||
|
var djBundlesByLocale = {};
|
||
|
var jsLocale, entry, bundle;
|
||
|
|
||
|
for (var i = 0; i < djLoadedBundles.length; i++){
|
||
|
entry = djLoadedBundles[i];
|
||
|
bundle = entry.module.nls[entry.bundlename];
|
||
|
for (jsLocale in bundle){
|
||
|
if (!djBundlesByLocale[jsLocale]){djBundlesByLocale[jsLocale]=[];}
|
||
|
djBundlesByLocale[jsLocale].push(entry);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
localeList = [];
|
||
|
|
||
|
//Save flattened bundles used by dojo.js.
|
||
|
var mkdir = false;
|
||
|
var dir = new java.io.File(destDirName);
|
||
|
var modulePrefix = buildUtil.mapPathToResourceName(fileName, kwArgs.profileProperties.dependencies.prefixes);
|
||
|
|
||
|
//Adjust modulePrefix to include the nls part before the last segment.
|
||
|
var lastDot = modulePrefix.lastIndexOf(".");
|
||
|
if(lastDot != -1){
|
||
|
modulePrefix = modulePrefix.substring(0, lastDot + 1) + "nls." + modulePrefix.substring(lastDot + 1, modulePrefix.length);
|
||
|
}else{
|
||
|
throw "Invalid module prefix for flattened bundle: " + modulePrefix;
|
||
|
}
|
||
|
|
||
|
for (jsLocale in djBundlesByLocale){
|
||
|
var locale = jsLocale.replace(/\_/g, '-');
|
||
|
if(!mkdir){ dir.mkdir(); mkdir = true; }
|
||
|
|
||
|
var outFile = new java.io.File(dir, nlsNamePrefix + "_" + locale + ".js");
|
||
|
//Make sure we can create the final file.
|
||
|
var parentDir = outFile.getParentFile();
|
||
|
if(!parentDir.exists()){
|
||
|
if(!parentDir.mkdirs()){
|
||
|
throw "Could not create directory: " + parentDir.getAbsolutePath();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var os = new java.io.BufferedWriter(
|
||
|
new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), "utf-8"));
|
||
|
try{
|
||
|
os.write("dojo.provide(\""+modulePrefix+"_"+locale+"\");");
|
||
|
for (var j = 0; j < djLoadedBundles.length; j++){
|
||
|
entry = djLoadedBundles[j];
|
||
|
var bundlePkg = [entry.modulename,"nls",entry.bundlename].join(".");
|
||
|
var translationPkg = [bundlePkg,jsLocale].join(".");
|
||
|
bundle = entry.module.nls[entry.bundlename];
|
||
|
if(bundle[jsLocale]){ //FIXME:redundant check?
|
||
|
os.write("dojo.provide(\""+bundlePkg+"\");");
|
||
|
os.write(bundlePkg+"._built=true;");
|
||
|
os.write("dojo.provide(\""+translationPkg+"\");");
|
||
|
os.write(translationPkg+"="+dojo.toJson(bundle[jsLocale])+";");
|
||
|
}
|
||
|
}
|
||
|
}finally{
|
||
|
os.close();
|
||
|
}
|
||
|
localeList.push(locale);
|
||
|
}
|
||
|
|
||
|
//Remove dojo.requireLocalization calls from the file.
|
||
|
fileContents = fileContents.replace(/dojo\.requireLocalization\(.*\)\;/g, "");
|
||
|
|
||
|
|
||
|
var preloadCall = '\ndojo.i18n._preloadLocalizations("' + modulePrefix + '", ' + dojo.toJson(localeList.sort()) + ');\n';
|
||
|
//Inject the dojo._preloadLocalizations call into the file.
|
||
|
//Do this at the end of the file, since we need to make sure dojo.i18n has been loaded.
|
||
|
//The assumption is that if dojo.i18n is not in this layer file, dojo.i18n is
|
||
|
//in one of the layer files this layer file depends on.
|
||
|
//Allow call to be inserted in the dojo.js closure, if that is in play.
|
||
|
i18nUtil.preloadInsertionRegExp.lastIndex = 0;
|
||
|
if(fileContents.match(i18nUtil.preloadInsertionRegExp)){
|
||
|
i18nUtil.preloadInsertionRegExp.lastIndex = 0;
|
||
|
fileContents = fileContents.replace(i18nUtil.preloadInsertionRegExp, preloadCall);
|
||
|
}else{
|
||
|
fileContents += preloadCall;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fileContents; //String
|
||
|
}
|
||
|
|
||
|
i18nUtil.preloadInsertionRegExp = /\/\/INSERT dojo.i18n._preloadLocalizations HERE/;
|
||
|
|
||
|
i18nUtil.flattenDirBundles = function(/*String*/prefixName, /*String*/prefixDir, /*Object*/kwArgs, /*RegExp*/nlsIgnoreRegExp){
|
||
|
//summary: Flattens the i18n bundles inside a directory so that only request
|
||
|
//is needed per bundle. Does not handle resource flattening for dojo.js or
|
||
|
//layered build files.
|
||
|
|
||
|
i18nUtil.setup(kwArgs);
|
||
|
var fileList = fileUtil.getFilteredFileList(prefixDir, /\.js$/, true);
|
||
|
var prefixes = kwArgs.profileProperties.dependencies.prefixes;
|
||
|
for(var i= 0; i < fileList.length; i++){
|
||
|
//Use new String so we get a JS string and not a Java string.
|
||
|
var jsFileName = String(fileList[i]);
|
||
|
var fileContents = null;
|
||
|
|
||
|
//Files in nls directories, except for layer bundles that already have been processed.
|
||
|
if(jsFileName.match(/\/nls\//) && !jsFileName.match(nlsIgnoreRegExp)){
|
||
|
fileContents = "(" + i18nUtil.makeFlatBundleContents(prefixName, prefixDir, jsFileName) + ")";
|
||
|
}else{
|
||
|
fileContents = i18nUtil.modifyRequireLocalization(readText(jsFileName), prefixes);
|
||
|
}
|
||
|
|
||
|
if(fileContents){
|
||
|
fileUtil.saveUtf8File(jsFileName, fileContents);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i18nUtil.modifyRequireLocalization = function(/*String*/fileContents, /*Array*/prefixes){
|
||
|
//summary: Modifies any dojo.requireLocalization calls in the fileContents to have the
|
||
|
//list of supported locales as part of the call. This allows the i18n loading functions
|
||
|
//to only make request(s) for locales that actually exist on disk.
|
||
|
var dependencies = [];
|
||
|
|
||
|
//Make sure we have a JS string, and not a Java string.
|
||
|
fileContents = String(fileContents);
|
||
|
|
||
|
var modifiedContents = fileContents;
|
||
|
|
||
|
if(fileContents.match(buildUtil.globalRequireLocalizationRegExp)){
|
||
|
modifiedContents = fileContents.replace(buildUtil.globalRequireLocalizationRegExp, function(matchString){
|
||
|
var replacement = matchString;
|
||
|
var partMatches = matchString.match(buildUtil.requireLocalizationRegExp);
|
||
|
var depCall = partMatches[1];
|
||
|
var depArgs = partMatches[2];
|
||
|
|
||
|
if(depCall == "requireLocalization"){
|
||
|
//Need to find out what locales are available so the dojo loader
|
||
|
//only has to do one script request for the closest matching locale.
|
||
|
var reqArgs = i18nUtil.getRequireLocalizationArgsFromString(depArgs);
|
||
|
if(reqArgs.moduleName){
|
||
|
//Find the list of locales supported by looking at the path names.
|
||
|
var locales = i18nUtil.getLocalesForBundle(reqArgs.moduleName, reqArgs.bundleName, prefixes);
|
||
|
|
||
|
//Add the supported locales to the requireLocalization arguments.
|
||
|
if(!reqArgs.localeName){
|
||
|
depArgs += ", null";
|
||
|
}
|
||
|
|
||
|
depArgs += ', "' + locales.join(",") + '"';
|
||
|
|
||
|
replacement = "dojo." + depCall + "(" + depArgs + ")";
|
||
|
}
|
||
|
}
|
||
|
return replacement;
|
||
|
});
|
||
|
}
|
||
|
return modifiedContents;
|
||
|
}
|
||
|
|
||
|
i18nUtil.makeFlatBundleContents = function(prefix, prefixPath, srcFileName){
|
||
|
//summary: Given a nls file name, flatten the bundles from parent locales into the nls bundle.
|
||
|
var bundleParts = i18nUtil.getBundlePartsFromFileName(prefix, prefixPath, srcFileName);
|
||
|
if(!bundleParts){
|
||
|
return null;
|
||
|
}
|
||
|
var moduleName = bundleParts.moduleName;
|
||
|
var bundleName = bundleParts.bundleName;
|
||
|
var localeName = bundleParts.localeName;
|
||
|
|
||
|
dojo.requireLocalization(moduleName, bundleName, localeName);
|
||
|
|
||
|
//Get the generated, flattened bundle.
|
||
|
var module = dojo.getObject(moduleName);
|
||
|
var bundleLocale = localeName ? localeName.replace(/-/g, "_") : "ROOT";
|
||
|
var flattenedBundle = module.nls[bundleName][bundleLocale];
|
||
|
|
||
|
if(!flattenedBundle){
|
||
|
throw "Cannot create flattened bundle for src file: " + srcFileName;
|
||
|
}
|
||
|
|
||
|
return dojo.toJson(flattenedBundle);
|
||
|
}
|
||
|
|
||
|
//Given a module and bundle name, find all the supported locales.
|
||
|
i18nUtil.getLocalesForBundle = function(moduleName, bundleName, prefixes){
|
||
|
//Build a path to the bundle directory and ask for all files that match
|
||
|
//the bundle name.
|
||
|
var filePath = buildUtil.mapResourceToPath(moduleName, prefixes);
|
||
|
|
||
|
var bundleRegExp = new RegExp("nls[/]?([\\w\\-]*)/" + bundleName + ".js$");
|
||
|
var bundleFiles = fileUtil.getFilteredFileList(filePath + "nls/", bundleRegExp, true);
|
||
|
|
||
|
//Find the list of locales supported by looking at the path names.
|
||
|
var locales = [];
|
||
|
for(var j = 0; j < bundleFiles.length; j++){
|
||
|
var bundleParts = bundleFiles[j].match(bundleRegExp);
|
||
|
if(bundleParts && bundleParts[1]){
|
||
|
locales.push(bundleParts[1]);
|
||
|
}else{
|
||
|
locales.push("ROOT");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return locales.sort();
|
||
|
}
|
||
|
|
||
|
i18nUtil.getRequireLocalizationArgsFromString = function(argString){
|
||
|
//summary: Given a string of the arguments to a dojo.requireLocalization
|
||
|
//call, separate the string into individual arguments.
|
||
|
var argResult = {
|
||
|
moduleName: null,
|
||
|
bundleName: null,
|
||
|
localeName: null
|
||
|
};
|
||
|
|
||
|
var l10nMatches = argString.split(/\,\s*/);
|
||
|
if(l10nMatches && l10nMatches.length > 1){
|
||
|
argResult.moduleName = l10nMatches[0] ? l10nMatches[0].replace(/\"/g, "") : null;
|
||
|
argResult.bundleName = l10nMatches[1] ? l10nMatches[1].replace(/\"/g, "") : null;
|
||
|
argResult.localeName = l10nMatches[2];
|
||
|
}
|
||
|
return argResult;
|
||
|
}
|
||
|
|
||
|
i18nUtil.getBundlePartsFromFileName = function(prefix, prefixPath, srcFileName){
|
||
|
//Pull off any ../ values from prefix path to make matching easier.
|
||
|
var prefixPath = prefixPath.replace(/\.\.\//g, "");
|
||
|
|
||
|
//Strip off the prefix path so we can find the real resource and bundle names.
|
||
|
var prefixStartIndex = srcFileName.lastIndexOf(prefixPath);
|
||
|
if(prefixStartIndex != -1){
|
||
|
var startIndex = prefixStartIndex + prefixPath.length;
|
||
|
|
||
|
//Need to add one if the prefiPath does not include an ending /. Otherwise,
|
||
|
//We'll get extra dots in our bundleName.
|
||
|
if(prefixPath.charAt(prefixPath.length) != "/"){
|
||
|
startIndex += 1;
|
||
|
}
|
||
|
srcFileName = srcFileName.substring(startIndex, srcFileName.length);
|
||
|
}
|
||
|
|
||
|
//var srcIndex = srcFileName.indexOf("src/");
|
||
|
//srcFileName = srcFileName.substring(srcIndex + 4, srcFileName.length);
|
||
|
var parts = srcFileName.split("/");
|
||
|
|
||
|
//Split up the srcFileName into arguments that can be used for dojo.requireLocalization()
|
||
|
var moduleParts = [prefix];
|
||
|
for(var i = 0; parts[i] != "nls"; i++){
|
||
|
moduleParts.push(parts[i]);
|
||
|
}
|
||
|
var moduleName = moduleParts.join(".");
|
||
|
if(parts[i+1].match(/\.js$/)){
|
||
|
var localeName = "";
|
||
|
var bundleName = parts[i+1];
|
||
|
}else{
|
||
|
var localeName = parts[i+1];
|
||
|
var bundleName = parts[i+2];
|
||
|
}
|
||
|
|
||
|
if(!bundleName || bundleName.indexOf(".js") == -1){
|
||
|
//Not a valid bundle. Could be something like a README file.
|
||
|
return null;
|
||
|
}else{
|
||
|
bundleName = bundleName.replace(/\.js/, "");
|
||
|
}
|
||
|
|
||
|
return {moduleName: moduleName, bundleName: bundleName, localeName: localeName};
|
||
|
}
|