- π΅ Locale-aware numbers. Formatting of currencies, decimals, and percentages.
- π Locale-aware dates and times formatting
- π Locale-aware display of relative time. I.e,
"now"
,"yesterday"
,"2 mo. ago"
- π¬ ICU Message Syntax. Pluralization and formatted segments (numbers, datetime, etc.).
- π Support for 150+ languages.
- π Built largely on standards. ICU message syntax & Native Intl API.
- β‘ Extensive Ember Service API and template helpers for formatting and translating.
- π Advanced addon support to provide translations to the host app
ember i ember-intl
Here is a light touch migration guide to help you get started. If you uncover any gaps, submit a PR to update the migration doc or open an issue.
Documentation is hosted in the repository within the /docs
folder.
Translations are defined in ICU message syntax and store in <project_root>/translations
in either JSON and/or YAML format. Nested directories are supported along with nested objects within your translation files.
Example basic translation file /translations/homepage/en-us.yaml
:
homepage:
banner: '<strong>{product}</strong> will cost <em>{price, number, USD}</em> if ordered by {deadline, date, time}'
This is can be done at any point within your app boots. This is typically done within your Application route's beforeModel
hook by calling intl.setLocale('en-us')
Read more about the Service API.
// app/routes/application.js
export default Route.extend({
intl: service(),
beforeModel() {
/* NOTE: if you lazily load translations, here is also where you would load them via `intl.addTranslations` */
return this.intl.setLocale(['fr-fr', 'en-us']); /* array optional */
}
});
Compiles a ICU message syntax strings with its hash values passed.
# en-us.yml
photos:
banner: "You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.}}"
Template Helper
Service API
export default Component.extend({
intl: service(),
banner: computed('intl.locale', 'model.photos.length', function() {
return this.intl.t('photos.banner', {
photos: this.get('model.photos.length')
});
})
});
Formats numbers using Intl.NumberFormat
, and returns the formatted string value.
Or programmatically convert a number within any Ember Object.
export default Component.extend({
intl: service(),
computedNumber: computed('intl.locale', 'cost', function() {
return this.intl.formatNumber(this.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.
export default Component.extend({
intl: service(),
computedNow: computed('intl.locale', function() {
return this.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 Component.extend({
intl: service(),
computedNow: computed('intl.locale', function() {
return this.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 Component.extend({
timestamp: computed(function() {
let date = new Date();
date.setDate(date.getDate() - 3);
return date;
})
});
units
is optional, by default will default to best-fit
. A full list of supported unit options
Or programmatically convert a relative time within any Ember Object.
export default Component.extend({
intl: service(),
yesterday: computed('intl.locale', function() {
let date = new Date();
return this.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 relative options
Template Helper
Service API
export default Component.extend({
intl: service(),
count: 0,
label: computed('intl.locale', 'model.photos.length', function() {
return this.intl.formatMessage(`
You took {numPhotos, plural,
=0 {no photos}
=1 {one photo}
other {# photos}
}
`,
{
numPhotos: this.get('model.photos.length')
});
}).readOnly()
});
Escapes all hash arguments and returns as an htmlSafe String which renders an ElementNode. To enable rendering HTML within translations, pass an htmlSafe
attribute to the t
helper.
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.intl.formatDate('Thu Jan 23 2014 13:00:44', {
format: 'hhmmss'
})
Output of both the helper and the programmatic example:
1:00:44 PM
- 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
Asynchronously loading translations instead of bundling translations within app.js
are fully-supported as of 2.x.
https://github.com/ember-intl/ember-intl/blob/master/docs/asynchronously-loading-translations.md
ember-intl ships with a number of helpers for assist with writing tests. Documentation
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.
- Simple migration tool to convert your translations files and application code to this addon. Feel free to report any issues with the migration tool here.