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."
+}