npm i --save adonis-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.
Internationalization is a process of translating your web apps into multiple different languages. Since web apps reach all parts of the world, internationalization makes it easier for you to detect the user language and translate your web apps for localized experience.
File (file)
Database (database)
It follows the conventions and libraries provided by Format.js.
All locale strings are defined using ICU Message Syntax.
All locale strings are stored within .json files inside resources/locales
directory or database table locales
based upon the driver you are using.
A middleware can be used to detect the user language in runtime.
Generic messages (same for all languages) are saved inside resources/locales/fallback
directory and fallback
group when using database driver.
The adonis-antl
package is not installed/setup by default, and you are required to install it when needed.
npm i --save adonis-antl
const providers = [
// ...
'adonis-antl/providers/AntlProvider'
// ...
]
const aliases = {
// ...
Antl: 'Adonis/Addons/Antl',
Formats: 'Adonis/Addons/AntlFormats'
// ...
}
Based upon the default driver you will have to store your locales inside the resources/locales
directory or the locales
database table. To make the setup process simple, you can run the following command.
const commands = [
// ...
'Adonis/Commands/Antl:Setup'
// ...
]
./ace antl:setup
# for database driver
./ace antl:setup --driver=database
Above command will create the resources/locales/*
directory or the migrations to create the database table.
The configuration for Antl Provider is saved inside config/app.js
file. Release version 3.1 includes the config by default but always make sure to keep it updated.
{
locales: {
driver: 'file',
locale: 'en',
fallbackLocale: 'en'
}
}
Key | Possible Values | Description |
---|---|---|
driver |
file, database |
The driver to use for reading/writing and removing locale strings. |
locale |
Any valid locale |
The default locale to be used when unable to detect user locale. |
fallbackLocale |
Any valid locale |
The fallback locale when detected user locale is not supported. |
Let’s start with a basic example of formatting raw values and messages written using ICU Syntax. This time, we will play with the Ace REPL within the command line.
./ace repl
repl+>
const Antl = use('Antl')
Antl.formatAmount(1000, 'usd')
// or
Antl
.for('fr') (1)
.formatAmount(1000, 'usd')
1 | The method for will let you switch the language for a single operation. |
!
Using the default file
driver, we can define locales inside the resources/locales
directory. Each language gets its own sub-directory.
{
"product.cost": "{product} will cost {price, number, usd}"
}
const Antl = use('Antl')
Antl.formatMessage('messages.product.cost', { product: 'Chair', price: 29 })
Chair will cost $29.00
Before you can start using the Antl provider, it is crucial to understand the ICU message syntax since it is a standard adopted by the web globally.
A message can be just a string literal in multiple different languages.
{
"greeting": "Hello!"
}
{
"greeting": "Bonjour!"
}
You can also define placeholders for simple arguments and pass dynamic data at runtime to replace them with their actual values.
{
"greeting": "Hello {name}"
}
{
"greeting": "Bonjour {name}"
}
use('Antl').formatMessage('messages.greeting', { name: 'Virk' })
// Returns - Hello Virk or Bonjour Virk
Formatted arguments give you the functionality to define the argument key, type and format as { key, type, format }
.
Name | Description |
---|---|
key |
Key is used to define the placeholder name which is used in the data object. |
type |
Defines the format type for the value. Internationalization has a set of defined types. |
format |
Format is an object of values defining how to format the type. For example: |
{
"cart.total": "Your cart total is {total, number, curr}"
}
Now when formatting the above message we need to pass curr
format to the number type, so that the inbuilt formatter can format the total as a currency.
const Antl = use('Antl')
Antl.formatMessage('messages.cart.total', { price: 59 }, (message) => {
message
.passFormat('curr')
.to('number')
.withValues({ currency: 'usd' })
})
Also, you can pass the format as an expression instead of attaching the callback.
const Antl = use('Antl')
Antl.formatMessage('messages.cart.total', { price: 59 }, 'curr:number[currency=usd]')
You can also access antl directly in your views using the antl
global.
{{ antl.formatMessage('messages.cart.total', { price: 59 }, 'curr:number[currency=usd]') }}
Below is the list of antl methods.
Permanently switch locale for all future translations.
Antl.setLocale('fr')
Antl.formatNumber(1000)
Return a list of registered locales as an array. It is based upon the messages saved inside a file/database.
Antl.locales()
Return a list of registered strings for a given/default locale. An optional group can be passed to fetch strings for a given group only.
This method can be helpful in populating a dropdown. |
Antl.strings()
// or
Antl.strings('messages')
// or
Antl.for('fr').strings()
This method is similar to strings but instead returns a flat object by joining nested objects with a (dot).
Antl.pair()
// or
Antl.pair('messages')
// or
Antl.for('fr').pair()
Get raw string for a given key
Antl.get('messages.cart.total')
// or
Antl.for('fr').get('messages.cart.total')
Update/Create value for a given key inside a group
This method will update the underlying store for the currently active driver which means it will update the database row or update the file system. |
yield Antl.set('messages', 'cart.total', 'You will be paying {total, number, curr}')
Remove a given key for the currently active locale.
yield Antl.remove('messages', 'cart.total')
This method is used to load
the locales for the currently active driver. First time Antl Provider will load all the strings for the default driver defined inside config/app.js
file whereas you are required to call this method manually whenever you switch the driver in runtime.
The load method smartly caches the values returned by a driver. Which means calling the method multiple time will have no side effects.
|
const db = Antl.driver('database')
yield db.load()
db.formatMessage('messages.cart.total', {total: 1000})
Since the load
method caches the values, you can make use of reload
to forcefully reloads all the strings for a given driver.
const db = Antl.driver('database')
yield db.reload()
db.formatMessage('messages.cart.total', {total: 1000})
Below is the list of formatter methods and available options you can pass to get desired output.
const Antl = use('Antl')
Antl.formatNumber(1000)
// or
Antl.formatNumber(1000, { style: 'percent' })
{{ antl.formatNumber(1000) }}
{# or #}
{{ antl.formatNumber(1000, { style: 'percent' }) }}
Key | Default Value | Possible Values | Description |
---|---|---|---|
style |
decimal |
decimal, currency, percentage |
The formatting style to be used for formatting the value. |
currency |
null |
A valid ISO 4217 currency code |
If style is currency, this option must pass a valid currency code to be used for formatting the value. Reference list of country code |
currencyDisplay |
symbol |
symbol, code |
How to display the currency. For example $ is the symbol and USD is the code |
useGrouping |
true |
true, false |
Whether to use grouping separators like thousand/lakh/crore separators. |
minimumIntegerDigits |
1 |
1-21 |
The minimum number of integer digits to use. |
minimumFractionDigits |
floating |
0-20 |
The minimum number of fraction digits to use. The default value is 0 for plain numbers and minor unit digits provided by the ISO 4217 for currency values. |
maximumFractionDigits |
floating |
0-20 |
The maximum number of fraction digits to use. The default value is greater than the minimumFractionDigits value. |
minimumSignificantDigits |
1 |
1-21 |
The minimum number of significant digits to use. |
maximumSignificantDigits |
minimumSignificantDigits |
1-21 |
The maximum number of significant digits to use. |
const Antl = use('Antl')
Antl.formatAmount(1000, 'usd')
// or
Antl.formatNumber(1000, { currencyDisplay: 'code' })
{{ antl.formatAmount(1000, 'usd') }}
{# or #}
{{ antl.formatAmount(1000, 'usd', { currencyDisplay: 'code' }) }}
The formatting options are similar to formatNumber
const Antl = use('Antl')
Antl.formatDate(new Date())
// or
Antl.formatDate(new Date(), { hour12: false })
{{ antl.formatDate(new Date()) }}
{# or #}
{{ antl.formatDate(new Date(), { hour12: false }) }}
Key | Default Value | Possible Values | Description |
---|---|---|---|
hour12 |
locale dependent |
true, false |
Whether to show time in 12 hours format or not. |
weekday |
none |
narrow, short, long |
The representation of the weekday. |
era |
none |
narrow, short, long |
The representation of the era. |
year |
none |
numeric, 2-digit |
The representation of the year. |
month |
none |
numeric, 2-digit, narrow, short, long |
The representation of the month. |
day |
none |
numeric, 2-digit |
The representation of the day. |
hour |
none |
numeric, 2-digit |
The representation of the hour. |
minute |
none |
numeric, 2-digit |
The representation of the minute. |
second |
none |
numeric, 2-digit |
The representation of the second. |
timeZoneName |
none |
short, long |
The representation of the time zone name. |
const Antl = use('Antl')
const threeHoursPrior = new Date().setHours(new Date().getHours() - 3)
Antl.formatRelative(threeHoursPrior)
// 3 hours ago
{{ antl.formatRelative(threeHoursPrior) }}
Key | Default Value | Possible Values | Description |
---|---|---|---|
units |
best fit |
second, minute, hour, day, month, year |
The particular rendering unit. For example 30 days ago instead of 1 month ago |
style |
best fit |
numeric |
The rendering style for the value. For example: numeric will force the output to 1 day ago instead of yesterday. |
Formatting a message requires you first to save your strings inside the locales files or the database table called locales
and it must follow the ICU Message Syntax.
const Antl = use('Antl')
Antl.formatMessage('messages.total', { total: 1000 })
// or
Antl.formatMessage('messages.total', { total: 1000 }, (message) => {
message.passFormat('curr').to.('number').withValues({ currency: 'usd' })
})
Since views do not allow adding callbacks to a function, you are supposed to pass a string expression to the formatMessage
method.
{{ antl.formatMessage('messages.total', { total: 1000 }) }}
{# or #}
{{ antl.formatMessage('messages.total', { total: 1000 }, 'curr:number[currency=usd]') }}
When working with Antl provider your messages are divided into segments of locale
and groups
. Locale refers to the language for which you have defined the message, and a group defines the category of the message. Take the following example:
├── locales
│ ├── en (1)
│ │ ├── messages.json (2)
1 | The en is the language for the message. |
2 | The file messages.json is the group called messages for all the strings defined inside this file. |
When translating/formatting a message, you can are required to pass a string starting with the group. messages.cart.total
. Also for generic messages which are same for all the languages can be defined next to the fallback
folder/group.
{
"greeting": "I am available to all the languages."
}
In the same way, you can define a group when using the database
driver.
id | locale | group | item | text |
---|---|---|---|---|
1 |
en |
messages |
cart.total |
Your cart total is {total, number, curr} |
2 |
fallback |
messages |
greeting |
I am available to all the languages |
So far we have seen the ways of formatting messages and values using Antl provider. All values will be formatted for the default locale defined in config/app.js
file.
{
locales: {
driver: 'file',
locale: 'en',
fallbackLocale: 'en'
}
}
You can change the default locale value, and all values will be formatted accordingly. To make this process dynamic based upon the user language, you are required to make use of Antl
middleware which will detect the user language and set it as the default language for all translations.
const globalMiddleware = [
// ...
'Adonis/Middleware/DetectLocale'
// ...
]
Now all HTTP requests header Accept-Language or query string param lang will be used to detect the user language.
Antl Provider makes use of the default driver defined inside config/app.js
file. Whereas you can switch the drivers in runtime to make use of a different driver.
const db = Antl.driver('db')
yield db.load() (1)
db.formatNumber(1000, { format: 'curr' })
1 | The load method should be called after switching the driver since it will load and cache all the strings for a given driver. |
You can extend Antl Provider by adding your own custom drivers and register them inside bootstrap/extend.js
file.
const Ioc = require('adonis-fold').Ioc
Ioc.extend('Adonis/Addons/Antl', 'mongo', (app) => {
return new Mongo()
})
class Mongo {
* load () { (1)
// load all locales and return as a nested object
}
* set (locale, group, key, value) { (2)
// save new/update value
}
* remove (locale, group, key) { (3)
// remove value for a given group
}
}
It should return all locale strings as a nested object of language
and group
. For example
{
"en": {
"messages": {
"cart.total": "Your cart total is"
}
}
}
The set
method should save the value for a given key, group and locale. It the value already exists, it should update it.
The remove
method should delete the value.