Use JSON to localize(translate) Auth0 email templates based on user language
Background
Answering questions in Auth0 community forum is one of the ways I give back to the community and also learn more about common problems or confusions Auth0 users face.
Recently, I came across a question asking how to customize the Auth0 email templates in a more maintainable way.
Link: https://community.auth0.com/t/localization-and-saving-the-user-language/90515
Auth0 supports email template customization for various emails that is sent to a user as part of different flows, such as verification email, password reset email, and so on. You can use a combination of Liquid and HTML to customize the email templates.
On top of that, Auth0 exposes some variables that you can use in the email templates. Things like the user's name, email, and other information.
Here is an example of the variables you can use in the email templates.
<html>
<head>
...
</head>
<body>
<center>
<p>
{% if user.user_metadata.lang == 'es' %}
<b>Hola {{ user.name }}, ...</b>
{% elsif user.user_metadata.lang == 'it' %}
<b>Ciao {{ user.name }}, ...</b>
{% else %}
<b>Hi {{user.name}} ...</b>
{% endif %}
</p>
<table ...>
<tr>
<td>
...
You can see that the email template is using Liquid to check the user's language and display the appropriate greeting.
This is a great feature and it allows you to customize the email templates to fit your needs.
Note: You need to set the user's language in the user's metadata. You can do this in different ways which is out of the scope of this article.
What is Liquid?
Liquid is a template language that uses a combination of objects, tags, and filters inside template files to display dynamic content. Auth0 uses Liquid to customize the email template.
Problem
If your application supports multiple languages, you might want to customize the email templates to display the appropriate message based on the user's language.
In a scenario like this, you might end up with a lot of if-else statements in the email template. This can make the email template hard to maintain.
Depending on the number of languages you need to support and the complexity of the email template, this can become a maintenance nightmare.
Add to that, the fact that most users manage the email templates in the Auth0 dashboard, which means:
The code is not version controlled
Editor experience is limited
You can't use any of the tools you use to write code
This code is not part of your test and build pipeline which means you can't test it and changes can break the email template
Solution
My solution to the problem is:
1- Keep these email templates as part of our codebase. This way, we can use all the tools we use to manage our code. We can use version control, we can use our editor, we can use our build pipeline, and so on.
2- Use code to generate the email template. This way, we can write reusable, modular code that is easy to maintain.
3- Use JSON to maintain different language translations. This gives us the flexibility to add new languages without having to change the code.
How to do it?
We can use any programming language to generate the email template. In this example, I will be using Node.js and TypeScript.
I have created a GitHub repository that can be used as a starting point for this solution.
The repository contains a simple Node.js application that can be used to generate the email template.
Prerequisites
Node.js installed on your machine.
Auth0 account with a tenant created.
Project setup
Project code is under the src
folder. There are 3 folders inside the src
folder:
templates
folder contains the email templates. These are the templates that will be used to generate the final email template. These templates are written in TypeScript so we can easily use variables and functions inside the them.languages
folder contains the language translations. These are JSON files that contain the translations for each language.scripts
folder contains the scripts that will be used to generate the final email template.
What is inside the templates
folder?
This folder contains a file for each email template. File name are the same as the template name in Auth0 for easy reference.
As an example, I have included a file called verification-email.ts
that contains the email template for the verification email.
I have copied the original Auth0 email template and stored it in a variable called html
. I am treating the original template as a string. Note that I am using backticks to define the string. This is because I want to use multi-line strings, be able to use variables and also call functions inside the string.
const html = `
...
<h1>${localizeMessage("welcome")}</h1>
<p>${localizeMessage("thankYou")}</p>
<p><a href="{{ url }}">${localizeMessage("confirm")}</a></p>
<p>
${localizeMessage("needHelp")}
</p>
...
`;
The localizeMessage
function is a helper function that will be used to localize the message. It takes a key as an argument and returns the appropriate Liquid if/else statement to support the translation for all available languages.
{% if user.user_metadata.lang == 'en' %}
Hello {{application.user}} Welcome to the site
{% elsif user.user_metadata.lang == 'fr' %}
Bonjour {{application.user}} Bienvenue sur le site
{% elsif user.user_metadata.lang == 'jp' %}
こんにちは{{application.user}}さん。サイトへようこそ。
{% else %}
Hello {{application.user}} Welcome to the site
{% endif %}
So anywhere in the email template I need to localize a message, I can call the localizeMessage
function and pass the key as an argument.
There is also an index.ts
file that exports an array which contains all the email template names. We will use this variable later in code to decide which templates to include in our build.
export const templates = ["verification-email"];
What is inside the languages
folder?
As an example I have included the translation for English, French and Japanese represented by the files en.json
, fr.json
, and jp.json
respectively.
Each json file is a map of message keys to the translated message. For example, the fr.json file might look like this:
{
"welcome": "Bonjour {{application.user}} Bienvenue sur le site",
"thankYou": "Merci de vous être inscrit. Veuillez vérifier votre adresse e-mail en cliquant sur le lien suivant:",
"confirm": "Confirmer mon compte",
"needHelp": "Si vous rencontrez des problèmes avec votre compte, n'hésitez pas à nous contacter en répondant à ce mail.",
"regards": "Cordialement",
"footer": "Si vous n'avez pas fait cette demande, veuillez nous contacter en répondant à ce mail."
}
For this to work properly, the message keys should be the same as the message keys in all language files.
There is also an index.ts
file that exports all the language codes as a single array. This is the array that will be used when deciding which language translation are available and should be included in the generated email template.
What is inside the scripts
folder?
This folder contains two main functions:
localizeMessage
which I described above. This function uses the array of language codes to decide which translations should be included in the generated email template.writeFile
which is used to write the generated email template to a file.
and an index.ts
file that contains the main function. This function loops over the list of templates exported from templates
folder and generates the localized email template for each one.
const generateTemplates = async () => {
for (const template of templates) {
const templateContent = require(`../templates/${template}`).default;
writeFile(template, templateContent);
}
};
How to run the project?
To run the project, we need to install the dependencies first. You can do that by running npm install
in the root folder of the project.
Next we need to build the project. You can do that by running npm run build
in the root folder of the project.
Build command will compile the TypeScript code. You can see the compiled JavaScript code in the build
folder.
Finally, we need to generate the email templates. You can do that by running npm run generate
in the root folder of the project.
This command will generate the email templates and store them in the output
folder.
Generated email templates are html files. You can open them in your browser to see the final result. There is a serve
script that can be used to serve the generated email templates. You can run npm run serve
to start the server.
Note: Build and Output folders are ignored by git. You can change this in the .gitignore
file.
How to use the generated email templates?
After you have generated the email templates, you can use them in your Auth0 tenant. You can find the instructions on how to do that in the Auth0 documentation.
Simply open the generated email template in your code editor and copy the content of the file. Then go to the Auth0 dashboard and open the email template you want to customize. Paste the content of the generated email template in the editor and save the changes.
How to add a new language?
To add a new language, you need to add a new JSON file in the languages
folder. The file name should be the language code. For example, if you want to add a new language called Spanish
, you need to create a file called es.json
in the languages
folder.
You need to also add the language code to the languages
array in the index.ts
file in the languages
folder.
How to add a new email template?
To add a new email template, you need to add a new file in the templates
folder. The file name should be the same as the template name in Auth0. For example, if you want to add a new email template called change-password
, you need to create a file called my-template.ts
in the templates
folder.
Then copy the content of the original email template from Auth0 and paste it in the my-template.ts
file and customize it as you like.
Don't forget to add the template name to the templates
array in the index.ts
file in the templates
folder.
Future improvements
Add validation for generated HTML files.
Integrate the project build and template generation with your project CI/CD pipeline.
Use Auth0 Management API to update an email template as part CI/CD pipeline.
Add test for templates as part of the CI/CD pipeline. We can automate sending a test email so we can make sure it works as expected before deploying it to production.
Conclusion
In this article, we tested the idea of using code and json language files to localize email templates. We created a simple project that can be used to generate localized email templates for Auth0. This project can be used as a starting point for your own project. You can add more functions to help you process the email templates and make them more dynamic.
For example, you might want to pull some data from other sources like external APIs or databases and use it in your email templates.
You can find the source code for this project on GitHub
Reference
Thanks for reading this article. Please reach out here or on Twitter if you have any feedback or questions.
Subscribe to my newsletter
Read articles from Parham directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Parham
Parham
Web & mobile developer, @Auth0Ambassador. Follow me for content on JavaScript, Angular, React, Ionic & Capacitor, Progressive web apps & UI/UX.