Handling languages in Ultimate with the Messaging Widget

Handling languages in Ultimate with the Messaging Widget

This article contains two approaches of collecting language context from customers contacting your AI Agent, powered by Ultimate via the Zendesk Messaging Widget.

Zendesk's native bot supports multiple languages and even offers an auto-translation feature for generative replies and custom flows.

The AI Agent powered by Ultimate uses a slightly different approach in which you can define duplicates of your replies for each language. So where generative replies automatically adapt the language of the conversation, you have full control of the steps and translations used in your flows per language.

However, in order for this to work correctly you need to make sure you can detect your conversation languages correctly. Zendesk's support help center has extensive documentation on this topic, but in this article I'd like to take a more structured and practical approach to this.

Managing Languages (Ultimate)
Languages are an important part of unlocking the value of Ultimate. Thus we have made it simple to add, activate and translate replies. This article will cover the first two points: Adding a new…

We'll focus on one specific use case, one that is – I think – the most common in use. We have a native Zendesk Messaging widget embedded on a website which is linked to the Ultimate Bot.

Retrieving a user's language

There's three ways to pass a locale to the Ultimate Bot:

  • System. If nothing is set, it just inherits and uses the locale of the browser or website language if defined. This is the least stable option and doesn't always work since every website and user's setup is unique.
  • Widget Locale. This uses the locale of the Zendesk Widget. You can use code to manually overwrite the locale client side so you're in control on what gets passed to the bot.
  • Ticket Fields. You can also pass conversation metadata to the Zendesk Widget. This is stored in ticket fields and can be retrieved by the bot to set the language.

Setting the language

The active language in a conversation managed by Ultimate is stored in a system variable called active_language

You can use actions to overwrite the current value with your own and you can do this at the start of a conversation, or midway a conversation.

If the active_language is set, Ultimate will use this value to select the right system language, and use active replies for that language.

If no languages match the system will fall back to the default language set.

To make sure you're matching the right language, you can add the expected values for that language as Locale Info to the language.

For example, in English you might expect enen-us and en-uk.

Using the Widget Language

You can set a Messaging Widget's language in Zendesk via the following javascript call:

<script>
  zE('messenger:set', 'locale', 'en-us');
</script>

This will translate the widgets' UI and will also store the locale on the user level.

This means that all conversation started by that user from then on will be considered to be in that language. This also means that if the user opens the widget and starts a conversationon a domain.com/en-us and then navigates to domain.com/fr the system will still assume this user is speaking English.

Retrieving the language

If you use the widget locale to set the language you can use it in Ultimate via Bot Settings > Events and Actions.

Create a new action that fires when a Chat is started

  • Give it a name: Set locale based on widget language
  • Target: Sunshine Conversations
  • Task: Get user
  • Field to retrieve: locale
  • Save as parameter: active_language

Next Steps

Nothing else needs to be done. If your active_language matches a language setup for your bot, it'll jump right into the Welcome Reply for that locale, and if not, it'll use the default language's Welcome Reply

Using a custom field language

You can set a Conversation language in Zendesk via the following Javascript call.

Note that the ID is that of an end-user editable text-field (or dropdown) in Zendesk.

<script>
  zE("messenger:set", "conversationFields", [
    {id: 1234567890, value: "en-us"}
  ]);
</script>

This will NOT translate the widgets' UI but will store the locale on the conversation level.

This means that only this conversation started by that user will be in this language. 
This also means that if the user opens the widget and starts a conversation on a domain.com/en-us and then navigates to domain.com/fr and starts a new conversation, system, will start the new conversation in french if set so by the code.

Retrieving the language

If you use the widget locale to set the language you can use it in Ultimate via Bot Settings > Events and Actions.

Create a new action that fires when a Chat is started

  • Give it a name: Set locale based on metadata
  • Target: Sunshine Conversations
  • Task: Get conversation metadata
  • Field to retrieve: <Metadata>
  • Key: zen:ticket_fields:1234567890
  • Save as parameter: active_language

Next Steps

Nothing else needs to be done. If your active_language matches a language setup for your bot, it'll jump right into the Welcome Reply for that locale, and if not, it'll use the default language's Welcome Reply

Verifying the data is correctly set

If you're just setting this up you might want to check if everything is setup correctly client side in order to make troubleshooting easier.

If you start a new conversation in the Web Widget, you can open your browser Inspect Tools, and go into the Networks tab. Look for a network call to AppUsers. This contains a payload that, within the conversations[] array has a metadata:{} object that will contain the ConversationsField you set earlier:

{
    "settings": {
      /.../
    },
    "conversations": [
        {
            "_id": "67865f8099658d0434f350bf",
            "type": "personal",
            "brandId": "21612166319762",
            "isDefault": true,
            "lastUpdatedAt": 1736859520.552,
            "createdAt": 1736859520.552,
            "metadata": {
                "zen:ticket_field:1234567890": "en-us"
            },
            "unreadCount": 0,
            "status": "active",
            /.../
        }
    ]
}

Similarly there's an appUser{} object that contains the locale you set via the widget locale setting.

{
    "settings": {
        /.../
    },
    "appUser": {
        "locale": "fr",
        "localeOrigin": "apiRequest",
        "signedUpAt": "2025-01-14T12:58:40.525Z",
        "identities": [],
        "conversationStarted": true,
        "clients": [
          /.../
        ]
}

By using this network inspection you can easily troubleshoot if a wrong language setting is caused by the locale not being passed to the widget initially, or a bad configuration you made in Ultimate.

What happens if I set both values?

You can set both the widget language and the ticket field language. As long as you don't retrieve and set both values in Ultimate you won't go into any conflict.

For example, in this scenario I set the widget to English, while setting the language field French

<script>
  zE('messenger:set', 'locale', 'en-us');
  zE("messenger:set", "conversationFields", [
    {id: 1234567890, value: "fr"}
  ]);
</script>

I can then choose to retrieve either one of these languages as the conversation language by either retrieving the user- or conversation metadata via an action.

If I do retrieve both, the last one set will win (or in other words the action lowest in the list)

Advanced Uses

Handling unsupported languages

Let's say my Bot only supports English and French. But I have a customer contacting me in Spanish.

Since Spanish is not a supported language the bot will respond with my default, English, Welcome reply.

I can however use conditional steps in my Welcome Reply to let the customer know that yes, I see he's speaking Spanish, and that he can choose between English and French to talk to the Bot.

  1. After the welcome message, add a Conditional Flow
  2. Set the Conditional to active_language
  3. If the language is not en we want to tell the customer we detected an unsupported language
    1. Add a bot message that "I detected your language as {{active_language}}. Please note I only support French and English for now. You can switch to French, or ask your question."
    2. Add a visitor question that offers French as an alternative
    3. Associate a Collect Parameter step to this option that sets the parameter active_language to fr
    4. Link to the French Welcome Reply
  4. In the other Condition (which is English) we ask the customer "How can I help you?" mimicking the original Welcome Reply

Use other variables to detect a language

We can use the conversationFields option to build more complex flows.

Let's say we pass a city to the widget:

<script>
  zE("messenger:set", "conversationFields", [
    {id: 1234567890, value: "rome"}
  ]);
</script>

We could create an action in Ultimate that stores this zen:ticket_field:134567890 as current_city in our conversation.

We can then use a conditional flow that looks at the City and, for example, sets the active_language to Italian for Rome, French for Paris and German for Berlin. Each of those conditions can then link to their respective Welcome Replies, thus linking location and cities to languages.

Create a language use-case

We can create an use-case that react to "Wrong language" replies. The reply can then offer a list of supported languages as a carousel or buttons.

The customer can then choose a language (which updates the active_language via an action or parameter) and links to the now correct welcome reply.