Internationalization and Localization with IonicFramework and Angular Translate

There are roughly seven billion people in the world (7,000,000,000) and roughly 6,500 languages.  Lucky for us, Android and iOS does not support all 6,500 of these languages.  However, many are supported and this means that when you make an application in your native language, chances are your audience is only going to be a fraction of these people.

Recently I discovered Angular Tranlate, a JavaScript library for AngularJS.  It allows you to create translation tables in your web application to quickly switch between depending on the language you desire.  When you pair this with IonicFramework, which supports AngularJS, you have a great way of adding internationalization and localization into your mobile application.

Adding Angular Translate to a project isn’t completed like in my other tutorials because it is not actually a Cordova plugin.  Angular Translate is just a JavaScript library to be added into your project and treated like any other web file.

Download the latest stable release of Angular Translate and copy the angular-translate.min.js file into your Ionic project at the following path:

When this has been completed, the library must referenced in your index.html file.  Your file should look something like this at the top:

Now things are going to get a little more interesting.  We need to add Angular Translate into our AngularJS application module and config.  This will not only make it usable, but easy to control as well.

You’ll see above that I created two language tables.  As simple as they may be, one is for English and one is for Spanish.  The preferred language, which will be chosen on application start is English and the fallback in case a translation does not exist, will be English as well.

If at any time you want to change languages during run-time, it can be done in your controller via the $translate.use() method.  If you want to change to Spanish you can use $translate.use(“es”) and all text linking to your translation tables will be changed.

So how do we link to the translation tables in our views?  This is pretty easy.  See the following example code:

Every time the language changes, so will anything formatted like above.  You might be asking how your Ionic app knows what language the device is set for.  The short answer is, your app by default has no idea what language to use.  To figure out which language the device is using, you’ll need to download and install the Apache Globalization Plugin for Cordova.

In the root of your Ionic project, with the Android and iOS platforms already installed, run the following command:

This plugin offers all kinds of useful internationalization tools, but we are only interested in the getPreferredLanguage and getLocaleName functions.

Adding the following to your module’s run method will result in the preferred language being found and then an application language being chosen:

We added some split logic to the above example because getPreferredLanguage will return values such as en-US when we only care about the first two characters.

Here is a fuller example to give you a better idea:

It is important to note that Cordova plugins do not work in PC web browsers.  To have the language automatically determined with the globalization plugin, the Ionic project must be run on an Android or iOS device.  However, Angular Translate will work fine on anything.

Adding internationalization to your mobile application will rank you significantly better in the app store.  Not just because you’ll have more related users, but because the app stores have a ranking algorithm that searches on certain criteria.  This is related to App Store Optimization (ASO) and is for a whole different topic.

A video version of this article can be seen below.

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

  • Luca

    Hi Nic

    Thanks for your tutorial, I’ve successfully implemented Angular Translate. How would you implement it if you would want to use $translateProvider.useLocalStorage();?

    I find it really useful because I allow users to change the language in the settings. Unfortunately Angular Translate takes the preferred language and stores it in the localStorage before Ionic’s run function. I don’t see a way to run the code only on the very first start of the app.

    Thanks for your toughs!

    • Hi Luca,

      What if you were to retrieve what $translateProvider.useLocalStorage(); sets on your own? For example I found this Angular Translate documentation for storage:

      http://angular-translate.github.io/docs/#/guide/10_storages

      After testing their example, I used Firebug to inspect my browsers local storage. It appears that useLocalStorage() is saving the language to NG_TRANSLATE_LANG_KEY. What if you search if it exists in Ionic’s run function?:

      if(window.localStorage["NG_TRANSLATE_LANG_KEY"] !== "undefined")
      $translate.use(window.localStorage["NG_TRANSLATE_LANG_KEY"]);

      Please let me know if this would accomplish what you need?

      Cheers,

      • Luca

        Hi Nic

        Thanks for your fast reply. I’ve already used Angular Translate’s localStorage, but it was set before I could check the device’s language. Because I have already an intro (runs only on the very first start) I’ll check the language there and override Angular Translate’s setting.

        Thanks again and keep up the good writings 🙂

  • Debi

    hi Nic
    I modify the code, but it didn’t work. I use getPreferredLanguage function , But the page without any change ;The following is my code.
    var exampleApp = angular.module('example', ['ionic', 'pascalprecht.translate'])
    .config(function($stateProvider, $urlRouterProvider, $translateProvider) {
    $translateProvider.translations('en', {
    hello_message: "Howdy",
    goodbye_message: "Goodbye"
    });
    $translateProvider.translations('es', {
    hello_message: "Hola",
    goodbye_message: "Adios"
    });
    $translateProvider.preferredLanguage("en");
    $translateProvider.fallbackLanguage("en");
    })
    .run(function($ionicPlatform, $translate) {
    $ionicPlatform.ready(function() {
    if(typeof navigator.globalization !== "undefined") {
    navigator.globalization.getPreferredLanguage(function(locale) {
    alert(locale.value);
    if(locale.value == "en-US") {
    $translate.use("en");
    alert( $translate.use());
    } else {
    $translate.use("es");
    alert( $translate.use());

    }
    }, null);
    }
    });
    });

    • Hi Debi,

      I have made some minor changes to the code in the tutorial to meet best practices. You should make sure to work with the AngularJS promise that $translate.use returns. See this example:

      $translate.use(locale.value).then(function(data) {
      console.log("SUCCESS -> " + data);
      }, function(error) {
      console.log("ERROR -> " + error);
      });

      By acknowledging the promise, the language should be changeable in the .run() method. Please see the YouTube video if it still doesn’t work, as I show it working via simulator in the video.

      Let me know if all this helps you.

      Cheers,

      • Debi

        Hi Nic,
        Thank you very much, it is useful.

  • Er Harshit Goel

    Hi Nic,

    I am new to AngualrJS translate seeing the project website and your example, i have a question,

    How can we load translation from a file ?

  • Eusebe

    Hi,
    Is there a way to use i18n for confirm / alert popups invoked in controllers ?
    By the way I’m wondering what is the best place for those popups ; in the ng-click, or in the controllers’ methods.

    • Hi,

      Per the official Angular Translate documentation ( https://github.com/angular-translate/angular-translate/wiki/Getting-Started ), you can translate via a controller by directly accessing the $translate service:

      $scope.translatedText = $translate(“TRANSLATE_ELEMENT_NAME”);

      Where TRANSLATE_ELEMENT_NAME is one of the keys in your translation table.

      I always prefer to initiate my popups via controllers, but it is ultimately up to you.

      Regards,

  • summ3r

    Hi, Nic! If you’re involved in localization projects and are interested in alternative tools to help manage the software translation process, I would warmly recommend you try https://poeditor.com/
    Cheers and good luck!

  • dareenzo

    Awesomeness. I had researched on the subject and I found out boilerplatejs ( http://boilerplatejs.org/ ) . But this one seems to be a more neat solutions. Props

  • Silvan Hofer

    You don’t have to use the cordova globalization plugin.

    you can use navigator.language (gives “de-ch” for me on android) or i think I’ve seen that Ionic too has such a property…

    • I believe navigator.language uses the language of your browser, not necessarily the language chosen in the settings of your device. I could be wrong though.

      The globalization plugin for sure uses whatever you choose in your settings which makes it a pretty safe solution.

      Thanks for commenting and adding this other possible solution though 🙂

      • Silvan Hofer

        No idea. I don’t even know, if it’s possible at all to change the browser language on Android/iOS and if this affects the WebView…

        But what drives me crazy and what I found absolutely no solution for is that the WebView language apparently is “de-ch” but the date or time input bound to ng-model and their selectors act as follows:

        1st: Date format displayed is not in correct locale format (no different if user selected or manually assigned from storage)
        2nd: Time selector (Android) shows AM/PM instead of 24hr format, after selection it’s then correct, e.g. 16:55
        3rd: when setting the model value from storage on time inputs, if seconds/milliseconds aren’t set to 0 it shows nothing, and it shows xx:xx:00.000 if they are 0 instead of just xx:xx
        4th: Android: Date/Time selectors show “Clear” instead of the german value, iPhone shows “Done” instead of the german value.

        Maybe you have some idea and maybe you could write a blog post about this since I found no solution in the internet (instead of possibly using another JS library but I can’t say the name like this anymore).

  • Dhananjay patil

    Hi,
    Can you please share code sample with me, I tried steps given above but its not working well.

    • I made the video to not have to host any full code since I walk through it 100%.

      What are your errors / problems?

      Regards,

      • Dhananjay Patil

        Hi,
        Now its working well, Problem was due to improper installation of plugin. Thanks for the help. Greate Tutorial.

  • Duncan

    Thanks for well documented & simplified angular translation!

    • No problem! Glad you found it useful 🙂

      • Duncan

        I have ran into a bottleneck whereby am getting ‘navigator.globalization’ as undefined, is there a work around for that?

        • A few possible reasons:

          Are you testing in a device or simulator or with your web browser? Device plugins will not work in a web browser.
          Are you using ionic serve, ionic view, or ionic live-reload? These are beta and are known to cause issues.
          Are you wrapping it in an $ionicPlatform.ready? Native device plugins need to be ready before using.

          Any of those seem like your issue?

  • John Mapley

    Just when I think I’ll scream if I click into another tech article that says “the article’s in this video, watch!”, I find someone who’s doing it right and providing text as well as video for those who want it. Thanks Nic 😀

    • Yep, I hate it when I end up in circles trying to match a write-up with a video and the other way around.

      Glad you enjoyed it 🙂

  • GEORGE CHRISTAKIS

    I have done your example, everything is OK but when I use Greek characters are not showing correctly (all characters are ??????????). Do yo have an idea why this happening?

    • My assumption is the font you’re using (or default font) doesn’t support your character set. Maybe try a different font?

      Regards,

      • GEORGE CHRISTAKIS

        thanks for the answer Nic. tried to change font but i had the same problem. hardcoded greek words working ok only words from angular translate not working

        • Strange. It could be a bug in Angular Translate. You may want to reach out to the developer.

          • GEORGE CHRISTAKIS

            thanks again for your answer Nic i will try to reach the developer

        • John Mapley

          Have you checked doctypes in your HTML and character encoding across all your files? Especially important if what’s appearing are “�” characters.

          • GEORGE CHRISTAKIS

            yes that was the problem because i was editing app.js file with visual studio (with the translations of angular translate ) i had to go to advance save options and save the file with utf8 encoding
            thanks for the reply

          • John Mapley

            Happy to help!

          • Good team effort guys! Always makes me happy when everyone helps each other 🙂

  • Marco

    Thanks it works.. but I’ve a problem the ui shows first the fallback language and than changes it to the language of the user… example if I’ve a label called LABEL_ERROR in english is defined “Events” and in italian “Notizie”.. when i’ve Italian as preffered language when i open my app i see “Events” for a little and the torn to “Notizie”.. and I’ve some labels that i translate iside controllers and thy stay in wrong language

    • Put your code on GitHub and I’ll take a look.

      Regards,

  • Hello, Nic. Thanks for the article. You have mentioned: “Not just because you’ll have more related users, but because the app stores have a ranking algorithm that searches on certain criteria. This is related to App Store Optimization (ASO) and is for a whole different topic.” Will AppStore recognize that your JS-based app has internationalization? I think XCode and similar Android tools announce supported languages in manifest(?) files, but AppStore mechanisms would not know you’re using the languages inside JS. Maybe there should be some workaround to declare supported languages… Thank you for any ideas here.

    • Yea, just add the languages you include to your appropriate manifest files. Forgot to include that bit of information.

      Regards,

  • Hey, thank you so much for this article! It worked perfectly.

  • Sase Habu

    you really are genius! Thanks Men

  • Luís Cunha

    Hi Nic,

    Thanks again for a great tutorial, I would just like to point out that there’s some security issues with using angular-translate with regards to XSS attacks when no sanitization strategy is configured, which can be guarded against by simply adding

    $translateProvider.useSanitizeValueStrategy(‘sanitize’);

    to the app .config(), as per http://angular-translate.github.io/docs/#/guide/19_security , and it makes it safe.

    • Awesome, thanks for sharing this information. I wrote this post more than a year ago and I don’t believe the sanitize features existed back then.

      Best,

  • Christian Hahn

    Hello, thx for this tutorial. I try to get this working on my app but nothing works.
    This is my code, without your example. i think my problem is something with deviceready. Can someone please help me?

    (function () {
    ‘use strict’;

    })();

  • davis

    If you’re searching for alternative tools to help manage the software translation process here’s a small list
    Smartling (from USA)
    Transifex (from USA)
    Poeditor (from USA)
    Crowdin (from Ukraine)
    Onesky (from Hong Kong)
    Phraseapp (from Germany)

  • Atiour Islam

    Hi how i can use other language like Bengali, Indian or other. i am fetching problem it is not supporting front.

  • Xavi Coso

    Hi. There’s a way to reload a view when the lang is changed.
    I’m developing an app with multiple views that get info for a external source and i want to reload this data when i change lang.
    You can see it on ionic view with the id b76b78ff.

    Thanks.

  • Topeson

    thank you. very nice

    • No problem, glad you enjoyed it 🙂

  • Raviraj Ganapuram

    Hi this is raj,
    i Impleted the abowe example its working fine, but when iam using to change the language using in controller its not happening

    $translate.use(lang);

    i am passing the lang is ”fr”, it not working

  • João Rennato

    Thank you SOOOO MUCH for this tutorial! It was stright forward and it REALLY helped! Keep up with the good work!

    • Thanks for the compliment! They are always appreciated 🙂

  • fabio balsamo

    Hi it is possible to change language in alert dialog? how?I try something like that

    var myPopup = $ionicPopup.show({
    title: ‘PrintAnywhere’,
    subTitle: ‘{{“print_message” | translate}}‘,
    scope: $scope,
    buttons: [
    {
    text: ‘Cancel’,
    type: ‘button-assertive’
    },
    {
    text: ‘Print‘,
    type: ‘button-positive’,
    }
    ]});
    Thanks

    • ykarthik reddy

      Hi fabio,

      Did u make it worked like that?

    • Jake Bauson

      This is not working on my end. Do you have other solution?

      Thanks

  • Guilherme de paula

    Eae guy okay ? Very good tutorial, so I wanted to know if I have to put a button so that when I click the button translate the application ?

    • I’m not sure what you’re asking. In my example I don’t make use of a button, I make use of the users local language settings. You can certainly use a button if you wanted to.

      Best,

  • Daniel

    Thanks Nic, works like a charm. Do you happen to know a way to “hide” all text until the promise is resolved?

    To be more specific, my app handles translation correctly, but it takes some time (less than a second) to get the locale of the device and changing the language, which is a little bit bad for UX. I was thinking about making a “blank locale” with no text and using it as the default until the actual locale is loaded, but I don’t know if there’s another way around this.

    • John Mapley

      Since this is presumably only an issue on initialisation, why don’t you just wait until the promise is resolved before hiding the splashscreen? (There’s a Cordova plugin to control this)

      • Daniel

        Sounds like a good alternative. Will give it a try. Thanks for the suggestion!

        • I’m loving all this community collaboration!

  • BIts India

    Thank you so much for this article! It worked perfectly.
    http://bitsindia.co.in

  • Mahendra Rajdhami

    Thanks for great Tutorial NIC. Its working fine. Now i want to manage language tables in separate js file for each language how can i do that?

    • The way I do it is as follows.

      Create a JavaScript file that has all your translations. For example, the file might contain the following:

      Use this global variables in your project like so:

      Best,

      • Eric Negron

        Hi Nic, Thanks for sharing. Practically speaking this not a good way to separate content. In most cases you will want to have 1 resource file for each language. When you work with translators they typically only speak one language and you want them to be able to clean translate the contents of an entire file to their language. Also you will want to use a tool like Smartling to automatically prepare the strings for the translators so they won’t break your code syntax or other markup (keys, variables, HTML). https://express.smartling.com

    • John M

      FWIW good morning in Japanese should be おはよう, not おはいよ 🙂

  • krrish Krishna

    Thanks for the awesome tutorial, Is it possible to load translations.json from sdCard storge ?

  • Bernardo Gomes

    Great Tutorial !

    • Thanks for the compliment

      • Bernardo Gomes

        I forgot one thing!

        I checked and found a doc about security .

        Maybe you can add information about $ translateProvider.useSanitizeValueStrategy ( ‘ sanitize ‘ ) ;

  • Finalweb Tecnico Pc-not La Ser

    i have ion-toggle how change true and false for SI and NO