Merge pull request #3696 from Rob--W/webL10n-tot
Update webL10n to latest version (september 2013) (+support for attributes in mozL10n.get)
This commit is contained in:
commit
e140d2ca58
264
external/webL10n/l10n.js
vendored
264
external/webL10n/l10n.js
vendored
@ -1,30 +1,31 @@
|
|||||||
/** Copyright (c) 2011-2012 Fabien Cazenave, Mozilla.
|
/**
|
||||||
*
|
* Copyright (c) 2011-2013 Fabien Cazenave, Mozilla.
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
*
|
||||||
* of this software and associated documentation files (the "Software"), to
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* deal in the Software without restriction, including without limitation the
|
* of this software and associated documentation files (the "Software"), to
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
* deal in the Software without restriction, including without limitation the
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
* furnished to do so, subject to the following conditions:
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
*
|
* furnished to do so, subject to the following conditions:
|
||||||
* The above copyright notice and this permission notice shall be included in
|
*
|
||||||
* all copies or substantial portions of the Software.
|
* The above copyright notice and this permission notice shall be included in
|
||||||
*
|
* all copies or substantial portions of the Software.
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
*
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
* IN THE SOFTWARE.
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
*/
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
Additional modifications for PDF.js project:
|
Additional modifications for PDF.js project:
|
||||||
- Disables language initialization on page loading;
|
- Disables language initialization on page loading;
|
||||||
- Adds fallback argument to the getL10nData;
|
- Removes consoleWarn and consoleLog and use console.log/warn directly.
|
||||||
- Removes consoleLog and simplifies consoleWarn;
|
|
||||||
- Removes window._ assignment.
|
- Removes window._ assignment.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*jshint browser: true, devel: true, es5: true, globalstrict: true */
|
/*jshint browser: true, devel: true, es5: true, globalstrict: true */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -36,13 +37,21 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
var gMacros = {};
|
var gMacros = {};
|
||||||
var gReadyState = 'loading';
|
var gReadyState = 'loading';
|
||||||
|
|
||||||
// read-only setting -- we recommend to load l10n resources synchronously
|
|
||||||
var gAsyncResourceLoading = true;
|
|
||||||
|
|
||||||
// debug helpers
|
/**
|
||||||
function consoleWarn(message) {
|
* Synchronously loading l10n resources significantly minimizes flickering
|
||||||
console.log('[l10n] ' + message);
|
* from displaying the app with non-localized strings and then updating the
|
||||||
};
|
* strings. Although this will block all script execution on this page, we
|
||||||
|
* expect that the l10n resources are available locally on flash-storage.
|
||||||
|
*
|
||||||
|
* As synchronous XHR is generally considered as a bad idea, we're still
|
||||||
|
* loading l10n resources asynchronously -- but we keep this in a setting,
|
||||||
|
* just in case... and applications using this library should hide their
|
||||||
|
* content until the `localized' event happens.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var gAsyncResourceLoading = true; // read-only
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOM helpers for the so-called "HTML API".
|
* DOM helpers for the so-called "HTML API".
|
||||||
@ -55,6 +64,12 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
return document.querySelectorAll('link[type="application/l10n"]');
|
return document.querySelectorAll('link[type="application/l10n"]');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getL10nDictionary() {
|
||||||
|
var script = document.querySelector('script[type="application/l10n"]');
|
||||||
|
// TODO: support multiple and external JSON dictionaries
|
||||||
|
return script ? JSON.parse(script.innerHTML) : null;
|
||||||
|
}
|
||||||
|
|
||||||
function getTranslatableChildren(element) {
|
function getTranslatableChildren(element) {
|
||||||
return element ? element.querySelectorAll('*[data-l10n-id]') : [];
|
return element ? element.querySelectorAll('*[data-l10n-id]') : [];
|
||||||
}
|
}
|
||||||
@ -70,7 +85,7 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
try {
|
try {
|
||||||
args = JSON.parse(l10nArgs);
|
args = JSON.parse(l10nArgs);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
consoleWarn('could not parse arguments for #' + l10nId);
|
console.warn('could not parse arguments for #' + l10nId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { id: l10nId, args: args };
|
return { id: l10nId, args: args };
|
||||||
@ -78,9 +93,41 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
|
|
||||||
function fireL10nReadyEvent(lang) {
|
function fireL10nReadyEvent(lang) {
|
||||||
var evtObject = document.createEvent('Event');
|
var evtObject = document.createEvent('Event');
|
||||||
evtObject.initEvent('localized', false, false);
|
evtObject.initEvent('localized', true, false);
|
||||||
evtObject.language = lang;
|
evtObject.language = lang;
|
||||||
window.dispatchEvent(evtObject);
|
document.dispatchEvent(evtObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
function xhrLoadText(url, onSuccess, onFailure, asynchronous) {
|
||||||
|
onSuccess = onSuccess || function _onSuccess(data) {};
|
||||||
|
onFailure = onFailure || function _onFailure() {
|
||||||
|
console.warn(url + ' not found.');
|
||||||
|
};
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url, asynchronous);
|
||||||
|
if (xhr.overrideMimeType) {
|
||||||
|
xhr.overrideMimeType('text/plain; charset=utf-8');
|
||||||
|
}
|
||||||
|
xhr.onreadystatechange = function() {
|
||||||
|
if (xhr.readyState == 4) {
|
||||||
|
if (xhr.status == 200 || xhr.status === 0) {
|
||||||
|
onSuccess(xhr.responseText);
|
||||||
|
} else {
|
||||||
|
onFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.onerror = onFailure;
|
||||||
|
xhr.ontimeout = onFailure;
|
||||||
|
|
||||||
|
// in Firefox OS with the app:// protocol, trying to XHR a non-existing
|
||||||
|
// URL will raise an exception here -- hence this ugly try...catch.
|
||||||
|
try {
|
||||||
|
xhr.send(null);
|
||||||
|
} catch (e) {
|
||||||
|
onFailure();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -108,7 +155,7 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function parseResource(href, lang, successCallback, failureCallback) {
|
function parseResource(href, lang, successCallback, failureCallback) {
|
||||||
var baseURL = href.replace(/\/[^\/]*$/, '/');
|
var baseURL = href.replace(/[^\/]*$/, '') || './';
|
||||||
|
|
||||||
// handle escaped characters (backslashes) in a string
|
// handle escaped characters (backslashes) in a string
|
||||||
function evalString(text) {
|
function evalString(text) {
|
||||||
@ -171,16 +218,17 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
|
|
||||||
// key-value pair
|
// key-value pair
|
||||||
var tmp = line.match(reSplit);
|
var tmp = line.match(reSplit);
|
||||||
if (tmp && tmp.length == 3)
|
if (tmp && tmp.length == 3) {
|
||||||
dictionary[tmp[1]] = evalString(tmp[2]);
|
dictionary[tmp[1]] = evalString(tmp[2]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// import another *.properties file
|
// import another *.properties file
|
||||||
function loadImport(url) {
|
function loadImport(url) {
|
||||||
loadResource(url, function(content) {
|
xhrLoadText(url, function(content) {
|
||||||
parseRawLines(content, false); // don't allow recursive imports
|
parseRawLines(content, false); // don't allow recursive imports
|
||||||
}, false, false); // load synchronously
|
}, null, false); // load synchronously
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill the dictionary
|
// fill the dictionary
|
||||||
@ -188,29 +236,8 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
return dictionary;
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the specified resource file
|
|
||||||
function loadResource(url, onSuccess, onFailure, asynchronous) {
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.open('GET', url, asynchronous);
|
|
||||||
if (xhr.overrideMimeType) {
|
|
||||||
xhr.overrideMimeType('text/plain; charset=utf-8');
|
|
||||||
}
|
|
||||||
xhr.onreadystatechange = function() {
|
|
||||||
if (xhr.readyState == 4) {
|
|
||||||
if (xhr.status == 200 || xhr.status === 0) {
|
|
||||||
if (onSuccess)
|
|
||||||
onSuccess(xhr.responseText);
|
|
||||||
} else {
|
|
||||||
if (onFailure)
|
|
||||||
onFailure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.send(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load and parse l10n data (warning: global variables are used here)
|
// load and parse l10n data (warning: global variables are used here)
|
||||||
loadResource(href, function(response) {
|
xhrLoadText(href, function(response) {
|
||||||
gTextData += response; // mostly for debug
|
gTextData += response; // mostly for debug
|
||||||
|
|
||||||
// parse *.properties text data into an l10n dictionary
|
// parse *.properties text data into an l10n dictionary
|
||||||
@ -233,13 +260,16 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// trigger callback
|
// trigger callback
|
||||||
if (successCallback)
|
if (successCallback) {
|
||||||
successCallback();
|
successCallback();
|
||||||
|
}
|
||||||
}, failureCallback, gAsyncResourceLoading);
|
}, failureCallback, gAsyncResourceLoading);
|
||||||
};
|
}
|
||||||
|
|
||||||
// load and parse all resources for the specified locale
|
// load and parse all resources for the specified locale
|
||||||
function loadLocale(lang, callback) {
|
function loadLocale(lang, callback) {
|
||||||
|
callback = callback || function _callback() {};
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
gLanguage = lang;
|
gLanguage = lang;
|
||||||
|
|
||||||
@ -247,8 +277,17 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
// and load the resource files
|
// and load the resource files
|
||||||
var langLinks = getL10nResourceLinks();
|
var langLinks = getL10nResourceLinks();
|
||||||
var langCount = langLinks.length;
|
var langCount = langLinks.length;
|
||||||
if (langCount == 0) {
|
if (langCount === 0) {
|
||||||
consoleWarn('no resource to load, early way out');
|
// we might have a pre-compiled dictionary instead
|
||||||
|
var dict = getL10nDictionary();
|
||||||
|
if (dict && dict.locales && dict.default_locale) {
|
||||||
|
console.log('using the embedded JSON directory, early way out');
|
||||||
|
gL10nData = dict.locales[lang] || dict.locales[dict.default_locale];
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
console.log('no resource to load, early way out');
|
||||||
|
}
|
||||||
|
// early way out
|
||||||
fireL10nReadyEvent(lang);
|
fireL10nReadyEvent(lang);
|
||||||
gReadyState = 'complete';
|
gReadyState = 'complete';
|
||||||
return;
|
return;
|
||||||
@ -260,21 +299,20 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
onResourceLoaded = function() {
|
onResourceLoaded = function() {
|
||||||
gResourceCount++;
|
gResourceCount++;
|
||||||
if (gResourceCount >= langCount) {
|
if (gResourceCount >= langCount) {
|
||||||
if (callback) // execute the [optional] callback
|
callback();
|
||||||
callback();
|
|
||||||
fireL10nReadyEvent(lang);
|
fireL10nReadyEvent(lang);
|
||||||
gReadyState = 'complete';
|
gReadyState = 'complete';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// load all resource files
|
// load all resource files
|
||||||
function l10nResourceLink(link) {
|
function L10nResourceLink(link) {
|
||||||
var href = link.href;
|
var href = link.href;
|
||||||
var type = link.type;
|
var type = link.type;
|
||||||
this.load = function(lang, callback) {
|
this.load = function(lang, callback) {
|
||||||
var applied = lang;
|
var applied = lang;
|
||||||
parseResource(href, lang, callback, function() {
|
parseResource(href, lang, callback, function() {
|
||||||
consoleWarn(href + ' not found.');
|
console.warn(href + ' not found.');
|
||||||
applied = '';
|
applied = '';
|
||||||
});
|
});
|
||||||
return applied; // return lang if found, an empty string if not found
|
return applied; // return lang if found, an empty string if not found
|
||||||
@ -282,10 +320,10 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < langCount; i++) {
|
for (var i = 0; i < langCount; i++) {
|
||||||
var resource = new l10nResourceLink(langLinks[i]);
|
var resource = new L10nResourceLink(langLinks[i]);
|
||||||
var rv = resource.load(lang, onResourceLoaded);
|
var rv = resource.load(lang, onResourceLoaded);
|
||||||
if (rv != lang) { // lang not found, used default resource instead
|
if (rv != lang) { // lang not found, used default resource instead
|
||||||
consoleWarn('"' + lang + '" resource not found');
|
console.warn('"' + lang + '" resource not found');
|
||||||
gLanguage = '';
|
gLanguage = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -706,7 +744,7 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
// return a function that gives the plural form name for a given integer
|
// return a function that gives the plural form name for a given integer
|
||||||
var index = locales2rules[lang.replace(/-.*$/, '')];
|
var index = locales2rules[lang.replace(/-.*$/, '')];
|
||||||
if (!(index in pluralRules)) {
|
if (!(index in pluralRules)) {
|
||||||
consoleWarn('plural form unknown for [' + lang + ']');
|
console.warn('plural form unknown for [' + lang + ']');
|
||||||
return function() { return 'other'; };
|
return function() { return 'other'; };
|
||||||
}
|
}
|
||||||
return pluralRules[index];
|
return pluralRules[index];
|
||||||
@ -723,8 +761,9 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
return str;
|
return str;
|
||||||
|
|
||||||
// initialize _pluralRules
|
// initialize _pluralRules
|
||||||
if (!gMacros._pluralRules)
|
if (!gMacros._pluralRules) {
|
||||||
gMacros._pluralRules = getPluralRules(gLanguage);
|
gMacros._pluralRules = getPluralRules(gLanguage);
|
||||||
|
}
|
||||||
var index = '[' + gMacros._pluralRules(n) + ']';
|
var index = '[' + gMacros._pluralRules(n) + ']';
|
||||||
|
|
||||||
// try to find a [zero|one|two] key if it's defined
|
// try to find a [zero|one|two] key if it's defined
|
||||||
@ -736,6 +775,8 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
str = gL10nData[key + '[two]'][prop];
|
str = gL10nData[key + '[two]'][prop];
|
||||||
} else if ((key + index) in gL10nData) {
|
} else if ((key + index) in gL10nData) {
|
||||||
str = gL10nData[key + index][prop];
|
str = gL10nData[key + index][prop];
|
||||||
|
} else if ((key + '[other]') in gL10nData) {
|
||||||
|
str = gL10nData[key + '[other]'][prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
@ -750,7 +791,7 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
function getL10nData(key, args, fallback) {
|
function getL10nData(key, args, fallback) {
|
||||||
var data = gL10nData[key];
|
var data = gL10nData[key];
|
||||||
if (!data) {
|
if (!data) {
|
||||||
consoleWarn('#' + key + ' missing for [' + gLanguage + ']');
|
console.warn('#' + key + ' is undefined.');
|
||||||
if (!fallback) {
|
if (!fallback) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -766,7 +807,7 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
for (var prop in data) {
|
for (var prop in data) {
|
||||||
var str = data[prop];
|
var str = data[prop];
|
||||||
str = substIndexes(str, args, key, prop);
|
str = substIndexes(str, args, key, prop);
|
||||||
str = substArguments(str, args);
|
str = substArguments(str, args, key);
|
||||||
rv[prop] = str;
|
rv[prop] = str;
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
@ -799,8 +840,8 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// replace {{arguments}} with their values
|
// replace {{arguments}} with their values
|
||||||
function substArguments(str, args) {
|
function substArguments(str, args, key) {
|
||||||
var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/;
|
var reArgs = /\{\{\s*(.+?)\s*\}\}/;
|
||||||
var match = reArgs.exec(str);
|
var match = reArgs.exec(str);
|
||||||
while (match) {
|
while (match) {
|
||||||
if (!match || match.length < 2)
|
if (!match || match.length < 2)
|
||||||
@ -808,12 +849,12 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
|
|
||||||
var arg = match[1];
|
var arg = match[1];
|
||||||
var sub = '';
|
var sub = '';
|
||||||
if (arg in args) {
|
if (args && arg in args) {
|
||||||
sub = args[arg];
|
sub = args[arg];
|
||||||
} else if (arg in gL10nData) {
|
} else if (arg in gL10nData) {
|
||||||
sub = gL10nData[arg][gTextProp];
|
sub = gL10nData[arg][gTextProp];
|
||||||
} else {
|
} else {
|
||||||
consoleWarn('could not find argument {{' + arg + '}}');
|
console.log('argument {{' + arg + '}} for #' + key + ' is undefined.');
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -833,23 +874,21 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
// get the related l10n object
|
// get the related l10n object
|
||||||
var data = getL10nData(l10n.id, l10n.args);
|
var data = getL10nData(l10n.id, l10n.args);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
consoleWarn('#' + l10n.id + ' missing for [' + gLanguage + ']');
|
console.warn('#' + l10n.id + ' is undefined.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate element (TODO: security checks?)
|
// translate element (TODO: security checks?)
|
||||||
// for the node content, replace the content of the first child textNode
|
|
||||||
// and clear other child textNodes
|
|
||||||
if (data[gTextProp]) { // XXX
|
if (data[gTextProp]) { // XXX
|
||||||
if (element.children.length === 0) {
|
if (getChildElementCount(element) === 0) {
|
||||||
element[gTextProp] = data[gTextProp];
|
element[gTextProp] = data[gTextProp];
|
||||||
} else {
|
} else {
|
||||||
var children = element.childNodes,
|
// this element has element children: replace the content of the first
|
||||||
found = false;
|
// (non-empty) child textNode and clear other child textNodes
|
||||||
|
var children = element.childNodes;
|
||||||
|
var found = false;
|
||||||
for (var i = 0, l = children.length; i < l; i++) {
|
for (var i = 0, l = children.length; i < l; i++) {
|
||||||
if (children[i].nodeType === 3 &&
|
if (children[i].nodeType === 3 && /\S/.test(children[i].nodeValue)) {
|
||||||
/\S/.test(children[i].textContent)) { // XXX
|
|
||||||
// using nodeValue seems cross-browser
|
|
||||||
if (found) {
|
if (found) {
|
||||||
children[i].nodeValue = '';
|
children[i].nodeValue = '';
|
||||||
} else {
|
} else {
|
||||||
@ -858,8 +897,11 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if no (non-empty) textNode is found, insert a textNode before the
|
||||||
|
// first element child.
|
||||||
if (!found) {
|
if (!found) {
|
||||||
consoleWarn('unexpected error, could not translate element content');
|
var textNode = document.createTextNode(data[gTextProp]);
|
||||||
|
element.insertBefore(textNode, element.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete data[gTextProp];
|
delete data[gTextProp];
|
||||||
@ -870,6 +912,21 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// webkit browsers don't currently support 'children' on SVG elements...
|
||||||
|
function getChildElementCount(element) {
|
||||||
|
if (element.children) {
|
||||||
|
return element.children.length;
|
||||||
|
}
|
||||||
|
if (typeof element.childElementCount !== 'undefined') {
|
||||||
|
return element.childElementCount;
|
||||||
|
}
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < element.childNodes.length; i++) {
|
||||||
|
count += element.nodeType === 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
// translate an HTML subtree
|
// translate an HTML subtree
|
||||||
function translateFragment(element) {
|
function translateFragment(element) {
|
||||||
element = element || document.documentElement;
|
element = element || document.documentElement;
|
||||||
@ -888,10 +945,21 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
// cross-browser API (sorry, oldIE doesn't support getters & setters)
|
// cross-browser API (sorry, oldIE doesn't support getters & setters)
|
||||||
return {
|
return {
|
||||||
// get a localized string
|
// get a localized string
|
||||||
get: function(key, args, fallback) {
|
get: function(key, args, fallbackString) {
|
||||||
var data = getL10nData(key, args, {textContent: fallback});
|
var index = key.lastIndexOf('.');
|
||||||
if (data) { // XXX double-check this
|
var prop = gTextProp;
|
||||||
return 'textContent' in data ? data.textContent : '';
|
if (index > 0) { // An attribute has been specified
|
||||||
|
prop = key.substr(index + 1);
|
||||||
|
key = key.substring(0, index);
|
||||||
|
}
|
||||||
|
var fallback;
|
||||||
|
if (fallbackString) {
|
||||||
|
fallback = {};
|
||||||
|
fallback[prop] = fallbackString;
|
||||||
|
}
|
||||||
|
var data = getL10nData(key, args, fallback);
|
||||||
|
if (data && prop in data) {
|
||||||
|
return data[prop];
|
||||||
}
|
}
|
||||||
return '{{' + key + '}}';
|
return '{{' + key + '}}';
|
||||||
},
|
},
|
||||||
@ -916,7 +984,21 @@ document.webL10n = (function(window, document, undefined) {
|
|||||||
translate: translateFragment,
|
translate: translateFragment,
|
||||||
|
|
||||||
// this can be used to prevent race conditions
|
// this can be used to prevent race conditions
|
||||||
getReadyState: function() { return gReadyState; }
|
getReadyState: function() { return gReadyState; },
|
||||||
|
ready: function(callback) {
|
||||||
|
if (!callback) {
|
||||||
|
return;
|
||||||
|
} else if (gReadyState == 'complete' || gReadyState == 'interactive') {
|
||||||
|
window.setTimeout(callback);
|
||||||
|
} else if (document.addEventListener) {
|
||||||
|
document.addEventListener('localized', callback);
|
||||||
|
} else if (document.attachEvent) {
|
||||||
|
document.documentElement.attachEvent('onpropertychange', function(e) {
|
||||||
|
if (e.propertyName === 'localized') {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}) (window, document);
|
}) (window, document);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user