Skip to main content

Localization

One template, many languages. Static copy lives in a translations table instead of being hard-coded into each template, so adding a new locale doesn't require new templates.

The model

  • A translation key identifies a string (e.g. order_scheduled.greeting).
  • A locale identifies a language (en, el, it, …).
  • A value is the translated text for that (key, locale) pair.

Each row in the translations table is a single tuple of those three fields.

How templates use it

Inside the MJML, every piece of static copy references a translation key rather than literal text, through the t filter ({{ 'order_scheduled.greeting' | t }}). At send time, the system resolves each key against the active locale and substitutes the localized value.

This means:

  • The same template renders in any supported language.
  • A new locale is a data change, not a template change.
  • Translators work in a single dataset, not across many template bodies.

Locale resolution

The locale used to render a template comes from the caller of the render or preview operation. Template authors can also override the locale per usage when a specific block must be rendered in a fixed language (for example, a legal disclaimer that must stay English).

Composing dynamic strings

Translations can be combined with data substitution to assemble dynamic sentences. A line like "Your order 0080245144 has been processed" is typically composed of:

  • a translated prefix (We would like to inform you that your order)
  • a value from the model ({{ Order.OrderNumber }})
  • a translated suffix (has been processed and is scheduled for delivery.)

Splitting strings this way keeps both languages grammatical without forcing positional placeholders that translators tend to misuse.

Missing-translation behavior

If a key isn't found for the active locale, the system returns the key itself unchanged. Partially translated content stays readable and the missing entry is obvious in QA — preferable to throwing an exception that takes the whole email down.