granula
Version:
i18n tool for angular.js applications
195 lines (176 loc) • 7.08 kB
JavaScript
(function() {
var SETTINGS_TEMPLATE, appliableOptions, fs, granula, htmlDocument, merge, merger, parseOptions, path, processHtmlFile, processor, wrench, writeSettings, _, _try;
_ = require('underscore');
granula = require('../granula/granula');
processor = require('./processor');
htmlDocument = require('./documents').htmlDocument;
fs = require('fs');
wrench = require('wrench');
merger = require('./merger');
path = require('path');
SETTINGS_TEMPLATE = "angular.module('granula').config([\"grServiceProvider\", function(grServiceProvider) {\n grServiceProvider.config(__OPTIONS__);\n}]);";
module.exports = {
/*
# options =
# src: string = '.' - directory to scan
# fileTypes: comma-separated string - which files to process ('html', 'js')
# out: string = './lang' - where to search/store language files
# languages: comma-separated tring - language files to create
# mapping:
# onlyMarked: boolean = true - if true then only elements marked with gr-key will be processed
# textAsKey: string = "nokey" - "always" - key is obtained from gr-key, error if empty.
# "never" - key is always obtained from text
# "nokey" - key obtains from gr-key if presents, from text otherwise
# wordsLimitForKey: int = 10 - how many first words will be taken for key
# replaceSpaces: false or string = false - shall spaces be replaced or not
# attrsToTranslate: comma-separated string - which attributes shall be translated. "title,alt,placeholder" by default
# generateSettingsFile: false or file name - generate file with these settings under 'out' directory
# translateMe: string - symbol or string to use as suffix for non-translated strings
*/
processFiles: function(options, cb) {
var processingResult,
_this = this;
options = parseOptions(options);
processingResult = {};
return wrench.readdirRecursive(options.src, function(error, files) {
var htmlFiles;
if (error) {
return cb(error);
}
if ((error === files && files === null)) {
return merge(options, processingResult, cb);
}
htmlFiles = files.filter(function(f) {
return f.toLowerCase().slice(-5) === '.html';
});
return htmlFiles.forEach(function(file) {
console.log("Processing " + file);
return processHtmlFile(processingResult, path.join(options.src, file), options);
});
});
}
};
_try = function(action) {
return {
"catch": function(react) {
var e;
try {
return action();
} catch (_error) {
e = _error;
return react();
}
}
};
};
merge = function(options, _arg, cb) {
var errors, lang, warnings,
_this = this;
errors = _arg.errors, warnings = _arg.warnings, lang = _arg.lang;
if (errors.length > 0) {
errors.forEach(function(e) {
return console.error("Error: " + e);
});
return cb("Processing interrupted due to errors");
}
warnings.forEach(function(w) {
return console.info(" -- Warning: " + w);
});
options.languages.forEach(function(language) {
var langFilePath, newJson, oldJson;
langFilePath = path.join(options.out, language + '.json');
oldJson = _try(function() {
return JSON.parse(fs.readFileSync(langFilePath));
})["catch"](function() {
return {};
});
newJson = merger.merge(oldJson, lang, options.mapping);
fs.writeFileSync(langFilePath, JSON.stringify(newJson, null, 4));
return console.log("Created " + langFilePath);
});
return writeSettings(options, lang, cb);
};
writeSettings = function(options, lang, cb) {
var settings, settingsFilePath;
if (options.mapping.generateSettingsFile) {
settingsFilePath = path.join(options.out, options.mapping.generateSettingsFile);
settings = SETTINGS_TEMPLATE.replace(/__OPTIONS__/, JSON.stringify(appliableOptions(options.mapping)));
fs.writeFileSync(settingsFilePath, settings);
console.log("Created " + settingsFilePath);
}
return cb(null);
};
appliableOptions = function(options) {
return _.pick(options, "textAsKey", "wordsLimitForKey", "replaceSpaces", "translateMe");
};
parseOptions = function(options) {
var csToList, mapping, validateEnum, validateInteger, _ref;
mapping = (_ref = options.mapping) != null ? _ref : {};
delete options.mapping;
options = _.defaults(options, {
src: '.',
fileTypes: 'html',
out: './lang',
languages: ""
});
options.mapping = _.defaults(mapping, {
onlyMarked: true,
textAsKey: "nokey",
wordsLimitForKey: 10,
replaceSpaces: false,
generateSettingsFile: "settings.js",
attrsToTranslate: "title,alt,placeholder",
translateMe: "✍ "
});
csToList = function(str) {
if (_.isEmpty(str)) {
return [];
}
return str.split(',');
};
options.fileTypes = csToList(options.fileTypes);
options.languages = csToList(options.languages);
options.mapping.attrsToTranslate = csToList(options.mapping.attrsToTranslate);
validateEnum = function(name, value, possible) {
if (_.isArray(value)) {
if (_.difference(value, possible).length > 0) {
throw new Error("Option '" + name + "' shall contain only following values: " + (possible.join(', ')));
}
} else {
if (_.indexOf(possible, value) === -1) {
throw new Error("Option '" + name + "' shall be one of the following values: " + (possible.join(', ')));
}
}
};
validateInteger = function(name, value) {
if (_.isNaN(parseInt(value))) {
throw new Error("Option '" + name + "' shall be number ");
}
};
validateEnum("fileTypes", options.fileTypes, ["html"]);
validateEnum("onlyMarked", options.mapping.onlyMarked, [true, false]);
validateEnum("textAsKey", options.mapping.textAsKey, ["nokey", "always", "never"]);
validateInteger("wordsLimitForKey", options.mapping.wordsLimitForKey);
if (options.languages.length === 0) {
throw new Error("At least one language shall be provided");
}
return options;
};
processHtmlFile = function(outputStruct, filePath, options) {
var htmlText, _ref;
htmlText = fs.readFileSync(filePath, (_ref = options.encoding) != null ? _ref : "utf-8");
outputStruct = _.defaults(outputStruct, {
lang: {},
errors: [],
warnings: []
});
return processor().processHtml(outputStruct.lang, htmlDocument(htmlText), options.mapping, {
addError: function(e) {
return outputStruct.errors.push(e);
},
addWarning: function(w) {
return outputStruct.warnings.push(w);
}
});
};
}).call(this);