The Role of i18next and Translation Management Systems in Serverless Architectures

In today's globalized world, localization has become a vital factor in ensuring business success. Customers prefer to interact with products and services in their native language, and businesses need to adapt to this demand. With the emergence of Serverless Architectures, it has become easier for developers to build and deploy applications without worrying about infrastructure management. But how can businesses ensure that their serverless applications are multilingual? In this article, we'll explore the role of i18next and TMS in serverless architectures and how they can help businesses build and deploy multilingual serverless applications.

What is Serverless Architecture?

Serverless architecture is a cloud computing model where the cloud provider manages the infrastructure and automatically allocates resources as needed. It's a pay-per-use model, where businesses only pay for the actual usage of the application. Developers can focus on writing code and building applications without worrying about infrastructure management, scalability, and availability.

What is i18next?

i18next is an open-source internationalization framework for JavaScript that provides a complete solution for managing translations in web applications. It's lightweight and easy to integrate into serverless applications. i18next allows developers to organize translations into files, use interpolation, pluralization, and format translations based on the user's locale. i18next also has support for popular frontend frameworks such as React, Angular and Vue, etc.

The Challenges of Multilingual Serverless Applications

One of the biggest challenges of building multilingual serverless applications is managing translations. Applications that are built for a global audience require content to be translated into multiple languages. Manually managing translations can be a daunting task, as it involves managing multiple translation files, keeping track of translations, and ensuring consistency across languages. Additionally, deploying multiple versions of the application for each language can be a logistical nightmare, especially if you have to manage multiple tiny parts like AWS Lambda functions.

For classic web applications, you usually have 2 parts where internationalization tasks occur: The client side (usually some modern single page app) and the server side. The translation resources are usually stored in the same place, so that the client and the server can read them. In case of i18next, the client can access them useing i18next-http-backend and the server can access them using i18next-fs-backend.

  • Here is an example of what this might look like on the client side.
  • Here for an example of how this could look on the server side.

But for serverless environments, you may have multiple clients, and you may have multiple small serverless functions that respond to a request in the appropriate language, or send some emails in the user's preferred language, and so on.

Serverless E-Mails

Let's think about a serverless function that generates and sends some emails. For example we want to send an invitation to someone. We need the email address, the recipient's preferred language, an email template and some translations.

To achieve this goal, you usually need to transform some raw data into html content (or text) to be displayed in the user's preferred language.

In this example we will use pug (formerly known as "Jade", and also originally created by TJ Holowaychuk) to define some templates that should be filled with the data needed in the email, and mjml to actually design the email content.

Let's create a new mail.js file, which we can use, to accomplish this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pug from 'pug'
import mjml2html from 'mjml'

export default (data) => {
// first let's compile and render the mail template that will include the data needed to show in the mail content
const mjml = pug.renderFile('./mailTemplate.pug', data)

// then transform the mjml syntax to normal html
const { html, errors } = mjml2html(mjml)
if (errors && errors.length > 0) throw new Error(errors[0].message)

// and return the html, if there where no errors
return html
}

The mailTemplate.pug could look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mjml
mj-body(background-color='#F4F4F4' color='#55575d' font-family='Arial, sans-serif')
mj-section(background-color='#024b3f' background-repeat='repeat' padding='20px 0' text-align='center' vertical-align='top')
mj-column
mj-image(align='center' padding='10px 25px' src='https://raw.githubusercontent.com/i18next/i18next/master/assets/i18next-ecosystem.jpg')
mj-section(background-color='#ffffff' background-repeat='repeat' padding='20px 0' text-align='center' vertical-align='top')
mj-column
mj-section(background-color='#ffffff' background-repeat='repeat' background-size='auto' padding='20px 0px 20px 0px' text-align='center' vertical-align='top')
mj-column
mj-text(align='center' color='#55575d' font-family='Arial, sans-serif' font-size='20px' line-height='28px' padding='0px 25px 0px 25px')
span=t('greeting', { name: name || 'there' })
br
br
mj-text(align='center' color='#55575d' font-family='Arial, sans-serif' font-size='16px' line-height='28px' padding='0px 25px 0px 25px')
=t('text')
mj-section(background-color='#024b3f' background-repeat='repeat' padding='20px 0' text-align='center' vertical-align='top')
mj-column
mj-text(align='center' color='#ffffff' font-family='Arial, sans-serif' font-size='13px' line-height='22px' padding='10px 25px')
=t('ending') 
a(style='color:#ffffff' href='https://www.i18next.com')
b www.i18next.com

Now let's define some translations...

1
2
3
4
5
6
7
8
9
10
11
12
13
// locales/en/translations.json
{
"greeting": "Hi {{name}}!",
"text": "You were invited to try i18next.",
"ending": "Internationalized with"
}

// locales/de/translations.json
{
"greeting": "Hallo {{name}}!",
"text": "Du bist eingeladen worden i18next auszuprobieren.",
"ending": "Internationalisiert mit"
}

...and use them in an i18n.js file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { dirname, join } from 'path'
import { readdirSync, lstatSync } from 'fs'
import { fileURLToPath } from 'url'
import i18next from 'i18next'
import Backend from 'i18next-fs-backend'

const __dirname = dirname(fileURLToPath(import.meta.url))
const localesFolder = join(__dirname, './locales')

i18next
.use(Backend)
.init({
// debug: true,
initImmediate: false, // setting initImediate to false, will load the resources synchronously
fallbackLng: 'en',
preload: readdirSync(localesFolder).filter((fileName) => {
const joinedPath = join(localesFolder, fileName)
return lstatSync(joinedPath).isDirectory()
}),
ns: 'news-mailer',
backend: {
loadPath: join(localesFolder, '{{lng}}/{{ns}}.json')
}
})

export default (lng) => i18next.getFixedT(lng)

So finally, all the above can be used like that:

1
2
3
4
5
6
7
8
9
10
11
import mail from './mail.js'
import getT from './i18n.js'

const t = getT('en')

const html = mail({
t,
name: 'John'
})
// that html now can be sent via some mail provider...
// await send('[email protected]', t('subject'), html)

This is how the resulting html could look like:

mail preview

🧑‍💻 A code example can be found here.

Translation Management Systems in Serverless Architecture

Ok, i18next seems to be able to handle these i18n tasks. But what about managing of all those translation files in these different serverless functions and also in the different clients? There's no central location anymore - it's all distributed.
We need a solution for that! We need a Translation Management System.

A Translation Management System (TMS) is a software platform that enables businesses to manage their translation workflow. It provides a central repository for storing translations and enables collaboration between translators. When integrated with i18next, TMS such as locize can streamline the localization process in a serverless architecture. Here are some of the benefits of using a TMS integrated with i18next in a serverless architecture:

Automatic updates of translations

When using a TMS, translations can be automatically updated whenever a new language is added or an existing translation is changed. This eliminates the need to manually update the translations in the codebase, which can be a time-consuming task.

Improved scalability

A TMS can handle translation requests from multiple applications and languages, making it easy to scale the localization process. By integrating a TMS with i18next, businesses can easily manage translations for multiple applications without worrying about the scalability of the translation process.

Reduced costs

By using a TMS, businesses can reduce the cost of managing translations. A TMS provides a central repository for storing translations, eliminating the need to manage translations in multiple codebases. This reduces the time and effort required to manage translations, resulting in lower costs.

Improved security

A TMS provides a secure environment for storing translations, making it easy to manage translations without worrying about security concerns. By using a TMS integrated with i18next, businesses can ensure that their translations are stored securely and are only accessible by authorized personnel.

Implementing Possible Approaches for TMS with i18next

Client side

For the client side it's that we can go full steam ahead. We can live download the translations on demand directly from the locize CDN. This way we can change translations or add new languages directly in locize without having to modify or redeploy the client app.

In addition, we can unleash a lot of extra features to speed up the localization process. For example:

  • We can use the saveMissing feature to add new keys and automatically translate them with machine translation.
  • We can find and filter in locize which keys are used or not used anymore, thanks to the last-used plugin.
  • We can find and edit translations directly in the In-Context editor.

Have a look at this tutorial or this video to just see just a few of these cool things.

Server(less) side

For the serverless side we could trigger a new serverless deployment every time a new translation version is published. Using webhook events or triggering a Github Action via GitHub Repository Dispatch Event.

Or download the latest translations each time a serverless function is built and deployed using the locize-cli or with the Github Action.

1
2
# i.e. for our email example, that we implemented
locize download --project-id=3183fd58-99d0-4d4b-896d-5768ca438c24 --ver=latest --namespace=news-mailer --clean=true --path=./locales

Conclusion

In summary, i18next and a translation management system like locize are powerful tools for managing translations in a serverless architecture. By integrating i18next with a TMS, businesses can streamline the localization process and reduce the cost of managing translations. The integration also provides improved scalability and security. Enterprises and developers can easily implement a TMS integrated with i18next in their serverless architecture by following the steps outlined above.

  • If you're already using i18next and want to unleash its full potential, have a look at this.
  • If you're new to i18next, have a look at this guide and check out the free crash course.
  • If you want to see a nice overview of the different i18n formats, have a look at this.
  • If you like to see how locize looks like, check out this video and try the free trial.
Share