mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-28 12:12:20 +00:00
Finish translation system. #191
This commit is contained in:
parent
32c9f197b1
commit
7a067a0f6e
@ -33,6 +33,7 @@
|
|||||||
<script type="text/javascript" src="vendor/vendor.js"></script>
|
<script type="text/javascript" src="vendor/vendor.js"></script>
|
||||||
<script type="text/javascript" src="modules/default/defaultmodules.js"></script>
|
<script type="text/javascript" src="modules/default/defaultmodules.js"></script>
|
||||||
<script type="text/javascript" src="js/logger.js"></script>
|
<script type="text/javascript" src="js/logger.js"></script>
|
||||||
|
<script type="text/javascript" src="translations/translations.js"></script>
|
||||||
<script type="text/javascript" src="js/translator.js"></script>
|
<script type="text/javascript" src="js/translator.js"></script>
|
||||||
<script type="text/javascript" src="js/class.js"></script>
|
<script type="text/javascript" src="js/class.js"></script>
|
||||||
<script type="text/javascript" src="js/module.js"></script>
|
<script type="text/javascript" src="js/module.js"></script>
|
||||||
|
@ -35,7 +35,7 @@ var Loader = (function() {
|
|||||||
// This is done after all the moduels so we can
|
// This is done after all the moduels so we can
|
||||||
// overwrite all the defined styls.
|
// overwrite all the defined styls.
|
||||||
|
|
||||||
loadFile('css/custom.css', function() {
|
loadFile("css/custom.css", function() {
|
||||||
// custom.css loaded. Start all modules.
|
// custom.css loaded. Start all modules.
|
||||||
startModules();
|
startModules();
|
||||||
});
|
});
|
||||||
|
@ -331,6 +331,7 @@ var MM = (function() {
|
|||||||
init: function() {
|
init: function() {
|
||||||
Log.info("Initializing MagicMirror.");
|
Log.info("Initializing MagicMirror.");
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
Translator.loadCoreTranslations(config.language);
|
||||||
Loader.loadModules();
|
Loader.loadModules();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
24
js/module.js
24
js/module.js
@ -58,7 +58,7 @@ var Module = Class.extend({
|
|||||||
* return Map<String, String> - A map with langKeys and filenames.
|
* return Map<String, String> - A map with langKeys and filenames.
|
||||||
*/
|
*/
|
||||||
getTranslations: function() {
|
getTranslations: function() {
|
||||||
return {};
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
/* getDom()
|
/* getDom()
|
||||||
@ -221,9 +221,25 @@ var Module = Class.extend({
|
|||||||
loadTranslations: function(callback) {
|
loadTranslations: function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var translations = this.getTranslations();
|
var translations = this.getTranslations();
|
||||||
var translationFile = translations && (translations[config.language.toLowerCase()] || translations.en) || undefined;
|
var lang = config.language.toLowerCase();
|
||||||
if(translationFile) {
|
|
||||||
Translator.load(this, translationFile, callback);
|
// The variable `first` will contain the first
|
||||||
|
// defined translation after the following line.
|
||||||
|
for (var first in translations) {break;}
|
||||||
|
|
||||||
|
if (translations) {
|
||||||
|
var translationFile = translations[lang] || undefined;
|
||||||
|
var translationsFallbackFile = translations[first];
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
Translator.load(self, translationFile, false, function() {
|
||||||
|
Translator.load(self, translationsFallbackFile, true, callback);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Translator.load(self, translationsFallbackFile, true, callback);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ var Server = function(config, callback) {
|
|||||||
app.use("/fonts", express.static(path.resolve(__dirname + "/../fonts")));
|
app.use("/fonts", express.static(path.resolve(__dirname + "/../fonts")));
|
||||||
app.use("/modules", express.static(path.resolve(__dirname + "/../modules")));
|
app.use("/modules", express.static(path.resolve(__dirname + "/../modules")));
|
||||||
app.use("/vendor", express.static(path.resolve(__dirname + "/../vendor")));
|
app.use("/vendor", express.static(path.resolve(__dirname + "/../vendor")));
|
||||||
|
app.use("/translations", express.static(path.resolve(__dirname + "/../translations")));
|
||||||
|
|
||||||
app.get("/", function(req, res) {
|
app.get("/", function(req, res) {
|
||||||
res.sendFile(path.resolve(__dirname + "/../index.html"));
|
res.sendFile(path.resolve(__dirname + "/../index.html"));
|
||||||
|
189
js/translator.js
189
js/translator.js
@ -6,8 +6,111 @@
|
|||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
var Translator = (function() {
|
var Translator = (function() {
|
||||||
|
|
||||||
|
/* loadJSON(file, callback)
|
||||||
|
* Load a JSON file via XHR.
|
||||||
|
*
|
||||||
|
* argument file string - Path of the file we want to load.
|
||||||
|
* argument callback function - Function called when done.
|
||||||
|
*/
|
||||||
|
function loadJSON(file, callback) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.overrideMimeType("application/json");
|
||||||
|
xhr.open("GET", file, true);
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
if (xhr.readyState == 4 && xhr.status == "200") {
|
||||||
|
callback(JSON.parse(stripComments(xhr.responseText)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* loadJSON(str, options)
|
||||||
|
* Remove any commenting from a json file so it can be parsed.
|
||||||
|
*
|
||||||
|
* argument str string - The string that contains json with comments.
|
||||||
|
* argument opts function - Strip options.
|
||||||
|
*
|
||||||
|
* return the stripped string.
|
||||||
|
*/
|
||||||
|
function stripComments(str, opts) {
|
||||||
|
// strip comments copied from: https://github.com/sindresorhus/strip-json-comments
|
||||||
|
|
||||||
|
var singleComment = 1;
|
||||||
|
var multiComment = 2;
|
||||||
|
|
||||||
|
function stripWithoutWhitespace() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripWithWhitespace(str, start, end) {
|
||||||
|
return str.slice(start, end).replace(/\S/g, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
|
var currentChar;
|
||||||
|
var nextChar;
|
||||||
|
var insideString = false;
|
||||||
|
var insideComment = false;
|
||||||
|
var offset = 0;
|
||||||
|
var ret = "";
|
||||||
|
var strip = opts.whitespace === false ? stripWithoutWhitespace : stripWithWhitespace;
|
||||||
|
|
||||||
|
for (var i = 0; i < str.length; i++) {
|
||||||
|
currentChar = str[i];
|
||||||
|
nextChar = str[i + 1];
|
||||||
|
|
||||||
|
if (!insideComment && currentChar === "\"") {
|
||||||
|
var escaped = str[i - 1] === "\\" && str[i - 2] !== "\\";
|
||||||
|
if (!escaped) {
|
||||||
|
insideString = !insideString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insideString) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!insideComment && currentChar + nextChar === "//") {
|
||||||
|
ret += str.slice(offset, i);
|
||||||
|
offset = i;
|
||||||
|
insideComment = singleComment;
|
||||||
|
i++;
|
||||||
|
} else if (insideComment === singleComment && currentChar + nextChar === "\r\n") {
|
||||||
|
i++;
|
||||||
|
insideComment = false;
|
||||||
|
ret += strip(str, offset, i);
|
||||||
|
offset = i;
|
||||||
|
continue;
|
||||||
|
} else if (insideComment === singleComment && currentChar === "\n") {
|
||||||
|
insideComment = false;
|
||||||
|
ret += strip(str, offset, i);
|
||||||
|
offset = i;
|
||||||
|
} else if (!insideComment && currentChar + nextChar === "/*") {
|
||||||
|
ret += str.slice(offset, i);
|
||||||
|
offset = i;
|
||||||
|
insideComment = multiComment;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
} else if (insideComment === multiComment && currentChar + nextChar === "*/") {
|
||||||
|
i++;
|
||||||
|
insideComment = false;
|
||||||
|
ret += strip(str, offset, i + 1);
|
||||||
|
offset = i + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret + (insideComment ? strip(str.substr(offset)) : str.substr(offset));
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
coreTranslations: {},
|
||||||
|
coreTranslationsFallback: {},
|
||||||
translations: {},
|
translations: {},
|
||||||
|
translationsFallback: {},
|
||||||
|
|
||||||
/* translate(module, key)
|
/* translate(module, key)
|
||||||
* Load a translation for a given key for a given module.
|
* Load a translation for a given key for a given module.
|
||||||
*
|
*
|
||||||
@ -15,10 +118,28 @@ var Translator = (function() {
|
|||||||
* argument key string - The key of the text to translate.
|
* argument key string - The key of the text to translate.
|
||||||
*/
|
*/
|
||||||
translate: function(module, key) {
|
translate: function(module, key) {
|
||||||
if(this.translations[module.name]) {
|
|
||||||
|
if(this.translations[module.name] && key in this.translations[module.name]) {
|
||||||
|
// Log.log("Got translation for " + key + " from module translation: ");
|
||||||
return this.translations[module.name][key];
|
return this.translations[module.name][key];
|
||||||
}
|
}
|
||||||
return undefined;
|
|
||||||
|
if (key in this.coreTranslations) {
|
||||||
|
// Log.log("Got translation for " + key + " from core translation.");
|
||||||
|
return this.coreTranslations[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.translationsFallback[module.name] && key in this.translationsFallback[module.name]) {
|
||||||
|
// Log.log("Got translation for " + key + " from module translation fallback.");
|
||||||
|
return this.translationsFallback[module.name][key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key in this.coreTranslationsFallback) {
|
||||||
|
// Log.log("Got translation for " + key + " from core translation fallback.");
|
||||||
|
return this.coreTranslationsFallback[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
},
|
},
|
||||||
/* load(module, file, callback)
|
/* load(module, file, callback)
|
||||||
* Load a translation file (json) and remember the data.
|
* Load a translation file (json) and remember the data.
|
||||||
@ -27,33 +148,63 @@ var Translator = (function() {
|
|||||||
* argument file string - Path of the file we want to load.
|
* argument file string - Path of the file we want to load.
|
||||||
* argument callback function - Function called when done.
|
* argument callback function - Function called when done.
|
||||||
*/
|
*/
|
||||||
load: function(module, file, callback) {
|
load: function(module, file, isFallback, callback) {
|
||||||
|
if (!isFallback) {
|
||||||
|
Log.log(module.name + " - Load translation: " + file);
|
||||||
|
} else {
|
||||||
|
Log.log(module.name + " - Load translation fallback: " + file);
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
if(!this.translations[module.name]) {
|
if(!this.translationsFallback[module.name]) {
|
||||||
this._loadJSON(module.file(file), function(json) {
|
loadJSON(module.file(file), function(json) {
|
||||||
|
if (!isFallback) {
|
||||||
self.translations[module.name] = json;
|
self.translations[module.name] = json;
|
||||||
|
} else {
|
||||||
|
self.translationsFallback[module.name] = json;
|
||||||
|
}
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* _loadJSON(file, callback)
|
|
||||||
* Load a JSON file via XHR.
|
/* loadCoreTranslations(lang)
|
||||||
|
* Load the core translations.
|
||||||
*
|
*
|
||||||
* argument file string - Path of the file we want to load.
|
* argument lang String - The language identifier of the core language.
|
||||||
* argument callback function - Function called when done.
|
|
||||||
*/
|
*/
|
||||||
_loadJSON: function(file, callback) {
|
loadCoreTranslations: function(lang) {
|
||||||
var xhr = new XMLHttpRequest();
|
var self = this;
|
||||||
xhr.overrideMimeType("application/json");
|
|
||||||
xhr.open("GET", file, true);
|
if (lang in translations) {
|
||||||
xhr.onreadystatechange = function () {
|
Log.log("Loading core translation file: " + translations[lang]);
|
||||||
if (xhr.readyState == 4 && xhr.status == "200") {
|
loadJSON(translations[lang], function(translations) {
|
||||||
callback(JSON.parse(xhr.responseText));
|
self.coreTranslations = translations;
|
||||||
}
|
});
|
||||||
};
|
} else {
|
||||||
xhr.send(null);
|
Log.log("Configured language not found in core translations.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.loadCoreTranslationsFallback();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* loadCoreTranslationsFallback()
|
||||||
|
* Load the core translations fallback.
|
||||||
|
* The first language defined in translations.js will be used.
|
||||||
|
*/
|
||||||
|
loadCoreTranslationsFallback: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// The variable `first` will contain the first
|
||||||
|
// defined translation after the following line.
|
||||||
|
for (var first in translations) {break;}
|
||||||
|
|
||||||
|
Log.log("Loading core translation fallback file: " + translations[first]);
|
||||||
|
loadJSON(translations[first], function(translations) {
|
||||||
|
self.coreTranslationsFallback = translations;
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -138,6 +138,8 @@ getStyles: function() {
|
|||||||
|
|
||||||
The getTranslations method is called to request translation files that need to be loaded. This method should therefore return a dictionary with the files to load, identified by the country's short name.
|
The getTranslations method is called to request translation files that need to be loaded. This method should therefore return a dictionary with the files to load, identified by the country's short name.
|
||||||
|
|
||||||
|
If the module does not have any module specific translations, the function can just be omitted or return `false`.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
````javascript
|
````javascript
|
||||||
getTranslations: function() {
|
getTranslations: function() {
|
||||||
@ -282,6 +284,13 @@ To show a module, you can call the `show(speed, callback)` method. You can call
|
|||||||
|
|
||||||
The Magic Mirror contains a convenience wrapper for `l18n`. You can use this to automatically serve different translations for your modules based on the user's `language` configuration.
|
The Magic Mirror contains a convenience wrapper for `l18n`. You can use this to automatically serve different translations for your modules based on the user's `language` configuration.
|
||||||
|
|
||||||
|
If no translation is found, a fallback will be used. The fallback sequence is as follows:
|
||||||
|
1. Translation as defined in module translation file of the user's preferred language.
|
||||||
|
2. Translation as defined in core translation file of the user's preferred language.
|
||||||
|
3. Translation as defined in module translation file of the fallback language (the first defined module translation file).
|
||||||
|
4. Translation as defined in core translation file of the fallback language (the first defined core translation file).
|
||||||
|
5. The key (identifier) of the translation.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
````javascript
|
````javascript
|
||||||
this.translate("INFO") //Will return a translated string for the identifier INFO
|
this.translate("INFO") //Will return a translated string for the identifier INFO
|
||||||
@ -294,7 +303,7 @@ this.translate("INFO") //Will return a translated string for the identifier INFO
|
|||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
**Note:** Currently there is no fallback if a translation identifier does not exist in one language. Right now you always have to add all identifier to all your translations even if they are not translated yet (see [#191](https://github.com/MichMich/MagicMirror/issues/191)).
|
**Note:** although comments are officially not supported in JSON files, MagicMirror allows it by stripping the comments before parsing the JSON file. Comments in translation files could help other translators.
|
||||||
|
|
||||||
|
|
||||||
## The Node Helper: node_helper.js
|
## The Node Helper: node_helper.js
|
||||||
|
@ -47,12 +47,10 @@ Module.register("calendar",{
|
|||||||
|
|
||||||
// Define required translations.
|
// Define required translations.
|
||||||
getTranslations: function() {
|
getTranslations: function() {
|
||||||
return {
|
// The translations for the defaut modules are defined in the core translation files.
|
||||||
en: "translations/en.json",
|
// Therefor we can just return false. Otherwise we should have returned a dictionairy.
|
||||||
de: "translations/de.json",
|
// If you're trying to build yiur own module including translations, check out the documentation.
|
||||||
nl: "translations/nl.json",
|
return false;
|
||||||
fr: "translations/fr.json"
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Override start method.
|
// Override start method.
|
||||||
@ -356,4 +354,3 @@ Module.register("calendar",{
|
|||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"TODAY": "Heute"
|
|
||||||
, "TOMORROW": "Morgen"
|
|
||||||
, "RUNNING": "noch"
|
|
||||||
, "LOADING": "Lade Termine …"
|
|
||||||
, "EMPTY": "Keine Termine."
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"TODAY": "Today"
|
|
||||||
, "TOMORROW": "Tomorrow"
|
|
||||||
, "RUNNING": "Ends in"
|
|
||||||
, "LOADING": "Loading events …"
|
|
||||||
, "EMPTY": "No upcoming events."
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"TODAY": "Aujourd'hui"
|
|
||||||
, "TOMORROW": "Demain"
|
|
||||||
, "RUNNING": "Se termine dans"
|
|
||||||
, "LOADING": "Chargement des RDV …"
|
|
||||||
, "EMPTY": "Aucun RDV."
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"TODAY": "Vandaag"
|
|
||||||
, "TOMORROW": "Morgen"
|
|
||||||
, "RUNNING": "Eindigd over"
|
|
||||||
, "LOADING": "Bezig met laden …"
|
|
||||||
, "EMPTY": "Geen geplande afspraken."
|
|
||||||
}
|
|
@ -62,6 +62,14 @@ Module.register("currentweather",{
|
|||||||
return ["weather-icons.css", "currentweather.css"];
|
return ["weather-icons.css", "currentweather.css"];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Define required translations.
|
||||||
|
getTranslations: function() {
|
||||||
|
// The translations for the defaut modules are defined in the core translation files.
|
||||||
|
// Therefor we can just return false. Otherwise we should have returned a dictionairy.
|
||||||
|
// If you're trying to build yiur own module including translations, check out the documentation.
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
// Define start sequence.
|
// Define start sequence.
|
||||||
start: function() {
|
start: function() {
|
||||||
Log.info("Starting module: " + this.name);
|
Log.info("Starting module: " + this.name);
|
||||||
@ -100,7 +108,7 @@ Module.register("currentweather",{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.loaded) {
|
if (!this.loaded) {
|
||||||
wrapper.innerHTML = "Loading weather ...";
|
wrapper.innerHTML = this.translate('LOADING');
|
||||||
wrapper.className = "dimmed light small";
|
wrapper.className = "dimmed light small";
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
@ -118,7 +126,7 @@ Module.register("currentweather",{
|
|||||||
|
|
||||||
if (this.config.showWindDirection) {
|
if (this.config.showWindDirection) {
|
||||||
var windDirection = document.createElement("span");
|
var windDirection = document.createElement("span");
|
||||||
windDirection.innerHTML = " " + this.windDirection;
|
windDirection.innerHTML = " " + this.translate(this.windDirection);
|
||||||
small.appendChild(windDirection);
|
small.appendChild(windDirection);
|
||||||
}
|
}
|
||||||
var spacer = document.createElement("span");
|
var spacer = document.createElement("span");
|
||||||
|
@ -31,6 +31,14 @@ Module.register("newsfeed",{
|
|||||||
return ["moment.js"];
|
return ["moment.js"];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Define required translations.
|
||||||
|
getTranslations: function() {
|
||||||
|
// The translations for the defaut modules are defined in the core translation files.
|
||||||
|
// Therefor we can just return false. Otherwise we should have returned a dictionairy.
|
||||||
|
// If you're trying to build yiur own module including translations, check out the documentation.
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
// Define start sequence.
|
// Define start sequence.
|
||||||
start: function() {
|
start: function() {
|
||||||
Log.info("Starting module: " + this.name);
|
Log.info("Starting module: " + this.name);
|
||||||
@ -100,7 +108,7 @@ Module.register("newsfeed",{
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
wrapper.innerHTML = "Loading news ...";
|
wrapper.innerHTML = this.translate("LOADING");
|
||||||
wrapper.className = "small dimmed";
|
wrapper.className = "small dimmed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,14 @@ Module.register("weatherforecast",{
|
|||||||
return ["weather-icons.css", "weatherforecast.css"];
|
return ["weather-icons.css", "weatherforecast.css"];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Define required translations.
|
||||||
|
getTranslations: function() {
|
||||||
|
// The translations for the defaut modules are defined in the core translation files.
|
||||||
|
// Therefor we can just return false. Otherwise we should have returned a dictionairy.
|
||||||
|
// If you're trying to build yiur own module including translations, check out the documentation.
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
// Define start sequence.
|
// Define start sequence.
|
||||||
start: function() {
|
start: function() {
|
||||||
Log.info("Starting module: " + this.name);
|
Log.info("Starting module: " + this.name);
|
||||||
@ -93,7 +101,7 @@ Module.register("weatherforecast",{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.loaded) {
|
if (!this.loaded) {
|
||||||
wrapper.innerHTML = "Loading weather ...";
|
wrapper.innerHTML = this.translate('LOADING');
|
||||||
wrapper.className = "dimmed light small";
|
wrapper.className = "dimmed light small";
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
27
translations/de.json
Normal file
27
translations/de.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
/* GENERAL */
|
||||||
|
"LOADING": "Lade …",
|
||||||
|
|
||||||
|
/* CALENDAR */
|
||||||
|
"TODAY": "Heute",
|
||||||
|
"TOMORROW": "Morgen",
|
||||||
|
"RUNNING": "noch",
|
||||||
|
"EMPTY": "Keine Termine.",
|
||||||
|
|
||||||
|
/* WEATHER */
|
||||||
|
"N": "N",
|
||||||
|
"NNE": "NNO",
|
||||||
|
"ENE": "ONO",
|
||||||
|
"E": "O",
|
||||||
|
"ESE": "OSO",
|
||||||
|
"SE": "SO",
|
||||||
|
"SSE": "SSO",
|
||||||
|
"S": "S",
|
||||||
|
"SSW": "SSW",
|
||||||
|
"SW": "SW",
|
||||||
|
"WSW": "WSW",
|
||||||
|
"W": "W",
|
||||||
|
"WNW": "WNW",
|
||||||
|
"NW": "NW",
|
||||||
|
"NNW": "NNW"
|
||||||
|
}
|
27
translations/en.json
Normal file
27
translations/en.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
/* GENERAL */
|
||||||
|
"LOADING": "Loading …",
|
||||||
|
|
||||||
|
/* CALENDAR */
|
||||||
|
"TODAY": "Today",
|
||||||
|
"TOMORROW": "Tomorrow",
|
||||||
|
"RUNNING": "Ends in",
|
||||||
|
"EMPTY": "No upcoming events.",
|
||||||
|
|
||||||
|
/* WEATHER */
|
||||||
|
"N": "N",
|
||||||
|
"NNE": "NNE",
|
||||||
|
"ENE": "ENE",
|
||||||
|
"E": "E",
|
||||||
|
"ESE": "ESE",
|
||||||
|
"SE": "SE",
|
||||||
|
"SSE": "SSE",
|
||||||
|
"S": "S",
|
||||||
|
"SSW": "SSW",
|
||||||
|
"SW": "SW",
|
||||||
|
"WSW": "WSW",
|
||||||
|
"W": "W",
|
||||||
|
"WNW": "WNW",
|
||||||
|
"NW": "NW",
|
||||||
|
"NNW": "NNW"
|
||||||
|
}
|
27
translations/fr.json
Normal file
27
translations/fr.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
/* GENERAL */
|
||||||
|
"LOADING": "Chargement …",
|
||||||
|
|
||||||
|
/* CALENDAR */
|
||||||
|
"TODAY": "Aujourd'hui",
|
||||||
|
"TOMORROW": "Demain",
|
||||||
|
"RUNNING": "Se termine dans",
|
||||||
|
"EMPTY": "Aucun RDV.",
|
||||||
|
|
||||||
|
/* WEATHER */
|
||||||
|
"N": "N",
|
||||||
|
"NNE": "NNE",
|
||||||
|
"ENE": "ENE",
|
||||||
|
"E": "E",
|
||||||
|
"ESE": "ESE",
|
||||||
|
"SE": "SE",
|
||||||
|
"SSE": "SSE",
|
||||||
|
"S": "S",
|
||||||
|
"SSW": "SSO",
|
||||||
|
"SW": "SO",
|
||||||
|
"WSW": "OSO",
|
||||||
|
"W": "O",
|
||||||
|
"WNW": "ONO",
|
||||||
|
"NW": "NO",
|
||||||
|
"NNW": "NNO"
|
||||||
|
}
|
27
translations/nl.json
Normal file
27
translations/nl.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
/* GENERAL */
|
||||||
|
"LOADING": "Bezig met laden …",
|
||||||
|
|
||||||
|
/* CALENDAR */
|
||||||
|
"TODAY": "Vandaag",
|
||||||
|
"TOMORROW": "Morgen",
|
||||||
|
"RUNNING": "Eindigd over",
|
||||||
|
"EMPTY": "Geen geplande afspraken.",
|
||||||
|
|
||||||
|
/* WEATHER */
|
||||||
|
"N": "N",
|
||||||
|
"NNE": "NNO",
|
||||||
|
"ENE": "ONO",
|
||||||
|
"E": "O",
|
||||||
|
"ESE": "OZO",
|
||||||
|
"SE": "ZO",
|
||||||
|
"SSE": "ZZO",
|
||||||
|
"S": "Z",
|
||||||
|
"SSW": "ZZW",
|
||||||
|
"SW": "ZW",
|
||||||
|
"WSW": "WZW",
|
||||||
|
"W": "W",
|
||||||
|
"WNW": "WNW",
|
||||||
|
"NW": "NW",
|
||||||
|
"NNW": "NNW"
|
||||||
|
}
|
13
translations/translations.js
Normal file
13
translations/translations.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* Magic Mirror
|
||||||
|
* Translation Definition
|
||||||
|
*
|
||||||
|
* By Michael Teeuw http://michaelteeuw.nl
|
||||||
|
* MIT Licensed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var translations = {
|
||||||
|
"en" : "translations/en.json",
|
||||||
|
"nl" : "translations/nl.json",
|
||||||
|
"de" : "translations/de.json",
|
||||||
|
"fr" : "translations/fr.json",
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user