translator
Version:
[ABANDONED] Translator for node and also for browser
481 lines (438 loc) • 15.4 kB
JavaScript
// Generated by CoffeeScript 1.6.3
(function() {
var Args, Cache, JsonLoader, Loader, Storage, Translator, callsite, isBrowser, path, pluralForms;
Cache = require('cache-storage');
Storage = require('cache-storage/lib/Storage/Storage');
Args = require('normalize-arguments');
path = require('./node/path');
pluralForms = require('./pluralForms');
Loader = require('./Loaders/Loader');
JsonLoader = require('./Loaders/Json');
isBrowser = typeof window !== 'undefined';
if (!isBrowser) {
callsite = require('callsite');
}
Translator = (function() {
Translator.prototype.loader = null;
Translator.prototype.language = null;
Translator.prototype.plurals = null;
Translator.prototype.replacements = null;
Translator.prototype.filters = null;
Translator.prototype.data = null;
Translator.prototype.cache = null;
function Translator(pathOrLoader) {
var config, data, language, stack, _config;
this.plurals = {};
this.replacements = {};
this.filters = [];
this.data = {};
if (!pathOrLoader) {
throw new Error('You have to set path to base directory or to config file or loader.');
}
if (typeof pathOrLoader === 'string') {
if (pathOrLoader.charAt(0) === '.' && isBrowser) {
throw new Error('Relative paths to dictionaries is not supported in browser.');
}
if (pathOrLoader.charAt(0) === '.') {
stack = callsite();
pathOrLoader = path.join(path.dirname(stack[1].getFileName()), pathOrLoader);
}
pathOrLoader = path.normalize(pathOrLoader);
config = {
path: pathOrLoader,
loader: 'Json'
};
if (pathOrLoader.match(/\.json$/) !== null) {
_config = require(pathOrLoader);
if (typeof _config.path !== 'undefined') {
config.path = _config.path;
}
if (typeof _config.loader !== 'undefined') {
config.loader = _config.loader;
}
if (config.path.charAt(0) === '.') {
config.path = path.join(path.dirname(pathOrLoader), config.path);
}
}
pathOrLoader = new (require('./Loaders/' + config.loader))(config.path);
}
this.setLoader(pathOrLoader);
for (language in pluralForms) {
data = pluralForms[language];
this.addPluralForm(language, data.count, data.form);
}
}
Translator.prototype.expand = function(main) {
var _this = this;
if (main == null) {
main = null;
}
if (main === null) {
main = isBrowser ? window : global;
}
main._ = function() {
return _this.translate.apply(_this, arguments);
};
main._m = function() {
return _this.translateMap.apply(_this, arguments);
};
main._p = function() {
return _this.translatePairs.apply(_this, arguments);
};
return main;
};
Translator.prototype.setLoader = function(loader) {
if (!(loader instanceof Loader)) {
throw new Error('Loader must be an instance of translator/Loaders/Loader.');
}
return this.loader = loader;
};
Translator.prototype.invalidate = function() {
return this.data = {};
};
Translator.prototype.setCacheStorage = function(cacheStorage) {
if (!cacheStorage instanceof Storage) {
throw new Error('Cache storage must be an instance of cache-storage/Storage/Storage.');
}
return this.cache = new Cache(cacheStorage, 'translator');
};
Translator.prototype.addPluralForm = function(language, count, form) {
this.plurals[language] = {
count: count,
form: form
};
return this;
};
Translator.prototype.addReplacement = function(search, replacement) {
this.replacements[search] = replacement;
return this;
};
Translator.prototype.removeReplacement = function(search) {
if (typeof this.replacements[search] === 'undefined') {
throw new Error('Replacement ' + search + ' was not found.');
}
delete this.replacements[search];
return this;
};
Translator.prototype.addFilter = function(fn) {
this.filters.push(fn);
return this;
};
Translator.prototype.applyFilters = function(translation) {
var filter, i, t, _i, _j, _len, _len1, _ref;
if (Object.prototype.toString.call(translation) === '[object Array]') {
for (i = _i = 0, _len = translation.length; _i < _len; i = ++_i) {
t = translation[i];
translation[i] = this.applyFilters(t);
}
return translation;
}
_ref = this.filters;
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
filter = _ref[_j];
translation = filter(translation);
}
return translation;
};
Translator.prototype.loadCategory = function(_path, name, language) {
var categoryName, conds, data, file;
if (language == null) {
language = this.language;
}
categoryName = _path + '/' + name;
if (typeof this.data[categoryName] === 'undefined') {
if (this.cache === null) {
data = this.loader.load(_path, name, language);
data = this.normalizeTranslations(data);
} else {
data = this.cache.load(language + ':' + categoryName);
if (data === null) {
data = this.loader.load(_path, name, language);
data = this.normalizeTranslations(data);
conds = {};
if (typeof window === 'undefined' || (typeof window !== 'undefined' && window.require.simq === true && typeof window.require.version !== 'undefined' && parseInt(window.require.version.replace(/\./g, '')) >= 510)) {
_path = this.loader.getFileSystemPath(_path, name, language);
if (_path !== null) {
conds.files = [_path];
}
}
this.cache.save(language + ':' + categoryName, data, conds);
} else {
file = this.loader.load(_path, name, language);
data = this.normalizeTranslations(file);
}
}
this.data[categoryName] = data;
}
return this.data[categoryName];
};
Translator.prototype.normalizeTranslations = function(translations) {
var buf, list, match, name, result, sub, t, translation, _i, _j, _len, _len1;
result = {};
for (name in translations) {
translation = translations[name];
list = false;
if ((match = name.match(/^--\s(.*)/)) !== null) {
name = match[1];
list = true;
}
if (typeof translation === 'string') {
result[name] = [translation];
} else if (Object.prototype.toString.call(translation) === '[object Array]') {
result[name] = [];
for (_i = 0, _len = translation.length; _i < _len; _i++) {
t = translation[_i];
if (typeof t === 'object') {
buf = [];
for (_j = 0, _len1 = t.length; _j < _len1; _j++) {
sub = t[_j];
if (/^\#.*\#$/.test(sub) === false) {
buf.push(sub);
}
}
result[name].push(buf);
} else {
if (/^\#.*\#$/.test(t) === false) {
if (list === true && typeof t !== 'object') {
t = [t];
}
result[name].push(t);
}
}
}
}
}
return result;
};
Translator.prototype.hasTranslation = function(message, language) {
if (language == null) {
language = this.language;
}
return this.findTranslation(message, language) !== null;
};
Translator.prototype.findTranslation = function(message, language) {
var data, info;
if (language == null) {
language = this.language;
}
info = this.getMessageInfo(message);
data = this.loadCategory(info.path, info.category, language);
if (typeof data[info.name] === 'undefined') {
return null;
} else {
return data[info.name];
}
};
Translator.prototype.translate = function(message, count, args) {
var found, language, match, num, params, translation;
if (count == null) {
count = null;
}
if (args == null) {
args = {};
}
params = Args(arguments, [Args.any, Args.number(null), Args.object({})]);
message = params[0];
count = params[1];
args = params[2];
language = this.language;
found = false;
if (typeof message !== 'string') {
return message;
}
if (count !== null) {
args.count = count;
}
if ((match = message.match(/^\:(.*)\:$/)) !== null) {
message = match[1];
if ((match = message.match(/^[a-z]+\|(.*)$/)) !== null) {
message = match[1];
}
} else {
if ((match = message.match(/^([a-z]+)\|(.*)$/)) !== null) {
language = match[1];
message = match[2];
}
if (language === null) {
throw new Error('You have to set language.');
}
num = null;
if ((match = message.match(/(.+)\[(\d+)\]$/)) !== null) {
message = match[1];
num = parseInt(match[2]);
}
message = this.applyReplacements(message, args);
translation = this.findTranslation(message, language);
found = this.hasTranslation(message, language);
if (num !== null) {
if (!this.isList(translation)) {
throw new Error('Translation ' + message + ' is not a list.');
}
if (typeof translation[num] === 'undefined') {
throw new Error('Item ' + num + ' was not found in ' + message + ' translation.');
}
translation = translation[num];
}
if (translation !== null) {
message = this.pluralize(message, translation, count, language);
}
}
message = this.prepareTranslation(message, args);
if (found) {
message = this.applyFilters(message);
}
return message;
};
Translator.prototype.translatePairs = function(message, key, value, count, args) {
var i, k, result, _i, _len;
if (count == null) {
count = null;
}
if (args == null) {
args = {};
}
key = "" + message + "." + key;
value = "" + message + "." + value;
key = this.translate(key, count, args);
value = this.translate(value, count, args);
if (Object.prototype.toString.call(key) !== '[object Array]' || Object.prototype.toString.call(value) !== '[object Array]') {
throw new Error('Translations are not arrays.');
}
if (key.length !== value.length) {
throw new Error('Keys and values translations have not got the same length.');
}
result = {};
for (i = _i = 0, _len = key.length; _i < _len; i = ++_i) {
k = key[i];
result[k] = value[i];
}
return result;
};
Translator.prototype.translateMap = function(list, count, args, base) {
var i, k, m, params, type, _i, _len;
if (count == null) {
count = null;
}
if (args == null) {
args = {};
}
if (base == null) {
base = null;
}
type = Object.prototype.toString.call(list);
if (type !== '[object Array]' && type !== '[object Object]') {
throw new Error('Translate map is only for arrays and objects.');
}
params = Args(arguments, [Args.oneOf([Args.array, Args.object]), Args.number(null), Args.object({}), Args.string(null)]);
list = params[0];
count = params[1];
args = params[2];
base = params[3];
base = base !== null ? base + '.' : '';
if (type === '[object Array]') {
for (i = _i = 0, _len = list.length; _i < _len; i = ++_i) {
m = list[i];
list[i] = this.translate(base + m, count, args);
}
} else {
for (k in list) {
m = list[k];
list[k] = this.translate(base + m, count, args);
}
}
return list;
};
Translator.prototype.isList = function(translation) {
return Object.prototype.toString.call(translation[0]) === '[object Array]';
};
Translator.prototype.pluralize = function(message, translation, count, language) {
var n, plural, pluralForm, result, t, _i, _j, _len, _len1;
if (count == null) {
count = null;
}
if (language == null) {
language = this.language;
}
if (count !== null) {
if (typeof translation[0] === 'string') {
pluralForm = 'n=' + count + ';plural=+(' + this.plurals[language].form + ');';
n = null;
plural = null;
eval(pluralForm);
message = plural !== null && typeof translation[plural] !== 'undefined' ? translation[plural] : translation[0];
} else {
result = [];
for (_i = 0, _len = translation.length; _i < _len; _i++) {
t = translation[_i];
result.push(this.pluralize(message, t, count, language));
}
message = result;
}
} else {
if (typeof translation[0] === 'string') {
message = translation[0];
} else {
message = [];
for (_j = 0, _len1 = translation.length; _j < _len1; _j++) {
t = translation[_j];
message.push(t[0]);
}
}
}
return message;
};
Translator.prototype.prepareTranslation = function(message, args) {
var m, result, _i, _len;
if (args == null) {
args = {};
}
if (typeof message === 'string') {
message = this.applyReplacements(message, args);
} else {
result = [];
for (_i = 0, _len = message.length; _i < _len; _i++) {
m = message[_i];
result.push(this.prepareTranslation(m, args));
}
message = result;
}
return message;
};
Translator.prototype.applyReplacements = function(message, args) {
var name, pattern, replacements, value;
if (args == null) {
args = {};
}
replacements = this.replacements;
for (name in args) {
value = args[name];
replacements[name] = value;
}
for (name in replacements) {
value = replacements[name];
if (value !== false) {
pattern = new RegExp('%' + name + '%', 'g');
message = message.replace(pattern, value);
}
}
return message;
};
Translator.prototype.getMessageInfo = function(message) {
var category, name, num, result, _path;
num = message.lastIndexOf('.');
_path = message.substr(0, num);
name = message.substr(num + 1);
num = _path.lastIndexOf('.');
category = _path.substr(num + 1);
_path = _path.substr(0, num).replace(/\./g, '/');
result = {
path: _path,
category: category,
name: name
};
return result;
};
return Translator;
})();
module.exports = Translator;
}).call(this);