How to add I18N for an angularJS app - Step by step - Hands-on

In this post, you will get to know how to add L10n(Localization) support in your angularJS apps.

First things first, difference between I18n and L10n [1]

Localization refers to the adaptation of a product, application or document content to meet the language, cultural and other requirements of a specific target market (a "locale").
Internationalization is the design and development of a product, application or document content that enables easy localization for target audiences that vary in culture, region, or language.

Assumptions before you start

You have a angularJS app up and working.
You have using gulp (grunt setup will be similar)
You have nodeJS installed for npm and bower packages.

Let's start

Part A: Generating the string files for different locales.

1. Decorate the strings that needs to be translated with 'translate' directive

Simply add translate angularJS directive to the HTML elements that have text you would like to localize.
For example:
<div translate>Hello world!</div>
translate directive is defined in angular-translate that we will install in a bit.

2. Install angular-gettext

bower install --save angular-gettext

3. Add gulp tasks to create localization files [2]

var gulp = require('gulp');
var gettext = require('gulp-angular-gettext'); gulp.task('pot', function () {
    return gulp.src(['src/partials/**/*.html', 'src/scripts/**/*.js'])
        .pipe(gettext.extract('template.pot', {
            // options to pass to angular-gettext-tools... 
        }))
        .pipe(gulp.dest('po/'));
});
gulp.task('translations', function () {
    return gulp.src('po/**/*.po')
        .pipe(gettext.compile({
            // options to pass to angular-gettext-tools... 
            format: 'json'
        }))
        .pipe(gulp.dest('dist/translations/'));
});
After defining the above tasks, run task 'pot'.
gulp pot
This would generate template.pot file. Install poedit[3] to open template.pot file. Add translation files for each locale from within poedit. The output would bunch of *.po files.

4. Convert *.po files to *.json files

From the previous step, you will end up with *.po files, one for each locale. Run following gulp task to convert *.po to corresponding *.json.
gulp translations
With this, you will get JSON files. For example en_US.json, ru_ru.json. Now these files would be used by your angular app as mention in Part B below.

Part B: Using the string files in angularJS app

1. Install angular translation packages

bower install --save angular-translate
bower install --save angular-translate-loader-static-files  

2. Inject it as dependency in your root module and define the locale.

app
.module('myApp', ['pascalprecht.translate'])
.config(function($translateProvider){
    $translateProvider.useStaticFilesLoader({
        prefix: 'dist/translations/',
        suffix: '.json'
    });

    $translateProvider.preferredLanguage('en_US'); // locale based on user input
});
The above code will look for dist/translations/en_US.json



[1] http://stackoverflow.com/a/754557/989139
[2] https://www.npmjs.com/package/gulp-angular-gettext
[3] https://download.poedit.net/Poedit-1.8.5-setup.exe

Implement callback on completion of multiple asynchronous functions

Lets say, you need to execute a function 'myCallback' after completion of 2 async functions apiCall1 and apiCall2. Following is how you can implement this. Lets define the 2 async functions first:
var apiCall1 = function(){
 var complete1 = $.Deferred();
 $.ajax({
  url: '/url1',
  success: function(){
   successHandler1();
   complete1.resolve();
  }
 });
 return complete1.promise();
}
var apiCall2 = function(){
 var complete2 = $.Deferred();
 $.ajax({
  url: '/url2',
  success: function(){
   successHandler2();
   complete2.resolve();
  }
 });
 return complete2.promise();
}
Here is how you can define 'myCallback':
var myCallback = function(){
 //do something
}
$.when(apiCall1, apiCall2).done(myCallback);
Check out a working sample on JSFiddle.

References:

Preventing Cross-site request forgery in ASP.NET MVC


Let us start with the problem called as XSRF (Cross-site request forgery). Later we will use the solutions and one specific to ASP.NET MVC.

XSRF: Lets assume you have an account with website example.com which uses cookie-based authentication. Following are the steps which shows how XSRF can be exploited:

  • When logging into this website, cookies are set in your browser by example.com which will be used for authentication. 
  • Somehow, you click on a link provided by hacker say, hacker.com. This page contains a form which submits any critical data to example.com. Now, your cookies will be sent along with it for authentication.
That's it, now hacker can change your recovery email address, password etc to hack your account

General Solutions:

  • Example.com should check the referral webpage link in the post request to check if the request is coming from same domain only. But this is not 100% safe as this can be spoofed.
  • Maintain a GUID as cookie and a hidden input field in form. Example.com will proceed with entertaining the request only if both have same value. 
Consider the example of forgery above in case of solution 2. Now, the GUID value as cookie will be sent in request from hacker.com by the browser. (Note that hacker.com can not read cross-domain cookies.) But that GUID value will not be a part of form. Hence, example.com will not serve the request.

Solution for ASP.NET MVC:
Use Html.AntiForgeryToken(). This sets a cookie with key __RequestVerificationToken and generates following HTML code:
<input name="__RequestVerificationToken" type="hidden" value="TdsFsfkdNddddzdfNh4YbZjmEG0sdqlUddqddiab/dfVgdd2swweFrVyeylvzuwR" />