text: 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) + ');\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;
  }
  
  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};
  }
  