Each user has a language property. The mobile and web SDKs set it from the device language the first time the user is created. You can set and overwrite it. See Set the user’s language.
Pass a code from Supported languages. Most codes are ISO 639-1 two-letter codes. Chinese is the exception: use zh-Hans for Simplified and zh-Hant for Traditional.In email, push, and SMS, read the property in Liquid as user.language. In-app messages cannot read user.language. They can only substitute tags. See Why did my in-app message ignore setLanguage?.
Open Messages > Push > New Message or a template, then click Add Languages.Option 1: CheckboxesSelect each language you support. The editor adds a tab per language. Recipients whose language you did not select receive the Any/English content.
Select Languages modal with a checkbox for each supported language.
Option 2: Import a spreadsheet
1
Copy the template
From Add Languages, open the import option and copy the template.
Import modal where you copy the spreadsheet template.
2
Fill one row per language
Use these column headers: language_code, title, subtitle, message. Include a row for en. These headers belong to this spreadsheet import. They are not the Dynamic Content CSV format.
3
Paste the sheet back and preview it
Paste the filled sheet into Add Languages and check the preview.
Import modal with language rows ready to insert.
4
Insert the content
Insert the rows. The editor adds a tab for each language and fills in the title, subtitle, and message.
Preview of imported content before it is inserted into the editor.
Option 3: Dynamic ContentUpload a CSV whose column headers are language codes (en, es, fr) and whose rows are message sections. Reference each cell with user.language. See Dynamic Content for the CSV shape and the Liquid.
The push editor stores text as HTML. In right-to-left languages, a character such as % can display in the wrong place. Add a right-to-left mark immediately after the character.
APISet contents to a map of language codes. Add headings for the title and subtitle for the iOS subtitle. Include en in every map, and use the same language codes in each map. en is required. Recipients whose language is not in the map receive the en text.Include headings for web push and Huawei. If you omit headings for web push, OneSignal uses your site name. subtitle is iOS only.
{ "app_id": "YOUR_APP_ID", "target_channel": "push", "included_segments": ["Subscribed Users"], "contents": { "en": "Your order has shipped.", "fr": "Votre commande a été expédiée.", "zh-Hans": "您的订单已发货。" }, "headings": { "en": "Order update", "fr": "Suivi de commande", "zh-Hans": "订单更新" }, "subtitle": { "en": "Track your package", "fr": "Suivez votre colis", "zh-Hans": "追踪您的包裹" }}
See Create message for targeting, scheduling, and the rest of the push fields.
Open Messages > Email > New Message or a template. Email has no language-map field.Option 1: One message per language segmentFollow Send one message per language segment. Create one email template per language and send it to the matching segment.Option 2: LiquidRead user.language and render one block per code. The else branch is the default for any other language.
{% assign lang = user.language | default: "en" %}{% if lang == "fr" %} Bonjour {{ first_name | default: "there" }}!{% elsif lang == "es" %} Hola {{ first_name | default: "there" }}!{% else %} Hi {{ first_name | default: "there" }}!{% endif %}
A recipient with user.language set to fr sees the French greeting. A recipient with de, or with no language set, sees the English greeting.
Email template that branches on the user's language with Liquid.
See Using Liquid syntax for case / when and other conditionals.Option 3: Dynamic ContentUpload a CSV whose column headers are language codes and reference the cells with user.language. See Dynamic Content.APIThe Create message API does not accept a language map for email. email_subject and email_body are single strings. Put the Liquid from the section above in a template, then send that template:
To send a different template to each language, target a language segment or a languagefilter instead of one template for every subscriber. See Create message.
Open Messages > In-App > New In-App or an existing in-app message, then click Add Languages. This works in the block editor, the HTML editor, and on in-app steps in a Journey.Each recipient sees the variant that matches their language property. Recipients with no matching variant see the default. Test & Preview sends each test device its own language variant. On the report, Group by Language compares impressions and clicks per language, and the CSV export includes the same breakdown.An existing single-language in-app message stays unchanged until you edit it or duplicate it. Either action migrates the message to the multi-language format. Each language variant has its own 1 MB size limit, separate from the default message.Option 1: CheckboxesSelect each language you support. The editor adds a tab per language. Recipients whose language you did not select receive the default variant.
Select Languages modal with a checkbox for each supported language.
Option 2: One message per language segmentFollow Send one message per language segment when each language needs its own in-app message instead of tabs on one message.Option 3: Tag substitutionUse Add Languages to localize the message. Use a tag only when you need conditional copy inside a single variant.
In-app Liquid can only substitute tags. It cannot read user.language, subscription.language, or any other property object. Calling setLanguage does not change which tag branch renders.
Set a tag to the same code you store on the language property, such as de rather than german. The tag must already be on the user when they open the app and start a new session. See Tags and supported personalization fields.
Tags
language : defirst_name : Jon
Template
{% assign lang = language %}{% if lang == "fr" %} Bonjour {{ first_name }}!{% elsif lang == "es" %} Hola {{ first_name }}!{% elsif lang == "de" %} Guten Tag {{ first_name }}!{% else %} Hello {{ first_name }}!{% endif %}
Result
Guten Tag Jon!
Open Messages > SMS > New Message or a template.Option 1: One message per language segmentFollow Send one message per language segment.Option 2: Dynamic ContentUpload a Dynamic Content CSV whose column headers are language codes and reference the cells with user.language.APISet contents to a map of language codes. SMS does not use headings or subtitle. Include en. Recipients whose language is not in the map receive the en text.
{ "app_id": "YOUR_APP_ID", "target_channel": "sms", "included_segments": ["Subscribed Users"], "contents": { "en": "Your order has shipped.", "fr": "Votre commande a été expédiée." }}
Store one of these codes on the user’s language property. en is the required default for push and SMS. Most codes are ISO 639-1. zh-Hans (Simplified Chinese) and zh-Hant (Traditional Chinese) are script subtags, not two-letter codes.
If a code is not in this table, OneSignal does not offer it in the dashboard language picker or the import template. Use the closest supported language, or email support@onesignal.com to request the language.
Their language property did not match a variant on the message, so OneSignal sent the default. In the dashboard that default is the Any/English tab. In the push and SMS APIs it is the en entry. Check the user’s language on their profile, then confirm that same code is a tab on the message or a key in contents.
Push and SMS contents require en. The push dashboard keeps the Any/English tab as the default for anyone whose language you did not add. Email and in-app tag conditionals use the else branch for every other language.
Can I localize email with a language map in the API?
No. Email email_subject and email_body are single strings. Branch on user.language with Liquid, use Dynamic Content, or send one template per language segment.
setLanguage updates the language property, and Add Languages uses that property. Liquid inside an in-app message does not. In-app Liquid can only read tags. Set a tag to the same code, such as de, and branch on that tag. The tag must be present before the user starts a new session.
How do I add languages to an existing in-app message?
Edit or duplicate the message. Either action migrates a single-language in-app message to the multi-language format. Until you do that, the message stays as it is.
The push editor stores text as HTML. A character such as % can display in the wrong place in a right-to-left language. Add a right-to-left mark immediately after the character.