Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time
223 lines (161 sloc) 5.4 KB



Doing graceful fallbacks are a core principle of i18next. This enables you to display the most accurate content possible.

language fallback

locals resolving

Per default locals containing region or script will take a translation from the pure language file if not found.


  "i18n": "Internationalisation"


  "i18n": "Internationalization",
  "i18n_short": "i18n"


// fallback to one language
    lng: 'en-GB'
}, () => {
  i18next.t('i18n'); // -> "Internationalisation"
  i18next.t('i18n_short'); // -> "i18n" (from en.json)

  // force loading en
  i18next.t('i18n', { lng: 'en' } ); // -> "Internationalization"

fallback language

If you can not provide the preferred language for a user you can specify a fallback language.

// fallback to one language
    fallbackLng: 'en'

// fallback ordered
    fallbackLng: ['fr', 'en']

// fallback depending on user language
    fallbackLng: { 
        'de-CH': ['fr', 'it'], 
        'zh-Hant': ['zh-Hans', 'en'],
        'es': ['fr'],
        'default': ['en']

// function that returns an array of fallbacks
// your function may also return a string or object as above
  fallbackLng: (code) => {
    if (!code || code === 'en') return ['en-US'];
    const fallbacks = [code];

    // We maintain en-US and en-AU. Some regions will prefer en-AU.
    if (code.startsWith('en-') && !['en-US', 'en-AU'].includes(code)) {
      if (['en-GB', 'en-NZ', 'en-IR'].includes(code)) fallbacks.push('en-AU');
      else fallbacks.push('en-US');
      return fallbacks;

    // add pure lang
    const langPart = code.split('-')[0];
    if (langPart !== code) fallbacks.push(langPart);

    // finally, developer language
    return fallbacks;

The default is set to dev which means developer language. At first this might look strange to set the default to a language but this enables to set the saveMissing feature to send new keys to that developer specific language. From there your translators can modify the texts to a translation file containing eg. proper english including defined terminology. For production just set fallbackLng to an existing language.

namespace fallback

i18next per default loads its translations from one file named translation. But you can set and structure it to load from multiple files, we call this files namespaces.

Additional to defining multiple namespaces to load you also can set fallback namespaces. So if a key to translate gets not found in the namespace it looks it up in the fallbacks.


  "title": "i18next"


  "button": {
    "save": "save"


    // files to load
    ns: ['app', 'common'],

    // default namespace (needs no prefix on calling t)
    defaultNS: 'app',

    // fallback, can be a string or an array of namespaces
    fallbackNS: 'common'
}, () => {
    i18next.t('title') // -> "i18next"

    i18next.t('') // -> "save" (fallback from common)

    // without fallbackNS you would have to prefix namespace 
    // to access keys in that namespace
    i18next.t('') // -> "save"

key fallback

key not found

If a key does not return a value the key acts as fallback:

i18next.t('notExistingKey'); // -> "notExistingKey"

So you could configure i18next to have the key being the fallback instead of loading a fallback language:


  "No one says a key can not be the fallback.": "Niemand sagt ein key kann nicht als Ersatz dienen."
  lng: 'de',

  // allow keys to be phrases having `:`, `.`
  nsSeparator: false,
  keySeparator: false,

  // do not load a fallback
  fallbackLng: false

i18next.t('No one says a key can not be the fallback.')
// -> "Niemand sagt ein key kann nicht als Ersatz dienen."

i18next.t('This will be shown if the current loaded translations do not have this.');
// -> "This will be shown if the current loaded translations do not have this."

While this works and might reduce files to load it makes the management of translations a lot harder as you will need to update changes to fallback values in code and json files.

Possible - but not recommended.

Missing values for existing keys

In addition to the above, if you want missing values to fallback to the key in cases where the keys (eg. got extracted by a code parser) exist in your JSON translation file with empty string as value, you also need this setting:

// allow an empty value to count as invalid (by default is true)
  returnEmptyString: false

calling with fallback keys

Calling the t function with an array of keys enables you to translate dynamic keys providing a non specific fallback value.

As a sample think of an error code you get and you like to show a specific warning in some cases:


  "error": {
    "unspecific": "Something went wrong.",
    "404": "The page was not found."


// const error = '404';
i18next.t([`error.${error}`, 'error.unspecific']) // -> "The page was not found"

// const error = '502';
i18next.t([`error.${error}`, 'error.unspecific']) // -> "Something went wrong"