Handlebars Intl Handlebars logo

Handlebars helpers for internationalization.

npm install handlebars-intl

This library provides a set of helpers to internationalize your Handlebars templates:

Features

Helpers

How It Works

Create a Handlebars Template Using a Helper

<p>{{formatNumber price style="currency" currency="USD"}}</p>

Render the Template

var intlData = {
    locales: 'en-US'
}

var context = {
    price: 1000
};

var html = template(context, {
    data: {intl: intlData}
});

Rendered

$1,000.00

Usage

Browser

1. Load the Scripts onto the Page

First, load Handlebars and Handlebars Intl onto the page:

<script src="handlebars/dist/handlebars.min.js"></script>
<script src="handlebars-intl/dist/handlebars-intl.min.js"></script>

By default, handlebars-intl ships with the locale data for English built-in to the library's runtime. When you need to format data in another locale, include its data; e.g., for French:

<script src="handlebars-intl/dist/locale-data/fr.js"></script>

All 150+ languages supported by this library use their root BCP 47 language tag; i.e., the part before the first hyphen (if any).

Note: Older browsers do not have the built-in Intl APIs (ECMA-402). Read more on how to patch the browser runtime using a polyfill.

2. Register the Helpers

HandlebarsIntl.registerWith(Handlebars);

Node/CommonJS

1. Require the Module

var Handlebars     = require('handlebars');
var HandlebarsIntl = require('handlebars-intl');

In Node.js, the data for all 150+ languages is pre-loaded and does not need to be loaded manually.

Note: Node.js <= 0.10 doesn't have the built-in Intl APIs (ECMA-402). Node.js 0.12 does, but the default build/distribution only supports English. Read more on how to patch Node.js using a polyfill.

2. Register the Helpers

HandlebarsIntl.registerWith(Handlebars);

Format Numbers with Separators

The {{formatNumber}} helper is used to represent a number in a way appropriate for the current locale. It formats numbers using Intl.NumberFormat, and returns the formatted string value.

<ul>
    <li>{{formatNumber num}}</li>
    <li>{{formatNumber completed style="percent"}}</li>
    <li>{{formatNumber price style="currency" currency="USD"}}</li>
</ul>

Rendered

  • 42 000
  • 90 %
  • 100,95 US$

Using Named Number Formats

Specifying formatting options (e.g.: style="currency" currency="USD") in every call to {{formatNumber}} in your templates can become a problem in large code bases, and isn't DRY. Instead, you can setup data.intl.formats.number to define named number formats.

<ul>
    <li>{{formatNumber num}}</li>
    <li>{{formatNumber completed "percentage"}}</li>
    <li>{{formatNumber price "USD"}}</li>
</ul>

Rendered

  • 42 000
  • 90 %
  • 100,95 US$

In the example above, "USD" and "percentage" are names of number formats defined in intlData, which is used when rendering the template. Check the RENDER tab to see the details.

See the custom formats section for more information.

Format Dates and Times Correctly

The {{formatDate}} helper is used to represent a date in a way appropriate for the current locale. It formats dates using Intl.DateTimeFormat, and returns the formatted string value.

<p>{{formatDate date day="numeric" month="long" year="numeric"}}</p>

Rendered

21. února. 2017

Using Named Date Formats

Specifying format options (e.g.: day="numeric" month="long" year="numeric") in every call to {{formatDate}} in your templates can become a problem in large code bases, and isn't DRY. Instead, you can setup data.intl.formats.date to define application-level named date formats.

<p>{{formatDate date "short"}}</p>

Rendered

21. února. 2017

In the example above, "short" is the name of a date format defined in formats.date in intlData. Check the RENDER tab to see the details.

See the custom formats section for more information.

Using Named Time Formats

The {{formatTime}} helper is just like the {{formatDate}} helper, except it will reference any named formats from data.intl.formats.time.

Format Dates Relative To "now"

The {{formatRelative}} helper is used to represent a relative time in a way appropriate for the current locale. It formats the relative time following the rules from Unicode CLDR, and returns the formatted string value.

<ul>
    <li>{{formatRelative postDate}}</li>
    <li>{{formatRelative commentDate}}</li>
    <li>{{formatRelative meetingDate}}</li>
</ul>

Rendered

  • včera
  • před 2 hodinami
  • za 1 hodinu

Using Specific Relative Units

By default, the relative time is formatted using the best fit unit of time. However, you can explicitly set the units option one of the following values:
"second", "minute", "hour", "day", "month" or "year".

<p>
    <b>{{formatRelative postDate}}</b> <i>(best fit)</i><br>
    <b>{{formatRelative postDate units="minute"}}</b> <i>(in minutes)</i>
</p>
<p>
    <b>{{formatRelative lastTrip}}</b> <i>(best fit)</i><br>
    <b>{{formatRelative lastTrip units="day"}}</b> <i>(in days)</i>
</p>

Rendered

včera (best fit)
před 1 320 minutami (in minutes)

před 2 měsíci (best fit)
před 70 dny (in days)

Using Specific Relative Styles

The style option provides another level of customization. By default, the relative time is computed with a "best fit" style, which means, for example, that instead of "1 day ago", it will display "yesterday", or "in 1 year" will be "next year", etc. The other style is "numeric", in which the output will always contain a number.

<p>
    <b>{{formatRelative postDate}}</b> <i>(best fit)</i><br>
    <b>{{formatRelative postDate style="numeric"}}</b> <i>(numeric)</i>
</p>
<p>
    <b>{{formatRelative lastTrip}}</b> <i>(best fit)</i><br>
    <b>{{formatRelative lastTrip style="numeric"}}</b> <i>(numeric)</i>
</p>

Rendered

včera (best fit)
před 1 dnem (numeric)

minulý rok (best fit)
před 1 rokem (numeric)

Using Named Relative Formats

Specifying format options (e.g.: style="numeric") in every call to {{formatRelative}} in your templates can become a problem in large code bases. Instead, you can setup data.intl.formats.relative to define application-level named relative formats.

<p>
    <b>{{formatRelative postDate}}</b> <i>(best fit)</i><br>
    <b>{{formatRelative postDate "hours"}}</b> <i>(hours, numeric)</i>
</p>
<p>
    <b>{{formatRelative lastTrip}}</b> <i>(best fit)</i><br>
    <b>{{formatRelative lastTrip "hours"}}</b> <i>(hours, numeric)</i>
</p>

Rendered

včera (best fit)
před 24 hodinami (hours, numeric)

předevčírem (best fit)
před 48 hodinami (hours, numeric)

In the example above, "hours" is the name of a relative format defined in the formats.relative component prop. Check the RENDER tab to see the details.

See the custom formats section for more information.

Pluralize Labels in Strings

When internationalizing Handlebars templates, you will need a way to localize your UI strings, including any logic pieces like pluralization rules for all the languages you wish to support. These strings should be externalized from your Handlebars templates so that the same template can be used for all languages. This library provides two methods that can work together to provide a way to lookup and format language-specific strings.

The {{intlGet}} helper implements a lookup process by path to access data from the intl object passed into the Handlebars data channel when rendering the template. Usually this helper is used in a subexpression to lookup translated string messages; e.g., (intlGet "messages.photos").

The {{formatMessage}} helper formats a translated message written in the ICU Message syntax, which is used by professional translators. The message format supports placeholders, plus choosing different strings based on pluralization, gender, or other criteria.

See the Guide for details on how to write those messages using the ICU Message syntax.

<p>
    {{formatMessage (intlGet "messages.photos")
        name=name
        numPhotos=numPhotos
        takenDate=takenDate}}
</p>

Rendered

21. února. 2017 Annie vyfotila 1 000 fotek.

In the example above, we use (intlGet "messages.photos") as a subexpression to delegate the lookup process for "message.photos". It is equivalent to the accessing the value from @data.intl.messages.photos, but it will provide descriptive error messages when accessing a property that is undefined, unlike Handlebars built-in data channel access syntax @. Check the RENDER tab to see the details.

Note: You can provide the messages object when rendering the top-level template, and messages — just like locales — will be propagated to any partial or helper.

Additionally, you can use named formats as described below, to specify a set of named format options to use in your messages, e.g: {someNum, number, USD} and {someDate, date, short} or {someTime, time, long}.

Format Messages That Contain HTML

If a message string contains HTML, you can use the {{formatHTMLMessage}} helper, which has the exact same API as {{formatMessage}} but it will not escape the HTML in the message's text. However, it will escape all the values the message if formatted with, but remember to be cautious of untrusted user input to prevent XSS injections.

Create Intl Lambda

The {{#intl}} block helper can be used to create a new intl data scope by updating the intl data supplied to Handlebars within the block. This is useful when you need to render part of the page in a particular locale, or need to supply the intl data to Handlebars via the template's context — some Handlebars integrations might not support supplying options.data.intl when rendering.

<p>
    <b>{{formatDate date day="numeric" month="long"}}</b>
    <i>(current locale)</i>
</p>

{{#intl locales="fr-FR"}}
    <p>
        <b>{{formatDate date day="numeric" month="long"}}</b>
        <i>("fr-FR" locale)</i>
    </p>
{{/intl}}

Rendered

21. února (current locale)

21 février ("fr-FR" locale)

You can use this approach for formats and messages, which are normally passed via intlData object when rendering the template. Check the RENDER tab to see the details.

Define Your Own Custom Formats

Handlebars Intl allows you to define named formats that you can be used throughout your entire application or within a template and its partials. These named formats can be specified for date, time, number and relative format types. The following example illustrates how these custom named formats work.

<ul>
    <li>{{formatNumber       price "USD"}}</li>
    <li>{{formatDate     timestamp "short"}}</li>
    <li>{{formatTime           now "hhmm"}}</li>
    <li>{{formatRelative yesterday "hours"}}</li>
</ul>

Rendered

  • 1 400,34 US$
  • 23. ledna. 2014
  • 16:27
  • před 24 hodinami

In the example above, "USD", "short", "hhmm", and "hours" are the named custom formats defined in formats in intlData. Check the RENDER tab to see the details.

Note: You can provide the formats object when rendering the top-level template, and formats — just like messages and locales — will be propagated to any partial or helper.