You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
8.3 KiB
JavaScript
310 lines
8.3 KiB
JavaScript
10 years ago
|
;(function(translator) {
|
||
12 years ago
|
"use strict";
|
||
10 years ago
|
/* globals RELATIVE_PATH, config, define */
|
||
12 years ago
|
|
||
10 years ago
|
// export the class if we are in a Node-like system.
|
||
|
if (typeof module === 'object' && module.exports === translator) {
|
||
|
exports = module.exports = translator;
|
||
|
}
|
||
12 years ago
|
|
||
10 years ago
|
var languages = {},
|
||
|
regexes = {
|
||
|
match: /\[\[.*?\]\]/g,
|
||
|
split: /[,][\s]*/,
|
||
|
replace: /\]+$/
|
||
|
};
|
||
12 years ago
|
|
||
11 years ago
|
translator.addTranslation = function(language, filename, translations) {
|
||
|
languages[language] = languages[language] || {};
|
||
|
languages[language].loaded = languages[language].loaded || {};
|
||
|
languages[language].loaded[filename] = translations;
|
||
11 years ago
|
languages[language].loading = languages[language].loading || {};
|
||
11 years ago
|
};
|
||
|
|
||
10 years ago
|
translator.getTranslations = function(language, filename, callback) {
|
||
|
if (languages[language] && languages[language].loaded[filename]) {
|
||
|
callback(languages[language].loaded[filename]);
|
||
|
} else {
|
||
|
translator.load(language, filename, function() {
|
||
|
callback(languages[language].loaded[filename]);
|
||
|
});
|
||
|
}
|
||
10 years ago
|
};
|
||
|
|
||
|
translator.escape = function(text) {
|
||
10 years ago
|
return typeof text === 'string' ? text.replace(/\[\[([\S]*?)\]\]/g, '\\[\\[$1\\]\\]') : text;
|
||
10 years ago
|
};
|
||
10 years ago
|
|
||
10 years ago
|
translator.unescape = function(text) {
|
||
10 years ago
|
return typeof text === 'string' ? text.replace(/\\\[\\\[([\S]*?)\\\]\\\]/g, '[[$1]]') : text;
|
||
10 years ago
|
};
|
||
|
|
||
11 years ago
|
translator.getLanguage = function() {
|
||
11 years ago
|
return config.defaultLang;
|
||
11 years ago
|
};
|
||
|
|
||
11 years ago
|
translator.prepareDOM = function() {
|
||
|
// Load the appropriate timeago locale file
|
||
11 years ago
|
if (config.userLang !== 'en_GB' && config.userLang !== 'en_US') {
|
||
11 years ago
|
// Correct NodeBB language codes to timeago codes, if necessary
|
||
|
var languageCode;
|
||
11 years ago
|
switch(config.userLang) {
|
||
11 years ago
|
case 'cs':
|
||
|
languageCode = 'cz';
|
||
|
break;
|
||
11 years ago
|
|
||
11 years ago
|
case 'fa_IR':
|
||
|
languageCode = 'fa';
|
||
|
break;
|
||
11 years ago
|
|
||
11 years ago
|
case 'pt_BR':
|
||
|
languageCode = 'pt-br';
|
||
|
break;
|
||
10 years ago
|
|
||
10 years ago
|
case 'nb':
|
||
|
languageCode = 'no';
|
||
|
break;
|
||
11 years ago
|
|
||
11 years ago
|
case 'zh_TW':
|
||
|
languageCode = 'zh-TW';
|
||
|
break;
|
||
11 years ago
|
|
||
11 years ago
|
case 'zh_CN':
|
||
|
languageCode = 'zh-CN';
|
||
|
break;
|
||
|
|
||
|
default:
|
||
11 years ago
|
languageCode = config.userLang;
|
||
11 years ago
|
break;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
$.getScript(RELATIVE_PATH + '/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '.js').success(function() {
|
||
10 years ago
|
$('.timeago').timeago();
|
||
11 years ago
|
}).fail(function() {
|
||
11 years ago
|
$.getScript(RELATIVE_PATH + '/vendor/jquery/timeago/locales/jquery.timeago.en.js');
|
||
|
});
|
||
11 years ago
|
|
||
|
// Add directional code if necessary
|
||
11 years ago
|
translator.translate('[[language:dir]]', function(value) {
|
||
11 years ago
|
if (value) {
|
||
11 years ago
|
$('html').css('direction', value).attr('data-dir', value);
|
||
11 years ago
|
}
|
||
|
});
|
||
11 years ago
|
}
|
||
11 years ago
|
};
|
||
11 years ago
|
|
||
10 years ago
|
translator.toggleTimeagoShorthand = function() {
|
||
|
if (!translator.timeagoStrings) {
|
||
|
translator.timeagoStrings = $.extend({}, jQuery.timeago.settings.strings);
|
||
|
jQuery.timeago.settings.strings = {
|
||
|
prefixAgo: null,
|
||
|
prefixFromNow: null,
|
||
|
suffixAgo: "",
|
||
|
suffixFromNow: "",
|
||
|
seconds: "1m",
|
||
|
minute: "1m",
|
||
|
minutes: "%dm",
|
||
|
hour: "1h",
|
||
|
hours: "%dh",
|
||
|
day: "1d",
|
||
|
days: "%dd",
|
||
|
month: "1mo",
|
||
|
months: "%dmo",
|
||
|
year: "1yr",
|
||
|
years: "%dyr",
|
||
|
wordSeparator: " ",
|
||
|
numbers: []
|
||
|
};
|
||
|
} else {
|
||
|
jQuery.timeago.settings.strings = $.extend({}, translator.timeagoStrings);
|
||
|
delete translator.timeagoStrings;
|
||
|
}
|
||
|
};
|
||
|
|
||
10 years ago
|
translator.translate = function (text, language, callback) {
|
||
11 years ago
|
if (typeof language === 'function') {
|
||
|
callback = language;
|
||
|
if ('undefined' !== typeof window && config) {
|
||
11 years ago
|
language = config.userLang || 'en_GB';
|
||
11 years ago
|
} else {
|
||
10 years ago
|
var meta = require('../../../src/meta');
|
||
11 years ago
|
language = meta.config.defaultLang || 'en_GB';
|
||
|
}
|
||
|
}
|
||
|
|
||
10 years ago
|
if (!text) {
|
||
|
return callback(text);
|
||
11 years ago
|
}
|
||
|
|
||
10 years ago
|
var keys = text.match(regexes.match);
|
||
11 years ago
|
|
||
11 years ago
|
if (!keys) {
|
||
10 years ago
|
return callback(text);
|
||
11 years ago
|
}
|
||
12 years ago
|
|
||
10 years ago
|
translateKeys(keys, text, language, callback);
|
||
|
};
|
||
|
|
||
|
function translateKeys(keys, text, language, callback) {
|
||
11 years ago
|
|
||
10 years ago
|
var count = keys.length;
|
||
|
if (!count) {
|
||
|
return callback(text);
|
||
|
}
|
||
11 years ago
|
|
||
10 years ago
|
var data = {text: text};
|
||
|
keys.forEach(function(key) {
|
||
|
translateKey(key, data, language, function(translated) {
|
||
|
--count;
|
||
|
if (count <= 0) {
|
||
|
callback(translated.text);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
11 years ago
|
|
||
10 years ago
|
function translateKey(key, data, language, callback) {
|
||
|
key = '' + key;
|
||
|
var variables = key.split(regexes.split);
|
||
11 years ago
|
|
||
10 years ago
|
var parsedKey = key.replace('[[', '').replace(']]', '').split(':');
|
||
|
if (!(parsedKey[0] && parsedKey[1])) {
|
||
10 years ago
|
return callback(data);
|
||
12 years ago
|
}
|
||
|
|
||
10 years ago
|
var languageFile = parsedKey[0];
|
||
|
parsedKey = ('' + parsedKey[1]).split(',')[0];
|
||
|
|
||
|
translator.load(language, languageFile, function(languageData) {
|
||
|
data.text = insertLanguage(data.text, key, languageData[parsedKey], variables);
|
||
|
callback(data);
|
||
|
});
|
||
|
}
|
||
12 years ago
|
|
||
10 years ago
|
function insertLanguage(text, key, value, variables) {
|
||
|
if (value) {
|
||
|
for (var i = 1, ii = variables.length; i < ii; i++) {
|
||
|
var variable = variables[i].replace(']]', '');
|
||
|
value = value.replace('%' + i, variable);
|
||
12 years ago
|
}
|
||
10 years ago
|
|
||
|
text = text.replace(key, value);
|
||
|
} else {
|
||
|
var string = key.split(':');
|
||
|
text = text.replace(key, string[string.length-1].replace(regexes.replace, ''));
|
||
12 years ago
|
}
|
||
10 years ago
|
|
||
|
return text;
|
||
|
}
|
||
12 years ago
|
|
||
11 years ago
|
translator.compile = function() {
|
||
|
var args = Array.prototype.slice.call(arguments, 0);
|
||
11 years ago
|
|
||
11 years ago
|
return '[[' + args.join(', ') + ']]';
|
||
|
};
|
||
|
|
||
11 years ago
|
translator.load = function (language, filename, callback) {
|
||
|
if (isLanguageFileLoaded(language, filename)) {
|
||
12 years ago
|
if (callback) {
|
||
11 years ago
|
callback(languages[language].loaded[filename]);
|
||
12 years ago
|
}
|
||
11 years ago
|
} else if (isLanguageFileLoading(language, filename)) {
|
||
12 years ago
|
if (callback) {
|
||
11 years ago
|
addLanguageFileCallback(language, filename, callback);
|
||
12 years ago
|
}
|
||
|
} else {
|
||
|
|
||
11 years ago
|
languages[language] = languages[language] || {loading: {}, loaded: {}, callbacks: []};
|
||
|
|
||
|
languages[language].loading[filename] = true;
|
||
|
|
||
|
load(language, filename, function(translations) {
|
||
12 years ago
|
|
||
11 years ago
|
languages[language].loaded[filename] = translations;
|
||
12 years ago
|
|
||
|
if (callback) {
|
||
11 years ago
|
callback(translations);
|
||
12 years ago
|
}
|
||
|
|
||
10 years ago
|
while (languages[language].callbacks && languages[language].callbacks[filename] && languages[language].callbacks[filename].length) {
|
||
11 years ago
|
languages[language].callbacks[filename].pop()(translations);
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
languages[language].loading[filename] = false;
|
||
12 years ago
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
11 years ago
|
function isLanguageFileLoaded(language, filename) {
|
||
|
var languageObj = languages[language];
|
||
|
return languageObj && languageObj.loaded && languageObj.loaded[filename] && !languageObj.loading[filename];
|
||
|
}
|
||
|
|
||
|
function isLanguageFileLoading(language, filename) {
|
||
|
return languages[language] && languages[language].loading && languages[language].loading[filename];
|
||
|
}
|
||
|
|
||
|
function addLanguageFileCallback(language, filename, callback) {
|
||
|
languages[language].callbacks = languages[language].callbacks || {};
|
||
|
|
||
|
languages[language].callbacks[filename] = languages[language].callbacks[filename] || [];
|
||
|
languages[language].callbacks[filename].push(callback);
|
||
|
}
|
||
|
|
||
|
function load(language, filename, callback) {
|
||
11 years ago
|
if ('undefined' !== typeof window) {
|
||
11 years ago
|
loadClient(language, filename, callback);
|
||
11 years ago
|
} else {
|
||
11 years ago
|
loadServer(language, filename, callback);
|
||
11 years ago
|
}
|
||
|
}
|
||
|
|
||
11 years ago
|
function loadClient(language, filename, callback) {
|
||
11 years ago
|
$.getJSON(config.relative_path + '/language/' + language + '/' + filename + '.json?v=' + config['cache-buster'], callback);
|
||
11 years ago
|
}
|
||
12 years ago
|
|
||
11 years ago
|
function loadServer(language, filename, callback) {
|
||
11 years ago
|
var fs = require('fs'),
|
||
12 years ago
|
path = require('path'),
|
||
11 years ago
|
winston = require('winston'),
|
||
10 years ago
|
meta = require('../../../src/meta');
|
||
11 years ago
|
|
||
11 years ago
|
language = language || meta.config.defaultLang || 'en_GB';
|
||
|
|
||
10 years ago
|
if (!fs.existsSync(path.join(__dirname, '../../language', language))) {
|
||
11 years ago
|
winston.warn('[translator] Language \'' + meta.config.defaultLang + '\' not found. Defaulting to \'en_GB\'');
|
||
11 years ago
|
language = 'en_GB';
|
||
|
}
|
||
|
|
||
10 years ago
|
fs.readFile(path.join(__dirname, '../../language', language, filename + '.json'), function(err, data) {
|
||
11 years ago
|
if (err) {
|
||
11 years ago
|
winston.error('Could not load `' + filename + '`: ' + err.message + '. Skipping...');
|
||
|
return callback({});
|
||
12 years ago
|
}
|
||
11 years ago
|
|
||
11 years ago
|
try {
|
||
|
callback(JSON.parse(data.toString()));
|
||
|
} catch (e) {
|
||
|
winston.error('Could not parse `' + filename + '.json`, syntax error? Skipping...');
|
||
|
callback({});
|
||
|
}
|
||
12 years ago
|
});
|
||
11 years ago
|
}
|
||
12 years ago
|
|
||
10 years ago
|
// Use the define() function if we're in AMD land
|
||
|
if (typeof define === 'function' && define.amd) {
|
||
|
define('translator', translator);
|
||
12 years ago
|
|
||
10 years ago
|
// Expose a global `translator` object for backwards compatibility
|
||
|
window.translator = {
|
||
|
translate: function() {
|
||
|
console.warn('[translator] Global invocation of the translator is now deprecated, please `require` the module instead.');
|
||
|
translator.translate.apply(translator, arguments);
|
||
|
}
|
||
|
}
|
||
12 years ago
|
}
|
||
10 years ago
|
})(
|
||
|
typeof exports === 'object' ? exports :
|
||
|
typeof define === 'function' && define.amd ? {} :
|
||
|
translator = {}
|
||
|
);
|