i18next Supported Locale Codes: There Is No Fixed List

If you came here looking for a canonical i18next supported locale codes list — a table of every language i18next "knows about" — there's something you should know first: it doesn't exist, and it isn't supposed to. i18next is deliberately locale-agnostic. It doesn't ship a whitelist of valid languages, doesn't validate your codes against a registry, and won't reject en-US, zh-Hant, or a made-up xx-YY unless you tell it to. This guide explains what "supported locales" really means in i18next, how the supportedLngs option works, and which locale code format you should use so translations resolve correctly.

TL;DR: what "supported locales" means in i18next

  • i18next has no built-in list of supported locale codes. It accepts any string you use as a language key.
  • You define your supported locales with the supportedLngs init option (an array like ['en', 'de', 'fr']).
  • Default is supportedLngs: false, meaning no restriction — every code is accepted.
  • Use BCP 47 / [Unicode] tags such as en, en-US, pt-BR, zh-CN (hyphens, not underscores).
  • The set of "supported" codes is whatever you configure plus the resources you load — nothing more, nothing less.

Why there is no official i18next locale list

Many i18n tools tie you to a predefined catalog of locales. i18next takes the opposite approach. It treats a "language" as just a key into your resource tree:

const resources = {   en: { translation: { key: 'value' } },   'en-US': { translation: { key: 'value' } },   de: { translation: { key: 'value' } }, };

Whatever keys you put at the top level are your languages. There is no registry inside i18next enforcing that en is real and klingon isn't. This is by design: it lets teams support regional variants, pseudo-locales for testing, RTL languages, or entirely custom codes without patching the library.

So the honest answer to "what locale codes does i18next support?" is: all of them, and none of them by default. Support is something you declare, not something you look up.

The supportedLngs option (formerly whitelist)

The closest thing to a "supported locales list" in i18next is the supportedLngs configuration option. This is where you restrict i18next to a known set of languages.

import i18n from 'i18next';  i18n.init({   supportedLngs: ['en', 'de', 'fr'],   fallbackLng: 'en', });

According to the i18next configuration docs, setting an array here stops i18next from resolving or requesting languages outside it — useful when you use a language detector and don't want a browser reporting es-419 to trigger a request for a file you never created.

Key facts about supportedLngs:

  1. Default value is false — no restriction, any code passes.
  2. It accepts an array of strings, e.g. ['en', 'en-US', 'de'].
  3. When set and paired with a backend such as i18next-http-backend, it prevents wasted network requests for unlisted languages.
  4. i18next internally exposes services.languageUtils.isSupportedCode(code) to test membership (this was renamed from isWhitelisted).

It used to be called whitelist

If you're reading an older tutorial that mentions whitelist, that's the same feature under its old name. The rename happened in the v20 → v21 era: whitelist became supportedLngs, and nonExplicitWhitelist became nonExplicitSupportedLngs, as recorded in the i18next changelog and migration guide. The change first shipped with backwards-compatible deprecation warnings, and the legacy whitelist names were later removed entirely. On any modern version, use supportedLngs.

As of 2026-07-14, the current major release line is i18next v26 (e.g. 26.3.4 on npm). Verify the latest against npmjs.com/package/i18next.

What locale code format should you use?

i18next follows the standard BCP 47 language-tag convention (the same UTS/Unicode locale identifiers used across the web). The docs are explicit on one point: use the en-US form with a hyphen, not underscores like en_US.

A tag is generally built as language, optionally language-REGION, and optionally with a script subtag:

PatternExampleMeaning
languageen, de, jaLanguage only
language-REGIONen-US, pt-BR, fr-CALanguage + country/region
language-Scriptzh-Hant, sr-CyrlLanguage + writing system
language-Script-REGIONzh-Hant-TWFully qualified

Because i18next doesn't validate against a registry, a typo like en-us or en_US won't throw — it will simply be treated as a distinct language key, and lookups can silently miss. Sticking to canonical BCP 47 casing (language lowercase, Script title case, REGION uppercase) keeps detection, fallback, and plural resolution predictable.

How i18next resolves a locale: load and fallbacks

Even though there's no master list, i18next has clear rules for turning one requested code into the sequence of codes it will actually look up. The load option controls this. Given a set language of en-US:

  • load: 'all'['en-US', 'en', 'dev']
  • load: 'currentOnly''en-US' only
  • load: 'languageOnly''en' only

Here dev is the default value of fallbackLng. You can inspect the resolved chain at runtime:

  • i18next.languages — the ordered array of codes used for lookup (specific → less specific → fallbacks).
  • i18next.language — the current detected or set language.
  • i18next.resolvedLanguage — the primary language actually in effect, ideal for a language switcher.

Regional variants and nonExplicitSupportedLngs

Suppose your supportedLngs contains only ['en', 'de'], but a user's browser reports de-AT. By default that variant isn't "supported." Set nonExplicitSupportedLngs: true and i18next will treat de-AT as valid because its base language de is in the list. Per the docs, note that combining this with an HTTP backend can produce failed requests for variant files that don't exist — so pair it with a sensible load strategy.

Detecting the user's locale

If you want i18next to pick a language automatically rather than hard-coding lng, add the i18next-browser-languageDetector plugin. It looks up the language, in configurable order, from sources such as:

  • URL query string (?lng=de)
  • Cookie / localStorage / sessionStorage
  • navigator (browser languages)
  • The <html lang> attribute
  • URL path or subdomain

The detector returns whatever code the environment provides — again, it does not restrict to a fixed list. That's exactly why supportedLngs matters: it's your guardrail against loading files for a locale you never authored. A common, robust setup looks like this:

import i18n from 'i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import HttpApi from 'i18next-http-backend'; import { initReactI18next } from 'react-i18next';  const supportedLngs = { en: 'English', de: 'Deutsch', ar: 'العربية' };  i18n
  .use(HttpApi)   .use(LanguageDetector)   .use(initReactI18next)   .init({     fallbackLng: 'en',     supportedLngs: Object.keys(supportedLngs), // ['en','de','ar']   });

Building your own "supported locales list"

Since the list lives in your app, the practical pattern is to treat supportedLngs as your single source of truth and derive everything else from it — the language switcher, route generation, and validation:

  1. Declare once: keep a supportedLngs array (or a { code: label } map) in one module.
  2. Feed it to init: pass Object.keys(...) into supportedLngs.
  3. Render a switcher: map the same object to <option> elements and call i18next.changeLanguage(code).
  4. Validate input: use i18next.services.languageUtils.isSupportedCode(code) before trusting a code from a URL or query string.

This keeps the "list" honest: it's whatever you actually ship translations for.

Common misconceptions, cleared up

  • "i18next only supports certain languages." False. It supports any code you use; support is configuration, not a built-in catalog.
  • "There's a getSupportedLngs() that returns all valid locales." There's no global registry to return. i18next.languages reflects the current resolution chain, and isSupportedCode() tests against your supportedLngs.
  • "Plurals only work for listed locales." Plural rules come from the runtime's Intl.PluralRules (used since the v21/v22 line), i.e. the JavaScript engine's own Unicode data — not an i18next locale list.
  • "Underscores are fine." Use hyphens. en-US, not en_US.

Conclusion

The search for an "i18next supported locale codes list" ends with a useful truth: i18next doesn't ship one, because it's locale-agnostic by design. The codes it supports are the codes you use — declared through the supportedLngs option (once called whitelist), formatted as BCP 47 tags like en-US or zh-Hant, and resolved via load, fallbackLng, and optional language detection. So don't hunt for a hidden catalog. Instead, define your own supported set in one place, feed it to supportedLngs, and let i18next handle the resolution. Next step: open your i18next init() config, add or audit your supportedLngs array, and confirm every listed code has matching translation resources.

References