

Applying internationalization and localization to AngularJS application
As we all know, first impression is very important. It is good user experience to display the text and apply the locale of the application in the user’s own language.
In this blog, we will see how to achieve this by adding few plugins to an existing project.
Prerequisits
We already have a project developed in AngularJS.It contains some of the most common components.
- labels
- a chart built by using HighCharts plugin (http://www.highcharts.com/)
- a table displaying numbers and dates
This is how it looks like:
How can we customize this application to be displayed in multiple languages and also to show localized dates and number?
Just follow these steps 🙂
Downloading and configuring plugins
1. First of all download the plugins:
- angular-translate plugin from https://angular-translate.github.io/
- Angular Dynamic Locale plugin from http://lgalfaso.github.io/angular-dynamic-locale/
2. Add them in the html:
– The i18n for Angular apps
1 |
<script src="plugins/angular-translate.min.js" type="text/javascript"></script> |
– Module that creates a loading function for a typical static file url pattern: “lang-en.json”, “lang-de.json”, etc.
1 2 |
<script src="plugins/angular-translate-loader-static-files.min.js" type="text/javascript"></script> |
– Module that helps dynamically change of locale
1 |
<script src="plugins/tmhDynamicLocale.min.js" type="text/javascript"></script> |
3. Add a list of dependencies in the main.js, where our main module “App” is defined
1 |
var app = angular.module('App', ["pascalprecht.translate", "tmh.dynamicLocale", "ngCookies"]); |
4. In the main.js, let’s configure the translateProvider
1 2 3 4 5 6 7 8 9 |
app.config(['$translateProvider', function ($translateProvider) { $translateProvider.useStaticFilesLoader({ prefix: 'i18n/locale-', suffix: '.json' }); $translateProvider.preferredLanguage('en'); $translateProvider.useSanitizeValueStrategy('escape'); }]); |
The translations can be defined in the code but instead are moved to separate files.There are reasons behind this decision – defined in the code makes it hard to use by translators, it is not a good practise.
We use the static file loader to load these files, the response of these urls must be an object of key-value pairs.ex.{ WELCOME_MSG”: “Welcome to our application!”}
The method useSanitizeValueStrategy( strategy ) defines strategy for escaping HTML in the translation, for security reasons.
In the main.js again, let’s configure the tmhDynamicLocaleProvider
1 2 |
app.config(function (tmhDynamicLocaleProvider) { tmhDynamicLocaleProvider.localeLocationPattern('i18n/angular-locale_{{locale}}.min.js'); |
This method is used to set the path of the angular locale files in the project. The locale files define the format of the numbers and dates displayed per language.You can download locale files from https://cdnjs.com/libraries/angular-i18n.
Creating language service
1. Let’s create LanguageService, inject some dependencies and define some member variables and methods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
angular.module('App').factory('LanguageService', LanguageService); LanguageService.$inject = ['$rootScope', '$translate','tmhDynamicLocale']; function LanguageService($rootScope, $translate, tmhDynamicLocale) { var service = {}; service.listLangs = ['en', 'de', 'es', 'fr']; service.language = 'en'; service.setLanguage = setLanguage; function setLanguage(langKey){ setUserLanguageLocale(langKey); } function setUserLanguageLocale(langKey){ service.language = langKey; $translate.use(langKey); tmhDynamicLocale.set(langKey); } return service; } |
Using the language service
1. Let’s add the LanguageService as dependency in the controller and define methods for changing the language
1 2 3 4 5 6 7 8 9 |
angular.module('App').controller('AppController', ['$scope', 'ChartService', 'LanguageService', function ($scope, ChartService, LanguageService)] $scope.listLangs = LanguageService.listLangs; $scope.language = LanguageService.language; $scope.changeLanguage = function (lang) { LanguageService.setLanguage(lang); }; |
2. And now, we can add buttons for selecting different language In the html
1 2 3 |
<div ng-repeat="lang in listLangs"> <a href="#" ng-click="changeLanguage(lang)" class="lang_button">{{lang}}</a> </div> |
!NB – Things to be aware of
At this stage of development a problem pops up – the chart does not apply the locale when changing the language.The chart must be forced to redraw.This should happen once the locale is changed.
According to the documentation: “The locale is changed asynchronously. After the locale is changed, the event ‘$localeChangeSuccess’ will be triggered”.That is why we add the following lines of code:
1 2 3 4 5 6 7 8 9 10 11 12 |
$rootScope.$on('$localeChangeSuccess', function () { redrawChartsOnLocaleChange(); }) function redrawChartsOnLocaleChange() { if ($rootScope.chartsToRedraw) { var i = 0; for (; i < $rootScope.chartsToRedraw.length; i++) { $rootScope.chartsToRedraw[i].redraw(); } } } |
The array $rootScope.chartsToRedraw contains the chart itself and is used in case there are more than one chart in the project.
Cookies
Everything works fine so far!
Except that every time you reload the application, the language by default is displayed.
Would it not be better to load the user’s language selected in the previous session?
Let’s use cookies!
1. The cookies module is added in the html:
1 |
<script src="plugins/angular-cookies.min.js" type="text/javascript"></script> |
2. And also injected in the LanguageService
1 |
LanguageService.$inject = ['$rootScope','$window', '$translate', '$cookies', 'tmhDynamicLocale']; |
3. That is how we read from and write in the browser cookies.
1 2 3 4 5 6 7 8 9 10 11 12 |
function writeCookie(langKey) { var now = new Date(), exp = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate()); $cookies.put('angular_app', langKey, { expires: exp }); } function readCookie(){ return $cookies.get('angular_app'); } |
Detecting browser language
1. And last but not least, for best user experience, if browser cookie is not available, let’s use the browser default language.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
function retrieveUserLanguage() { //Check browser cookies var userLanguage = readCookie(); var isInCookies = (userLanguage) ? true :false; //Check browser default language if(!isInCookies){ userLanguage = detectBrowserLanguage(); } if(service.listLangs.indexOf(userLanguage) == -1){ userLanguage = 'en'; } setLanguage(userLanguage); } function detectBrowserLanguage() { var browserLang = 'en'; var browserLanguges = $window.navigator.languages; // Firefox 1.0+ var isFirefox = typeof InstallTrigger !== 'undefined'; // Safari 3.0+ "[object HTMLElementConstructor]" var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0 || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || safari.pushNotification); // Internet Explorer 6-11 var isIE = /*@cc_on!@*/false || !!document.documentMode; // Chrome 1+ var isChrome = !!window.chrome && !!window.chrome.webstore; if(isFirefox || isChrome || isIE){ browserLang = (browserLanguges && browserLanguges.length >=1) ? browserLanguges[0] : browserLang; browserLang = (browserLang.indexOf('-') != -1) ? browserLang.substring(0,browserLang.indexOf('-')) : browserLang; } return browserLang; } |
You can find the project in this git repository : https://github.com/denitsaoooooo/i18n-app