Zentrale Lokalisierung in einer angularJS App

angularJS ist großartig und macht Spaß. Je mehr Code ich damit entwickle, umso begeisterter bin ich.

Um auch in unserer Web App einen zentralen Platz für unsere Lokalisierungen zu haben, habe ich einen Service geschrieben, der sich zentral um die Lokalisierung von allen Texten kümmern soll. Als Java-Entwickler wollte ich etwas ähnliches entwickeln, wie ResourceBundles und Properties-Dateien.

Meine Lösung ist als Angular-Service implementiert und die Lokalisierungstexte sind in JSON-Dateien ausgelagert. Der Service lädt die passende JSON-Datei asynchron per [highlight1]$http-Service[/highlight1] nach und stellt die Texte systemweit über eine [highlight1]localizationService.translate()[/highlight1]-Methode zur Verfügung. Die Lokalisierungsstrings lassen sich den Java-Properties parametrisieren, wobei die aktuelle Implementierung nur einen Parameter auswertet, weil wir aktuell nur einen benötigen. Die Formatierung greift dabei auf eine format-Methode am String-Prototyp zurück.

Hinweis: der Code um die Browsersprache zu erkennen fehlt, damit der Code einfacher zu verstehen ist.

	function localizationServiceFactory($http, $q) {
		var translationsDE, errorMessage;

		function loadTranslations() {
			var deferred = $q.defer();

			if (!translationsDE) {
				$http.get("/json/translations/translationsDE.json").then(
					function(data) {
						translationsDE = data;
						errorMessage = '';
						deferred.resolve();
					},
					function(error) {
						translationsDE = {};
						errorMessage = error;
					}
				);
			} else {
				deferred.resolve();
			}

			return deferred.promise;
		}

		function translate(key, param) {
			var translation = "";

			return loadTranslations().then(function() {
				if (key) {
					translation = translationsDE[key];

					//unbekannter Key = gib Key zurück
					if(!translation) {
						translation = key;
					}

					if (param) {
						translation = translation.format(param);
					}
				}

				return translation;
			});
		}

		return {
			translate:translate
		};
	}

	localizationServiceFactory.$inject = ['backendService', '$q'];
	angularModule.factory("localizationService", localizationServiceFactory);
{
	"MEIN_STRING": "Das ist die Lokalisierung",
	"NOCH_EIN_STRING": "Und noch eine",
	"FALSCHER_BENUTZER": "Benutzername {0} wurde nicht gefunden."
}
//format Methode, {0} {1} usw.
if (!String.prototype.hasOwnProperty("format")) {
	String.prototype.format = function() {
		var formatted, i, regexp;
		formatted = this;
		for (i = 0; i < arguments.length; i++) {
			regexp = new RegExp('\\{'+i+'\\}', 'gi');
			formatted = formatted.replace(regexp, arguments[i]);
		}
		return formatted;
	};
}

Das wirklich schöne an dem Service ist, dass er die JSON-Datei asynchron nachlädt, wenn sie gebraucht wird. Wenn man den Code zur Spracherkennung entsprechend baut, lädt er auch nur die tatsächlich benötigte Lokalisierung. Nicht benötigte Lokalisierungen landen erst gar nicht im Browser.

Was mich am meisten beeindruckt hat, ist der Umgang von AngularJS mit dem [highlight1]Promise-Objekt[/highlight1] das die translate-Methode in jedem Fall zurückgibt. In diesem Fall sorgt angularJS nämlich automatisch dafür, dass die Aufrufe von translate aus einem Controller heraus synchron aufgelöst werden, sodass man im Controller ohne besonderes Zutun auf jeden Fall einen lokalisierten String bekommt, obwohl der $http-Request asynchron abläuft und zum Zeitpunkt des Aufrufes eventuell noch gar nicht abgeschlossen ist.

Man könnte es fast als Magie bezeichnen 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

*