This library provides Ember Handlebar helpers and a localization service. The service, and helpers, provide a way to format dates, numbers, strings messages, including pluralization.
Ember Intl is part of FormatJS, the docs can be found on the website:
- ember-cli >= 0.2.0
- ember > 1.13.0
ember install ember-intl@beta
- Polyfill the Intl.js API (required for Safari/PhantomJS, and legacy browser)
- Instructions on loading from assets directory
- Instructions on conditionally loading the polyfill based on User-Agent
- Instructions on disabling polyfill
Translations are defined in /translations
, outside of app
in either JSON or YAML format. Example of /translations/en-us.yaml
:
# en-us
product:
info: '{product} will cost {price, number, USD} if ordered by {deadline, date, time}'
title: 'Hello world!'
html:
info: '<strong>{product}</strong> will cost <em>{price, number, USD}</em> if ordered by {deadline, date, time}'
If you wish, you can organize your translations into subdirectories such as /translations/login-page/en-us.yaml
and translations/purchase-page/en-us.yaml
.
Open, or create, app/routes/application.js
and in the beforeModel
hook set intl.locale
. Example:
// app/routes/application.js
export default Ember.Route.extend({
intl: Ember.inject.service(),
beforeModel() {
// define the app's runtime locale
// For example, here you would maybe do an API lookup to resolver
// which locale the user should be targeted and perhaps lazily
// load translations using XHR and calling intl's `addTranslation`/`addTranslations`
// method with the results of the XHR request
this.get('intl').setLocale('en-us');
}
});
- A default locale is required. This is used as the "source of truth" to determine if any translations are missing a translation at build time. It will offer warnings displaying with locale's are missing translations for a particular key. The default locale is configurable within
config/environment.js
.
// config/environment.js
return {
intl: {
defaultLocale: 'en-us' // default value
}
};
Formats numbers using Intl.NumberFormat
, and returns the formatted string value.
Or programmatically convert a number within any Ember Object.
// example
export default Ember.Component.extend({
intl: Ember.inject.service(),
computedNumber: Ember.computed('cost', function() {
return this.get('intl').formatNumber(this.get('cost')/*, optional options hash */);
})
});
List of supported format number options
Formats dates using Intl.DateTimeFormat
, and returns the formatted string value.
Or programmatically convert a date within any Ember Object.
// example
export default Ember.Component.extend({
intl: Ember.inject.service(),
computedNow: Ember.computed(function() {
return this.get('intl').formatDate(new Date()/*, optional options hash */);
})
});
List of supported format date options
This is just like the {{format-date}}
helper, except it will reference any string-named format
from formats.time
.
Or programmatically convert a time within any Ember Object.
// example
export default Ember.Component.extend({
intl: Ember.inject.service(),
computedNow: Ember.computed(function() {
return this.get('intl').formatTime(new Date()/*, optional options hash */);
})
});
List of supported format date options
Formats dates relative to "now" using IntlRelativeFormat
, and returns the formatted string value.
export default Ember.Component.extend({
timestamp: Ember.computed(function() {
var date = new Date();
date.setDate(date.getDate() - 3);
return date;
})
});
Or programmatically convert a relative time within any Ember Object.
// example
export default Ember.Component.extend({
intl: Ember.inject.service(),
yesterday: Ember.computed(function() {
var date = new Date();
return this.get('intl').formatRelative(date.setDate(date.getDate() - 1)/*, optional options hash */);
})
});
Recompute the relative timestamp on an interval by passing an interval
argument (in milliseconds).
List of supported format date options
Formats ICU Message strings with the given values supplied as the hash arguments. A short-hand form of the {{format-message}}
is {{t}}
.
You have {numPhotos, plural,
=0 {no photos.}
=1 {one photo.}
other {# photos.}}
Or programmatically convert a message within any Ember Object.
export default Ember.Component.extend({
intl: Ember.inject.service(),
yesterday: Ember.computed(function() {
return this.get('intl').formatMessage('Hello {name}', { name: 'Jason' });
})
});
This is done by using the {{l}}
(lowercase L) helper as a subexpression. This is useful for computed properties where you are programmatically constructing a translation string.
This delegates to the {{t}}
helper, but will first HTML-escape all of the hash argument values. This allows the message
string to contain HTML and it will be considered safe since it's part of the template and not user-supplied data.
Specifying format options (e.g.: style="currency" currency="USD") in every use of format helper can become a problem in large code bases, and isn't DRY. Instead, you can provide named formats through the use of exporting a POJO from app/formats
. All helpers accept a format
property which accepts a key that maps to the format option under its respected type (time, date, number, relative).
For example:
// app/formats.js
export default {
date: {
hhmmss: {
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
}
}
};
this.get('intl').formatDate('Thu Jan 23 2014 13:00:44', {
format: 'hhmmss'
})
Output of both the helper and the programmatic example:
1:00:44 PM
There are two options on how to load the Intl.js polyfill, either through the polyfill which ships with ember-intl or through polyfill.io. Both of which are documented: https://github.com/yahoo/ember-intl/wiki/Intl.js-Polyfill
- All helpers accept optional arguments:
locale
argument to explicitly pass/override the application localeformat
argument which you pass in a key corresponding to a format configuration inapp/formats.js
Phantom does support the Intl API, so in order for for you ember-intl to work in a browser which does not support the Intl API, it needs to be polyfilled.
To resolve this, add the following above all script tags in tests/index.html
:
<script src="assets/intl/intl.complete.js"></script>
date value is not finite in DateTimeFormat.format()
Browser vendors implement date/time parsing differently. For example, the following will parse correctly in Chrome but fail in Firefox: new Intl.DateTimeFormat().format('2015-04-21 20:47:31 GMT');
The solution is the ensure that the value you are passing in is in a format which is valid for the Date
constructor. This library currently does not try and normalize date strings outside of what the browser already implements.
ember server
- Visit your app at http://localhost:4200.
ember test
ember test --server