A simple plugin for using i18next with fastify.
npm install fastify-i18next-pluginimport 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))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:
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'))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'))
})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'] })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))fallbackLng(String): The default language code to use. Default: the first language in thelanguagesarray.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 thequerylanguage detector. Default:lng.param(String): The path paramter to use for theparamlanguage detector. Default:lng.sessionKey(String): The session property to use for thesessionlanguage detector. Default:lng.cookieName(String): The cookie to use for thecookielanguage 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.
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 patternapp.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
})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
})