angular-localize
A localization module for AngularJS.
Table of contents
- [Module setup](#module-setup)
- [Translation mappings](#translation-mappings)
- [How to automatically create the translation mappings](#how-to-automatically-create-the-translation-mappings)
- [localize directive](#localize-directive)
- [Localize using the element content](#localize-using-the-element-content)
- [Localize using the localize attribute](#localize-using-the-localize-attribute)
- [Localize with dynamic user data](#localize-with-dynamic-user-data)
- [Configuring the observable directive attributes](#configuring-the-observable-directive-attributes)
- [localize service](#localize-service)
- [Localize filter](#localize-filter)
- [Localize factory](#localize-factory)
Getting started
Module setup
The easiest way to install thelocalize
module is via
NPM:npm install angular-localize --save
You can then include
angular-localize
after including its dependencies,
angular and
angular-sanitize:<script src="node_modules/angular/angular.js"></script>
<script src="node_modules/angular-sanitize/angular-sanitize.js"></script>
<script src="node_modules/angular-localize/angular-localize.js"></script>
Translation mappings
Thelocalize
module requires an object of translation mappings.By convention, this is a global object variable called
i18n
,
which must be available before the Angular application is initialized:window.i18n = {,
'Hello world!': 'Hallo Welt!',
'Hello {name}!': function (data) {
return 'Hallo ' + data.name + '!';
}
};
The
localize
module uses this map to lookup the translation results.The values of the map can be either static translation strings or dynamic translation functions.
The translation functions are expected to return strings with the translation result.
An optional object with dynamic user data is passed as only argument to the translation functions.
If no matching mapping is found, the key is used as the translation result.
Instead of storing the translation functions in a global object, it's also possible to decorate the
localizeConfig
service to override the
i18n
configuration property:angular.module('localize').config(['$provide', function ($provide) {
$provide.decorator('localizeConfig', ['$delegate', function ($delegate) {
$delegate.i18n = {
'Hello world!': 'Hallo Welt!',
'Hello {name}!': function (data) {
return 'Hallo ' + data.name + '!';
}
};
return $delegate;
}]);
}]);
How to automatically create the translation mappings
grunt-locales, a plugin for the Grunt task runner, provides command-line scripts to automate the creation of the translation mappings.grunt-locales parses
localize
attributes in HTML files as well as localize
method calls in JS files and
collects the parsed locale strings in JSON files for translation.The translated JSON locale files are then compiled into JavaScript files containing the object with the translation mappings.
To support translation features like pluralization and gender selection, grunt-locales relies on Alex Sexton's MessageFormat library to parse the locale strings and compile dynamic translation functions.
Usage Examples
localize directive
Localize using the element content
Any HTML element which can contain text nodes can be localized simply by adding thelocalize
attribute:<p localize>Save the Orangutans!</p>
If a translation function for the key
"Save the Orangutans!"
exists,
the localize
directive will replace the element content with the result of
executing the function.Localized element content can also contain HTML:
<p localize>Save the <strong>Orangutans</strong>!</p>
In this case, the key for the translation function is
"Save the <strong>Orangutans</strong>!"
.The result of the translation function of localizations defined via element content will always be assigned as HTML, but sanitized via angular-sanitize.
Localize using the localize attribute
Instead of the element content, the localization key can also be defined as value of thelocalize
attribute:<p localize="Save the Orangutans!"></p>
If no translation function for the key
"Save the Orangutans!"
exists,
the attribute value will be used as element content.Localizations defined via
localize
attribute cannot contain HTML tags,
as the translation result will be assigned as text, not as HTML.
This limitation enables a slightly faster localization, as no sanitization is
required.Localize with dynamic user data
It's also possible to provide dynamic user data to the translation functions.The
localize
directive observes all non-directive data-*
attributes and
passes them as normalized map of key/value pairs to the translation function:<p data-name="{{user.name}}" localize="Hello {name}!"></p>
Whenever
user.name
is updated, the translation function for "Hello {name}!"
gets called with an object, e.g. {name: 'Bob'}
as argument and the element
content is updated accordingly.This also works with the localization key as element content, which allows the use of HTML for the translation result:
<p data-name="{{user.name}}" localize>Hello <strong>{name}</strong>!</p>
In this case, all dynamic user data is escaped (HTML special characters are replaced with their respective HTML entity) before it is passed to the translation function.
Configuring the observable directive attributes
By default, thelocalize
directive only observes non-directive
data-attributes, which are identified by the observableAttrs
regular expression, a property of the localizeConfig
service.You can override the default setting by decorating the
localizeConfig
service:angular.module('localize').config(['$provide', function ($provide) {
$provide.decorator('localizeConfig', ['$delegate', function ($delegate) {
$delegate.observableAttrs = /^data-(?!ng-|localize)/;
return $delegate;
}]);
}]);
The regular expression is matched against the non-normalized attribute names of the directive. The default setting will match any
data-*
attributes which are
not followed by the strings ng-
or localize
.localize service
Thelocalize
service is an equivalent to the localize
directive and can be
used to generate localized results in situations where the directive cannot be
used:angular.module('example')
.controller([
'$scope', 'localize',
function ($scope, localize) {
$scope.text = localize(
'Hello {name}!',
{name: $scope.user.name}
);
}
]);
The
localize
service expects the localization key as first argument and an
optional object with user data as second argument.If the third argument is set to
true
, the user data will be escaped
(HTML special characters are replaced with their respective HTML entity),
which allows to output the translation result as HTML, although it still needs
to be properly sanitized depending on the security context:angular.module('example')
.controller([
'$scope', 'localize',
function ($scope, localize) {
$scope.text = localize(
'Hello <strong>{name}</strong>!',
{name: $scope.user.name},
true
);
}
]);
Generally, it is preferable to use the
localize
directive instead of the
service whenever possible, as the directive can determine its security context.However, grunt-locales is able to parse both the directive attributes as well as the localize service calls.
localize filter
Thelocalize
filter provides the same functionality as the service.It can be useful in templates where the localization strings are dynamic, e.g. for error messages:
<p>{{errorMessage | localize}}</p>
It is also possible to pass an object with localization arguments to the
localize
filter:<p>{{errorMessage | localize:data}}</p>
If the result of the localization is rendered as HTML, the localization arguments must be escaped by setting the second filter argument to
true
:<p ng-bind-html="errorMessage | localize:data:true"></p>
localize factory
ThelocalizeFactory
is a service to facilitate the creation of additional,
attribute-based localize
directives.Executing the
localizeFactory
function returns a
directive definition object that
identifies the attribute to update via its directive name.The following is the simple code required to create a
localize-title
directive:angular.module('example')
.directive('localizeTitle', ['localizeFactory', function (localizeFactory) {
return localizeFactory();
}]);
Directives created via the
localizeFactory
work the same way as the original
localize
directive, but instead of updating the element content,
they update their associated HTML attribute.The following is an example use of the created
localize-title
directive:<p data-name="{{user.name}}" localize-title="Hello {name}!"></p>
This directive will update the
title
attribute based on the translation
function and provided user data.The updated attribute is always the directive name with the
localize-
prefix removed.Therefore, as a convention, the directive name must always start with
localize
as prefix.