> adonis install @adonisjs/antl
You are viewing the legacy version of AdonisJS. Visit https://adonisjs.com for newer docs. This version will receive security patches until the end of 2021.
AdonisJs has first class support for internationalization built on top of formatjs.io standards.
Using the Antl Provider, you can easily translate numbers, dates, and messages into multiple languages.
As the Antl Provider is not installed by default, we need to pull it from npm
:
> adonis install @adonisjs/antl
Next, we need to register the provider inside the start/app.js
file:
const providers = [
'@adonisjs/antl/providers/AntlProvider'
]
Your locales
configuration object must be saved inside the config/app.js
file with the following options:
Option | Value | Description |
---|---|---|
|
ISO 639 |
The default application locale (must be one of the available locales from ISO 639 codes). |
|
|
The loader to use for loading your different language translations. |
module.exports = {
locales: {
loader: 'file',
locale: 'en'
}
}
When using the file
loader, all locales are stored inside the resources/locales
directory.
Each locale directory should contain a list of group translation files, like so:
└── resources
└── locales
├── en
│ ├── alerts.json
│ ├── cart.json
│ └── store.json
└── fr
├── alerts.json
├── cart.json
└── store.json
In the example above, each locale contains 3 hypothetical translation groups: alerts , cart and store . Create as many group files per locale as per your application needs.
|
You can also create a directory named fallback
to store messages which are used when the message for the current language can’t be found:
└── resources
└── locales
├── en
│ └── messages.json
├── fallback
│ └── messages.json
└── fr
└── messages.json
When using the database
loader, all locales are fetched from the locales
database table.
The adonis install command creates the migration for the locales table.
|
You can always reference the latest migration source file on Github. |
An example locales
database table might look like so:
id | locale | group | item | text |
---|---|---|---|---|
1 |
en |
messages |
greeting |
Hello {name} |
2 |
fr |
messages |
greeting |
Bonjour {name} |
3 |
en |
cart |
total |
Cart total is {total, number, usd} |
4 |
fr |
cart |
total |
Le panier est total {total, number, usd} |
You must define a group value for each locales item.
|
You can access the current and default locale via the Antl
object:
const Antl = use('Antl')
Antl.currentLocale()
Antl.defaultLocale()
AdonisJs uses the industry standard ICU Message syntax to format messages.
The following topics define the usage of the ICU message syntax.
To retrieve a translation value, simply reference it by its group.item
key:
{
"greeting": "Hello"
}
Antl.formatMessage('messages.greeting')
You can pass dynamic arguments to inject into placeholders which are defined by { }
curly braces inside your messages:
{
"greeting": "Hello {name}"
}
Antl.formatMessage('messages.greeting', { name: 'virk' })
The values passed to a message can be optionally formatted by type.
You must register your formats before you can use them (see Registering Formats). |
For example, when passing a number we can format it as a currency
:
{
"total": "Cart total is {total, number, usd}"
}
For the placeholder {total, number, usd}
in the message above:
total
is the value passed.
number
is the type of the value.
usd
is the format for that type of value.
As the ICU message syntax doesn’t understand formats directly, we need to pass them manually when formatting a message:
const Antl = use('Antl')
const Formats = use('Antl/Formats')
Antl.formatMessage(
'cart.total',
{ total: 20 },
[Formats.pass('usd', 'number')]
)
In the example above, we are simply calling formatMessage
with 3 arguments:
cart.total
is the reference to the message to be formatted.
{ total: 20 }
is the data passed to that message.
[Formats.pass('usd', 'number')]
is an array of possible formats.
The select
format defines conditional output based on the passed value:
{gender, select,
male {He}
female {She}
other {They}
} will respond shortly
Try and edit the message above in your browser. |
The plural
format defines plurilization options based on the passed value:
{count, plural,
=0 {No candy left}
one {Got # candy left}
other {Got # candies left}
}
Try and edit the message above in your browser. |
Below is the list of methods you can use to format messages or raw values.
The formatMessage
method expects the key
to be formatted (group.item):
const Antl = use('Antl')
Antl.formatMessage('messages.greeting')
It can also accept an object of dynamic data
to pass to the message:
const Antl = use('Antl')
Antl.formatMessage('response.eta', { gender: 'male' })
Finally, it can also accept an array of formats
to parse passed data with:
const Antl = use('Antl')
const Formats = use('Antl/Formats')
Antl.formatMessage(
'cart.total',
{ total: 20 },
[
Formats.pass('usd', 'number')
]
)
Format value as a number (accepts NumberFormat options
as defined here):
Antl.formatNumber(10)
// as currency
Antl.formatNumber(10, {
style: 'currency',
currency: 'usd'
})
// as percentage
Antl.formatNumber(10, {
style: 'percent'
})
Format value with style
set to currency:
Antl.formatAmount(100, 'usd')
Format value as date (accepts DateTimeFormat options
as defined here):
Antl.formatDate(new Date())
// pull weekday for the date
Antl.formatDate(new Date(), {
weekday: 'long'
})
// pull day only
Antl.formatDate(new Date(), {
day: '2-digit'
})
Format a date relative to the current date/time (accepts RelativeFormat options
as defined here):
Antl.formatRelative(new Date())
// always in numeric style
Antl.formatRelative(new Date(), {
style: 'numeric'
})
The formatMessage method only accepts an array of pre-registered formats.
To register your formats for a given type:
const Formats = use('Antl/Formats')
Formats.add('usd', {
style: 'currency',
currency: 'usd'
})
Use it as follows:
Antl.formatMessage(
'cart.total'
{ total: 20 },
[
Formats.pass('usd', 'number')
]
)
The Formats.pass
method takes two arguments:
The first argument is the format to be used.
The second argument is the type to which the format should be applied.
You can pass multiple formats to a given type. For example:
{
"total": "USD total { usdTotal, number, usd } or in GBP { gbpTotal, number, gbp }"
}
Next, register the usd
and gbp
formats.
Formats.add('usd', {
style: 'currency',
currency: 'usd'
})
Formats.add('gbp', {
style: 'currency',
currency: 'gbp'
})
Finally, you can format the message as follows:
Antl.formatMessage(
'cart.total',
{ usdTotal: 20, gbpTotal: 13 },
[
Formats.pass('usd', 'number'),
Formats.pass('gbp', 'number')
]
)
USD total $20.00 or in GBP £13.00
The Antl Provider makes it simple to format the locale at runtime.
To do so, simply call forLocale
before formatMessage
:
Antl
.forLocale('fr')
.formatMessage('response.eta')
You can switch between loaders at runtime by calling the loader
method:
const Antl = use('Antl')
// asynchronous
await Antl.bootLoader()
// get antl instance for a booted loader
const AntlDb = Antl.loader('database')
// all methods are available
AntlDb.formatMessage()
Always call bootLoader before Antl.loader (you only need to call bootLoader once).
|
The Antl Provider binds the locale
property to the Http Context object:
Route.get('/', ({ locale }) => {
return `User language is ${locale}`
})
The locale property is resolved as follows:
The Accept-Language
HTTP header or lang
query parameter is examined to detect the user language.
The user language is matched against the list of available locales configured by your application. The configured locales are determined by messages saved inside the database or file system for given languages.
If the user language is not supported by your application, it will fallback to the default locale defined inside the config/app.js
file.
Since we can access the user locale
based on standard conventions, you can format messages in one of the following ways.
You can import the Antl Provider globally and manually call the forLocale
method when formatting values:
const Antl = use('Antl')
Route.get('/', ({ locale }) => {
return Antl
.forLocale(locale)
.formatNumber(20, { style: 'currency', currency: 'usd' })
})
You can also use the antl
object which is passed to all route handlers like request and response:
Route.get('/', ({ antl }) => {
return antl
.formatNumber(20, { style: 'currency', currency: 'usd' })
})
For example, you could then switch locale for a view like so:
Route.get('/', ({ antl, view }) => {
antl.switchLocale('fr')
return view.render('some-view')
}
As the antl
context instance is shared with all views, you can access its methods inside your view templates like so:
{{ antl.formatNumber(20, currency = 'usd', style = 'currency') }}
Alternatively, you can use the @mustache
tag to write multiple lines:
@mustache(antl.formatNumber(
20,
{ currency: 'usd', style: 'currency }
))
There is no way to switch loader inside templates. |