Recently we at ICAN came across an interesting issue that needed solving. We’re developing an app with localisation. Users can choose to use the app in either English or Chinese currently. As we’re using AngularJS we decided to go with Angular-translate to achieve this. The issue we were facing was simple, all data sent to our backend needed to be sent in English for future analytical processing.

I’ll elaborate. With angular-translate you can convert strings of text into any language but this means that if you’re using the app in Chinese and you update your country to China the app will save that data as 中国. We needed this information to be sent to our server as ‘China’ rather than ‘中国’. Similarly, if the data stored in the server is the literal string ‘China’ and a Chinese user fetches that data they will need to be able to see 中国 instead.

In this blog, I want to show you how we solved this issue from start to finish.

First off, I’ve mentioned a little about angular-translate, the AngularJS module used to easily localise your app for multiple languages. It’s very quick and easy to setup, simple type the following into your terminal.

npm install --save-dev angular-translate

Once installed add the module to your existing Angular app just like any other module.

You can see a quick example of how the module looks and works here.

var app = angular.module('at', ['pascalprecht.translate']);
app.config(function ($translateProvider) {
    $translateProvider.translations('en', {
     'LOGIN': 'Login',
     'LOGOUT': 'Logout',
     'REGISTER': 'Register',
     'CREATE': 'Create an account',
     'OK': 'Ok',
     'EDIT': 'Edit',
     'SAVE': 'Save',
     'CONTINUE': 'Continue',
     'CANCEL': 'Cancel',
     'BACK': 'Back'
    });
    $translateProvider.translations('zh', {
     'LOGIN': '登录',
     'LOGOUT': '登出',
     'REGISTER': '注册',
     'CREATE': '创建新帐号',
     'OK': '成功',
     'EDIT': '保存',
     'SAVE': '保存',
     'CONTINUE': '继续',
     'CANCEL': '取消',
     'BACK': '返回'
    });
    $translateProvider.preferredLanguage('en');
});

Now whenever you want to translate a string you can use

{{ 'LOGIN' | translate }}

If the preferred language is ‘en’ then LOGIN will be replaced with the string ‘Login’. If the preferred language is ‘zh’ then LOGIN will be replaced with ‘登录’. Simple.

This is all fine and well until things get a little more complicated. We also use the preferred language to load language specific files. For example, we have two files we use when selecting a country.

country_en.json is a long file so I’ll just show a snippet of what it looks like here

{
   "Americas": [{
     "code": "AW",
     "name": "Aruba"
   },{
     "code": "AI",
     "name": "Anguilla"
   },{
     "code": "AR",
     "name": "Argentina"
   }...]
}...

We also have country_zh.json which is loaded when the preferred language is ‘zh’ or Chinese. It looks like this

{
   "美洲": [{
     "code": "AW",
     "name": "阿鲁巴"
   },{
     "code": "AI",
     "name": "安圭拉"
   },{
     "code": "AR",
     "name": "阿根廷"
   }...]
}...

Our app uses the preferred language variable to determine which file is loaded and rendered to the screen, the user’s selection is then saved to be sent to our server for storage. Before the data is sent we have an intermediary stage that converts Chinese text to its English equivalent. This is how we’ve set up our factories.

app.factory('FILES', function ($http, lang) {
   return functions = {
     en_zh: function () {
       return $http.get('json/converters/en-zh.json');
     },

     zh_en: function () {
       return $http.get('json/converters/zh-en.json');
     },

     countryList: function () {
       return $http.get('json/country_' + lang + '.json'); 
     }
   };
});

and

app.factory('TRANSLATE', function (FILES) {

   return {
       toEnglish: function (key, value) {

         return FILES.zh_en().then(function (data) {
           var data = data.data[0];
           var result = {};
 
           for(var i in data){
             if(i == value){
               result[key] = data[i];
               return result;
             }
           }
           result[key] = value;
           return result;
         });
       },
       toChinese: function (key, value) {

         return FILES.en_zh().then(function (data) {
           var data = data.data[0];
           var result = {};

           for(var i in data){
             if(i == value){
               result[key] = data[i];
               return result;
             }
           }
           result[key] = value;
           return result;
       });
     }
   }
});

To convert either toEnglish or toChinese we can simply add the TRANSLATE module to a function like so.

function editProfile(data, callback, TRANSLATE, $q, $http) {

   var promises = [];
   var url = 'http://www.example.com/';

   for (var i in data){
     var promise = TRANSLATE.toEnglish(i, data[i]);
     promises.push(promise);
   }

   $q.all(promises).then(function(results){
     var data = {};

     for(var i in results){
       Object.assign(data, results[i]);
     }

     var req = {
       method: 'POST',
       url: url,
       headers: {
         "Content-Type": 'application/json'
       },
       withCredentials: true,
       data: data
     };

     $http(req).success(function (result) {
       callback(result);
     });
   })
}

The example above is when a user updates their profiles, their data is sent to this function as form data. The data is sent through toEnglish. This iterates through the file zh_en.json and if it finds a match the data will be updated to English.

// zh_en.json
{
  '阿鲁巴': 'Aruba',
  '安圭拉': 'Anguilla',
  '阿根廷': 'Argentina'
}

Once all date has been through the process the results will be sent to the server using Angular’s $http method.

You can see from the code above that this process can be used to fetch English strings and convert them to Chinese as well if the user is using the app with the Chinese language setting.

// en_zh.json
{
  'Aruba': '阿鲁巴',
  'Anguilla': '安圭拉',
  'Argentina': '阿根廷'
}