Translation

Stream translates chat messages so that people who speak different languages can talk in the same channel. There are two ways to translate:

  • Automatic (recommended): messages arrive already translated into the channel's languages.
  • On demand: translate one message into any language with an API call.

Automatic translation

When a message is sent in a channel with automatic translation on, Stream translates its text into the channel's target languages before the message is delivered. The translations are stored on the message in message.i18n, so every member receives them with the message itself.

Here is how it works:

  1. A user sends a message in a channel with automatic translation enabled.

  2. The sender's language is the source language. When it is not set, the language is detected from the text.

  3. Stream translates the text into the channel's target languages and stores each translation in message.i18n.

  4. The message is delivered to the channel members with its translations included.

Info:

Set a language on every user and add your users as channel members. Stream uses the members' languages to pick the default target language.

Choose target languages

Set the channel's auto_translation_language to a comma-separated list of language codes, such as "en,es,fr". Each message is translated into every listed language except the sender's own.

  • A message is translated into at most 5 target languages. The list is a priority order: when there are more, the first-listed languages are kept.
  • Spaces around codes are ignored, and empty or duplicate entries are dropped.
  • Use codes from the Available languages table. Codes are not checked when the setting is saved, so a typo is accepted and then skipped at translation time.
  • Delivery waits up to a few seconds for the translations. A target language that doesn't finish in time, or that fails at the translation provider, is missing from message.i18n, without an error.

A single code, such as "en", is a list with one language.

Default: the members' most common language

With no auto_translation_language set, each message is translated into one language: the most common language among the other channel members. The sender's own language never counts toward it.

Only a member language from the Available languages table can become the default target. Codes in auto_translation_language skip that check, which is why a code that is never picked as the default can still work when you list it.

This target is not only a fallback. With a list set, the members' most common language is still added when it is not already in the list and there is room under the 5-language cap.

Here is how the two combine:

auto_translation_language Sender Other members speak Translated into
(not set) en mostly es es
es,fr en mostly de es, fr, de
en,es en only es es
en,es,fr,de,it pt mostly ja en, es, fr, de, it (ja dropped by the 5-language cap)

Enable automatic translation

Automatic translation is not enabled by default. Turning it on or off is server-side only: a client token can't change auto_translation_enabled, or create a channel with it on. Use a server-side SDK or the CLI from your backend.

  • App-wide: on or off. When it is on, every channel in the app is translated.
  • Per channel: on or off, plus the channel's target languages in auto_translation_language. Besides your backend, any user allowed to update the channel can change the target languages with a full channel update. A partial update of either field needs server-side auth.

Translation runs when it is enabled for the app or for the channel. When it is enabled app-wide, setting auto_translation_enabled: false on a channel does not turn it off for that channel.

Node.js
const channel = client.chat.channel("messaging", "melting-pot");

// enable auto-translation only for this channel
await channel.update({ data: { auto_translation_enabled: true } });

// translate messages into English, Spanish and French
await channel.update({
  data: {
    auto_translation_enabled: true,
    auto_translation_language: "en,es,fr",
  },
});

// auto translate messages for all channels
await client.updateApp({ auto_translation_enabled: true });

Set user language

A user's language is the source language of the messages they send. When it is not set, Stream detects the language from the text. The members' languages also decide the default target language. Setting a language for every user is still recommended.

// sets the user language
await client.connectUser({ id: "userId", language: "en" }, userToken);

// watch a channel
await client.channel("messaging", "melting-pot").watch();
Info:

A member's language is not automatically a target language. Without a list, only the members' most common language is a target. To translate into more languages, list them in auto_translation_language (see Choose target languages).

Reading translations

When a message is translated, the i18n object is added. The i18n includes the message text in all languages and the code of the original language.

The i18n object has one field for each language named using this convention language-code_text

Here is an example after translating a message from English into French and Italian.

// Show the reader's language, falling back to the original text
const text = message.i18n?.[`${client.user?.language}_text`] ?? message.text;

Translate a message on demand

Use this endpoint to translate an existing message into a language that is not one of the channel's target languages, for example when a user changes their language. The translation is added to the same i18n object as automatic translations.

The source language is inferred from the user language or detected automatically by analyzing its text. If possible, store the user language, see Set user language.

await channel.sendMessage({
  message: {
    id: messageID,
    text: "Hello, I would like to have more information about your product.",
  },
});

// returns the message.text translated into French
const response = await client.translateMessage(
  { id: messageID },
  { language: "fr" },
);

// the translation will be added to the i18n object
console.log(response.message.i18n?.fr_text);
// "Bonjour, J'aimerais avoir plus d'informations sur votre produit.",

The endpoint returns the translated message, updates it and sends a message.updated event to all users on the channel.

Info:

Only the text field is translated, custom fields and attachments are not included.

Poll translation

Polls attached to a message in an auto-translated channel are translated too. The poll name, description, option texts and free-form answers get an i18n object with the same shape as a message's i18n: one <language-code>_text field per language, plus language for the original language.

Field Translation
name name_i18n
description description_i18n
options[].text options[].text_i18n
latest_answers[].answer_text latest_answers[].answer_text_i18n

Here is how it works:

  1. A poll is created. Creating a poll does not translate it.

  2. The poll is sent in a message on a channel with automatic translation enabled. The poll is translated into the same languages as the message.

  3. Later changes are translated into the languages the poll already has. This covers updating the poll name or description, adding or updating an option, and casting a vote with an answer_text.

const poll = message.poll;
const language = client.user?.language;

// Fall back to the original text when a field has no translation for the language
const name = poll?.name_i18n?.[`${language}_text`] ?? poll?.name;
const options = poll?.options.map(
  (option) => option.text_i18n?.[`${language}_text`] ?? option.text,
);

Keep these points in mind:

  • Translating changes to a poll (updates, new options and answers) requires automatic translation to be enabled for the app. When it is only enabled on the channel, the poll is translated once when it is sent. Later changes are not translated, and the old translations of a changed field are removed.

  • When the same poll is sent to several channels, it is translated into the languages of each channel, up to 10 languages including the original.

  • Poll translations are billed the same way as message translations (see Caveats and limits).

Caveats and limits

  • Each message is translated into at most 5 target languages. When the configured list plus the members' most common language comes to more than 5, the first-listed languages are kept.

  • Translations are billed per character of the original text, for each language it is translated into. Adding target languages multiplies the cost. See pricing for the rate.

  • A target language that doesn't finish within a few seconds, or that fails, is missing from message.i18n. Fall back to message.text when the reader's language is missing.

  • Language codes are not validated when they are saved. An unrecognized code in auto_translation_language is skipped at translation time, without an error.

  • Enabling automatic translation app-wide applies to every channel. A channel cannot opt out with auto_translation_enabled: false.

  • Error messages are not translated.

  • When a custom command rewrites the text, the new text is translated.

  • A before message send webhook can keep, re-translate or replace a message's translations, see its Translations section.

  • When a message is updated, translations are recomputed automatically for every language the message already has.

  • Changing translation settings or a user's language has no effect on messages that are already translated.

Available languages

Use these codes in auto_translation_language and in a user's language.

Language name Language code
Afrikaans af
Albanian sq
Amharic am
Arabic ar
Azerbaijani az
Bengali bn
Bosnian bs
Bulgarian bg
Chinese (Simplified) zh
Chinese (Traditional) zh-TW
Croatian hr
Czech cs
Danish da
Dari fa-AF
Dutch nl
English en
Estonian et
Finnish fi
French fr
French (Canada) fr-CA
Georgian ka
German de
Greek el
Haitian Creole ht
Hausa ha
Hebrew he
Hindi hi
Hungarian hu
Indonesian id
Italian it
Japanese ja
Korean ko
Latvian lv
Lithuanian lt
Malay ms
Norwegian no
Persian fa
Pashto ps
Polish pl
Portuguese pt
Romanian ro
Russian ru
Serbian sr
Slovak sk
Slovenian sl
Somali so
Spanish es
Spanish (Mexico) es-MX
Swahili sw
Swedish sv
Tagalog tl
Tamil ta
Thai th
Turkish tr
Ukrainian uk
Urdu ur
Vietnamese vi