#kodio_2014

AngularJS and i18n

Beyond basic localization

By Pascal Precht / @PascalPrecht

Hi, I'm Pascal.

Innovation Engineer

ANIMATED GIF EXECUTER™

?

"AngularJS is what HTML would have been, had it been designed for applications." - Miško Hevery
++

Two way data-binding

The code:


            <label>How do you like Kod.io? It's</label>
<input type="text" ng-model="word">
<p>Kod.io is {{word}}</p>!

            

The output:

!

Kod.io is {{word}}!

Song Interpret
{{song.title}} {{song.artist}}

The code:


<section ng-controller="FilterCtrl">
  <input type="text" ng-model="search">
  <table>
    <tr>
      <td>Song</td>
      <td>Interpret</td>
    </tr>
    <tr ng-repeat="song in songs | orderBy:'title' | filter:search">
      <td>{{song.title}}</td>
      <td>{{song.artist}}</td>
    </tr>
  </table>
</section>
            

Still not impressed?

Drag me!

The code:


              <div draggable></div>

              

app.directive('draggable', function($document) {
  var startX=0, startY=0, x = 0, y = 0;
  return function(scope, element, attr) {
    element.css({
      position: 'relative',
      cursor: 'pointer'
    });
    element.bind('mousedown', function(event) {
      startX = event.screenX - x;
      startY = event.screenY - y;
      $document.bind('mousemove', mousemove);
      $document.bind('mouseup', mouseup);
    });

    function mousemove(event) {
      y = event.screenY - startY;
      x = event.screenX - startX;
      element.css({
        top: y + 'px',
        left:  x + 'px'
      });
    }

    function mouseup() {
      $document.unbind('mousemove', mousemove);
      $document.unbind('mouseup', mouseup);
    }
  }
});
              

Oh really?
Now that's impressive.

There's so much more

  • Dependency Injection
  • Views and Routes
  • Animations
  • Testability

Go and check out the docs!

What about i18n?

"Internationalization is the process of developing products in such a way that they can be localized for languages and cultures easily."
"Localization is the process of adapting applications and text to enable their usability in a particular cultural or linguistic market."

...WTF?

In other words:

Internationalizing an application means abstracting all of the strings and other locale-specific bits out of an application.

Localizing an application means providing translations and localized formats for the abstracted bits.

i18n support in Angular

Date filter

The code:


            {{ 1288323623006 | date:'fullDate' }}
{{ 1288323623006 | date:'yyyy-MM-dd HH:mm:ss' }}
            

The output:

{{ 1288323623006 | date:'fullDate' }}
{{ 1288323623006 | date:'yyyy-MM-dd HH:mm:ss' }}

Number filter

The code:


              Default formatting: {{number | number}}
No fractions: {{number | number:0}}
            

The output:

Default formatting: {{number | number}}

No fractions: {{number | number:0}}

Currency filter

The code:


Default currency symbol ($): {{amount | currency}}
Custom currency identifier (USD$): {{amount | currency:"USD$"}}
            

The output:

Default currency symbol ($): {{amount | currency}}

Custom currency identifier (USD$): {{amount | currency:"USD$"}}

ngPluralize

The code:


<label>Enter a number:</label>
<input type="text" ng-model="personCount">
<ng-pluralize 
  count="personCount"
  when="{'0': 'Nobody is viewing.',
        'one': '1 person is viewing.',
        'other': '{} people are viewing.'}"
  ></ng-pluralize>
            

The output:

Unfortunately... that's it.

Oh noes!

I got you covered.

Introducing...

angular-translate

angular-translate features:

  • Typical components: service, filter, directive
  • Variable replacement
  • Multi-Language
  • Fallback languages
  • Asynchronous loading

...and many more.

Teaching your app a language

The JavaScript code:


var app = angular.module('myApp', ['pascalprecht.translate']);

app.config(function ($translateProvider) {
  $translateProvider
    .translations('en', {
      'APP_TITLE': 'Hey this is my app title',
      'SOME_TEXT': 'Here\'s some text.'
    })
    .translations('de', {
      'APP_TITLE': 'Hey, dass ist mein App-Title',
      'SOME_TEXT': 'Hier ist etwas Text.'
    })
    .preferredLanguage('en');
});
              

The HTML code:


              <h1 translate="APP_TITLE"></h1>
<p translate="SOME_TEXT"></p>
              

The output:

Changing language at runtime

The HTML code:


              <div ng-controller="LangCtrl">
  <button ng-click="changeLanguage('en')">english</button>
  <button ng-click="changeLanguage('de')">german</button>
  <h1 translate="APP_TITLE"></h1>
  <p translate="SOME_TEXT"></p>
</div>
              

The JavaScript code:


app.controller('LangCtrl', function ($scope, $translate) {
  $scope.changeLanguage = function (langKey) {
    $translate.use(langKey);
  };
});
              

The output:

Variable replacement

The JavaScript code:


app.config(function ($translateProvider) {
  $translateProvider
    .translations('en', {
      'USER_LOGIN': 'Hello, you are logged in as {{user}}',
      'SOME_OTHER_TEXT': 'I need {{count | number}} beers right now!'
    })
    .translations('de', {
      'USER_LOGIN': 'Hallo, du bist eingeloggt als {{user}}',
      'SOME_OTHER_TEXT': 'Ich brauche jetzt {{count | number}} Bier!'
    })
    .preferredLanguage('en');
});
              

The HTML code:


<p translate="USER_LOGIN" translate-value-user="{{user}}"></p>
<p translate="SOME_OTHER_TEXT" translate-value-count="{{count}}"></p>
              

The output:

Gimme more awesomeness!

Fallback languages

The JavaScript code:


app.config(function ($translateProvider) {
  $translateProvider
    .translations('en', {
      'USER_LOGIN': 'Hello, you are logged in as {{user}}',
      'SOME_OTHER_TEXT': 'I need {{count | number}} beers right now!'
    })
    .translations('de', {
      'USER_LOGIN': 'Hallo, du bist eingeloggt als {{user}}',
      'SOME_OTHER_TEXT': 'Ich brauche jetzt {{count | number}} Bier!'
    })
    .translations('fr', {
      'GREETING': 'Salut!'
    })
    .preferredLanguage('en')
    .fallbackLanguage('fr');
});
              

The HTML code:


<p translate="USER_LOGIN" translate-value-user="{{user}}"></p>
<p translate="SOME_OTHER_TEXT" translate-value-count="{{count}}"></p>
<p translate="GREETING"></p>
              

The output:

Asynchronous Loading

Static files loader

The JavaScript code:


app.config(function ($translateProvider) {
  $translateProvider.useStaticFilesLoader({
    prefix: 'lang-',
    suffix: '.json'
  })
  .preferredLanguage('en');
});
              

Request: /lang-{langKey}.json

Custom loader

The JavaScript code:


app.config(function ($translateProvider, $provide) {
  $provide.factory('customLoader', function ($timeout, $q) {
    return function (options) {
      var deferred = $q.defer();
      $timeout(function () {
        deferred.resolve({
          'FOO': 'bar',
          'BAR': 'foo'
        });
      }, 5000);
      return deferred.promise;
    };
  });
  $translateProvider
    .useLoader('customLoader')
    .preferredLanguage('en');
});
              

The HTML code:


<p translate="FOO"></p>
<p translate="BAR"></p>
              

The output:

Just one more thing!

Ever seen a cat with Samuel Jackson face?