Sometimes we need a mobile app to be internationalized when we use AngularJS.

AngularJS supports i18n/l10n for date, number and currency filters. If we want to change something as simple as a literal, we will have to do something else. To do this there are several possible approaches, but today we will go with a really simple one.

The AngularJS i18n example

Step 1: Create a service

Yeah, using services in AngularJS is something amazing, so lets create (another) one. This one will only take care of literals, but you would be able to upgrade it with any features you’d like.

app.factory('Language', function() {

    var languageFile = {
        "es" : {
            "hello-world" : "Hola, mundo!",
            "username" : "Nombre de usuario"
        },
        "en" : {
            "hello-world" : "Hello, world!",
            "username" : "User name"
        }
    };

    var defaultLanguage = "es";
    var currentLanguage = "es";

    function get(key, language) {
        try {
            return languageFile[getCurrentLanguage(language)][key];
        } catch(e) {
            return "Unknown text";
        }
    };
    function getCurrentLanguage(language) {
        try {
            if (language) {
                if (languageFile[language]) {
                    currentLanguage = language;
                } else {
                    return defaultLanguage;
                }
            }
        } catch(e) {
        }
        return currentLanguage;
    };

    function setLanguage(language) {
        if (language) {
            currentLanguage = language;
        }
    };
    function getLanguage() {
        return currentLanguage;
    };
    // PUBLIC METHODS DEFINITION
    return {
        get : get,
        getLanguage : getLanguage,
        setLanguage : setLanguage
    };
});

Well, just with this you have a way to know which language is active and to get a string from a key. It can be improved, of course! I can imagine a way to load the data from files, to pass some arguments so we can add dynamic values, etc. etc. Remember, this is just an example!

Step 2: Use it in the controller

So obvious. Now you have a service that manages the languages in your app. Of course, you want to use it in both your controller (if you have to create alerts, emails, … there are a lot of options) and your HTML code. Lets go with the controller, as it is the fastest way.

app.controller('MainController', ['$scope', 'Language', function($scope, Language) {
    $scope.myLabel = Language.get("username");
}]);

As easy as that. You will get the value for that key for the default language. Of course, if you want to change languages, use

Language.setLanguage("en");

or

Language.get("username", "en");

But what about the data in your HTML? Are you going to create as many variables in the controller as literals? No need of that!!

Step 3: Create a directive to use it in your HTML

Let’s use a directive, so we can call the language service in the HTML.

app.directive("language", ['Language', function(Language) {

    return {
        restrict : 'E',
        scope : {
            key : "@",
            message : "="
        },
        link : function(scope, element, attrs) {
            var text = "";
            if (scope.key) {
                text = Language.get(scope.key);
            } else if (scope.message) {
                text = Language.get(scope.message);
            }
            element.replaceWith(text);
        }
    };
}]);

Easy enough. This directive will allow you to get a key (like “username”) and get the translation for it. OR will allow you to get a variable from the controller (I choose “message” as name for it) so you can get the key from the controller. You can use this directly in your code like

<language key="hello-world"></language>

That piece of code will be replaced by something like

Hello, world!

But what happens when you have to use this in a placeholder, for example? Well, here is the directive for that…

app.directive("placeholderLanguage", ['Language', function(Language) {

    return {
        restrict : 'A',
        scope : {
            key : "@languageKey",
            message : "=languageMessage"
        },
        link : function(scope, element, attrs) {
            var text = "";
            if (scope.key) {
                text = Language.get(scope.key);
            } else if (scope.message) {
                text = Language.get(scope.message);
            }
            if (text != "") {
                attrs.$set('placeholder', text);
            }
        }
    };
}]);

And you can use it like

 <input placeholder-language language-key="username" />

This directive can be easily changed to allow updating any attribute.

Step 4: Enjoy it!

Check the working example in jsFiddle. Change the currentLanguage from “es” to “en”. And that’s all!