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