Presented by Rahul Doshi | @doshprompt
Our solution is based on a simple architecture. We will have a folder for each language that we would like to support. Inside will be localized resource files for each route or module we want to support.
We will also pick a default language that will be used to fall back to the site’s native language if a given user’s language is not supported.
100% of the code is run on the front-end within the browser, and no special server-side support needs to be provided.
The proposed directory structure:
lang ├── en-US │ ├── common.json │ ├── login.json │ ├── home.json │ └── ... ├── fr-FR │ ├── common.json │ ├── login.json │ ├── home.json │ └── ... └── ...
Below is an example of the file format:
{ "cancel": "Cancel", "no": "No", "ok": "OK", "yes": "Yes" }
A service will form the core of our localization engine, providing an interface that will be responsible for checking the user's language settings and requesting the appropriate resource based on the language.
It will also provide several methods, a lookup method that will return a localized string for a given key from the loaded resource file, a way to get/set the locale, and finally, a way to setup some defaults.
Lastly, it will notify us (via promises) when an individual file or a group of files has been successfully loaded into memory and is ready for use.
JavaScript:
$scope.strings = {}; locale.ready('common').then(function() { $scope.strings.helloWorld = locale.getString('common.helloWorld'); });
HTML:
<p>{{ strings.helloWorld }}</p>Edit in Plunker
Output:
Hello World!
This is naive as it requires you to manually refresh all the strings through the controller upon a change in language invoked by the user. Also does not take advantage of angular's excellent two-way bindings.Using Fliters:
<p>{{ 'common.helloWorld' | i18n }}</p>Edit in Plunker
Output:
Hello World!
Improvements with a Directive:
<p data-i18n="common.helloWorld"></p>Edit in Plunker
Output:
Hello World!
example.json
{ "nameOuput": "My name is %fullname" }
Filter:
<p>{{ 'example.nameOutput' | i18n:'Rahul Doshi' }}</p>
Directive:
<p data-i18n="example.nameOutput" data-fullname="Rahul Doshi"></p>Edit in Plunker
Good for when you want to avoid angular's interpolation in setting certain attributes on the DOM element such as placeholder for an input.
<input data-i18n-attr="{placeholder: 'login.emailPrompt'}">Edit in Plunker
In your controller:
$scope.numCount = 1; $scope.pluralStrings = { nobodyIsViewing: 'common.nobodyIsViewing', onePersonIsViewing: 'common.onePersonIsViewing', manyPeopleAreViewing: 'common.manyPeopleAreViewing' };
On the page:
<input type="number" min="0" data-ng-model="personCount"> <span data-ng-pluralize data-count="personCount" data-when="{ '0': '{{ pluralStrings.nobodyIsViewing | i18n }}', '1': '{{ pluralStrings.onePersonIsViewing | i18n }}', 'other': '{{ pluralStrings.manyPeopleAreViewing | i18n:personCount }}' }"> </span>Edit in Plunker
Experimental: using with ng-switch
<div data-ng-switch="user.gender"> <span> data-ng-switch-when="m" data-i18n="common.male"></span> <span> data-ng-switch-when="f" data-i18n="common.female"></span> </div>
ng-if also works with filter
Gender: <span data-ng-if="user.gender == 'm'">{{ 'common.male' | i18n }}</span> <span data-ng-if="user.gender == 'f'">{{ 'common.female' | i18n }}</span>Edit in Plunker
Slides: http://doshprompt.github.io/angular-localization-lightning-talk
Meetup: http://doshprompt.github.io/angular-localization-meetup