githubEdit

Nesting

Nesting allows you to reference other keys in a translation. Could be useful to build glossary terms.

Basic

keys

{
    "nesting1": "1 $t(nesting2)",
    "nesting2": "2 $t(nesting3)",
    "nesting3": "3",
}

sample

i18next.t('nesting1'); // -> "1 2 3"

You can reference keys from other namespaces by prepending the namespace: "nesting1": "1 $t(common:nesting2)",

Passing options to nestings

You can pass entire data models in options.

keys

{
    "girlsAndBoys": "They have $t(girls, {\"count\": {{girls}} }) and $t(boys, {\"count\": {{boys}} })",
    "boys": "{{count}} boy",
    "boys_other": "{{count}} boys",
    "girls": "{{count}} girl",
    "girls_other": "{{count}} girls",
}

sample

circle-info

Make sure the options string is valid JSON and can be parsed using JSON.parse

'sampleKey': 'test $t(nest2, { "changedVarName": "{{var}}" })'

Passing nesting to interpolated

keys

sample

circle-info

If you're using >= v21.0.0 you need to set skipOnVariables to false:

Additional options

Prefix/Suffix for nesting and other options can be overridden in init interpolation options or by passing additional options to t function:

sample

option
default
description

nestingPrefixEscaped

undefined

escaped prefix for nesting (regexSafe)

nestingSuffixEscaped

undefined

escaped suffix for nesting (regexSafe)

While there are a lot of options going with the defaults should get you covered.

Security note: interpolated values inside a nesting-options block

When you combine the nested-options syntax with interpolation and have disabled the default escapeValue: true, user-controlled input in those interpolated values can break out of the JSON options literal and inject additional options.

Example of the risky pattern:

If userInput is 1", "lng": "xx, the substituted options string becomes { "count": "1", "lng": "xx" } โ€” the injected lng redirects the nested lookup to a locale the attacker chose. In combination with a translation that contains raw HTML this can escalate to DOM XSS when the output is rendered into the page.

i18next 26.0.6+ logs a runtime warning when this configuration is detected (at warn level, via the library's configured logger) so you can spot it during development.

Mitigation โ€” any one of the following is sufficient:

  1. Keep the default interpolation.escapeValue: true. HTML-escaping neutralises the " before JSON.parse, so the attack cannot succeed. If you need raw HTML output in a specific call, use the explicit {{- var }} unescape syntax for values you have already sanitised.

  2. Sanitise every user-controlled string before passing it as a t() option โ€” at minimum strip or escape " and \.

  3. Avoid the $t(key, { ... "{{var}}" ... }) pattern when the variable can be influenced by untrusted input. Pass the nested call's options directly from the caller's language instead of through the translation template.

The risky pattern only fires when all of these are true: (a) escapeValue: false, (b) a translation uses interpolation inside a $t() options JSON block, and (c) the interpolation variable carries attacker-controlled data. Applications that rely on the default escapeValue: true are not affected.

Last updated