Browse Source

Merge pull request #5826 from Rob--W/webL10n-update-march-2015

WebL10n update (March 2015)
Tim van der Meij 10 years ago
parent
commit
6a77a97785
  1. 203
      external/webL10n/l10n.js

203
external/webL10n/l10n.js vendored

@ -22,11 +22,12 @@
/* /*
Additional modifications for PDF.js project: Additional modifications for PDF.js project:
- Disables language initialization on page loading; - Disables language initialization on page loading;
- Removes consoleWarn and consoleLog and use console.log/warn directly. - Removes console.warn and console.log and use console.log/warn directly.
- Removes window._ assignment. - Removes window._ assignment.
- Remove compatibility code for OldIE.
*/ */
/*jshint browser: true, devel: true, globalstrict: true */ /*jshint browser: true, devel: true, es5: true, globalstrict: true */
'use strict'; 'use strict';
document.webL10n = (function(window, document, undefined) { document.webL10n = (function(window, document, undefined) {
@ -98,14 +99,14 @@ document.webL10n = (function(window, document, undefined) {
document.dispatchEvent(evtObject); document.dispatchEvent(evtObject);
} }
function xhrLoadText(url, onSuccess, onFailure, asynchronous) { function xhrLoadText(url, onSuccess, onFailure) {
onSuccess = onSuccess || function _onSuccess(data) {}; onSuccess = onSuccess || function _onSuccess(data) {};
onFailure = onFailure || function _onFailure() { onFailure = onFailure || function _onFailure() {
console.warn(url + ' not found.'); console.warn(url + ' not found.');
}; };
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', url, asynchronous); xhr.open('GET', url, gAsyncResourceLoading);
if (xhr.overrideMimeType) { if (xhr.overrideMimeType) {
xhr.overrideMimeType('text/plain; charset=utf-8'); xhr.overrideMimeType('text/plain; charset=utf-8');
} }
@ -174,8 +175,10 @@ document.webL10n = (function(window, document, undefined) {
} }
// parse *.properties text data into an l10n dictionary // parse *.properties text data into an l10n dictionary
function parseProperties(text) { // If gAsyncResourceLoading is false, then the callback will be called
var dictionary = []; // synchronously. Otherwise it is called asynchronously.
function parseProperties(text, parsedPropertiesCallback) {
var dictionary = {};
// token expressions // token expressions
var reBlank = /^\s*|\s*$/; var reBlank = /^\s*|\s*$/;
@ -185,57 +188,69 @@ document.webL10n = (function(window, document, undefined) {
var reSplit = /^([^=\s]*)\s*=\s*(.+)$/; // TODO: escape EOLs with '\' var reSplit = /^([^=\s]*)\s*=\s*(.+)$/; // TODO: escape EOLs with '\'
// parse the *.properties file into an associative array // parse the *.properties file into an associative array
function parseRawLines(rawText, extendedSyntax) { function parseRawLines(rawText, extendedSyntax, parsedRawLinesCallback) {
var entries = rawText.replace(reBlank, '').split(/[\r\n]+/); var entries = rawText.replace(reBlank, '').split(/[\r\n]+/);
var currentLang = '*'; var currentLang = '*';
var genericLang = lang.split('-', 1)[0]; var genericLang = lang.split('-', 1)[0];
var skipLang = false; var skipLang = false;
var match = ''; var match = '';
for (var i = 0; i < entries.length; i++) { function nextEntry() {
var line = entries[i]; // Use infinite loop instead of recursion to avoid reaching the
// maximum recursion limit for content with many lines.
while (true) {
if (!entries.length) {
parsedRawLinesCallback();
return;
}
var line = entries.shift();
// comment or blank line? // comment or blank line?
if (reComment.test(line)) if (reComment.test(line))
continue; continue;
// the extended syntax supports [lang] sections and @import rules // the extended syntax supports [lang] sections and @import rules
if (extendedSyntax) { if (extendedSyntax) {
if (reSection.test(line)) { // section start?
match = reSection.exec(line); match = reSection.exec(line);
// RFC 4646, section 4.4, "All comparisons MUST be performed if (match) { // section start?
// in a case-insensitive manner." // RFC 4646, section 4.4, "All comparisons MUST be performed
currentLang = match[1].toLowerCase(); // in a case-insensitive manner."
skipLang = (currentLang !== '*') &&
(currentLang !== lang) && (currentLang !== genericLang); currentLang = match[1].toLowerCase();
continue; skipLang = (currentLang !== '*') &&
} else if (skipLang) { (currentLang !== lang) && (currentLang !== genericLang);
continue; continue;
} } else if (skipLang) {
if (reImport.test(line)) { // @import rule? continue;
}
match = reImport.exec(line); match = reImport.exec(line);
loadImport(baseURL + match[1]); // load the resource synchronously if (match) { // @import rule?
loadImport(baseURL + match[1], nextEntry);
return;
}
} }
}
// 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]);
}
} }
} }
nextEntry();
} }
// import another *.properties file // import another *.properties file
function loadImport(url) { function loadImport(url, callback) {
xhrLoadText(url, function(content) { xhrLoadText(url, function(content) {
parseRawLines(content, false); // don't allow recursive imports parseRawLines(content, false, callback); // don't allow recursive imports
}, null, false); // load synchronously }, null);
} }
// fill the dictionary // fill the dictionary
parseRawLines(text, true); parseRawLines(text, true, function() {
return dictionary; parsedPropertiesCallback(dictionary);
});
} }
// load and parse l10n data (warning: global variables are used here) // load and parse l10n data (warning: global variables are used here)
@ -243,29 +258,30 @@ document.webL10n = (function(window, document, undefined) {
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
var data = parseProperties(response); parseProperties(response, function(data) {
// find attribute descriptions, if any // find attribute descriptions, if any
for (var key in data) { for (var key in data) {
var id, prop, index = key.lastIndexOf('.'); var id, prop, index = key.lastIndexOf('.');
if (index > 0) { // an attribute has been specified if (index > 0) { // an attribute has been specified
id = key.substring(0, index); id = key.substring(0, index);
prop = key.substr(index + 1); prop = key.substr(index + 1);
} else { // no attribute: assuming text content by default } else { // no attribute: assuming text content by default
id = key; id = key;
prop = gTextProp; prop = gTextProp;
} }
if (!gL10nData[id]) { if (!gL10nData[id]) {
gL10nData[id] = {}; gL10nData[id] = {};
}
gL10nData[id][prop] = data[key];
} }
gL10nData[id][prop] = data[key];
}
// trigger callback // trigger callback
if (successCallback) { if (successCallback) {
successCallback(); successCallback();
} }
}, failureCallback, gAsyncResourceLoading); });
}, failureCallback);
} }
// load and parse all resources for the specified locale // load and parse all resources for the specified locale
@ -328,24 +344,23 @@ document.webL10n = (function(window, document, undefined) {
// 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; // Note: If |gAsyncResourceLoading| is false, then the following callbacks
// are synchronously called.
this.load = function(lang, callback) { this.load = function(lang, callback) {
var applied = lang;
parseResource(href, lang, callback, function() { parseResource(href, lang, callback, function() {
console.warn(href + ' not found.'); console.warn(href + ' not found.');
applied = ''; // lang not found, used default resource instead
console.warn('"' + lang + '" resource not found');
gLanguage = '';
// Resource not loaded, but we still need to call the callback.
callback();
}); });
return applied; // return lang if found, an empty string if not found
}; };
} }
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); resource.load(lang, onResourceLoaded);
if (rv != lang) { // lang not found, used default resource instead
console.warn('"' + lang + '" resource not found');
gLanguage = '';
}
} }
} }
@ -861,28 +876,17 @@ document.webL10n = (function(window, document, undefined) {
// replace {{arguments}} with their values // replace {{arguments}} with their values
function substArguments(str, args, key) { function substArguments(str, args, key) {
var reArgs = /\{\{\s*(.+?)\s*\}\}/; var reArgs = /\{\{\s*(.+?)\s*\}\}/g;
var match = reArgs.exec(str); return str.replace(reArgs, function(matched_text, arg) {
while (match) {
if (!match || match.length < 2)
return str; // argument key not found
var arg = match[1];
var sub = '';
if (args && arg in args) { if (args && arg in args) {
sub = args[arg]; return args[arg];
} else if (arg in gL10nData) {
sub = gL10nData[arg][gTextProp];
} else {
console.log('argument {{' + arg + '}} for #' + key + ' is undefined.');
return str;
} }
if (arg in gL10nData) {
str = str.substring(0, match.index) + sub + return gL10nData[arg];
str.substr(match.index + match[0].length); }
match = reArgs.exec(str); console.log('argument {{' + arg + '}} for #' + key + ' is undefined.');
} return matched_text;
return str; });
} }
// translate an HTML element // translate an HTML element
@ -962,7 +966,6 @@ document.webL10n = (function(window, document, undefined) {
translateElement(element); translateElement(element);
} }
// cross-browser API (sorry, oldIE doesn't support getters & setters)
return { return {
// get a localized string // get a localized string
get: function(key, args, fallbackString) { get: function(key, args, fallbackString) {
@ -990,17 +993,20 @@ document.webL10n = (function(window, document, undefined) {
// get|set the document language // get|set the document language
getLanguage: function() { return gLanguage; }, getLanguage: function() { return gLanguage; },
setLanguage: function(lang) { loadLocale(lang, translateFragment); }, setLanguage: function(lang, callback) {
loadLocale(lang, function() {
if (callback)
callback();
translateFragment();
});
},
// get the direction (ltr|rtl) of the current language // get the direction (ltr|rtl) of the current language
getDirection: function() { getDirection: function() {
// http://www.w3.org/International/questions/qa-scripts // http://www.w3.org/International/questions/qa-scripts
// Arabic, Hebrew, Farsi, Pashto, Urdu // Arabic, Hebrew, Farsi, Pashto, Urdu
var rtlList = ['ar', 'he', 'fa', 'ps', 'ur']; var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
var shortCode = gLanguage.split('-', 1)[0];
// use the short language code for "full" codes like 'ar-sa' (issue 5440)
var shortCode = gLanguage.split('-')[0];
return (rtlList.indexOf(shortCode) >= 0) ? 'rtl' : 'ltr'; return (rtlList.indexOf(shortCode) >= 0) ? 'rtl' : 'ltr';
}, },
@ -1013,14 +1019,13 @@ document.webL10n = (function(window, document, undefined) {
if (!callback) { if (!callback) {
return; return;
} else if (gReadyState == 'complete' || gReadyState == 'interactive') { } else if (gReadyState == 'complete' || gReadyState == 'interactive') {
window.setTimeout(callback); window.setTimeout(function() {
callback();
});
} else if (document.addEventListener) { } else if (document.addEventListener) {
document.addEventListener('localized', callback); document.addEventListener('localized', function once() {
} else if (document.attachEvent) { document.removeEventListener('localized', once);
document.documentElement.attachEvent('onpropertychange', function(e) { callback();
if (e.propertyName === 'localized') {
callback();
}
}); });
} }
} }

Loading…
Cancel
Save