Platform docs
Auth, users, webhooks & more
Info:
This is beta documentation for Stream Video React SDK v2. For the latest stable version, see the latest version (v1).

Localization

Built-in translation service powered by i18next for language switching and custom translations.

Best Practices

  • Use useI18n() hook to access the t() translation function.
  • Register your own copy via the translations prop on StreamVideo - it layers over the SDK's English, so a partial dictionary is safe.
  • Set language via language prop - a language code such as en or de.
  • Type your dictionaries as TranslationDictionary so a typo or a stale key is a compile error.
  • For advanced control, create your own Streami18n instance and pass it via i18nInstance.
Note:

The i18n API changed in v2. translationsOverrides is now translations, fallbackLanguage is gone, and every key is a namespaced dotted identifier instead of an English sentence. See Migrating from v1 below.

Integration

The service is made available through the StreamVideo provider. That means that all the child components of this provider can access the translation context by using the useI18n context consumer.

The context carries the following properties:

  1. the translator function t - takes a translation key and the English copy for it, and returns the translation for the active language.
  2. the date/time parser tDateTimeParser - a dayjs instance bound to the active language and timezone, used to render timestamps.

Translation keys

Every string the SDK renders is a namespaced dotted key, written at its call site together with the English copy:

t("participantList.muteAll.label", "Mute all");

The second argument is i18next's defaultValue. It is what makes English the built-in language: the SDK ships no en.json and no translations export. If a key is missing from your dictionary - or you have registered no dictionary at all - the inline English renders, never the raw dotted key.

Plural keys pass count together with one default per plural form:

t("callFeedback.starRating.rateStars.ariaLabel", {
  count: star,
  defaultValue_one: "Rate {{ count }} star",
  defaultValue_other: "Rate {{ count }} stars",
});

In a dictionary those keys are written out per form - callFeedback.starRating.rateStars.ariaLabel_one, callFeedback.starRating.rateStars.ariaLabel_other, and _zero / _two / _few / _many for the languages that need them.

The complete key list is the TranslationCatalog type exported from the SDK, so your editor autocompletes it. The SDK repository can also emit a flat translator-facing JSON on demand with yarn i18n:export in packages/react-sdk.

Configuration

The i18n parameters StreamVideo accepts are:

type StreamVideoI18nProps = {
  i18nInstance?: Streami18n;
  language?: string;
  translations?: Record<string, LooseTranslationDictionary>;
};

In the following sections, we will look more into these individual configuration parameters.

Custom translations

To translate the SDK into another language, or to change some of the English copy, pass dictionaries keyed by language code to the translations prop.

The dictionaries are registered over the SDK's built-in copy rather than replacing it. Any key you leave out falls back to the English written at the call site, so a partial dictionary is safe and you do not have to translate everything before shipping a language.

import type { LooseTranslationDictionary } from "@stream-io/video-react-sdk";

const translations: Record<string, LooseTranslationDictionary> = {
  de: {
    "callControls.cancelCallButton.leaveCall.title": "Anruf verlassen",
    "participantList.muteAll.label": "Alle stummschalten",
  },
};

const App = () => {
  // ...
  return (
    <StreamVideo client={client} language="de" translations={translations}>
      {/*...*/}
    </StreamVideo>
  );
};

A dictionary may also carry your own application's keys alongside the SDK's - that is what LooseTranslationDictionary allows.

Note:

In v1 this prop was called translationsOverrides, and despite what that page said it replaced the SDK's dictionary instead of merging with it, so every key you did not translate rendered as a raw key. That is fixed: translations registers over the SDK's defaults.

Typed dictionaries

Two dictionary types are exported:

Type Accepts Use it when
TranslationDictionary only the SDK's keys the dictionary holds SDK copy only - a typo or a removed key fails the build
LooseTranslationDictionary the SDK's keys plus any other string one dictionary carries both SDK and application copy

TranslationDictionary is the stricter of the two and the one to prefer for SDK-only files: a key that no longer exists is caught at compile time instead of silently never applying.

import type { TranslationDictionary } from "@stream-io/video-react-sdk";

export const de: TranslationDictionary = {
  "callControls.cancelCallButton.leaveCall.title": "Anruf verlassen",
};

TranslationKey (a union of every key t() accepts) and TranslationCatalog (the key to English copy map) are exported too.

Adding a language

Dates and relative times are rendered by dayjs, which needs the locale file for the language imported once in your application. Without it, dates render with the English locale and the SDK logs a warning.

import "dayjs/locale/nl";
import { Streami18n, StreamVideo } from "@stream-io/video-react-sdk";

const i18n = new Streami18n({ language: "nl" });
i18n.registerTranslation("nl", {
  "callControls.cancelCallButton.leaveCall.title": "Gesprek verlaten",
});

const App = () => (
  <StreamVideo client={client} i18nInstance={i18n}>
    {/*...*/}
  </StreamVideo>
);

No dayjs locale file defines the calendar strings - those belong to the calendar plugin - so a language whose relative dates ("Today at 14:30") must read natively needs a calendar config passed as the third argument to registerTranslation.

Provide your own instance of Streami18n

You may want to initialize the service somewhere else and pass the instance through the prop i18nInstance. If an instance is provided, StreamVideo adopts it and initializes it; the instance is not swapped out on later renders.

import { Streami18n, StreamVideo } from "@stream-io/video-react-sdk";

const i18n = new Streami18n({
  language: "en",
  translationsForLanguage: {
    "participantList.muteAll.label": "Silence everyone",
  },
});

const App = () => (
  <StreamVideo client={client} i18nInstance={i18n}>
    {/*...*/}
  </StreamVideo>
);

Streami18n also accepts timezone, formatters, disableDateTimeTranslations, DateTimeParser (to supply your own dayjs or moment module) and i18nextConfigOverrides, which is applied over the SDK's i18next init options and can reach settings the SDK does not surface.

registerTranslation(language, dictionary, dayjsLocaleConfig?) and setLanguage(language) may be called at any point, before or after initialization. setLanguage resolves with no value - the new t is published to i18n.state, which the provider subscribes to.

Language

You can set the current language for the translation service with the language prop. This should be a language code (for example en, de) - a key of translations, or a language you registered on your own Streami18n instance.

const App = () => {
  /*  a hook that keeps track of the current language in your app  */
  const { language, setLanguage } = useLanguage();
  // ...
  return (
    <StreamVideo
      client={client}
      language={language}
      translations={translations}
    >
      {/*...*/}
    </StreamVideo>
  );
};

Changing language switches languages in place. A language with no registered dictionary is not an error: the SDK's English copy renders.

Fallback behaviour

There is no fallbackLanguage option. The fallback is the English copy written inline at every call site, so a key missing from the active language's dictionary already renders correct English. i18next's own fallbackLng is turned off for that reason.

If you deliberately want one language to fall back to another - a regional dictionary completed by its base language, say - turn it back on through the escape hatch:

const i18n = new Streami18n({
  language: "de-AT",
  i18nextConfigOverrides: { fallbackLng: "de" },
});

Translation function

The function is passed a translation key and the English copy for it, and returns the translation for the active language. If the key is not in the active dictionary, the English copy is returned.

Accessing the translation function

You can access the translation function in any child component of StreamVideo through the context consumer useI18n:

import { useI18n } from "@stream-io/video-react-sdk";

const CustomButton = () => {
  const { t } = useI18n();

  return (
    <button>
      {t("callControls.cancelCallButton.leaveCall.title", "Leave call")}
    </button>
  );
};

useI18n() returns { t, tDateTimeParser }. It also works outside a provider, where the default translator renders each call site's inline English.

Note:

t() only accepts keys the SDK defines. If your key is only known at runtime - the value of a lookup table, for instance - wrap it in the exported asDynamicKey() helper, and supply the copy for it through your dictionaries. Prefer a switch over literal t() calls where you can: it keeps the copy statically visible and translatable.

Migrating from v1

v1 v2
translationsOverrides translations - registers over the defaults instead of replacing them
fallbackLanguage removed - use i18nextConfigOverrides: { fallbackLng }
StreamI18n Streami18n (different class, different options)
StreamI18nProvider removed - use StreamVideo
TranslationsMap Record<string, LooseTranslationDictionary>
TranslationLanguage, TranslatorFunction removed
the translations export / en.json removed - English is inline at each call site
useI18n().i18n removed - useI18n() returns { t, tDateTimeParser }
t("Leave call") t("callControls.cancelCallButton.leaveCall.title", "Leave call")

Every key changed. The old English-sentence key to new namespaced key mapping is published as ai-docs/i18n-2.0-key-map.json in the SDK repository; see also the v1 to v2 migration guide.

Warning:

An override under an old key fails silently: it never matches, so the SDK's English renders with no error. Type your dictionaries as TranslationDictionary to turn that into a compile error.

Final recommendations

As the translation service is based on i18next, we encourage you to consult the library's documentation in order to learn about:

Add Chat to my app: getstream.io/SKILL.md

The fastest way to build with Stream. Start a new project or improve an existing one. Full CLI and documentation integration out of the box.


Ask your agent:

/stream Build me a Social App with Feeds and Moderation.
/stream Any livestream calls running?
/stream Video React v2: <Your Question>