Merge pull request #211 from CFenner/l10n

implements l10n
This commit is contained in:
Michael Teeuw 2016-04-21 08:53:10 +02:00
commit 44c1266a8c
7 changed files with 125 additions and 15 deletions

View File

@ -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="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>
<script type="text/javascript" src="js/loader.js"></script> <script type="text/javascript" src="js/loader.js"></script>

View File

@ -144,11 +144,13 @@ var Loader = (function() {
Log.log("Scripts loaded for: " + module.name); Log.log("Scripts loaded for: " + module.name);
mObj.loadStyles(function() { mObj.loadStyles(function() {
Log.log("Styles loaded for: " + module.name); Log.log("Styles loaded for: " + module.name);
mObj.loadTranslations(function() {
Log.log("Translations loaded for: " + module.name);
moduleObjects.push(mObj); moduleObjects.push(mObj);
callback(); callback();
}); });
}); });
});
}; };

View File

@ -52,6 +52,15 @@ var Module = Class.extend({
return []; return [];
}, },
/* getTranslations()
* Returns a map of translation files the module requires to be loaded.
*
* return Map<String, String> - A map with langKeys and filenames.
*/
getTranslations: function() {
return {};
},
/* getDom() /* getDom()
* This method generates the dom which needs to be displayed. This method is called by the Magic Mirror core. * This method generates the dom which needs to be displayed. This method is called by the Magic Mirror core.
* This method needs to be subclassed if the module wants to display info on the mirror. * This method needs to be subclassed if the module wants to display info on the mirror.
@ -146,7 +155,7 @@ var Module = Class.extend({
}, },
/* file(file) /* file(file)
* Retrieve the path to a module fike. * Retrieve the path to a module file.
* *
* argument file string - Filename. * argument file string - Filename.
* *
@ -204,6 +213,32 @@ var Module = Class.extend({
loadNextScript(); loadNextScript();
}, },
/* loadScripts()
* Load all required scripts by requesting the MM object to load the files.
*
* argument callback function - Function called when done.
*/
loadTranslations: function(callback) {
var self = this;
var translations = this.getTranslations();
var translationFile = translations && (translations[config.language] || translations["en"]) || undefined;
if(translationFile) {
Translator.load(this, translationFile, callback);
} else {
callback();
}
},
/* translate(key, defaultValue)
* Request the translation for a given key.
*
* argument key string - The key of the string to translage
* argument defaultValue string - The default value if no translation was found. (Optional)
*/
translate: function(key, defaultValue) {
return Translator.translate(this, key) || defaultValue || '';
},
/* updateDom(speed) /* updateDom(speed)
* Request an (animated) update of the module. * Request an (animated) update of the module.
* *

57
js/translator.js Normal file
View File

@ -0,0 +1,57 @@
/* exported Translator */
/* Magic Mirror
* Translator (l10n)
*
* By Christopher Fenner http://github.com/CFenner
* MIT Licensed.
*/
var Translator = (function() {
return {
translations: {},
/* translate(module, key)
* Load a translation for a given key for a given module.
*
* argument module Module - The module to load the translation for.
* argument key string - The key of the text to translate.
*/
translate: function(module, key) {
if(this.translations[module.name]) {
return this.translations[module.name][key];
}
return undefined;
},
/* load(module, file, callback)
* Load a translation file (json) and remember the data.
*
* argument module Module - The module to load the translation file for.
* argument file string - Path of the file we want to load.
* argument callback function - Function called when done.
*/
load: function(module, file, callback) {
var self = this;
if(!this.translations[module.name]) {
this._loadJSON(module.file(file), function(json) {
self.translations[module.name] = json;
callback();
});
}
},
/* _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.
*/
_loadJSON: function(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(xhr.responseText));
}
};
xhr.send(null);
}
};
})();

View File

@ -29,13 +29,6 @@ Module.register("calendar",{
titleReplace: { titleReplace: {
"De verjaardag van ": "" "De verjaardag van ": ""
}, },
loadingText: "Loading events &hellip;",
emptyCalendarText: "No upcoming events.",
// TODO: It would be nice if there is a way to get this from the Moment.js locale.
todayText: "Today",
tomorrowText: "Tomorrow",
runningText: "Ends in"
}, },
// Define required scripts. // Define required scripts.
@ -48,6 +41,14 @@ Module.register("calendar",{
return ["moment.js"]; return ["moment.js"];
}, },
// Define required translations.
getTranslations: function() {
return {
en: "translations/en.json",
de: "translations/de.json"
};
},
// Override start method. // Override start method.
start: function() { start: function() {
Log.log("Starting module: " + this.name); Log.log("Starting module: " + this.name);
@ -91,7 +92,7 @@ Module.register("calendar",{
wrapper.className = "small"; wrapper.className = "small";
if (events.length === 0) { if (events.length === 0) {
wrapper.innerHTML = (this.loaded) ? this.config.emptyCalendarText : this.config.loadingText; wrapper.innerHTML = (this.loaded) ? this.translate("EMPTY") : this.translate("LOADING");
wrapper.className = "small dimmed"; wrapper.className = "small dimmed";
return wrapper; return wrapper;
} }
@ -121,9 +122,9 @@ Module.register("calendar",{
var now = new Date(); var now = new Date();
if (event.fullDayEvent) { if (event.fullDayEvent) {
if (event.today) { if (event.today) {
timeWrapper.innerHTML = this.config.todayText; timeWrapper.innerHTML = this.translate("TODAY");
} else if (event.startDate - now < 24 * 60 * 60 * 1000) { } else if (event.startDate - now < 24 * 60 * 60 * 1000) {
timeWrapper.innerHTML = this.config.tomorrowText; timeWrapper.innerHTML = this.translate("TOMORROW");
} else { } else {
timeWrapper.innerHTML = moment(event.startDate,"x").fromNow(); timeWrapper.innerHTML = moment(event.startDate,"x").fromNow();
} }
@ -136,7 +137,7 @@ Module.register("calendar",{
timeWrapper.innerHTML = moment(event.startDate,"x").calendar(); timeWrapper.innerHTML = moment(event.startDate,"x").calendar();
} }
} else { } else {
timeWrapper.innerHTML = this.config.runningText + ' ' + moment(event.endDate,"x").fromNow(true); timeWrapper.innerHTML = this.translate("RUNNING") + ' ' + moment(event.endDate,"x").fromNow(true);
} }
} }
// timeWrapper.innerHTML = moment(event.startDate,'x').format('lll'); // timeWrapper.innerHTML = moment(event.startDate,'x').format('lll');

View File

@ -0,0 +1,7 @@
{
"TODAY": "Heute"
, "TOMORROW": "Morgen"
, "RUNNING": "Endet in"
, "LOADING": "Lade Termine &hellip;"
, "EMPTY": "Keine Termine."
}

View File

@ -0,0 +1,7 @@
{
"TODAY": "Today"
, "TOMORROW": "Tomorrow"
, "RUNNING": "Ends in"
, "LOADING": "Loading events &hellip;"
, "EMPTY": "No upcoming events."
}