Update src/static/js/html10n.js

Added missing semicolons (#1440)
pull/1444/head
Manuel Knitza 2013-02-01 21:28:22 +01:00
parent f8cc7e0d7b
commit b9b5ebf661
1 changed files with 115 additions and 115 deletions

View File

@ -23,27 +23,27 @@
window.html10n = (function(window, document, undefined) { window.html10n = (function(window, document, undefined) {
// fix console // fix console
var console = window.console var console = window.console;
function interceptConsole(method){ function interceptConsole(method){
if (!console) return function() {} if (!console) return function() {};
var original = console[method] var original = console[method];
// do sneaky stuff // do sneaky stuff
if (original.bind){ if (original.bind){
// Do this for normal browsers // Do this for normal browsers
return original.bind(console) return original.bind(console);
}else{ }else{
return function() { return function() {
// Do this for IE // Do this for IE
var message = Array.prototype.slice.apply(arguments).join(' ') var message = Array.prototype.slice.apply(arguments).join(' ');
original(message) original(message);
} }
} }
} }
var consoleLog = interceptConsole('log') var consoleLog = interceptConsole('log')
, consoleWarn = interceptConsole('warn') , consoleWarn = interceptConsole('warn')
, consoleError = interceptConsole('warn') , consoleError = interceptConsole('warn');
// fix Array.prototype.instanceOf in, guess what, IE! <3 // fix Array.prototype.instanceOf in, guess what, IE! <3
@ -84,14 +84,14 @@ window.html10n = (function(window, document, undefined) {
* MicroEvent - to make any js object an event emitter (server or browser) * MicroEvent - to make any js object an event emitter (server or browser)
*/ */
var MicroEvent = function(){} var MicroEvent = function(){}
MicroEvent.prototype = { MicroEvent.prototype = {
bind : function(event, fct){ bind : function(event, fct){
this._events = this._events || {}; this._events = this._events || {};
this._events[event] = this._events[event] || []; this._events[event] = this._events[event] || [];
this._events[event].push(fct); this._events[event].push(fct);
}, },
unbind : function(event, fct){ unbind : function(event, fct){
this._events = this._events || {}; this._events = this._events || {};
if( event in this._events === false ) return; if( event in this._events === false ) return;
this._events[event].splice(this._events[event].indexOf(fct), 1); this._events[event].splice(this._events[event].indexOf(fct), 1);
@ -100,7 +100,7 @@ window.html10n = (function(window, document, undefined) {
this._events = this._events || {}; this._events = this._events || {};
if( event in this._events === false ) return; if( event in this._events === false ) return;
for(var i = 0; i < this._events[event].length; i++){ for(var i = 0; i < this._events[event].length; i++){
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1)) this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
} }
} }
}; };
@ -122,50 +122,50 @@ window.html10n = (function(window, document, undefined) {
* and caching all necessary resources * and caching all necessary resources
*/ */
function Loader(resources) { function Loader(resources) {
this.resources = resources this.resources = resources;
this.cache = {} // file => contents this.cache = {}; // file => contents
this.langs = {} // lang => strings this.langs = {}; // lang => strings
} }
Loader.prototype.load = function(lang, cb) { Loader.prototype.load = function(lang, cb) {
if(this.langs[lang]) return cb() if(this.langs[lang]) return cb();
if (this.resources.length > 0) { if (this.resources.length > 0) {
var reqs = 0; var reqs = 0;
for (var i=0, n=this.resources.length; i < n; i++) { for (var i=0, n=this.resources.length; i < n; i++) {
this.fetch(this.resources[i], lang, function(e) { this.fetch(this.resources[i], lang, function(e) {
reqs++; reqs++;
if(e) return setTimeout(function(){ throw e }, 0) if(e) return setTimeout(function(){ throw e }, 0);
if (reqs < n) return;// Call back once all reqs are completed if (reqs < n) return;// Call back once all reqs are completed
cb && cb() cb && cb();
}) })
} }
} }
} }
Loader.prototype.fetch = function(href, lang, cb) { Loader.prototype.fetch = function(href, lang, cb) {
var that = this var that = this;
if (this.cache[href]) { if (this.cache[href]) {
this.parse(lang, href, this.cache[href], cb) this.parse(lang, href, this.cache[href], cb)
return; return;
} }
var xhr = new XMLHttpRequest() var xhr = new XMLHttpRequest();
xhr.open('GET', href, /*async: */true) xhr.open('GET', href, /*async: */true);
if (xhr.overrideMimeType) { if (xhr.overrideMimeType) {
xhr.overrideMimeType('application/json; charset=utf-8'); xhr.overrideMimeType('application/json; charset=utf-8');
} }
xhr.onreadystatechange = function() { xhr.onreadystatechange = function() {
if (xhr.readyState == 4) { if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status === 0) { if (xhr.status == 200 || xhr.status === 0) {
var data = JSON.parse(xhr.responseText) var data = JSON.parse(xhr.responseText);
that.cache[href] = data that.cache[href] = data;
// Pass on the contents for parsing // Pass on the contents for parsing
that.parse(lang, href, data, cb) that.parse(lang, href, data, cb);
} else { } else {
cb(new Error('Failed to load '+href)) cb(new Error('Failed to load '+href));
} }
} }
}; };
@ -174,39 +174,39 @@ window.html10n = (function(window, document, undefined) {
Loader.prototype.parse = function(lang, currHref, data, cb) { Loader.prototype.parse = function(lang, currHref, data, cb) {
if ('object' != typeof data) { if ('object' != typeof data) {
cb(new Error('A file couldn\'t be parsed as json.')) cb(new Error('A file couldn\'t be parsed as json.'));
return return;
} }
if (!data[lang]) lang = lang.substr(0, lang.indexOf('-') == -1? lang.length : lang.indexOf('-')) if (!data[lang]) lang = lang.substr(0, lang.indexOf('-') == -1? lang.length : lang.indexOf('-'));
if (!data[lang]) { if (!data[lang]) {
cb(new Error('Couldn\'t find translations for '+lang)) cb(new Error('Couldn\'t find translations for '+lang));
return return;
} }
if ('string' == typeof data[lang]) { if ('string' == typeof data[lang]) {
// Import rule // Import rule
// absolute path // absolute path
var importUrl = data[lang] var importUrl = data[lang];
// relative path // relative path
if(data[lang].indexOf("http") != 0 && data[lang].indexOf("/") != 0) { if(data[lang].indexOf("http") != 0 && data[lang].indexOf("/") != 0) {
importUrl = currHref+"/../"+data[lang] importUrl = currHref+"/../"+data[lang];
} }
this.fetch(importUrl, lang, cb) this.fetch(importUrl, lang, cb);
return return;
} }
if ('object' != typeof data[lang]) { if ('object' != typeof data[lang]) {
cb(new Error('Translations should be specified as JSON objects!')) cb(new Error('Translations should be specified as JSON objects!'));
return return;
} }
this.langs[lang] = data[lang] this.langs[lang] = data[lang];
// TODO: Also store accompanying langs // TODO: Also store accompanying langs
cb() cb();
} }
@ -216,11 +216,11 @@ window.html10n = (function(window, document, undefined) {
var html10n = var html10n =
{ language : null { language : null
} }
MicroEvent.mixin(html10n) MicroEvent.mixin(html10n);
html10n.macros = {} html10n.macros = {};
html10n.rtl = ["ar","dv","fa","ha","he","ks","ku","ps","ur","yi"] html10n.rtl = ["ar","dv","fa","ha","he","ks","ku","ps","ur","yi"];
/** /**
* Get rules for plural forms (shared with JetPack), see: * Get rules for plural forms (shared with JetPack), see:
@ -664,14 +664,14 @@ window.html10n = (function(window, document, undefined) {
* @param langs An array of lang codes defining fallbacks * @param langs An array of lang codes defining fallbacks
*/ */
html10n.localize = function(langs) { html10n.localize = function(langs) {
var that = this var that = this;
// if only one string => create an array // if only one string => create an array
if ('string' == typeof langs) langs = [langs] if ('string' == typeof langs) langs = [langs];
this.build(langs, function(er, translations) { this.build(langs, function(er, translations) {
html10n.translations = translations html10n.translations = translations;
html10n.translateElement(translations) html10n.translateElement(translations);
that.trigger('localized') that.trigger('localized');
}) })
} }
@ -682,78 +682,78 @@ window.html10n = (function(window, document, undefined) {
* @param element A DOM element, if omitted, the document element will be used * @param element A DOM element, if omitted, the document element will be used
*/ */
html10n.translateElement = function(translations, element) { html10n.translateElement = function(translations, element) {
element = element || document.documentElement element = element || document.documentElement;
var children = element? getTranslatableChildren(element) : document.childNodes; var children = element? getTranslatableChildren(element) : document.childNodes;
for (var i=0, n=children.length; i < n; i++) { for (var i=0, n=children.length; i < n; i++) {
this.translateNode(translations, children[i]) this.translateNode(translations, children[i]);
} }
// translate element itself if necessary // translate element itself if necessary
this.translateNode(translations, element) this.translateNode(translations, element);
} }
function asyncForEach(list, iterator, cb) { function asyncForEach(list, iterator, cb) {
var i = 0 var i = 0
, n = list.length , n = list.length;
iterator(list[i], i, function each(err) { iterator(list[i], i, function each(err) {
if(err) consoleLog(err) if(err) consoleLog(err);
i++ i++;
if (i < n) return iterator(list[i],i, each); if (i < n) return iterator(list[i],i, each);
cb() cb();
}) })
} }
function getTranslatableChildren(element) { function getTranslatableChildren(element) {
if(!document.querySelectorAll) { if(!document.querySelectorAll) {
if (!element) return [] if (!element) return [];
var nodes = element.getElementsByTagName('*') var nodes = element.getElementsByTagName('*')
, l10nElements = [] , l10nElements = [];
for (var i=0, n=nodes.length; i < n; i++) { for (var i=0, n=nodes.length; i < n; i++) {
if (nodes[i].getAttribute('data-l10n-id')) if (nodes[i].getAttribute('data-l10n-id'))
l10nElements.push(nodes[i]); l10nElements.push(nodes[i]);
} }
return l10nElements return l10nElements;
} }
return element.querySelectorAll('*[data-l10n-id]') return element.querySelectorAll('*[data-l10n-id]');
} }
html10n.get = function(id, args) { html10n.get = function(id, args) {
var translations = html10n.translations var translations = html10n.translations;
if(!translations) return consoleWarn('No translations available (yet)') if(!translations) return consoleWarn('No translations available (yet)');
if(!translations[id]) return consoleWarn('Could not find string '+id) if(!translations[id]) return consoleWarn('Could not find string '+id);
// apply args // apply args
var str = substArguments(translations[id], args) var str = substArguments(translations[id], args);
// apply macros // apply macros
return substMacros(id, str, args) return substMacros(id, str, args);
// replace {{arguments}} with their values or the // replace {{arguments}} with their values or the
// associated translation string (based on its key) // associated translation string (based on its key)
function substArguments(str, args) { function substArguments(str, args) {
var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/ var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/
, match , match;
while (match = reArgs.exec(str)) { while (match = reArgs.exec(str)) {
if (!match || match.length < 2) if (!match || match.length < 2)
return str // argument key not found return str; // argument key not found
var arg = match[1] var arg = match[1]
, sub = '' , sub = '';
if (arg in args) { if (arg in args) {
sub = args[arg] sub = args[arg];
} else if (arg in translations) { } else if (arg in translations) {
sub = translations[arg] sub = translations[arg];
} else { } else {
consoleWarn('Could not find argument {{' + arg + '}}') consoleWarn('Could not find argument {{' + arg + '}}');
return str return str;
} }
str = str.substring(0, match.index) + sub + str.substr(match.index + match[0].length) str = str.substring(0, match.index) + sub + str.substr(match.index + match[0].length);
} }
return str return str;
} }
// replace {[macros]} with their values // replace {[macros]} with their values
@ -766,21 +766,21 @@ window.html10n = (function(window, document, undefined) {
// a macro has been found // a macro has been found
// Note: at the moment, only one parameter is supported // Note: at the moment, only one parameter is supported
var macroName = reMatch[1] var macroName = reMatch[1]
, paramName = reMatch[2] , paramName = reMatch[2];
if (!(macroName in gMacros)) return str if (!(macroName in gMacros)) return str;
var param var param;
if (args && paramName in args) { if (args && paramName in args) {
param = args[paramName] param = args[paramName];
} else if (paramName in translations) { } else if (paramName in translations) {
param = translations[paramName] param = translations[paramName];
} }
// there's no macro parser yet: it has to be defined in gMacros // there's no macro parser yet: it has to be defined in gMacros
var macro = html10n.macros[macroName] var macro = html10n.macros[macroName];
str = macro(translations, key, str, param) str = macro(translations, key, str, param);
return str return str;
} }
} }
@ -788,26 +788,26 @@ window.html10n = (function(window, document, undefined) {
* Applies translations to a DOM node (recursive) * Applies translations to a DOM node (recursive)
*/ */
html10n.translateNode = function(translations, node) { html10n.translateNode = function(translations, node) {
var str = {} var str = {};
// get id // get id
str.id = node.getAttribute('data-l10n-id') str.id = node.getAttribute('data-l10n-id');
if (!str.id) return if (!str.id) return;
if(!translations[str.id]) return consoleWarn('Couldn\'t find translation key '+str.id) if(!translations[str.id]) return consoleWarn('Couldn\'t find translation key '+str.id);
// get args // get args
if(window.JSON) { if(window.JSON) {
str.args = JSON.parse(node.getAttribute('data-l10n-args')) str.args = JSON.parse(node.getAttribute('data-l10n-args'));
}else{ }else{
try{ try{
str.args = eval(node.getAttribute('data-l10n-args')) str.args = eval(node.getAttribute('data-l10n-args'));
}catch(e) { }catch(e) {
consoleWarn('Couldn\'t parse args for '+str.id) consoleWarn('Couldn\'t parse args for '+str.id);
} }
} }
str.str = html10n.get(str.id, str.args) str.str = html10n.get(str.id, str.args);
// get attribute name to apply str to // get attribute name to apply str to
var prop var prop
@ -817,31 +817,31 @@ window.html10n = (function(window, document, undefined) {
, "innerHTML": 1 , "innerHTML": 1
, "alt": 1 , "alt": 1
, "textContent": 1 , "textContent": 1
} };
if (index > 0 && str.id.substr(index + 1) in attrList) { // an attribute has been specified if (index > 0 && str.id.substr(index + 1) in attrList) { // an attribute has been specified
prop = str.id.substr(index + 1) prop = str.id.substr(index + 1);
} else { // no attribute: assuming text content by default } else { // no attribute: assuming text content by default
prop = document.body.textContent ? 'textContent' : 'innerText' prop = document.body.textContent ? 'textContent' : 'innerText';
} }
// Apply translation // Apply translation
if (node.children.length === 0 || prop != 'textContent') { if (node.children.length === 0 || prop != 'textContent') {
node[prop] = str.str node[prop] = str.str;
} else { } else {
var children = node.childNodes, var children = node.childNodes,
found = false found = false;
for (var i=0, n=children.length; i < n; i++) { for (var i=0, n=children.length; i < n; i++) {
if (children[i].nodeType === 3 && /\S/.test(children[i].textContent)) { if (children[i].nodeType === 3 && /\S/.test(children[i].textContent)) {
if (!found) { if (!found) {
children[i].nodeValue = str.str children[i].nodeValue = str.str;
found = true found = true;
} else { } else {
children[i].nodeValue = '' children[i].nodeValue = '';
} }
} }
} }
if (!found) { if (!found) {
consoleWarn('Unexpected error: could not translate element content for key '+str.id, node) consoleWarn('Unexpected error: could not translate element content for key '+str.id, node);
} }
} }
} }
@ -852,32 +852,32 @@ window.html10n = (function(window, document, undefined) {
*/ */
html10n.build = function(langs, cb) { html10n.build = function(langs, cb) {
var that = this var that = this
, build = {} , build = {};
asyncForEach(langs, function (lang, i, next) { asyncForEach(langs, function (lang, i, next) {
if(!lang) return next(); if(!lang) return next();
that.loader.load(lang, next) that.loader.load(lang, next);
}, function() { }, function() {
var lang var lang;
langs.reverse() langs.reverse();
// loop through priority array... // loop through priority array...
for (var i=0, n=langs.length; i < n; i++) { for (var i=0, n=langs.length; i < n; i++) {
lang = langs[i] lang = langs[i];
if(!lang || !(lang in that.loader.langs)) continue; if(!lang || !(lang in that.loader.langs)) continue;
// ... and apply all strings of the current lang in the list // ... and apply all strings of the current lang in the list
// to our build object // to our build object
for (var string in that.loader.langs[lang]) { for (var string in that.loader.langs[lang]) {
build[string] = that.loader.langs[lang][string] build[string] = that.loader.langs[lang][string];
} }
// the last applied lang will be exposed as the // the last applied lang will be exposed as the
// lang the page was translated to // lang the page was translated to
that.language = lang that.language = lang;
} }
cb(null, build) cb(null, build);
}) })
} }
@ -893,8 +893,8 @@ window.html10n = (function(window, document, undefined) {
* Returns the direction of the language returned be html10n#getLanguage * Returns the direction of the language returned be html10n#getLanguage
*/ */
html10n.getDirection = function() { html10n.getDirection = function() {
var langCode = this.language.indexOf('-') == -1? this.language : this.language.substr(0, this.language.indexOf('-')) var langCode = this.language.indexOf('-') == -1? this.language : this.language.substr(0, this.language.indexOf('-'));
return html10n.rtl.indexOf(langCode) == -1? 'ltr' : 'rtl' return html10n.rtl.indexOf(langCode) == -1? 'ltr' : 'rtl';
} }
/** /**
@ -903,28 +903,28 @@ window.html10n = (function(window, document, undefined) {
html10n.index = function () { html10n.index = function () {
// Find all <link>s // Find all <link>s
var links = document.getElementsByTagName('link') var links = document.getElementsByTagName('link')
, resources = [] , resources = [];
for (var i=0, n=links.length; i < n; i++) { for (var i=0, n=links.length; i < n; i++) {
if (links[i].type != 'application/l10n+json') if (links[i].type != 'application/l10n+json')
continue; continue;
resources.push(links[i].href) resources.push(links[i].href);
} }
this.loader = new Loader(resources) this.loader = new Loader(resources);
this.trigger('indexed') this.trigger('indexed');
} }
if (document.addEventListener) // modern browsers and IE9+ if (document.addEventListener) // modern browsers and IE9+
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
html10n.index() html10n.index();
}, false) }, false);
else if (window.attachEvent) else if (window.attachEvent)
window.attachEvent('onload', function() { window.attachEvent('onload', function() {
html10n.index() html10n.index();
}, false) }, false);
// gettext-like shortcut // gettext-like shortcut
if (window._ === undefined) if (window._ === undefined)
window._ = html10n.get; window._ = html10n.get;
return html10n return html10n;
})(window, document) })(window, document);