Skip to content

Rich text and interpolation

When a translated string carries markup or a value, you render it with <Trans>. It is the SDK's only rich-text component.

Import Trans from @sonenta/react-i18next. Placeholders come from values, tags from components.

import { Trans } from "@sonenta/react-i18next";
<Trans
i18nKey="cta.terms"
defaults="Hi {{name}}, please accept the <bold>terms</bold>."
values={{ name: "Marc" }}
components={{ bold: <strong /> }}
/>
Hi Marc, please accept the <strong>terms</strong>.

components takes an object, as above, where the key is the tag name. It also takes an array, in which case the tags in the string are numbered (<0>, <1>, …). The object form reads better when a translator has to review the string: <bold> means something, <0> does not.

A tag present in a translated value but absent from components does not disappear, and it is not interpreted. It is escaped, so it is shown to the user as-is.

Translated value:

Read this <foreign lang="en">as-is</foreign> please.

What your user sees on screen, if foreign is not mapped:

Read this <foreign lang="en">as-is</foreign> please.

That is deliberate, not a bug: the SDK never guesses which component you meant. But it is visible in production, so map every tag your translators can produce.

Pass the t from the surrounding useTranslation(ns) with <Trans t={t} …>. Without it, the sentence can resolve against a different namespace than you think, and you get the raw key or a homonym's value.

const { t } = useTranslation("checkout");
<Trans t={t} i18nKey="cta.terms" components={{ bold: <strong /> }} />

Thirteen props, none of them required. In practice you need i18nKey, plus defaults for as long as the key is not published yet.

i18nKey, ns, namespace, defaults, values, components, count, context, tOptions, shouldUnescape, parent, t, children.