fastify-i18next-plugin v0.1.0
fastify-i18next-plugin
A simple plugin for using i18next with fastify.
Install
npm install fastify-i18next-plugin
Example
import fastify from 'fastify'
import i18nPlugin from 'fastify-i18next-plugin'
const app = fastify()
app.register(i18nPlugin, {
// Languages to support (required)
languages: ['en', 'it'],
resources: {
// Lang
en: {
// i18next namespace
messages: {
// Key and message
hello: 'Hello {{name}}'
}
},
it: {
messages: {
hello: 'Ciao {{name}}'
}
}
}
})
app.get('/en', (request, reply) => {
// Set language of the messages returned from request.t()
request.setLanguage('en')
return request.t('messages:hello', { name: 'Daria' })
})
app.get('/it', (request, reply) => {
// Set language of the messages returned from request.t()
request.setLanguage('it')
return request.t('messages:hello', { name: 'Daria' })
})
// Hello Daria
app.inject('/en')
.then(res => console.log(res.payload))
// Ciao Daria
app.inject('/it')
.then(res => console.log(res.payload))
Loading JSON resources from disk
Providing a path pattern to opts.loadPath
will allow you load JSON locale files
from disk. The path must include {{ns}}
and {{lng}}
patterns so that the
namespace and language of the resource can be determined.
For example, given the following structure:
└ locales/
├ en/
│ ├ messages.json
│ └ greetings.json
└ it/
├ messages.json
└ greetings.json
The path ./locales/{{lng}}/{{ns}}.json
will load the messages.json
and
greetings.json
files in the en
and it
directories, and add them to the
messages and greetings namespaces for English and Italian.
Eg:
// ./locales/it/greetings.json
{
"nested": {
"hello": "Ciao!"
}
}
import { join } from 'node:path'
import fastify from 'fastify'
import i18nPlugin from 'fastify-i18next-plugin'
const app = fastify()
await app.register(i18nPlugin, {
languages: ['en', 'it'],
// Will load: ./locales/en/greetings.json, ./locales/it/greetings.json
// setting the langues from the path and namespace from the filename
loadPath: join(import.meta.dirname, './locales/{{lng}}/{{ns}}.json')
})
// Ciao!
console.log(app.t('greetings:nested.hello', 'it'))
Loading resources within another plugin
You can still load resources after the plugin is registered using the
fastify.addI18nResource()
and fastify.loadI18nResources()
functions.
import fastify from 'fastify'
import i18nPlugin from 'fastify-i18next-plugin'
const app = fastify()
app.register(i18nPlugin, {
languages: ['en', 'it']
})
app.register((instance) => {
instance.addI18nResource('en', 'greeting', { hello: 'Hello' })
instance.addI18nResource('it', 'greeting', { hello: 'Ciao' })
instance.loadI18nResources('./locales/{{lng}}.{{ns}}.json')
instance.log.info(instance.t('greeting:hello', 'en'))
})
Adding i18next formatters
Use the fastify.addI18nFormatter()
and fastify.addI18nCachedFormatter()
functions to add i18next formatters. See the i18next formatting documention
for more info about their usage.
import fastify from 'fastify'
import i18nPlugin from 'fastify-i18next-plugin'
const app = fastify()
await app.register(i18nPlugin, {
languages: ['en', 'it'],
resources: {
en: {
messages: {
hello: 'Hello {{name, upper}}',
helloAll: 'Hello {{names, list}}'
}
}
}
})
app.addI18nFormatter('upper', (val) => val.toUpperCase())
app.addI18nCachedFormatter('list', (lng) => {
const formatter = new Intl.ListFormat(lng, {
style: 'long',
type: 'conjunction',
})
return (val) => formatter.format(val)
})
// Hello DARIA
app.t('messages:hello', 'en', { name: 'Daria' })
// Hello Niall, James, and Tim
app.t('messages:helloAll', 'en', { names: ['Niall', 'James', 'Tim'] })
Detecting the language for the request
Setting the languageDetectors
option will add a hook to detect the language
from any or all of the following: a URL path parameter, query string, cookie,
session or accept header.
The detectors will run in the order they appear in the languageDetectors
array and stop as soon as a supported language is found.
When using either the session or cookie detectors, the detected language will be persisted to the session or cookie, even if it was detected by a different detector, eg: the query string detector.
import fastify from 'fastify'
import cookiePlugin from '@fastify/cookie'
import i18nPlugin from 'fastify-i18next-plugin'
const app = fastify()
app.register(cookiePlugin)
app.register(i18nPlugin, {
fallbackLng: 'en',
languages: ['en', 'it', 'cy'],
languageDetectors: ['query', 'cookie']
})
app.get('/', (request, reply) => {
return request.lng
})
// 'en', fallback language
app.inject('/').then(res => console.log(res.payload))
// 'it', detected from lng cookie
app.inject({
path: '/',
cookies: { lng: 'it' }
})
.then(res => console.log(res.payload))
// 'cy', detected from lng query, the cookie won't be checked as it is lower
// priority
app.inject({
path: '/',
query: { lng: 'cy' },
cookies: { lng: 'it' }
})
.then(res => console.log(res.payload))
Plugin options
fallbackLng
(String): The default language code to use. Default: the first language in thelanguages
array.languages
(Array): List of language codes to support, trying to change to a language not in the list will instead set the fallback language.resources
(Object): Object map of locale messages, in the format{ lang: { namespace: { key: message } } }
.loadPath
(String): Path to load JSON file resources from, namespace and language are determined from path parameters, eg:./locales/{{lng}}/{{ns}}.json
.languageDetectors
(Array): A list of language detectors to use, will be run in the supplied order until a supported language is detected. Can be one to many of the following:"query"
: Detect language from query string."param"
: Detect language from parsed URL path parameter (eg: request.params.lng)."accept"
: Detect language from the language accept header. Note: the @fastify/accepts plugin must be loaded to use this detector."cookie"
: Detect language from cookie value (will also persist any detected language to this cookie). Note: the @fastify/cookie plugin must be loaded to use this detector."session"
: Detect language from session value (will also persist any detected language to this sesion property). Note: the @fastify/session plugin must be loaded to use this detector.
queryKey
(String): The query value to use for thequery
language detector. Default:lng
.param
(String): The path paramter to use for theparam
language detector. Default:lng
.sessionKey
(String): The session property to use for thesession
language detector. Default:lng
.cookieName
(String): The cookie to use for thecookie
language detector. Default:lng
.cookieOpts
(Object): The cookie options to use when setting the language cookie. See the @fastify/cookie options for more details. Default:{ path: '/', sameSite: true, httpOnly: true }
decorateLocals
(Boolean): Decorate reply.locals with language properties andt()
for use in templates, for example when using @fastify/view.
Server decorators
app.t('namespace:key') // Get a message for the fallback language
app.t('namespace:key', opts) // Get a message with options object, eg data to interpolate
app.addI18nFormatter('name', func) // Add an i18next formatter
app.addI18nCachedFormatter('name', func) // Add an i18next cached formatter
app.addI18nResource('lang', 'namespace', { key: 'Message' }) // Add new locales messages
app.loadI18nResources('./locales/{{lng}}.{{ns}}.json') // Load JSON locales files from a path pattern
Request decorators
app.get('/', (request, reply) => {
request.setLanguage('en') // Sets language to English
request.lng // The currently set language code
request.lngDir // Direction of current language, eg: 'ltr', 'rtl'
request.lngs // The currently support languages, eg: ['en', 'it']
request.t('messages:hello') // Get a message for the current language
request.i18nKeyExists('messages:hello') // Returns true if given key has a value
})
reply.locals properties (if decorateLocals
is true
)
app.get('/', (request, reply) => {
reply.locals.t('messages:hello') // same as request.t
reply.locals.exists('messages:hello') // same as request.i18nKeyExists
reply.locals.lngs // same as request.lngs
reply.locals.lng // same as request.lng
reply.locals.lngDir // same as request.lngDir
reply.locals.language // same as request.lng
reply.locals.languageDir // same as request.lngDir
})
5 months ago