Nowadays, any kinds of web applications often require a multilingual support. In this post, I will demonstrate how to build custom multilingual support for your Angular app using browser’s cache and promises. This solution is easy and doesn’t have any dependencies.

While learning front-end development, I’ve noticed that reading documentation and building things by yourself will help you to understand the language and improve your programming skills.

First of all, this tutorial has an educational purpose. So, it will be most useful for novice web developers.

I hope it will help you better understand how cookies and promises work in AngularJS.

Preparation

Let’s assume that we have a web application in two languages: English and Finnish. We want to change its labels such as “year” and “period” depending on the chosen language.

We will have all our labels in the separate file in the JSON format. It will allow us to easier maintain them. Let’s call it labels.json. It will have the following structure.

{
  "en": {
    "year": "Year",
    "period": "Period"
  },
  "fi": {
    "year": "Vuosi",
    "period": "Jakso"
  }
}

Let’s create an empty Angular application. We will utilize browser’s cookies, so we need to inject ngCookies module. It’s not necessary, but it will help us improve users’ experience.

<html>
  <head>
    <title>Multilingual App</title>
  </head>
  <body ng-app="multilingualApp">
    <script>
      angular.module("multilingualApp", ["ngCookies"]);
    </script>
  </body>
</html>

Get Language

Once we have our application in place, we can start building the actual multilingual support.

In the application, users will be able to switch between two languages by clicking on the buttons. But what language should we show by default?

We could just choose one of the languages, for instance, English, but there is a better option. The idea for better user experience is to utilize cookies and browser settings.

First of all, let’s create a getLanguage() service. On page load, we will check if the browser has language saved in cookies. If not, we will get the language of user’s browser.

Read more about ngCookies, how to get and set them in the Angular documentation. You can get browser’s language from the $window object, which is the reference to browser’s window object.

As we have only two languages, then we need to add a fallback, all non-Finnish browsers will set our language to English.

function getLanguage($cookies, $window) {
  // Get previously saved language if there is any
  this.language = $cookies.get("language");
  if (!this.language) {
    // If there is no language saved in browsers cookies,
    // get the language of the user's browser
    this.language = $window.navigator.language || $window.navigator.userLanguage;
    // Language fallback, if language isn't Finnish, set it to English
    if (this.language !== "fi") this.language = "en";
  }
}

Now we can inject our service into a component and use it to get the current language.

Get Labels

Since we have the language defined, we can start building a service to get our labels. It will be a simple HTTP GET request to a JSON file. It will return labels as a Promise object based on the chosen language.

Read more about $http and $q deferred object. You can also check my previous post, where I was using $q object for sharing data between Angular components.

function getLabels($http, $q, getLanguage) {
  let deferred = $q.defer();

  $http({
    method: "GET",
    url: "/labels.json",
    cache: true
  }).success((data) => {
    // Filter JSON data by the language
    deferred.resolve(data[getLanguage.language]);
  }).error((msg) => {
    deferred.reject(msg);
  });

  return deferred.promise();
}

Using Labels

At this stage, we have JSON file and can get labels from it. We also know what language client is using.

Let’s say we have a component named appComponent. First of all, to use our dynamic labels we need to inject getLabels() service to it.

angular
.module("multilingualApp", [ngCookies])
.service("getLanguage", getLanguage)
.service("getLabels", getLabels)
.component("appComponent", {
  templateUrl: "app.component.html",
  controller: function appComponentCtrl(getLabels) {
    this.$onInit = () => {
      getLabels.then((labels) => {
        this.labels = labels;
      });
    };
  }
});

All you need now is just to use an expression in a template like so:

{{$ctrl.labels.period}} – {{$ctrl.labels.year}}

Pretty simple, right? The only thing, we have forgotten – how a user could change the language.

Set Language

Let’s create a service called “set language”. It will change the language, save it in the browser and refresh the page.

function setLanguage($cookies, $window) {
  this.addToCookie = (value) => {
    // Put new value to the language cookie
    $cookie.put("language", value);
    // Refresh the page
    $window.location.reload();
  };
}

After the page reloads, it will take the new language from the browser and show corresponding labels.

All you need now is to add this service to a component and create a method for a ngClick event.

...
controller: function appComponentCtrl(getLabels, setLanguage) {
  this.$onInit = () => {
    ...
    this.setLanguage = (language) => {
      setLanguage.addToCookie(language);
    };
  };
}
...

<span ng-click="$ctrl.setLanguage('en')">En</span>
<span ng-click="$ctrl.setLanguage('fi')">Fi</span>

That’s it, now we can change the language and see that labels are changing. The only drawback, which you may have already noticed is that this solution requires a page reload.

It might be useful for you to try to solve it by your own. Create a single language service with “get” and “set” methods. Try to utilize a deferred.notify() method to notify controllers about changes.

Hope you will find this helpful and will improve your front-end development skills.

 

Good luck!