Send emails in your customer's language

A customer in Munich should not get an order confirmation in English, and you should not need three layouts and three workflows to avoid it. One email layout can carry every language you sell in. Your Shopify Flow step says which language a customer speaks, and the app sends the matching version. Everybody else gets the layout in its main language.

This guide goes from a single-language layout to emails in your customer's language, and covers what happens in every edge case: unknown languages, regional variants, later edits, testing and troubleshooting.

How it works

  • A layout has one main language. That is the layout itself, the version you have today.
  • You add translations to it: German, French, as many as 30 per layout. Each has its own subject, preview text and content.
  • In Shopify Flow, the Send Transactional Email action has a Language field. Set it to the customer's language, for example {{order.customerLocale}}.
  • When the email is sent, the app picks the matching translation. If there is none, the main language is sent. An email is never blocked because of its language.

One layout, one workflow, every language.

Step 1: Add a language

  1. Open the layout under Email Layouts.
  2. Click Add language at the top of the page.
  3. Choose the language under Language to add and click Add language.

The new language starts as a copy of your saved layout and opens in the editor right away. Translate the subject, the preview text and the content, then Save.

With an AI provider connected you can choose Translate with AI instead of a copy. Every text is translated; Liquid tags such as {{ variables.order_name }}, links and the design stay exactly as they are. Nothing is sent before you have reviewed and saved it. See Create, edit and translate layouts with AI.

The Add language dialog of an email layout with German selected
Add language: pick the language. It starts as a copy of the layout, ready to translate.

Layouts you made before languages existed

A layout created before this feature has no main language yet. We never asked what it is written in, and we do not guess. The first time you add a language to such a layout, the dialog starts with one extra question: Main language of this layout.

  • Nothing is preselected. Choose the language the layout is written in today: German for a German layout.
  • Language to add and the Add language button stay disabled until you have chosen.
  • You are asked once per layout. Layouts you create from now on choose their language on the create page.

Getting this right matters: customers whose language has no translation receive the main language, and translations are matched against it.

The Add language dialog on a layout made before languages existed: Main language of this layout comes first and is required, then the language to add
A layout you created before languages existed asks first which language it is written in. Nothing is preselected, and Add language stays disabled until you have chosen.

Step 2: Translate in the same editor

A translation opens in the editor you already know: the visual builder for builder layouts, rich text or HTML for the others. Switching language does not change the screen, only the content.

  • Switch with the Language picker: in the bar above the canvas in the visual builder, at the top of the Email content card in a rich text / HTML layout.
  • The entry marked (layout) is the main language.
The German version of a rich text layout: same screen, name and description read-only, subject and body in German
Switching language keeps the screen as it is. Name and description are shared and read-only here; subject, preview text and body belong to the language.
The visual builder showing the German version of an order confirmation
The visual builder works the same way: choose the language in the bar above the canvas.

Step 3: Tell Shopify Flow which language to send

In the Send Transactional Email action, set Language to the Flow variable that holds your customer's language:

Trigger Language
Order created, Order paid {{order.customerLocale}}
Customer created {{customer.locale}}
Fulfillment created {{fulfillment.order.customerLocale}}

For a workflow that serves one market only, type a fixed code such as de.

The field is optional. Workflows you built before keep working unchanged: without a Language they send the main language, exactly as they always did.

The Send Transactional Email action in Shopify Flow with the fields Reply-To, From name, Language set to order.customerLocale, and Variables
The action in Shopify Flow: Language takes the customer's language, here {{order.customerLocale}}. Reply-To and From name are new as well.

Which version a customer gets

The app looks for the best match, in this order:

  1. The exact language. fr-CA sends your fr-ca translation.
  2. The base language. de-CH and de-AT send your de translation. One German translation covers Germany, Austria and Switzerland.
  3. A regional variant. pt sends your pt-br translation.
  4. Otherwise the main language. The layout itself is sent.

Upper and lower case and the separator do not matter: de-DE, de-de and de_DE are the same.

What if the language does not exist?

Nothing breaks. The email is sent in the main language when:

  • the customer's language has no translation (a Japanese customer, and you translated into German and French),
  • the Language field is empty, or the Flow variable has no value for that customer,
  • the value is not a language at all.

The send is never rejected and never fails because of the Language field. The only check happens while you build the workflow: if you type a fixed value that is not a language code, such as english, Shopify Flow shows a hint to use a code like de, fr or pt-BR. Flow variables always pass.

One layout for every language

Sometimes a whole translation is more than you need: the email is the same for everybody, except for one sentence. For that, every layout knows {{ language }}.

{{ language }} is the Language your Flow step sent, in lower case (de, fr, de-at). When the step sends none, it is the layout's main language. It works in the subject, the preview text and the body, in the visual builder as well as in rich text / HTML layouts, and also inside a translation.

{% if language == "de" %}
  <p>Retouren aus Deutschland gehen an unser Lager in Hamburg.</p>
{% else %}
  <p>International returns are refunded within 10 working days.</p>
{% endif %}

In the visual builder, put this into an HTML / Code block. In a rich text / HTML layout, switch the body to HTML.

Shopify often sends a region with the language, such as de-AT or en-GB. {{ language }} keeps it (de-at), so compare only the first two letters when you mean "any German":

{% assign lang = language | slice: 0, 2 %}
{% if lang == "de" %}Hallo{% elsif lang == "fr" %}Bonjour{% else %}Hello{% endif %}

{{ language }} is what the step asked for, not the translation that was found. For a Japanese customer it says ja even though the main language was sent, so one layout without any translation can still react to it. The System Variables card in the editor lists it with its current value and copies it with a click. On a layout that has no main language yet, it stays empty until a Flow step sends a Language.

An HTML layout whose body uses if language equals de, next to the System Variables card listing the language variable
{{ language }} in a layout: one paragraph for German customers, another for everybody else. The System Variables card shows its current value.

Test before you go live

  • Send test email has a Language picker as soon as the layout has translations. Send yourself every language once.
  • The test uses your Test Variables, not live data. A real workflow run is the final check; see Testing your email setup.
  • To test the whole chain, run the workflow for an order whose customer has the language you translated into.

Check what was sent

History records the language of every email. Open an event: Language under Event details shows the translation that was sent, or Main language of the layout. Resend sends the same language again.

A History event of a sent email with status, duration and the language German under Event details
An event in History: Language under Event details shows which version went out.

Change the main language

Your shop started in English and most customers are German now? Open the German translation and click Set as main language. German becomes the layout itself and English becomes a translation: the two trade places and nothing is lost. From then on, customers without a matching translation, and emails without a Language, get German. You can undo it from version history.

The dialog Make German the main language, explaining that the two languages trade places
Set as main language: the translation and the layout trade places. Nothing is lost, and it can be undone from version history.

Remove a language

Open the translation and click Delete followed by its name, for example Delete German. Customers with that language get the main language from the next email on. The translation stays in the layout's version history and can be restored. See Layout version history.

If something is not as expected

A customer got the main language instead of their own. Open the email in History and look at Language. "Main language of the layout" means no translation matched: the Language field of the Flow step is empty, the variable had no value for that customer, or you have no translation for that language. Check the step first; the table in Step 3 has the right variable per trigger.

Add language is greyed out. The layout has no main language yet. Choose Main language of this layout at the top of the dialog first.

The language I need is not in the list. The list holds the most common languages. Any valid language code can be added through the API.

I changed the layout, but the German email still shows the old text. Translations are copies. Make the change in the German version too.

I do not see the Language field in the Flow action. The step was added before this update, and Shopify Flow keeps the fields a step was created with. Delete the Send Transactional Email step and add it again: Language then sits between From name and Variables (JSON).

Through the API

Translations can be read and written with GET and PUT /api/v1/email-templates/:id/translations/:locale, a translation becomes the main language with POST /api/v1/email-templates/:id/translations/:locale/promote, and the MCP tools are list_template_translations, set_template_translation and promote_template_translation. Any valid language code is accepted, up to 30 languages per layout. See REST API reference and Connect an AI assistant (MCP).