diff --git a/index.html b/index.html index a6d7265c..d08291cc 100644 --- a/index.html +++ b/index.html @@ -33,6 +33,7 @@ + diff --git a/js/loader.js b/js/loader.js index 2553a187..2dbd40b2 100644 --- a/js/loader.js +++ b/js/loader.js @@ -144,9 +144,11 @@ var Loader = (function() { Log.log("Scripts loaded for: " + module.name); mObj.loadStyles(function() { Log.log("Styles loaded for: " + module.name); - - moduleObjects.push(mObj); - callback(); + mObj.loadTranslations(function() { + Log.log("Translations loaded for: " + module.name); + moduleObjects.push(mObj); + callback(); + }); }); }); diff --git a/js/module.js b/js/module.js index 9be652bf..3b789853 100644 --- a/js/module.js +++ b/js/module.js @@ -52,6 +52,15 @@ var Module = Class.extend({ return []; }, + /* getTranslations() + * Returns a map of translation files the module requires to be loaded. + * + * return Map - A map with langKeys and filenames. + */ + getTranslations: function() { + return {}; + }, + /* getDom() * 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. @@ -146,7 +155,7 @@ var Module = Class.extend({ }, /* file(file) - * Retrieve the path to a module fike. + * Retrieve the path to a module file. * * argument file string - Filename. * @@ -204,6 +213,32 @@ var Module = Class.extend({ 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) * Request an (animated) update of the module. * diff --git a/js/translator.js b/js/translator.js new file mode 100644 index 00000000..3ef18ed9 --- /dev/null +++ b/js/translator.js @@ -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); + } + }; +})(); diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 30712f44..861411ac 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -29,13 +29,6 @@ Module.register("calendar",{ titleReplace: { "De verjaardag van ": "" }, - loadingText: "Loading events …", - 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. @@ -48,6 +41,14 @@ Module.register("calendar",{ return ["moment.js"]; }, + // Define required translations. + getTranslations: function() { + return { + en: "translations/en.json", + de: "translations/de.json" + }; + }, + // Override start method. start: function() { Log.log("Starting module: " + this.name); @@ -91,7 +92,7 @@ Module.register("calendar",{ wrapper.className = "small"; 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"; return wrapper; } @@ -121,9 +122,9 @@ Module.register("calendar",{ var now = new Date(); if (event.fullDayEvent) { if (event.today) { - timeWrapper.innerHTML = this.config.todayText; + timeWrapper.innerHTML = this.translate("TODAY"); } else if (event.startDate - now < 24 * 60 * 60 * 1000) { - timeWrapper.innerHTML = this.config.tomorrowText; + timeWrapper.innerHTML = this.translate("TOMORROW"); } else { timeWrapper.innerHTML = moment(event.startDate,"x").fromNow(); } @@ -136,7 +137,7 @@ Module.register("calendar",{ timeWrapper.innerHTML = moment(event.startDate,"x").calendar(); } } 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'); diff --git a/modules/default/calendar/translations/de.json b/modules/default/calendar/translations/de.json new file mode 100644 index 00000000..53530085 --- /dev/null +++ b/modules/default/calendar/translations/de.json @@ -0,0 +1,7 @@ +{ + "TODAY": "Heute" + , "TOMORROW": "Morgen" + , "RUNNING": "Endet in" + , "LOADING": "Lade Termine …" + , "EMPTY": "Keine Termine." +} diff --git a/modules/default/calendar/translations/en.json b/modules/default/calendar/translations/en.json new file mode 100644 index 00000000..4dcf3a62 --- /dev/null +++ b/modules/default/calendar/translations/en.json @@ -0,0 +1,7 @@ +{ + "TODAY": "Today" + , "TOMORROW": "Tomorrow" + , "RUNNING": "Ends in" + , "LOADING": "Loading events …" + , "EMPTY": "No upcoming events." +}