Tutorials

How to Localize Email Templates: A Complete Developer Guide

Ali Osman Delismen
Ali Osman Delismen
·9 min read
Share
How to Localize Email Templates: A Complete Developer Guide

Email is still the highest-ROI channel for most SaaS companies. But most teams localize their product UI and completely forget about their emails — sending English welcome emails to users in Brazil, billing alerts to Japanese customers in a language they may not read fluently, and onboarding sequences that ignore cultural context entirely.

This guide covers everything you need to know about email template localization: what to translate, how to handle dynamic variables, RTL language support, and how to build a workflow that scales without turning your engineering team into professional translators.

Why Email Localization Is Harder Than UI Localization

Localizing a button label is straightforward. Localizing an email is a different beast:

  • Rich formatting — HTML emails have complex layouts that break with longer text in German or shorter text in Chinese
  • Dynamic variablesHello {{name}}, your {{plan}} subscription renews on {{date}} needs to handle variable ordering that differs by language
  • Plural forms — "You have 1 message" vs "You have 3 messages" — ICU MessageFormat handles this, but most email tools don't
  • RTL languages — Arabic and Hebrew require mirrored layouts, right-aligned text, and directional HTML attributes
  • Date and number formatting — December 3 in the US is 3. Dezember in Germany and ٣ ديسمبر in Arabic
  • Tone and formality — German business emails use formal "Sie", Japanese has honorifics, Brazilian Portuguese is warmer than European Portuguese

These aren't reasons to avoid email localization — they're reasons to build it properly from the start.

Step 1: Audit Your Email Templates

Before writing a single line of code, inventory every email your product sends:

Transactional emails (highest priority):

  • Welcome / account created
  • Email verification
  • Password reset
  • Payment confirmation / receipt
  • Subscription renewal reminder
  • Invoice / billing
  • Account suspension / deletion warning

Engagement emails (medium priority):

  • Onboarding sequences (day 1, day 3, day 7)
  • Feature announcement
  • Usage milestones ("You've reached 1,000 translations!")
  • Re-engagement campaigns

Operational emails (lower priority, but still important for enterprise):

  • Team invitation
  • Role change notification
  • API key expiration warning
  • Maintenance alerts

For each email, note: does it contain dynamic variables? Plural forms? Dates? User-generated content? This informs your localization approach.

Step 2: Separate Content from Template Structure

The most common mistake is embedding translated text directly in HTML templates. Instead, treat email content like you treat your UI — use a key-value translation system.

The wrong approach

<!-- en/welcome.html -->
<h1>Welcome to Better i18n, {{firstName}}!</h1>
<p>You're all set to start localizing your app.</p>

<!-- de/welcome.html -->
<h1>Willkommen bei Better i18n, {{firstName}}!</h1>
<p>Sie können jetzt mit der Lokalisierung Ihrer App beginnen.</p>

Maintaining 8 copies of every email template for 8 languages is a nightmare. Change the layout once and you have 8 files to update.

The right approach

<!-- welcome.html (single template) -->
<h1>{{t "email.welcome.heading" firstName=firstName}}</h1>
<p>{{t "email.welcome.body"}}</p>
// en.json
{
  "email": {
    "welcome": {
      "heading": "Welcome to Better i18n, {firstName}!",
      "body": "You're all set to start localizing your app."
    }
  }
}

// de.json
{
  "email": {
    "welcome": {
      "heading": "Willkommen bei Better i18n, {firstName}!",
      "body": "Sie können jetzt mit der Lokalisierung Ihrer App beginnen."
    }
  }
}

This gives you one template, N translation files.

Step 3: Use ICU MessageFormat for Variables and Plurals

ICU MessageFormat is the industry standard for handling complex localization cases in strings. Most modern i18n libraries support it — and you should use it for email copy too.

Basic variable substitution

"email.welcome.heading" = "Welcome to Better i18n, {firstName}!"

Plural forms

"email.usage.messages" = "{count, plural, one {You have # unread message.} other {You have # unread messages.}}"

This automatically handles "1 message" vs "3 messages" — and Russian, which has four plural forms.

Date formatting

Rather than passing pre-formatted dates as strings, pass ISO timestamps and format them in the template engine with the locale context:

// Instead of:
t('email.renewal', { date: 'December 3, 2025' }) // wrong locale format

// Do:
t('email.renewal', { date: new Date('2025-12-03') })
// Result in en: "December 3, 2025"
// Result in de: "3. Dezember 2025"
// Result in ja: "2025年12月3日"

Step 4: Handle RTL Languages

Arabic and Hebrew are right-to-left, which affects your entire email layout. Add dir attribute based on locale:

<!DOCTYPE html>
<html dir="{{direction}}" lang="{{locale}}">
const direction = ['ar', 'he', 'fa', 'ur'].includes(locale) ? 'rtl' : 'ltr';

For RTL emails:

  • Text aligns right by default
  • Use logical CSS properties: padding-inline-start: 24px instead of padding-left
  • Icons and arrows that indicate direction need mirrored versions
  • Multi-column layouts may need to flip column order

Test your RTL emails in Gmail, Apple Mail, and Outlook — each handles dir differently.

Step 5: Build a Translation Workflow for Email Content

Option A: Manual process (doesn't scale)

Export string files → send to translation vendor → wait → import back → hope nothing broke. Works for 2 languages. Falls apart at 8.

Option B: Automated with Better i18n

Better i18n treats email translation keys the same as UI translation keys:

{
  "email.welcome.subject": "Welcome to Better i18n!",
  "email.welcome.heading": "Welcome, {firstName}!",
  "email.welcome.body": "Your account is ready. Let's get started.",
  "email.welcome.cta": "Open Dashboard"
}

Sync via CLI or GitHub integration, use AI translation for speed, review for quality, then access at send time:

import { loadTranslations } from '@better-i18n/core';

async function sendWelcomeEmail(user: User) {
  const t = await loadTranslations(user.locale, 'email');

  await emailProvider.send({
    to: user.email,
    subject: t('email.welcome.subject'),
    html: renderTemplate('welcome', {
      heading: t('email.welcome.heading', { firstName: user.firstName }),
      body: t('email.welcome.body'),
      cta: t('email.welcome.cta'),
      direction: getDirection(user.locale),
      locale: user.locale,
    }),
  });
}

Step 6: Test Your Localized Emails

Content testing:

  • All variables render correctly in each locale
  • Pluralization works for edge cases (0, 1, 2, 11, 100)
  • Long German/Finnish text doesn't break layout
  • Short Chinese/Japanese text doesn't look sparse

Visual testing:

  • RTL layout renders correctly in Gmail, Outlook, Apple Mail
  • Images have localized alt text
  • CTA button text fits correctly in all languages

Use a tool like Litmus or Email on Acid for cross-client rendering, and test at least 3 representative languages (Western Latin, RTL, and Asian).

Common Mistakes to Avoid

Hardcoding locale-specific assumptions — Don't assume all users have first + last names, that dates use MM/DD/YYYY, or that phone numbers have 10 digits.

Translating emails last — Email localization requires different expertise than UI localization. Plan for it from the start.

Ignoring email client limitations — Some clients strip <style> tags. Test your RTL layout in Outlook specifically.

Not updating translations when copy changes — Better i18n's translation key system flags untranslated or outdated keys automatically.

The Business Case for Email Localization

Numbers from SaaS companies that have invested in email localization:

  • 35-50% higher open rates for emails in the recipient's native language
  • 20-30% higher click-through rates on localized CTAs
  • Reduced churn in non-English markets where product value was communicated in English
  • Enterprise deals unlocked when procurement teams can review billing communications in their language

The ROI on email localization is typically 3-6 months for SaaS companies targeting multiple language markets.

Getting Started

  1. Audit your 3 highest-impact transactional emails (welcome, billing, password reset)
  2. Extract all strings into a translation system (Better i18n or equivalent)
  3. Translate to your top 2-3 non-English markets
  4. Set up automated sync so new email copy gets flagged for translation
  5. Expand from there

Better i18n makes steps 2-4 dramatically faster — your email strings live alongside your UI strings, AI translation handles the first pass, and GitHub sync keeps everything in sync automatically.

Start localizing your emails free →