Skip to main content

Get localized connected content on Braze from Lokalise.

Ilya Krukowski avatar
Written by Ilya Krukowski
Updated over a week ago

This feature is available from the Pro plan and above.

Use this app to localize your Braze campaigns with Lokalise.

Getting started

This integration is based on Braze’s connected content. On Braze, you will use connected content whenever you want a piece of content to be localized, including within content blocks. Сonnected content will be retrieved from a different dedicated URL for each language. Therefore, your users should have language information tied to their profiles.

If you haven't already done so, open your Braze dashboard and proceed to Users > User import. Here you can import your users as explained in Braze documentation. When preparing a CSV file for importing, make sure to include a language column with users' languages. We will use this language field later when displaying translations. It’s very important that you use the same language codes as on Lokalise.

In Lokalise, you will create a translation key for each of the connected content variables that you define in Braze. Once the translations are ready, you can generate one JSON file per language, and get it published on the URLs that will serve your connected content.

Preparing your translations on Lokalise

First, prepare your translations on Lokalise, on a software localization project. You’ll need to create the translation keys manually, with the same name that you’re using on Braze connected content variables. For example, let's create a simple translation key description:

Known issues

  • Your keys must be assigned to the Web platform.

  • Please avoid using keys containing periods . or the _on string. For instance, use this_is_the_key instead of, and use join_us_instagram instead of join_us_on_instagram.

  • Only verified translations will be available for Braze in the JSON resource file.

Configuring the Braze app on Lokalise

Open your project, and click Apps:

Here search for the Braze app, click on it and then press Install.

You'll see the following screen:

On the translation file URL, Lokalise publishes a JSON file containing all the translations for your keys in the project. You'll get as many translation file URLs as target languages you have in your project. This is why the resulting translation file URLs have two pieces:

  • The first part of the URL path is common to all languages.

  • The JSON file name at the end of the URL is based on the language code. Remember, it’s very important that you use exactly the same language codes on Lokalise and Braze user profiles.

The translation file URL is the URL that you will need when configuring a Braze campaign. You can update the content on the JSON file by clicking Refresh; note that the URL will stay the same and you don't need to change your connected content call on Braze's side.

To test that this URL works correctly, just copy it, replace {{${language}}} with a language code (for example, en) and open this URL in your browser. You will see a JSON file with your keys and translations:

That's it!

Using translations in Braze campaign

When you are ready, return to Braze and proceed to Campaigns.

First, remember that the connected content will be retrieved from a different dedicated URL for each language. Therefore, your users should have language information tied to their profiles.

Open an existing campaign or create a new one. For the purposes of this article, we'll create a new Email campaign with some sample content.

Click Edit Email Body:

You will see your email's HTML markup which utilizes Liquid template language.

To utilize your translations, you need to add the connected content request once in the HTML, either at the top of the document or right before the first place where a translation is needed. You do it by inserting the following markup:

{% connected_content{{${language}}}.json :save translations %}

Replace the URL with the translation file URL fetched in the previous step.

  • {{${language}}} means "insert user language at this position". Alternatively, you can hardcode your language code, for example en.json.

    • Note: To ensure that the appropriate translated JSON file is retrieved for each user, you must place either the {{${language}}} profile attribute or another similar custom attribute that holds the user’s language at the end of the translation files URL. E.g., /{{${language}}}.json. The values held in these attributes must match the prefix of each of the translated JSON files. This will ensure the correct translation file is returned for each user.

  • :save translations is going to save the JSON content under the translations variable.

Now simply use the translations variable to display the desired translations by their keys.

For example, to display the description key you would say:

{{ translations.description }}

Now simply save the email template and preview it. You should see your translation being displayed:

Note on Liquid variables

When previewing your content on Braze, please make sure that you've provided the necessary values for the variables, especially for the $language.

To achieve that, switch to the Preview as a User tab and fill in the necessary values:

So, here we are setting the language to en for previewing. Also note that here you can add values for other variables, for example, for the $first_name variable that can be used in your translations.

Note on using variables and placeholders inside Lokalise translations

If your Lokalise translations directly contain Liquid tags or Liquid variables, you'll need to use the :rerender flag. This is because these values have to be processed by Braze before rendering the translation content. In other words, first you resolve the Liquid variables and get your translations, and then you render the template again using their content.

Here's an example where a custom field registration_date taken from a user profile is used in the Lokalise translations. It needs to be properly rendered in the Braze template:

{% assign date_test = {{custom_attribute.${registration_date}}} %}

{% connected_content :rerender :save translations %}

<div>Your registration date was: {{date_test}}</div>


In Lokalise, the translation string looks like it is shown on the screenshot below. Please note that if Liquid filters are used (the date filter on the screenshot below), we recommend using single quotes instead of double quotes:

Here's the result when rendering the previous snippet in a Braze template:

As you can see, the date is stored in ISO-8601 format in the custom attribute in the user profile but it is rendered in a different format using the |date: '%B %d, %Y' filter.

Please note that if you use Liquid variables in Lokalise translations, you'll need to declare these variables on Braze as explained in the section above (even if you don't use these variables).

Using Lokalise keys in subjects and preheaders

Lokalise keys can be used in Braze subjects and preheaders however in order to achieve that you'll also need to add the connected_content directly into the corresponding fields. Here's an example:

As you can see, before using the translations, we have to add the {% connected_content XXXX :save translations %} with a link to the JSON file.

Please note that if you would like to use the dynamic language in the connected_content link, you'll need to follow the steps listed in the previous section.

Handling missing translations

If you'd like to handle the cases when some translations are not available, you can use the following approach:

{% connected_content{{language}}.json :save translations %}

{% if translations.survey != blank %}


{% else %}

{% connected_content :save fallback %}


{% endif %}

In this example we are checking that the survey key is not blank. If it's present, we simply display it. Otherwise we try to fetch fallback English translations and find the value of survey there. Usually the fallback language is the base language of your Lokalise project.

Here's another example where we conditionally load English translations for all languages that are not de, fr, or nl:

{% if ${language} == 'de' | 'fr' | 'nl' %}

{% connected_content{{${language}}}.json :save translations %}


{% else %}

{% connected_content :save translations %}


{% endif %}

Braze team also recommends using content blocks instead of the full code snippets, and connecting these blocks in the relevant places.

For example, if your content block looks like this:

{% connected_content{{projectID}}/{{bundleID}}/{{language}}.json :save translations %}

You can use the block in the following way:

{% assign projectID = "0a7baed882b0db67dc93ed845780992139e47523" %}
{% assign bundleID = "7a7baed882b0db67dc93ed845780992139e47523" %}

{{content block variable here}}

Handling broken Liquid variables

To avoid issues with JSON refreshing due to broken Liquid variables, follow these simple steps:

  1. Open your Lokalise project and navigate to Settings > QA checks.

  2. Look for Unbalanced brackets (target) and set it to Error. Don't forget to save your changes.

By making this adjustment, Lokalise will help you avoid some pitfalls:

  • If there are unbalanced brackets in the target language, Lokalise will not allow JSON regeneration and will alert you with an error.

  • Contributors will be prevented from saving changes if they introduce or fail to correct unbalanced brackets in the target language.

  • It's important to note, however, that this setting does not block the import of broken Liquid code via the Lokalise API.

Please note, however, that when you integrate the Braze app into an existing Lokalise project that already has broken Liquid code in the target languages, Lokalise permits one initial JSON export without errors. Any attempts to refresh JSON thereafter will result in errors.

Potential technical issues

Liquid variables rendering

Liquid variables might not be rendered if a translation key is broken (in other words, written incorrectly). For example, this is a valid form: {{${first_name} | default: ''}}.

However, these are invalid and will cause issues:

{{${first_name}) | default: ''}}
{{${first_name} | Standard: ''}}
{{${Vorname | Standard: ''}}}}

To detect such issues in your translations, use the following custom filter on Lokalise:

  • Translation > contains > {{${. By adding this filter, we instruct Lokalise to bring up keys that contain any Liquid variable coming from Braze.

  • Translation > does not contain > {{${first_name} | default: ''}}. Enter the expected Liquid variable so that Lokalise brings up everything that does not look like it.

Missing special characters and emojis

We're aware of a problem where special characters and emojis may not appear in Braze. This issue is caused by a bug in Braze, confirmed by their team. It relates to a fallback client that is sometimes activated (about 2% of the time).

Until this bug is resolved, you can contact Braze Support and request them to disable the fallback client for your account. Please note that this may lead to a small increase in retry attempts for connected content. Therefore, we recommend configuring the retry attempts as outlined in the Connected Content retries article on Braze.

Frequently asked questions

What happens if I accidentally delete a key from Lokalise?
The corresponding string on Braze won't have a translation anymore.

If I have an en locale but override it with en-US on Lokalise, will Braze read it as en-US?
No, locale ISO codes must match on Braze and Lokalise.

Can we use the :rerender flag when connecting Lokalise content?
Yes, sure. You can consult Braze docs to learn how to add this flag.

After refreshing the translation file on Lokalise, I can't see any changes on the translated content on Braze. Why?
Braze caches translated content on their side, and it can take a few minutes to refresh. If you're testing your campaigns and you need to see the results of translations immediately, you can use the :cache_max_age parameter as explained in this article.

Did this answer your question?