handlebars-i18n adds internationalization to handlebars.js using i18next and Intl.
npm install handlebars-i18nWhat it is about: handlebars-i18n adds the translation features of i18next
to handlebars.js. It also provides date, number, and currency formatting
via Intl. Use as node module or in the web browser. handlebars-i18n is listed amongst i18next’s official framework helpers.

!Node.js version




!npm
!npm
!GitHub stars
- handlebars-i18n comes lightweight, well tested, and with detailed examples
- allows granular custom presets per language
- supports Typescript
- has an optional CLI for automatic Translations via DeepL
handlebars-i18n is free but not free of value. If you make serious use of handlebars-i18n, I’d be delighted if you

``sh`
npm i handlebars-i18n
Import with ES6 syntax:
`typescript`
import HandlebarsI18n from "handlebars-i18n";
HandlebarsI18n.init();
As commonJS within node environment:
`javascript`
const HandlebarsI18n = require("handlebars-i18n");
HandlebarsI18n.init();
Usage in web browser (old school):
`javascript
`
Via CDN:
`javascript`
Initialize i18next with your language strings and default settings:
`javascript
const i18next = require("i18next");
i18next.init({
resources: {
"en": {
translation: {
"phrase1": "What is good?",
"phrase2": "{{thing}} is good."
}
},
"de": {
translation: {
"phrase1": "Was ist gut?",
"phrase2": "{{thing}} ist gut."
}
}
},
lng: "en",
compatibilityJSON: 'v2'
});
`
Set your Handlebars.js data object:
`javascript`
let data = {
myItem: "handlebars-i18n",
myPrice: 1200.99,
myDate: "2020-03-11T03:24:00"
}
Initialize handlebars-i18n:
`javascript`
HandlebarsI18n.init();
Optionally configure your language specific number, currency, and date-time defaults:
`javascript`
HandlebarsI18n.configure([
["en", "PriceFormat", {currency: "USD"}],
["de", "PriceFormat", {currency: "EUR"}]
]);
Finally use in template:
` {{__ "phrase1"}} hbs`
* output: en → What is good? | de → Was ist gut?
` {{__ "phrase2" thing=myItem}} hbs`
* output: en → handlebars-i18n is good. | de → handlebars-i18n ist gut.
` {{_date myDate}} hbs`
* output: en → March 11, 2020 at 3:24 AM | de → 11.3.2020, 03:24
` {{_price myPrice}} hbs`
* output: en → \$1,200.99 | de → 1.200,99 $
:point_right: See the examples folder in the repo for more use cases and details.
- Open examples/browser-example/index.html in your web browser to see an implementation with a simple UI.npm run example:js
- Prompt from the root of this repo to log a very basic node example to console.npm run example:ts
- Prompt to compile and log a typescript example.
:metal: handlebars-i18n has its own command line
interface handlebars-i18n-cli.
`sh`
npm i handlebars-i18n-cli --save-dev
* programmatically extract/ update translation strings from handlebars templates and generate i18next conform
JSON files from it
* automatic translation of i18next JSON via DeepL’s free API
Returns the phrase associated with the given key for the selected language. __ will take all options
i18next’s t-function would take.
The key can be passed hard encoded in the template when written in quotes:
`hbs`
{{__ "keyToTranslationPhrase"}}
… or it can be referenced via a handlebars variable:
`hbs`
{{__ keyFromHandlebarsData}}
Variable Replacement
Template usage:
`hbs`
{{__ "whatIsWhat" a="Everything" b="fine"}}
The i18next resource:
`javascript`
"en" : {
translation : {
"whatIsWhat" : "{{a}} is {{b}}."
}
}
* output: en → Everything is fine.
Plurals
`hbs`
{{__ "keyWithCount" count=8}}
`javascript`
"en" : {
translation : {
"keyWithCount" : "{{count}} item",
"keyWithCount_plural" : "{{count}} items"
}
}, ...
Override the globally selected language
`hbs`
{{__ "key1" lng="de"}}
Will output the contents for de even though a different language is globally set.
Looping over an array (or object) of translations
`hbs`
{{#each (__ "fruits")}}
{{/each}}fruits
In this case the key would contain an array of translation strings, like:
`javascript`
{
en: {
translation: {
fruits: ["Apple", "Banana", "Cherry"]
}
},
returnObjects: true
}
It is recommended to set returnObjects actively to true in the i18next.init object if you want to loop over
an array or objects of properties.
---
Checks if a i18next translation key exists. Returns true or false.
`hbs`
{{#if (keyExists "myKey")}} {{__ "myKey"}} {{/if}}
---
Returns the shortcode of i18next’s currently selected language such as en, de, ja … etc.
`hbs`
{{_locale}}
---
Checks a string against i18next’s currently selected language. Returns true or false.
`hbs`
{{#if (localeIs "en")}} ... {{/if}}
---
Outputs a formatted date according to the language specific conventions.
`hbs`
{{_date}}
If called without argument the current date is returned. Any other input date can be passed as a conventional date
string, a number (timestamp in milliseconds), or a date array. _date accepts all arguments
Javascript’s new Date()
constructor would accept.
Date argument given as date string:
`hbs`
{{_date "2020-03-11T03:24:00"}}
or
`hbs`
{{_date "December 17, 1995 03:24:00"}}
Date argument given as number (milliseconds since begin of unix epoch):
`hbs`
{{_date 1583922952743}}
Date argument given as javascript date array [year, monthIndex [, day [, hour [, minutes [,
seconds [, milliseconds]]]]]]:
`hbs`
{{_date "[2012, 11, 20, 3, 0, 0]"}}
Additional arguments for formatting:
You can add multiple arguments for individual formatting.
See Intl DateTimeFormat
for your option arguments. Alternatively check this repo’s TS types
in handlebars-i18n.d.ts.
`hbs`
{{_date 1583922952743 year="2-digit" day="2-digit" timeZone="America/Los_Angeles"}}
---
Adds a time offset in a given unit to a date, returns the modified date.
`hbs`
{{_dateAdd "1996-12-17" 24 unit="hour"}}
* output: en → 12/18/1996
The first argument is a date (see function _date for valid date inputs). The second argument is a time amount givensecond
as number. The option unit specifies the time amount. Possible units
are | minute | hour | day | week | month | quarter | year (default is hour)._date
Further options as for function can be applied.
---
Outputs the time difference between two given dates in the requested unit.
`hbs`
{{_dateDiff "2000-12-17" "2001-12-17" unit="year"}}
* output: en → in 1 year
The second date argument is subtracted from the first. If the difference is a positive value, a future event statement
is made. A negative value refers to a past date. (If no second argument is given, the default date is the present moment).
Allowed date input formats are similar to _date, options equal _dateRel. Default unit is hour.
---
Outputs a string with a relative date statement, formatted according to the language specific conventions.
`hbs`
{{_dateRel 7 unit="hour"}}
* output: en → in 7 hours
`hbs`
{{_dateRel -7 unit="hour"}}
* output: en → 7 hours ago
A positive number argument leads to a future event statement, a negative refers to a past date. Possible units
are second | minute | hour | day | week | month | quarter | year (default is hour).numberingSystem
For a complete set of options (such as or localeMatcher)
see Intl.RelativeTimeFormat Constructor.
Alternatively check this repo’s TS types in handlebars-i18n.d.ts.
---
Outputs a formatted number according to the language specific conventions of number representation.
`hbs`
{{_num 3.14159}}
Additional arguments for formatting:
You can add multiple arguments for individual formatting.
See Intl NumberFormat
for your option arguments. Alternatively check this repo’s TS types
in handlebars-i18n.d.ts.
`hbs`
{{_num 3.14159 maximumFractionDigits=2}}
* output: en → 3.14 | de → 3,14
---
Outputs a formatted currency string according to the language specific conventions of price representation.
`hbs`
{{_price 9999.99}}
Additional arguments for formatting:
You can add multiple arguments for individual currency formatting.
See Intl NumberFormat
for your option arguments. Alternatively check this repo’s TS types
in handlebars-i18n.d.ts.
`hbs`
{{_price 1000 currency="JPY" minimumFractionDigits=2}}
---
methodInstead of defining the formatting options for each date, number or price anew, you can configure global settings for
all languages or only for specific languages.
`javascript`
HandlebarsI18n.configure("all", "DateTimeFormat", {timeZone: "America/Los_Angeles"});
First argument is the language shortcode or "all" for all languages. Second is the format option you want toDateTimeFormat
address (, RelativeTimeFormat, NumberFormat, or PriceFormat). Third argument is the options object
with the specific settings.
Examples for generic settings:
`javascript`
HandlebarsI18n.configure("all", "RelativeTimeFormat", {style: "long", unit: "second"});
`javascript`
HandlebarsI18n.configure("all", "NumberFormat", {numberingSystem: "latn", maximumFractionDigits: 0});
`javascript`
HandlebarsI18n.configure("all", "PriceFormat", {currency: "HKD", currencyDisplay: "code"});
You can also define specific subsets to be used in the template, i.e. if you want the date in different formats such as:
- 2020 (year-only)standard-date
- 11.3.2020 ()time-only
- 7:24:02 ()
To do this, define a 4th parameter with a custom name:
`javascript`
HandlebarsI18n.configure([
["en", "DateTimeFormat", {year: "numeric"}, "year-only"],
["en", "DateTimeFormat", {year: "numeric", month: "numeric", day: "numeric"}, "standard-date"],
['en', 'DateTimeFormat', {hour: "numeric", minute: "numeric", second: "numeric", hour12: false}, "time-only"]
]);
Call a subset in template with the parameter format="custom-name", like:
`hbs`
{{_date myDate format="year-only"}}
Subsets must be defined per language, a subset for "all" is invalid.
The general lookup cascade is:
- 1st Priority: The argument given in the template for custom configurations by the key "format",
i.e. {{_date format="my-custom-format"}}{{_date timeZone="America/Los_Angeles" year="2-digit"}}
- 2nd Priority: The extra argument(s) given in the template,
e.g.
- 3rd Priority: The global setting configured for the current language, such as "en"
- 4th Priority: The global setting configured for all languages
- Default: The Intl default setting
Example:
This defines that all prices for all languages are represented in Dollar:
`javascript`
HandlebarsI18n.configure("all", "PriceFormat", {currency: "USD"});
This defines that all prices for all languages are represented in Dollar, but that for the language French the currency
is Euro:
`javascript`
HandlebarsI18n.configure([
["all", "PriceFormat", {currency: "USD"}],
["fr", "PriceFormat", {currency: "EUR"}]
]);
Dismiss all existing configurations:
`javascript`
HandlebarsI18n.reset();
Sometimes you may want to use a Handlebars object you have already modified before, or you may want to use multiple
discrete instances of Handlebars. In this case you can pass you custom Handlebars instance to the init function to use
it instead of the generic Handlebars object like so:
`javascript`
const HandlebarsModified = require("handlebars");
HandlebarsModified.registerHelper("foo", function () {
return "bar"
});
HandlebarsI18n.init(HandlebarsModified);
HandlebarsI18n will have your previously defined method foo by now.
The same can be done for a custom instance of i18next. Pass it as the second argument to the init function.
`javascript`
const i18nextCustom = require("i18next");
i18nextCustom.createInstance( / pass some params here ... /);
HandlebarsI18n.init(null, i18nextCustom);
`sh``
npm test
MIT License, Copyright (c) 2020–26 Florian Walzel
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
For your contribution, I would like to
thank @MickL, @dargmuesli, and @DiefBell.
There is a different package named handlebars-i18next
by @jgonggrijp which might also suit your needs. Cheers!