libreoffice-online/browser/js/l10n.js
Ashod Nakashian 7d2f736084 browser: catch failure to get localization files
When we fail to download the localizaion javascript
file, for whatever reason, we end up failing to load
the document. This is far from ideal.
Instead, we simply log the error and move on.
The end result in such a failure scenario is that
the document loads, but the UI is only available
in English.

Change-Id: I5d29ff68870d0cd84d86658ccfd4e3185cc62562
Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2023-05-03 06:52:25 -04:00

290 lines
7.9 KiB
JavaScript

/*
* l10n.js
* 2016-05-17
*
* By Eli Grey, http://eligrey.com
* Licensed under the MIT License
* See https://github.com/eligrey/l10n.js/blob/master/LICENSE.md
*/
/*global XMLHttpRequest, setTimeout, document, navigator, ActiveXObject*/
/*! @source http://purl.eligrey.com/github/l10n.js/blob/master/l10n.js*/
(function () {
"use strict";
var
undef_type = "undefined"
, string_type = "string"
, nav = {}
, String_ctr = String
, has_own_prop = Object.prototype.hasOwnProperty
, load_queues = {}
, localizations = {}
, FALSE = !1
, TRUE = !0
, browserless = FALSE
// the official format is application/vnd.oftn.l10n+json, though l10n.js will also
// accept application/x-l10n+json and application/l10n+json
, l10n_js_media_type = /^\s*application\/(?:vnd\.oftn\.|x-)?l10n\+json\s*(?:$|;)/i
, XHR
// property minification aids
, $locale = "locale"
, $default_locale = "defaultLocale"
, $to_locale_string = "toLocaleString"
, $to_lowercase = "toLowerCase"
, array_index_of = Array.prototype.indexOf || function (item) {
var
len = this.length
, i = 0
;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
, request_JSON = function (uri) {
if(browserless)
return loadFromDisk(uri);
var req = new XHR(),
data = {};
try {
// sadly, this has to be blocking to allow for a graceful degrading API
req.open("GET", uri, FALSE);
req.send(null);
} catch (e) {
console.log('Localization Error: Unable to get localization data: ' + uri, e);
}
// Status codes can be inconsistent across browsers so we simply try to parse
// the response text and catch any errors. This deals with failed requests as
// well as malformed json files.
try {
data = JSON.parse(req.responseText);
} catch(e) {
// warn about error without stopping execution
setTimeout(function () {
// Error messages are not localized as not to cause an infinite loop
var l10n_err = new Error("Unable to load localization data: " + uri);
l10n_err.name = "Localization Error";
throw l10n_err;
}, 0);
}
return data;
}
, load = String_ctr[$to_locale_string] = function (data) {
// don't handle function.toLocaleString(indentationAmount:Number)
if (arguments.length > 0 && typeof data !== "number") {
if (typeof data === string_type) {
load(request_JSON(data));
} else if (data === FALSE) {
// reset all localizations
localizations = {};
} else {
// Extend current localizations instead of completely overwriting them
var locale, localization, message;
for (locale in data) {
if (has_own_prop.call(data, locale)) {
localization = data[locale];
locale = locale[$to_lowercase]();
if (!(locale in localizations) || localization === FALSE) {
// reset locale if not existing or reset flag is specified
localizations[locale] = {};
}
if (localization === FALSE) {
continue;
}
// URL specified
if (typeof localization === string_type) {
if (String_ctr[$locale][$to_lowercase]().indexOf(locale) === 0) {
localization = request_JSON(localization);
} else {
// queue loading locale if not needed
if (!(locale in load_queues)) {
load_queues[locale] = [];
}
load_queues[locale].push(localization);
continue;
}
}
for (message in localization) {
if (has_own_prop.call(localization, message)) {
localizations[locale][message] = localization[message];
}
}
}
}
}
}
// Return what function.toLocaleString() normally returns
return Function.prototype[$to_locale_string].apply(String_ctr, arguments);
}
, loadFromDisk = String_ctr[$to_locale_string] = function (uri) {
var fs = require('fs');
var read = fs.readFileSync(uri, 'utf8');
return JSON.parse(read);
}
, process_load_queue = function (locale) {
var
queue = load_queues[locale]
, i = 0
, len = queue.length
, localization
;
for (; i < len; i++) {
localization = {};
localization[locale] = request_JSON(queue[i]);
load(localization);
}
delete load_queues[locale];
}
, use_default
, localize = String_ctr.prototype[$to_locale_string] = function () {
var
using_default = use_default
, current_locale = String_ctr[using_default ? $default_locale : $locale]
, parts = current_locale[$to_lowercase]().split("-")
, i = parts.length
, this_val = this.valueOf()
, locale
;
use_default = FALSE;
// Iterate through locales starting at most-specific until a localization is found
do {
locale = parts.slice(0, i).join("-");
// load locale if not loaded
if (locale in load_queues) {
process_load_queue(locale);
}
if (locale in localizations && this_val in localizations[locale]) {
return localizations[locale][this_val];
}
}
while (i--);
if (!using_default && String_ctr[$default_locale]) {
use_default = TRUE;
return localize.call(this_val);
}
return this_val;
}
;
try
{
nav = self.navigator;
}
catch(selfNotFoundException)
{
if(global.nav)
{
nav = global.nav;
}
else
{
var nodeError = "Problem setting nav in L10N. You are most likely running in a non-browser environment like Node." +
"If this is the case, you can resolve this error by setting global.nav to an object which contains a \"language\" field. ";
throw new Error(nodeError);
}
browserless = TRUE;
}
if (!browserless && typeof XMLHttpRequest === undef_type && typeof ActiveXObject !== undef_type) {
var AXO = ActiveXObject;
XHR = function () {
try {
return new AXO("Msxml2.XMLHTTP.6.0");
} catch (xhrEx1) {}
try {
return new AXO("Msxml2.XMLHTTP.3.0");
} catch (xhrEx2) {}
try {
return new AXO("Msxml2.XMLHTTP");
} catch (xhrEx3) {}
throw new Error("XMLHttpRequest not supported by this browser.");
};
} else {
try
{
XHR = XMLHttpRequest;
}
catch(xhrEx4)
{
if(global.XMLHttpRequest) {
XHR = global.XMLHttpRequest;
}
else {
var nodeError = "Problem setting XHR in L10N. You are most likely running in a non-browser environment like Node." +
"If this is the case, you can resolve this error by setting global.XMLHttpRequest to a function which produces XMLHttpRequests. " +
"\nTip: if you are using node, you might want to use the XHR2 package (usage: global.XMLHttpRequest = require('xhr2')";
throw new Error(nodeError);
}
}
}
String_ctr[$default_locale] = String_ctr[$default_locale] || "";
var lang = nav && (nav.language || nav.userLanguage) || "";
String_ctr[$locale] = lang;
document.documentElement.lang = lang;
if (!browserless || typeof document !== undef_type) {
var
elts = document.getElementsByTagName("link")
, i = elts.length
, localization
;
while (i--) {
var
elt = elts[i]
, rel = (elt.getAttribute("rel") || "")[$to_lowercase]().split(/\s+/)
;
if (l10n_js_media_type.test(elt.type)) {
if (array_index_of.call(rel, "localizations") !== -1) {
// multiple localizations
load(elt.getAttribute("href"));
} else if (array_index_of.call(rel, "localization") !== -1) {
// single localization
localization = {};
localization[(elt.getAttribute("hreflang") || "")[$to_lowercase]()] =
elt.getAttribute("href");
load(localization);
}
}
}
}
else
{
if(global.l10NLocalFilePath) {
load(global.l10NLocalFilePath);
}
else {
var nodeError = "Problem loading localization file. You are most likely running in a non-browser environment like Node." +
"If this is the case, you can resolve this error by setting global.l10NLocalFilePath to the path of your localization file. ";
throw new Error(nodeError);
}
}
}());