blob: d34df6580760fe527565ebecf7caec5ec4c61d3b [file] [log] [blame]
#!/usr/bin/node
// Load required modules
var fs = require('fs');
var path = require('path');
// Use localize for internal localizations
var localize = new require('localize')(__dirname);
localize.throwOnMissingTranslation(false);
var translate = localize.translate;
// Defaults for ``xlocalize``
var defaultLang = "en";
var recurse = true;
var extensions = ['html', 'js'];
var outLangs = [];
// Load arguments
for(var i = 0; i < process.argv.length; i++) {
switch(process.argv[i]) {
case "-l":
defaultLang = process.argv[i+1];
break;
case "-r":
recurse = true;
break;
case "-R":
recurse = false;
break;
case "-e":
extensions = process.argv[i+1].split(",");
break;
case "-t":
outLangs = process.argv[i+1].split(",");
break;
case "-h":
case "--help":
console.log("xlocalize USAGE:\n");
console.log("-l\tSet the default language for the translations.json file(s) (default: en)");
console.log("-r\tSet xlocalize to generate translations.json files recursively (default)");
console.log("-R\tSet xlocalize to only generate a translations.json file for the current directory");
console.log("-e\tSet the file extensions to include for translation (default: html,js)");
console.log("-t\tSet the languages to translate to (comma separated)");
console.log("-h\tShow this help message.");
process.exit();
default:
break;
}
}
// Set internal localize object to use the user's default language
localize.setLocale(defaultLang);
// ## The *mergeObjs* function
// is a helper function that clones the value of various object into a new one.
// This simplistic one is fast, but assumes no recursive objects to merge.
function mergeObjs() {
var outObj = {};
for(var i in arguments) {
if(arguments[i] instanceof Object) {
for(var j in arguments[i]) {
// Does not check for collisions, newer object
// definitions clobber old definitions
outObj[j] = arguments[i][j];
}
}
}
return outObj;
}
// ## The *processDir* function
// generates a ``translations.json`` file for the current directory, but does
// not override the previous file -- only augments it
function processDir(dir) {
// JSON object for the current directory
var dirJSON = {};
// Path where translations will go
var translations = path.join(dir, "translations.json");
// Check for pre-existing ``translations.json`` file
if(path.existsSync(translations)) {
var currJSON = JSON.parse(fs.readFileSync(translations, "utf8"));
dirJSON = mergeObjs(dirJSON, currJSON);
}
// Build pattern matching for searchable files
var extRegExpStr = "(";
for(var i = 0; i < extensions.length; i++) {
extRegExpStr += extensions[i];
if(i < extensions.length-1) { extRegExpStr += "|"; }
else { extRegExpStr += ")$"; }
}
var extRegExp = new RegExp(extRegExpStr);
// Process files in the current directory
var files = fs.readdirSync(dir);
files.forEach(function(file) {
if(extRegExp.test(file)) {
processFile(path.join(dir, file), dirJSON);
}
if(recurse && fs.statSync(path.join(dir, file)).isDirectory()) {
processDir(path.join(dir, file));
}
});
// Output dirJSON to file
fs.writeFileSync(translations, JSON.stringify(dirJSON, null, " "), "utf8");
}
// ## The *processFile* function
// extracts all translatable pieces of a source file into the dirJSON object,
// unless already there.
function processFile(filename, dirJSON) {
// Hacky, hacky RegExp parsing right now; replace with something better
var fileContents = fs.readFileSync(filename, "utf8");
var translatables = fileContents.match(/translate\s*\([^\),]*/);
if(translatables) {
for(var i = 0; i < translatables.length; i++) {
if(/^translate\s*\(\s*['"](.*)['"]$/.test(translatables[i])) { // A string-looking thing
if(!dirJSON[RegExp.$1]) { // Does not yet exist
dirJSON[RegExp.$1] = {};
}
outLangs.forEach(function(lang) {
if(!dirJSON[RegExp.$1][lang]) { // No translation, yet
dirJSON[RegExp.$1][lang] = translate("MISSING TRANSLATION");
}
});
} else {
var translateMessage = translate("FOUND VARIABLE INPUT: $[1]", translatables[i]);
dirJSON[translateMessage] = {};
outLangs.forEach(function(lang) {
dirJSON[translateMessage][lang] = translate("MISSING TRANSLATION");
});
}
}
}
}
// Get the ball rollin'
processDir(process.cwd());