MagicMirror/js/translator.js

150 lines
4.8 KiB
JavaScript
Raw Normal View History

2020-05-03 18:59:26 +02:00
/* global translations */
2020-04-21 07:36:18 +02:00
/* MagicMirror²
2016-04-21 01:03:26 +02:00
* Translator (l10n)
*
2020-04-28 23:05:28 +02:00
* By Christopher Fenner https://github.com/CFenner
2016-04-21 01:03:26 +02:00
* MIT Licensed.
*/
2021-07-14 15:06:23 +02:00
const Translator = (function () {
/**
2016-05-11 12:38:41 +02:00
* Load a JSON file via XHR.
*
* @param {string} file Path of the file we want to load.
* @returns {Promise<object>} the translations in the specified file
2016-05-11 12:38:41 +02:00
*/
async function loadJSON(file) {
2021-03-25 17:29:27 +01:00
const xhr = new XMLHttpRequest();
return new Promise(function (resolve, reject) {
xhr.overrideMimeType("application/json");
xhr.open("GET", file, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// needs error handler try/catch at least
let fileinfo = null;
try {
fileinfo = JSON.parse(xhr.responseText);
} catch (exception) {
// nothing here, but don't die
Log.error(" loading json file =" + file + " failed");
}
resolve(fileinfo);
}
};
xhr.send(null);
});
2016-05-11 12:38:41 +02:00
}
2016-04-21 01:03:26 +02:00
return {
2016-05-11 12:38:41 +02:00
coreTranslations: {},
coreTranslationsFallback: {},
2016-04-21 01:03:26 +02:00
translations: {},
2016-05-11 12:38:41 +02:00
translationsFallback: {},
2020-07-27 14:26:01 +02:00
/**
2016-04-21 01:03:26 +02:00
* Load a translation for a given key for a given module.
*
* @param {Module} module The module to load the translation for.
2020-07-27 14:26:01 +02:00
* @param {string} key The key of the text to translate.
* @param {object} variables The variables to use within the translation template (optional)
* @returns {string} the translated key
2016-04-21 01:03:26 +02:00
*/
translate: function (module, key, variables) {
variables = variables || {}; // Empty object by default
/**
* Combines template and variables like:
* template: "Please wait for {timeToWait} before continuing with {work}."
* variables: {timeToWait: "2 hours", work: "painting"}
* to: "Please wait for 2 hours before continuing with painting."
*
2020-07-27 14:26:01 +02:00
* @param {string} template Text with placeholder
* @param {object} variables Variables for the placeholder
* @returns {string} the template filled with the variables
*/
function createStringFromTemplate(template, variables) {
if (Object.prototype.toString.call(template) !== "[object String]") {
return template;
}
if (variables.fallback && !template.match(new RegExp("{.+}"))) {
template = variables.fallback;
}
return template.replace(new RegExp("{([^}]+)}", "g"), function (_unused, varName) {
return varName in variables ? variables[varName] : "{" + varName + "}";
});
}
2016-05-11 12:38:41 +02:00
if (this.translations[module.name] && key in this.translations[module.name]) {
2016-05-11 12:38:41 +02:00
// Log.log("Got translation for " + key + " from module translation: ");
return createStringFromTemplate(this.translations[module.name][key], variables);
2016-04-21 01:03:26 +02:00
}
2016-05-11 12:38:41 +02:00
if (key in this.coreTranslations) {
// Log.log("Got translation for " + key + " from core translation.");
return createStringFromTemplate(this.coreTranslations[key], variables);
2016-05-11 12:38:41 +02:00
}
if (this.translationsFallback[module.name] && key in this.translationsFallback[module.name]) {
// Log.log("Got translation for " + key + " from module translation fallback.");
return createStringFromTemplate(this.translationsFallback[module.name][key], variables);
2016-05-11 12:38:41 +02:00
}
if (key in this.coreTranslationsFallback) {
// Log.log("Got translation for " + key + " from core translation fallback.");
return createStringFromTemplate(this.coreTranslationsFallback[key], variables);
2016-05-11 12:38:41 +02:00
}
return key;
2016-04-21 01:03:26 +02:00
},
2019-06-04 09:33:53 +02:00
2020-07-27 14:26:01 +02:00
/**
2016-04-21 01:03:26 +02:00
* Load a translation file (json) and remember the data.
*
* @param {Module} module The module to load the translation file for.
2020-07-27 14:26:01 +02:00
* @param {string} file Path of the file we want to load.
* @param {boolean} isFallback Flag to indicate fallback translations.
2016-04-21 01:03:26 +02:00
*/
async load(module, file, isFallback) {
Log.log(`${module.name} - Load translation${isFallback ? " fallback" : ""}: ${file}`);
2021-01-29 22:34:12 +01:00
if (this.translationsFallback[module.name]) {
return;
2016-05-11 12:38:41 +02:00
}
const json = await loadJSON(module.file(file));
const property = isFallback ? "translationsFallback" : "translations";
this[property][module.name] = json;
2016-04-21 01:03:26 +02:00
},
2016-05-11 12:38:41 +02:00
2020-07-27 14:26:01 +02:00
/**
2016-05-11 12:38:41 +02:00
* Load the core translations.
2016-04-21 01:03:26 +02:00
*
2020-07-27 14:26:01 +02:00
* @param {string} lang The language identifier of the core language.
2016-04-21 01:03:26 +02:00
*/
loadCoreTranslations: async function (lang) {
2016-05-11 12:38:41 +02:00
if (lang in translations) {
Log.log("Loading core translation file: " + translations[lang]);
this.coreTranslations = await loadJSON(translations[lang]);
2016-05-11 12:38:41 +02:00
} else {
Log.log("Configured language not found in core translations.");
}
await this.loadCoreTranslationsFallback();
2016-05-11 12:38:41 +02:00
},
2020-07-27 14:26:01 +02:00
/**
* Load the core translations' fallback.
2016-05-11 12:38:41 +02:00
* The first language defined in translations.js will be used.
*/
loadCoreTranslationsFallback: async function () {
2021-07-02 17:24:29 +02:00
let first = Object.keys(translations)[0];
if (first) {
2018-02-13 07:17:46 +01:00
Log.log("Loading core translation fallback file: " + translations[first]);
this.coreTranslationsFallback = await loadJSON(translations[first]);
}
}
2016-04-21 01:03:26 +02:00
};
})();
2021-07-14 15:06:23 +02:00
window.Translator = Translator;