Internationalization (i18n)
Send locale-specific email templates based on user language preferences.
Configuration
Add i18n options to your module configuration:
typescript
MailerModule.forRoot({
transport: { host: 'smtp.example.com', port: 587 },
template: {
dir: join(__dirname, 'templates'),
adapter: new HandlebarsAdapter(),
},
i18n: {
defaultLocale: 'en',
templateDirPattern: '{{locale}}/',
fallback: true,
},
})Directory Structure
Organize your templates by locale:
templates/
en/
welcome.hbs
reset-password.hbs
es/
welcome.hbs
reset-password.hbs
fr/
welcome.hbsSending Localized Emails
Pass the locale option in sendMail():
typescript
// Sends using templates/es/welcome.hbs
await this.mailerService.sendMail({
to: 'user@example.com',
subject: 'Bienvenido',
template: 'welcome',
locale: 'es',
context: { name: 'Juan' },
});Fallback Behavior
A locale with a region falls back to its language first: for locale: 'es-CO' the mailer uses templates/es-CO/welcome.hbs if it exists, otherwise templates/es/welcome.hbs (new in v4). Both - and _ separate the region (pt_BR → pt). Templates of every bundled adapter are detected, .mjml included.
typescript
// templates/es-CO/welcome.hbs doesn't exist, templates/es/welcome.hbs does
await this.mailerService.sendMail({
to: 'user@example.com',
template: 'welcome',
locale: 'es-CO',
context: { name: 'Juan' },
});If neither exists and fallback: true (default), the system falls back to defaultLocale:
typescript
// templates/fr/reset-password.hbs doesn't exist
// Falls back to templates/en/reset-password.hbs
await this.mailerService.sendMail({
to: 'user@example.com',
template: 'reset-password',
locale: 'fr',
context: { resetLink: 'https://...' },
});Custom Pattern
The templateDirPattern controls how locale maps to the directory structure:
typescript
// Default: '{{locale}}/' → templates/es/welcome.hbs
// Custom: '{{locale}}-templates/' → templates/es-templates/welcome.hbs
i18n: {
defaultLocale: 'en',
templateDirPattern: '{{locale}}-templates/',
}TIP
- Works with all template adapters (Handlebars, Pug, EJS, Nunjucks, Liquid, MJML)
- If no
localeis provided, the template is resolved normally (no i18n prefix) - Set
fallback: falseto throw an error when a locale template is missing - A locale that is not a language tag (letters, digits,
-and_only, such asen,es-CO,zh_Hant_TW) is ignored with a warning anddefaultLocaleis used, so user input never shapes a file path - Localized templates are looked up in
template.dironly, not in the extratemplate.dirs - Mail classes receive the
localeinrender(), so they can translate the subject too