diff --git a/CHANGELOG.md b/CHANGELOG.md index 5374f6af49..fb30e58c88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,6 @@ _This release is scheduled to be released on 2023-04-01._ - Update dates in Calendar widgets every minute - Cleanup jest coverage for patches - Update `stylelint` dependencies, switch to `stylelint-config-standard` and handle `stylelint` issues -- Convert lots of callbacks to async/await - Fixed Open-Meteo wind speed units ### Fixed diff --git a/js/loader.js b/js/loader.js index d48188bce4..70ed32c5fe 100644 --- a/js/loader.js +++ b/js/loader.js @@ -160,7 +160,7 @@ const Loader = (function () { Log.log("Scripts loaded for: " + module.name); mObj.loadStyles(function () { Log.log("Styles loaded for: " + module.name); - mObj.loadTranslations().then(() => { + mObj.loadTranslations(function () { Log.log("Translations loaded for: " + module.name); moduleObjects.push(mObj); callback(); diff --git a/js/main.js b/js/main.js index d310d3cab5..3eed494bff 100644 --- a/js/main.js +++ b/js/main.js @@ -485,7 +485,8 @@ const MM = (function () { Log.setLogLevel(config.logLevel); - Translator.loadCoreTranslations(config.language).then(() => Loader.loadModules()); + Translator.loadCoreTranslations(config.language); + Loader.loadModules(); }, /** diff --git a/js/module.js b/js/module.js index 0c5445c3fc..6d15452994 100644 --- a/js/module.js +++ b/js/module.js @@ -302,8 +302,10 @@ const Module = Class.extend({ /** * Load all translations. + * + * @param {Function} callback Function called when done. */ - async loadTranslations() { + loadTranslations(callback) { const translations = this.getTranslations() || {}; const language = config.language.toLowerCase(); @@ -311,6 +313,7 @@ const Module = Class.extend({ const fallbackLanguage = languages[0]; if (languages.length === 0) { + callback(); return; } @@ -318,14 +321,17 @@ const Module = Class.extend({ const translationsFallbackFile = translations[fallbackLanguage]; if (!translationFile) { - return Translator.load(this, translationsFallbackFile, true); + Translator.load(this, translationsFallbackFile, true, callback); + return; } - await Translator.load(this, translationFile, false); - - if (translationFile !== translationsFallbackFile) { - return Translator.load(this, translationsFallbackFile, true); - } + Translator.load(this, translationFile, false, () => { + if (translationFile !== translationsFallbackFile) { + Translator.load(this, translationsFallbackFile, true, callback); + } else { + callback(); + } + }); }, /** diff --git a/js/translator.js b/js/translator.js index 104f2766eb..77d4b8f0da 100644 --- a/js/translator.js +++ b/js/translator.js @@ -11,28 +11,26 @@ const Translator = (function () { * Load a JSON file via XHR. * * @param {string} file Path of the file we want to load. - * @returns {Promise} the translations in the specified file + * @param {Function} callback Function called when done. */ - async function loadJSON(file) { + function loadJSON(file, callback) { 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.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"); } - }; - xhr.send(null); - }); + callback(fileinfo); + } + }; + xhr.send(null); } return { @@ -50,7 +48,7 @@ const Translator = (function () { * @returns {string} the translated key */ translate: function (module, key, variables) { - variables = variables || {}; // Empty object by default + variables = variables || {}; //Empty object by default /** * Combines template and variables like: @@ -103,17 +101,21 @@ const Translator = (function () { * @param {Module} module The module to load the translation file for. * @param {string} file Path of the file we want to load. * @param {boolean} isFallback Flag to indicate fallback translations. + * @param {Function} callback Function called when done. */ - async load(module, file, isFallback) { + load(module, file, isFallback, callback) { Log.log(`${module.name} - Load translation${isFallback ? " fallback" : ""}: ${file}`); if (this.translationsFallback[module.name]) { + callback(); return; } - const json = await loadJSON(module.file(file)); - const property = isFallback ? "translationsFallback" : "translations"; - this[property][module.name] = json; + loadJSON(module.file(file), (json) => { + const property = isFallback ? "translationsFallback" : "translations"; + this[property][module.name] = json; + callback(); + }); }, /** @@ -121,26 +123,30 @@ const Translator = (function () { * * @param {string} lang The language identifier of the core language. */ - loadCoreTranslations: async function (lang) { + loadCoreTranslations: function (lang) { if (lang in translations) { Log.log("Loading core translation file: " + translations[lang]); - this.coreTranslations = await loadJSON(translations[lang]); + loadJSON(translations[lang], (translations) => { + this.coreTranslations = translations; + }); } else { Log.log("Configured language not found in core translations."); } - await this.loadCoreTranslationsFallback(); + this.loadCoreTranslationsFallback(); }, /** - * Load the core translations' fallback. + * Load the core translations fallback. * The first language defined in translations.js will be used. */ - loadCoreTranslationsFallback: async function () { + loadCoreTranslationsFallback: function () { let first = Object.keys(translations)[0]; if (first) { Log.log("Loading core translation fallback file: " + translations[first]); - this.coreTranslationsFallback = await loadJSON(translations[first]); + loadJSON(translations[first], (translations) => { + this.coreTranslationsFallback = translations; + }); } } }; diff --git a/tests/e2e/translations_spec.js b/tests/e2e/translations_spec.js index f389f9a415..4d2d1c1e9d 100644 --- a/tests/e2e/translations_spec.js +++ b/tests/e2e/translations_spec.js @@ -21,8 +21,8 @@ describe("Translations", () => { server = app.listen(3000); }); - afterAll(async () => { - await server.close(); + afterAll(() => { + server.close(); }); it("should have a translation file in the specified path", () => { @@ -48,15 +48,17 @@ describe("Translations", () => { dom.window.onload = async () => { const { Translator, Module, config } = dom.window; config.language = "en"; - Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); + Translator.load = sinon.stub().callsFake((_m, _f, _fb, callback) => callback()); Module.register("name", { getTranslations: () => translations }); const MMM = Module.create("name"); - await MMM.loadTranslations(); + const loaded = sinon.stub(); + MMM.loadTranslations(loaded); + expect(loaded.callCount).toBe(1); expect(Translator.load.args.length).toBe(1); - expect(Translator.load.calledWith(MMM, "translations/en.json", false)).toBe(true); + expect(Translator.load.calledWith(MMM, "translations/en.json", false, sinon.match.func)).toBe(true); done(); }; @@ -65,16 +67,18 @@ describe("Translations", () => { it("should load translation + fallback file", (done) => { dom.window.onload = async () => { const { Translator, Module } = dom.window; - Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); + Translator.load = sinon.stub().callsFake((_m, _f, _fb, callback) => callback()); Module.register("name", { getTranslations: () => translations }); const MMM = Module.create("name"); - await MMM.loadTranslations(); + const loaded = sinon.stub(); + MMM.loadTranslations(loaded); + expect(loaded.callCount).toBe(1); expect(Translator.load.args.length).toBe(2); - expect(Translator.load.calledWith(MMM, "translations/de.json", false)).toBe(true); - expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true); + expect(Translator.load.calledWith(MMM, "translations/de.json", false, sinon.match.func)).toBe(true); + expect(Translator.load.calledWith(MMM, "translations/en.json", true, sinon.match.func)).toBe(true); done(); }; @@ -84,15 +88,17 @@ describe("Translations", () => { dom.window.onload = async () => { const { Translator, Module, config } = dom.window; config.language = "--"; - Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); + Translator.load = sinon.stub().callsFake((_m, _f, _fb, callback) => callback()); Module.register("name", { getTranslations: () => translations }); const MMM = Module.create("name"); - await MMM.loadTranslations(); + const loaded = sinon.stub(); + MMM.loadTranslations(loaded); + expect(loaded.callCount).toBe(1); expect(Translator.load.args.length).toBe(1); - expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true); + expect(Translator.load.calledWith(MMM, "translations/en.json", true, sinon.match.func)).toBe(true); done(); }; @@ -106,8 +112,10 @@ describe("Translations", () => { Module.register("name", {}); const MMM = Module.create("name"); - await MMM.loadTranslations(); + const loaded = sinon.stub(); + MMM.loadTranslations(loaded); + expect(loaded.callCount).toBe(1); expect(Translator.load.callCount).toBe(0); done(); @@ -130,13 +138,14 @@ describe("Translations", () => {