Merge branch 'develop' into electron11

This commit is contained in:
Karsten Hassel 2021-01-30 22:49:33 +01:00
commit e322be2624
6 changed files with 231 additions and 38 deletions

View File

@ -27,6 +27,7 @@ _This release is scheduled to be released on 2021-04-01._
- Converted newsfeed module to use templates.
- Update documentation and help screen about invalid config files.
- Moving weather provider specific code and configuration into each provider and making hourly part of the interface.
- Bump electron to v11
### Removed
@ -41,6 +42,7 @@ _This release is scheduled to be released on 2021-04-01._
- Fix Issue with weather forecast icons unit tests with different timezones (#2221)
- Fix issue with unencoded characters in translated strings when using nunjuck template (`Loading …` as an example)
- Fix socket.io backward compatibility with socket v2 clients
- 3rd party module language loading if language is English
## [2.14.0] - 2021-01-01

View File

@ -311,33 +311,31 @@ var Module = Class.extend({
*
* @param {Function} callback Function called when done.
*/
loadTranslations: function (callback) {
var self = this;
var translations = this.getTranslations();
var lang = config.language.toLowerCase();
loadTranslations(callback) {
const translations = this.getTranslations() || {};
const language = config.language.toLowerCase();
// The variable `first` will contain the first
// defined translation after the following line.
for (var first in translations) {
break;
const languages = Object.keys(translations);
const fallbackLanguage = languages[0];
if (languages.length === 0) {
return callback();
}
if (translations) {
var translationFile = translations[lang] || undefined;
var translationsFallbackFile = translations[first];
const translationFile = translations[language];
const translationsFallbackFile = translations[fallbackLanguage];
// If a translation file is set, load it and then also load the fallback translation file.
// Otherwise only load the fallback translation file.
if (translationFile !== undefined && translationFile !== translationsFallbackFile) {
Translator.load(self, translationFile, false, function () {
Translator.load(self, translationsFallbackFile, true, callback);
});
if (!translationFile) {
return Translator.load(this, translationsFallbackFile, true, callback);
}
Translator.load(this, translationFile, false, () => {
if (translationFile !== translationsFallbackFile) {
Translator.load(this, translationsFallbackFile, true, callback);
} else {
Translator.load(self, translationsFallbackFile, true, callback);
callback();
}
} else {
callback();
}
});
},
/**

View File

@ -103,26 +103,18 @@ var Translator = (function () {
* @param {boolean} isFallback Flag to indicate fallback translations.
* @param {Function} callback Function called when done.
*/
load: function (module, file, isFallback, callback) {
if (!isFallback) {
Log.log(module.name + " - Load translation: " + file);
} else {
Log.log(module.name + " - Load translation fallback: " + file);
load(module, file, isFallback, callback) {
Log.log(`${module.name} - Load translation${isFallback && " fallback"}: ${file}`);
if (this.translationsFallback[module.name]) {
return callback();
}
var self = this;
if (!this.translationsFallback[module.name]) {
loadJSON(module.file(file), function (json) {
if (!isFallback) {
self.translations[module.name] = json;
} else {
self.translationsFallback[module.name] = json;
}
callback();
});
} else {
loadJSON(module.file(file), (json) => {
const property = isFallback ? "translationsFallback" : "translations";
this[property][module.name] = json;
callback();
}
});
},
/**

108
package-lock.json generated
View File

@ -382,6 +382,41 @@
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
"integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ=="
},
"@sinonjs/commons": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz",
"integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
}
},
"@sinonjs/fake-timers": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
"integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.0"
}
},
"@sinonjs/samsam": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz",
"integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.6.0",
"lodash.get": "^4.4.2",
"type-detect": "^4.0.8"
}
},
"@sinonjs/text-encoding": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz",
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
"@stylelint/postcss-css-in-js": {
"version": "0.37.2",
"resolved": "https://registry.npmjs.org/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz",
@ -3898,6 +3933,12 @@
"verror": "1.10.0"
}
},
"just-extend": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz",
"integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==",
"dev": true
},
"keyv": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
@ -4013,6 +4054,12 @@
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
"dev": true
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
"dev": true
},
"lodash.isobject": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
@ -4537,6 +4584,36 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"nise": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz",
"integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.0",
"@sinonjs/fake-timers": "^6.0.0",
"@sinonjs/text-encoding": "^0.7.1",
"just-extend": "^4.0.2",
"path-to-regexp": "^1.7.0"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"dev": true
},
"path-to-regexp": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"dev": true,
"requires": {
"isarray": "0.0.1"
}
}
}
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
@ -5926,6 +6003,37 @@
}
}
},
"sinon": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz",
"integrity": "sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.8.1",
"@sinonjs/fake-timers": "^6.0.1",
"@sinonjs/samsam": "^5.3.1",
"diff": "^4.0.2",
"nise": "^4.0.4",
"supports-color": "^7.1.0"
},
"dependencies": {
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",

View File

@ -58,6 +58,7 @@
"nyc": "^15.1.0",
"prettier": "^2.2.1",
"pretty-quick": "^3.1.0",
"sinon": "^9.2.4",
"spectron": "^13.0.0",
"stylelint": "^13.8.0",
"stylelint-config-prettier": "^8.0.2",

View File

@ -7,6 +7,7 @@ const translations = require("../../translations/translations.js");
const helmet = require("helmet");
const { JSDOM } = require("jsdom");
const express = require("express");
const sinon = require("sinon");
describe("Translations", function () {
let server;
@ -34,6 +35,97 @@ describe("Translations", function () {
}
});
describe("loadTranslations", () => {
let dom;
beforeEach(() => {
dom = new JSDOM(
`<script>var Translator = {}; var Log = {log: function(){}}; var config = {language: 'de'};</script>\
<script src="file://${path.join(__dirname, "..", "..", "js", "class.js")}"></script>\
<script src="file://${path.join(__dirname, "..", "..", "js", "module.js")}"></script>`,
{ runScripts: "dangerously", resources: "usable" }
);
});
it("should load translation file", (done) => {
dom.window.onload = async function () {
const { Translator, Module, config } = dom.window;
config.language = "en";
Translator.load = sinon.stub().callsFake((_m, _f, _fb, callback) => callback());
Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");
const loaded = sinon.stub();
MMM.loadTranslations(loaded);
expect(loaded.callCount).to.equal(1);
expect(Translator.load.args.length).to.equal(1);
expect(Translator.load.calledWith(MMM, "translations/en.json", false, sinon.match.func)).to.be.true;
done();
};
});
it("should load translation + fallback file", (done) => {
dom.window.onload = async function () {
const { Translator, Module } = dom.window;
Translator.load = sinon.stub().callsFake((_m, _f, _fb, callback) => callback());
Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");
const loaded = sinon.stub();
MMM.loadTranslations(loaded);
expect(loaded.callCount).to.equal(1);
expect(Translator.load.args.length).to.equal(2);
expect(Translator.load.calledWith(MMM, "translations/de.json", false, sinon.match.func)).to.be.true;
expect(Translator.load.calledWith(MMM, "translations/en.json", true, sinon.match.func)).to.be.true;
done();
};
});
it("should load translation fallback file", (done) => {
dom.window.onload = async function () {
const { Translator, Module, config } = dom.window;
config.language = "--";
Translator.load = sinon.stub().callsFake((_m, _f, _fb, callback) => callback());
Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");
const loaded = sinon.stub();
MMM.loadTranslations(loaded);
expect(loaded.callCount).to.equal(1);
expect(Translator.load.args.length).to.equal(1);
expect(Translator.load.calledWith(MMM, "translations/en.json", true, sinon.match.func)).to.be.true;
done();
};
});
it("should load no file", (done) => {
dom.window.onload = async function () {
const { Translator, Module } = dom.window;
Translator.load = sinon.stub();
Module.register("name", {});
const MMM = Module.create("name");
const loaded = sinon.stub();
MMM.loadTranslations(loaded);
expect(loaded.callCount).to.equal(1);
expect(Translator.load.callCount).to.equal(0);
done();
};
});
});
const mmm = {
name: "TranslationTest",
file(file) {