i18next Internationalization Framework
i18next is a comprehensive and highly popular internationalization (i18n) framework designed for JavaScript environments, supporting browsers, Node.js, and Deno. It provides a robust core for handling translations, enabling features like flexible backend connections for loading translations (e.g., via XHR), optional caching, automatic user language detection, proper pluralization rules, translation context management, variable interpolation, and nested translations. The current stable version is 26.0.6, with a regular release cadence addressing bug fixes, type improvements, and occasional minor features, alongside major releases introducing breaking changes and significant enhancements. Its key differentiators include its extensibility through a rich plugin ecosystem and its framework-agnostic nature, allowing integration with React, Angular, Vue, and vanilla JavaScript applications. It focuses on providing a powerful core while allowing developers to choose their preferred building blocks.
Common errors
-
`i18next.initImmediate is not a function` or `TypeError: Cannot read properties of undefined (reading 'initImmediate')`
cause Attempting to use the `initImmediate` option which was removed in i18next v26.0.0.fixUpdate your i18next configuration to use `initAsync: true` instead of `initImmediate: true`. -
Translation does not update after `cloneInstance().changeLanguage()` when the language is not yet fully loaded.
cause A race condition where `init()`'s deferred `load()` could overwrite `isLanguageChangingTo`, causing `setLngProps` to be skipped.fixUpgrade i18next to version 26.0.5 or newer, which contains a fix for this specific race condition. Ensure you are awaiting the `changeLanguage` call if immediate updates are required. -
Type error: 'string' is not assignable to type 'number' for inline formatting options like `{{price, currency(EUR)}}`.cause TypeScript was incorrectly inferring the type for inline formatted variables as `string` instead of their base type (e.g., `number` for `currency`).fixUpgrade i18next to version 26.0.4 or newer. This version correctly resolves inline formatting options to their base format types. -
Formatter crashes when `alwaysFormat` is `true` and no format specifier is present, or returns `NaN` for `undefined`/`null` values.
cause Bugs in the Formatter logic in earlier v26 releases when handling missing format specifiers or `undefined`/`null` input values.fixUpgrade i18next to version 26.0.1 or newer. These issues were resolved, with the Formatter now returning `undefined`/`null` as-is and handling missing format specifiers gracefully.
Warnings
- breaking The deprecated `initImmediate` option has been removed. It was previously mapped to `initAsync` (introduced in v24) for backward compatibility. Direct usage of `initAsync` is now required.
- breaking The legacy monolithic `interpolation.format` function has been removed. i18next now exclusively relies on the built-in Formatter or a custom Formatter module registered via `.use()` for value formatting.
- breaking A security vulnerability (GHSA-qjwx-ccf3-6w6j) was identified where combining `escapeValue: false` with interpolated variables inside `$t(key, { ... "{{var}}" ... })` nesting-options can lead to arbitrary code injection. An attacker-controlled string containing `"` could break out of the JSON literal.
- gotcha Using `escapeValue: false` can introduce XSS vulnerabilities if interpolated values are not properly sanitized. This is particularly relevant in frameworks that do not automatically escape content (e.g., vanilla JS rendering, but less so for React which escapes by default).
Install
-
npm install i18next -
yarn add i18next -
pnpm add i18next
Imports
- i18next
const i18next = require('i18next');import i18next from 'i18next';
- init
import { init } from 'i18next';import i18next from 'i18next'; i18next.init(...);
- TFunction
import { TFunction } from 'i18next';import type { TFunction } from 'i18next';
Quickstart
import i18next from 'i18next';
const initI18n = async () => {
await i18next.init({
debug: true,
lng: 'en',
fallbackLng: 'en',
resources: {
en: {
translation: {
'welcome': 'Welcome to our site, {{name}}!',
'plural_key_one': '{{count}} item',
'plural_key_other': '{{count}} items',
'greeting_context_male': 'Hello Sir',
'greeting_context_female': 'Hello Madam',
'formatted_date': 'Today is {{date, DATE_HUGE}}'
}
},
de: {
translation: {
'welcome': 'Willkommen auf unserer Seite, {{name}}!',
'plural_key_one': '{{count}} Artikel',
'plural_key_other': '{{count}} Artikel',
'greeting_context_male': 'Hallo Herr',
'greeting_context_female': 'Hallo Frau',
'formatted_date': 'Heute ist der {{date, DATE_HUGE}}'
}
}
},
interpolation: {
escapeValue: false // not needed for react.js, xss is prevented by react
}
});
console.log(i18next.t('welcome', { name: 'User' }));
console.log(i18next.t('plural_key', { count: 1 }));
console.log(i18next.t('plural_key', { count: 5 }));
console.log(i18next.t('greeting', { context: 'male' }));
console.log(i18next.t('greeting', { context: 'female' }));
// Example of using a formatter (requires a formatter plugin or custom setup)
// i18next.services.formatter.add('DATE_HUGE', (value, lng, options) => {
// return new Intl.DateTimeFormat(lng, { year: 'numeric', month: 'long', day: 'numeric' }).format(value);
// });
// console.log(i18next.t('formatted_date', { date: new Date() }));
await i18next.changeLanguage('de');
console.log(i18next.t('welcome', { name: 'Nutzer' }));
};
initI18n();