# I18Next > There are a few options to load translations to your application instrumented by i18next. The most common approach to this adding a so called [**backend plugin**](https://www.i18next.com/overview/plug --- # Source: https://www.i18next.com/how-to/add-or-load-translations.md # Add or Load Translations There are a few options to load translations to your application instrumented by i18next. The most common approach to this adding a so called [**backend plugin**](https://www.i18next.com/overview/plugins-and-utils#backends) to i18next. The range of backends is large from loading translations in the browser using [xhr/fetch](https://github.com/i18next/i18next-http-backend) request to loading translations from databases or [filesystem](https://github.com/i18next/i18next-fs-backend) in [Node.js](https://nodejs.org/). ## Add on init You can add the translations on init ```javascript import i18next from 'i18next'; i18next .init({ resources: { en: { namespace1: { key: 'hello from namespace 1' }, namespace2: { key: 'hello from namespace 2' } }, de: { namespace1: { key: 'hallo von namespace 1' }, namespace2: { key: 'hallo von namespace 2' } } } }); ``` ## Add after init You can add the translations after init ```javascript import i18next from 'i18next'; i18next.init({ resources: {} }); i18next.addResourceBundle('en', 'namespace1', { key: 'hello from namespace 1' }); ``` There are more options to adding, removing translations...learn more about [resource handling](https://www.i18next.com/overview/api). {% hint style="info" %} Please make sure to at least pass in an empty resources object on init. Else i18next will try to load translations and give you a warning that you are not using a backend. {% endhint %} ### Combined with a backend plugin If you want to lazy load some translations via a backend plugin, you may need to use the `partialBundledLanguages: true` option. This allows some resources (or no resources) to be set on initialization while others can be loaded using a backend connector. You may also want to set the `ns` option. To an empty array if you do not want to load any namespaces (also not the [default namespace](https://www.i18next.com/overview/configuration-options#languages-namespaces-resources): `'translation'`) or to an array containing the namespaces to load. ```javascript import i18next from 'i18next'; i18next.init({ partialBundledLanguages: true, ns: [], resources: {} }); i18next.addResourceBundle('en', 'namespace1', { key: 'hello from namespace 1' }); // or via backend // i18next.loadNamespaces(['myNamespace1', 'myNamespace2']) // i18next.loadLanguages(['de', 'fr']) // etc. ``` ## Lazy load in memory translations [i18next-resources-to-backend](https://github.com/i18next/i18next-resources-to-backend) helps to transform resources to an i18next backend. This means, you can also lazy load translations, for example when using webpack: ```javascript import i18next from 'i18next'; import resourcesToBackend from 'i18next-resources-to-backend'; i18next .use(resourcesToBackend((language, namespace) => import(`./locales/${language}/${namespace}.json`))) .init({ /* other options */ }) ``` ## Load using a backend plugin Each [plugin](https://www.i18next.com/principles/plugins) comes with a set of configuration settings like path to load resources from. Those settings are documented on the individual readme file of each repository. Here is a sample using the [i18next-http-backend](https://github.com/i18next/i18next-http-backend) to load resources from the server. ```javascript import i18next from 'i18next'; import Backend from 'i18next-http-backend'; i18next .use(Backend) .init({ backend: { // for all available options read the backend's repository readme file loadPath: '/locales/{{lng}}/{{ns}}.json' } }); ``` {% hint style="danger" %} Having a combination of [defining resources](#add-on-init) + [having a backend](#load-using-a-backend-plugin) will not implicitly take one or the other source as fallback resources.\ If you need some fallback behaviour you may use the [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend). A short example can be found [here](https://github.com/i18next/i18next-http-backend/blob/master/example/fallback/app.js).\ With [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend) you can also create some [caching behaviour](https://www.i18next.com/how-to/caching). {% endhint %} {% hint style="info" %} [What's a plugin?](https://www.i18next.com/principles/plugins) {% endhint %} {% hint style="info" %} 🎓 Check out this topic in the [i18next crash course video](https://youtu.be/SA_9i4TtxLQ?t=953). {% endhint %} ## Load using a [smart backend plugin](https://github.com/locize/i18next-locize-backend) serving directly from a [CDN](https://docs.locize.com/whats-inside/cdn-content-delivery-network) Just use the [i18next-locize-backend](https://github.com/locize/i18next-locize-backend) to load resources from the [CDN](https://docs.locize.com/whats-inside/cdn-content-delivery-network). ```javascript import i18next from 'i18next'; import Backend from 'i18next-locize-backend'; i18next .use(Backend) .init({ backend: { projectId: '[PROJECT_ID]', apiKey: '[API_KEY]', referenceLng: '[LNG]' } }); ``` [Here](https://github.com/locize/react-tutorial) you can find a step by step guide with a React.js app, which will unleash the full power of i18next in combination with locize.\ See how your developer experience with this localization workflow [could look like](https://youtu.be/osScyaGMVqo).\ There's also the possibility to have an [even more focused developer experience](https://youtu.be/VfxBpSXarlU), with the help of the [autoutomatic translation workflow](https://www.locize.com/docs/automatic-translation) and the use of the save missing keys functionality, new keys not only gets added to locize automatically, while developing the app, but are also [automatically translated](https://youtu.be/VfxBpSXarlU) into the target languages using machine translation (like [Google Translate](https://cloud.google.com/translate)). {% embed url="" %} {% embed url="" %} {% hint style="success" %} Check out [this blog post](https://www.locize.com/blog/i18next-locize-ai-human) to learn more about how you can use generative AI together with i18next. [](https://www.locize.com/blog/i18next-locize-ai-human) {% endhint %} #### [**locize**](https://locize.com) is the perfect translation management tool for your [**i18next**](https://www.i18next.com) project #### ➡️ [i18next](https://www.i18next.com/) + [locize](https://locize.com/) = [true continuous localization](https://locize.com/how-it-works.html#continouslocalization) --- # Source: https://www.i18next.com/overview/api.md # API ### init `i18next.init(options, callback) // -> returns a Promise` The default export of the i18next module is an i18next instance ready to be initialized by calling `init`. You can create additional instances using the [createInstance](#createinstance) function. Please read the [options page](https://www.i18next.com/overview/configuration-options) for details on configuration options. The callback will be called after all translations were loaded or with an error when failed (in case of using a backend). **So you should wait for init to complete (wait for the callback or promise resolution) before using the `t` function!** {% hint style="info" %} In case of [react-i18next](https://react.i18next.com/) make sure useSuspense is enabled or handle the ready state in [HOCs](https://react.i18next.com/latest/withtranslation-hoc#not-using-suspense) or [hooks](https://react.i18next.com/latest/usetranslation-hook#not-using-suspense) yourself. {% endhint %} {% hint style="danger" %} Do not call init multiple times.\ To change language use [changeLanguage](#changelanguage). If you need complete different configs use [createInstance](#createinstance) or [cloneInstance](#cloneinstance). {% endhint %} {% hint style="warning" %} An error can occur if for example there was a loading issue when using a [backend](https://www.i18next.com/plugins-and-utils#backends) plugin. {% endhint %} {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.init({ fallbackLng: 'en', ns: ['file1', 'file2'], defaultNS: 'file1', debug: true }, (err, t) => { if (err) return console.log('something went wrong loading', err); t('key'); // -> same as i18next.t }); // with only callback i18next.init((err, t) => { if (err) return console.log('something went wrong loading', err); t('key'); // -> same as i18next.t }); // using Promises i18next .init({ /* options */ }) .then(function(t) { t('key'); }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.init({ fallbackLng: 'en', ns: ['file1', 'file2'], defaultNS: 'file1', debug: true }, (err, t) => { if (err) return console.log('something went wrong loading', err); t($ => $.key); // -> same as i18next.t }); // with only callback i18next.init((err, t) => { if (err) return console.log('something went wrong loading', err); t($ => $.key); // -> same as i18next.t }); // using Promises i18next .init({ /* options */ }) .then(function(t) { t($ => $.key); }); ``` {% endtab %} {% endtabs %} ### use `i18next.use(module)` The use function is there to load additional plugins to i18next. For available module see the [plugins page](https://www.i18next.com/overview/plugins-and-utils) and don't forget to read the documentation of the plugin. ```javascript import i18next from 'i18next'; import Backend from 'i18next-http-backend'; import Cache from 'i18next-localstorage-cache'; import postProcessor from 'i18next-sprintf-postprocessor'; import LanguageDetector from 'i18next-browser-languagedetector'; i18next .use(Backend) .use(Cache) .use(LanguageDetector) .use(postProcessor) .init(options, callback); ``` ### t `i18next.t(keys, options)` Please have a look at the translation functions like [interpolation](https://www.i18next.com/translation-function/interpolation), [formatting](https://www.i18next.com/translation-function/formatting) and [plurals](https://www.i18next.com/translation-function/plurals) for more details on using it. {% tabs %} {% tab title="JavaScript" %} You can specify either one key as a `String` or multiple keys as an `Array` of `String`. The first one that resolves will be returned. ```javascript i18next.t('my.key'); // -> will return value in set language i18next.t(['unknown.key', 'my.key']); // -> will return value for 'my.key' in set language ``` {% endtab %} {% tab title="TypeScript" %} You can select the key you want using a selector function (`$ => $.my.key`). Keys will auto-complete automatically. If you want to set a default value, use the `defaultValue` option: ```typescript i18next.t($ => $.my.key); // -> will return value in set language i18next.t($ => $.unknown.key, { defaultValue: t($ => $.my.key) }); // -> will return value for 'my.key' in set language ``` {% endtab %} {% endtabs %} ### exists `i18next.exists(key, options)` Uses the same resolve functionality as the `t` function and returns true if a key exists. ```javascript i18next.exists('my.key'); // -> true if exists, false if not ``` ### getFixedT `i18next.getFixedT(lng, ns, keyPrefix)` Returns a `t` function that defaults to given language or namespace. All arguments can be optional/null. `lng` and `ns` params could be arrays of languages or namespaces and will be treated as fallbacks in that case. The optional `keyPrefix` will be automatically applied to the returned t function. i.e. {% tabs %} {% tab title="JavaScript" %} ```javascript const t = i18next.getFixedT(null, null, 'user.accountSettings.changePassword') const title = t('title'); // same as i18next.t('user.accountSettings.changePassword.title'); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript const t = i18next.getFixedT(null, null, 'user.accountSettings.changePassword') const title = t($ => $.title); // same as i18next.t($ => $.user.accountSettings.changePassword.title); ``` {% endtab %} {% endtabs %} {% hint style="warning" %} If you want to use keys with a prefixed namespace and the `keyPrefix` argument was provided, you'll need to override it in the `t` function options. See below for an example. {% endhint %} {% tabs %} {% tab title="JavaScript" %} ```javascript const t = i18next.getFixedT(null, null, 'user.accountSettings.changePassword') const title = t('ns:title'); // this will not work const title = t('ns:title', { keyPrefix: '' }); // this will work ``` {% endtab %} {% tab title="TypeScript" %} ```typescript const t = i18next.getFixedT(null, null, 'user.accountSettings.changePassword') const title = t($ => $.title, { ns: 'ns' }); // this won't work const title = t($ => $.title, { ns: 'ns', keyPrefix: '' }); // this will work ``` {% endtab %} {% endtabs %} On the returned function you can like in the `t` function override the languages or namespaces by passing them in options or by prepending namespace. {% tabs %} {% tab title="JavaScript" %} ```javascript // fix language to german const de = i18next.getFixedT('de'); de('myKey'); // or fix the namespace to anotherNamespace const anotherNamespace = i18next.getFixedT(null, 'anotherNamespace'); anotherNamespace('anotherNamespaceKey'); // no need to prefix ns i18n.t('anotherNamespace:anotherNamespaceKey'); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // fix language to german const de = i18next.getFixedT('de'); de($ => $.myKey); // or fix the namespace to anotherNamespace const anotherNamespace = i18next.getFixedT(null, 'anotherNamespace'); anotherNamespace($ => $.anotherNamespaceKey); // no need to prefix ns i18n.t($ => $.anotherNamespace.anotherNamespaceKey); ``` {% endtab %} {% endtabs %} ### changeLanguage `i18next.changeLanguage(lng, callback) // -> returns a Promise` Changes the language. The callback will be called as soon translations were loaded or an error occurs while loading. Calling `changeLanguage` without `lng` uses the [language detector](https://www.i18next.com/misc/creating-own-plugins#languagedetector) to choose the language to set. **HINT:** For easy testing—setting `lng` to 'cimode' will cause the `t` function to always return the key. {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.changeLanguage('en', (err, t) => { if (err) return console.log('something went wrong loading', err); t('key'); // -> same as i18next.t }); // using Promises i18next .changeLanguage('en') .then((t) => { t('key'); // -> same as i18next.t }); // manually re-detecting language i18next.changeLanguage().then(...) ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.changeLanguage('en', (err, t) => { if (err) return console.log('something went wrong loading', err); t($ => $.key); // -> same as i18next.t }); // using Promises i18next .changeLanguage('en') .then((t) => { t($ => $.key); // -> same as i18next.t }); // manually re-detecting language i18next.changeLanguage().then(...) ``` {% endtab %} {% endtabs %} ### language `i18next.language` Is set to the current detected or set language. If you need the primary used language depending on your configuration (supportedLngs, load) you will prefer using [`i18next.resolvedLanguage`](#resolvedlanguage) or [`i18next.languages[0]`](#languages). ### languages `i18next.languages` Is set to an array of language codes that will be used to look up the translation value. When the language is set, this array is populated with the new language codes. Unless overridden, this array is populated with less-specific versions of that code for fallback purposes, followed by the list of fallback languages. {% hint style="info" %} Values are unique, so if they appear earlier in the array, they will not be added again. {% endhint %} ```javascript // initialize with fallback languages i18next.init({ fallbackLng: ["es", "fr", "en-US", "dev"] }); // change the language i18next.changeLanguage("en-US-xx"); // new language and its more generic forms, followed by fallbacks i18next.languages; // ["en-US-xx", "en-US", "en", "es", "fr", "dev"] // change the language again i18next.changeLanguage("de-DE"); // previous language is not retained i18next.languages; // ["de-DE", "de", "es", "fr", "en-US", "dev"] ``` ### resolvedLanguage `i18next.resolvedLanguage` Is set to the current resolved language.\ It can be used as primary used language, for example in a language switcher. *(introduced in v21.0.0)* ### hasLoadedNamespace `i18next.hasLoadedNamespace(ns, options) // -> returns true or false` Checks if namespace has loaded yet. i.e. used by [react-i18next](https://react.i18next.com/) ### loadNamespaces `i18next.loadNamespaces(ns, callback) // -> returns a Promise` Loads additional namespaces not defined in init options. ```javascript i18next.loadNamespaces('myNamespace', (err) => { /* resources have been loaded */ }); i18next.loadNamespaces(['myNamespace1', 'myNamespace2'], (err) => { /* resources have been loaded */ }); // using Promises i18next .loadNamespaces(['myNamespace1', 'myNamespace2']) .then(() => {}); ``` ### loadLanguages `i18next.loadLanguages(lngs, callback) // -> returns a Promise` Loads additional languages not defined in init options (preload). ```javascript i18next.loadLanguages('de', (err) => { /* resources have been loaded */ }); i18next.loadLanguages(['de', 'fr'], (err) => { /* resources have been loaded */ }); // using Promises i18next .loadLanguages(['de', 'fr']) .then(() => {}); ``` ### reloadResources `i18next.reloadResources() // -> returns a Promise` Reloads resources on given state. Optionally you can pass an array of languages and namespaces as params if you don't want to reload all. ```javascript // reload all i18next.reloadResources(); // reload languages i18next.reloadResources(['de', 'fr']); // reload namespaces for all languages i18next.reloadResources(null, ['ns1', 'ns2']); // reload namespaces in languages i18next.reloadResources(['de', 'fr'], ['ns1', 'ns2']); // reload a namespace in a language i18next.reloadResources('de', 'ns1'); // optional third param callback i18next@>=11.9.0 i18next.reloadResources('de', 'ns1', () => { /* reloaded */ }); // using Promises i18next .reloadResources() .then(() => {}); ``` ### setDefaultNamespace `i18next.setDefaultNamespace(ns)` Changes the default namespace. ### dir `i18next.dir(lng)` Returns `rtl` or `ltr` depending on languages read direction. ```javascript // for current language i18next.dir(); // for another language i18next.dir('en-US'); // -> "ltr"; i18next.dir('ar'); // -> "rtl"; ``` ### format `i18next.format(data, format, lng)` *introduced in v8.4.0 and legacy since v21.3.0* Exposes `interpolation.format`t function added on init. For formatting used in translation files checkout the [formatting doc](https://www.i18next.com/translation-function/formatting#legacy-format-function-i18next-less-than-21.3.0). {% tabs %} {% tab title="JavaScript" %} ```javascript // key = 'hello {{what}}' i18next.t('key', { what: i18next.format('world', 'uppercase') }); // -> hello WORLD ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // key = 'hello {{what}}' i18next.t($ => $.key, { what: i18next.format('world', 'uppercase') }); // -> hello WORLD ``` {% endtab %} {% endtabs %} ## instance creation ### createInstance `i18next.createInstance(options, callback)` Will return a new i18next instance. Please read the [options page](https://www.i18next.com/overview/configuration-options) for details on configuration options. Providing a callback will automatically call init. The callback will be called after all translations were loaded or with an error when failed (in case of using a backend). {% tabs %} {% tab title="JavaScript" %} ```javascript const newInstance = i18next.createInstance({ fallbackLng: 'en', ns: ['file1', 'file2'], defaultNS: 'file1', debug: true }, (err, t) => { if (err) return console.log('something went wrong loading', err); t('key'); // -> same as i18next.t }); // is the same as const newInstance = i18next.createInstance(); newInstance.init({ fallbackLng: 'en', ns: ['file1', 'file2'], defaultNS: 'file1', debug: true }, (err, t) => { if (err) return console.log('something went wrong loading', err); t('key'); // -> same as i18next.t }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript const newInstance = i18next.createInstance({ fallbackLng: 'en', ns: ['file1', 'file2'], defaultNS: 'file1', debug: true }, (err, t) => { if (err) return console.log('something went wrong loading', err); t($ => $.key); // -> same as i18next.t }); // is the same as const newInstance = i18next.createInstance(); newInstance.init({ fallbackLng: 'en', ns: ['file1', 'file2'], defaultNS: 'file1', debug: true }, (err, t) => { if (err) return console.log('something went wrong loading', err); t($ => $.key); // -> same as i18next.t }); ``` {% endtab %} {% endtabs %} ### cloneInstance `i18next.cloneInstance(options)` Creates a clone of the current instance. Shares store, plugins and initial configuration. Can be used to create an instance sharing storage but being independent on set language or default namespaces. ```javascript const newInstance = i18next.cloneInstance({ fallbackLng: 'en', defaultNS: 'file1' }); ``` #### forkResourceStore By setting the forkResourceStore option to true, it will not shares the store. ```javascript const newInstance = i18next.cloneInstance({ forkResourceStore: true, keySeparator: '[[my-new-separator]]' }); ``` ## events {% hint style="info" %} Every event can be unsubscribed using `i18next.off('name', myFunction);` All attached listeners can be unsubscribed using `i18next.off('name');` {% endhint %} ### onInitialized `i18next.on('initialized', function(options) {})` Gets fired after initialization. ### onLanguageChanged `i18next.on('languageChanged', function(lng) {})` Gets fired when changeLanguage got called. ### onLoaded `i18next.on('loaded', function(loaded) {})` Gets fired on loaded resources. ### onFailedLoading `i18next.on('failedLoading', function(lng, ns, msg) {})` Gets fired if loading resources failed (after the in-built retry algorithm). ### onMissingKey `i18next.on('missingKey', function(lngs, namespace, key, res) {})` Gets fired on accessing a key not existing. Needs [saveMissing](https://www.i18next.com/configuration-options#missing-keys) set to true. ## store events Please be aware the `i18next.store` is only available on i18next after the init call. ### onAdded `i18next.store.on('added', function(lng, ns) {})` Gets fired when resources got added. ### onRemoved `i18next.store.on('removed', function(lng, ns) {})` Gets fired when resources got removed. ## resource handling Can be accessed on `i18next` or `i18next.services.resourceStore`. ### getResource `i18next.getResource(lng, ns, key, options)` Gets one value by given key. options: | option | default | description | | ------------------- | ------- | ---------------------------------------------------------------------- | | keySeparator | "." | char to separate keys, or false if no separator is preferred | | ignoreJSONStructure | true | if a key is not found as nested key, it will try to lookup as flat key | ### addResource `i18next.addResource(lng, ns, key, value, options)` Adds one key/value. options: | option | default | description | | ------------ | ------- | ------------------------------------------------------------ | | keySeparator | "." | char to separate keys, or false if no separator is preferred | | silent | false | if set to true adding will not emit an added event | ### addResources `i18next.addResources(lng, ns, resources)` Adds multiple key/values. ### addResourceBundle `i18next.addResourceBundle(lng, ns, resources, deep, overwrite)` Adds a complete bundle. Setting deep (default false) param to true will extend existing translations in that file. Setting deep and overwrite (default false) to true it will overwrite existing translations in that file. So omitting deep and overwrite will overwrite all existing translations with the one provided in resources. Using deep you can choose to keep existing nested translation and to overwrite those with the new ones. ```javascript i18next.addResourceBundle('en', 'translations', { key: 'value', }, true, true); ``` ### hasResourceBundle `i18next.hasResourceBundle(lng, ns)` Checks if a resource bundle exists. ### getDataByLanguage `i18next.getDataByLanguage(lng)` Returns a resource data by language. ### getResourceBundle `i18next.getResourceBundle(lng, ns)` Returns a resource bundle. ### removeResourceBundle `i18next.removeResourceBundle(lng, ns)` Removes an existing bundle. --- # Source: https://www.i18next.com/how-to/backend-fallback.md # Backend Fallback ## Browser fallback with local / bundled translations With i18next you can configure a fallback backend to be used in the browser. It will try to load from your primary backend (in this case from your [http backend](https://github.com/i18next/i18next-http-backend)) and if the primary backend is not reachable or does not serve translations, your second backend (in this case [local or bundled](https://github.com/i18next/i18next-resources-to-backend) translations) will be used. This is all possible thanks to the [chained backend](https://github.com/i18next/i18next-chained-backend). ```javascript import i18next from "i18next"; import ChainedBackend from "i18next-chained-backend"; import HttpBackend from "i18next-http-backend"; import resourcesToBackend from "i18next-resources-to-backend"; const bundledResources = { en: { translation: { key: 'value' } } }; i18next .use(ChainedBackend) .init({ fallbackLng: "en", // ... your i18next config backend: { backends: [ HttpBackend, resourcesToBackend(bundledResources) ], backendOptions: [{ loadPath: '/locales/{{lng}}/{{ns}}.json' }] } }); ``` ### You can also lazy load the in memory translations, i.e. when using webpack ```javascript import i18next from "i18next"; import ChainedBackend from "i18next-chained-backend"; import HttpBackend from "i18next-http-backend"; import resourcesToBackend from "i18next-resources-to-backend"; i18next .use(ChainedBackend) .init({ fallbackLng: "en", // ... your i18next config backend: { backends: [ HttpBackend, resourcesToBackend((lng, ns) => import(`./locales/${lng}/${ns}.json`)) ], backendOptions: [{ loadPath: '/locales/{{lng}}/{{ns}}.json' }] } }); ``` {% hint style="info" %} More information can be found here:\ [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend)\ [i18next-resources-to-backend](https://github.com/i18next/i18next-resources-to-backend)\ [i18next-http-backend](https://github.com/i18next/i18next-http-backend) {% endhint %} ## Server side fallback with filesystem On server side you can also use the i18next-fs-backend for example instead of the in memory fallback. ```javascript import i18next from "i18next"; import ChainedBackend from "i18next-chained-backend"; import HttpBackend from "i18next-http-backend"; import FsBackend from "i18next-fs-backend"; i18next .use(ChainedBackend) .init({ fallbackLng: "en", // ... your i18next config backend: { backends: [ HttpBackend, FsBackend ], backendOptions: [{ loadPath: '/locales/{{lng}}/{{ns}}.json' }, { loadPath: './locales_cache/{{lng}}/{{ns}}.json' }] } }); ``` {% hint style="info" %} More information can be found here:\ [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend)\ [i18next-fs-backend](https://github.com/i18next/i18next-fs-backend)\ [i18next-http-backend](https://github.com/i18next/i18next-http-backend) {% endhint %} {% hint style="danger" %} We suggest not to use multiple backends with the [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend) in combination with saveMissing or updateMissing, because it may happen, that the trigger for this is based on stale data. {% endhint %} --- # Source: https://www.i18next.com/principles/best-practices.md # Best Practices > This content is available to you thanks to the contribution of following people: > > * [Jenny Reid](https://github.com/jennylreid) ### Implications of interpolation for localization When translating into other languages, interpolation causes real problems. Fundamentally, what interpolation does is concatenate pieces of text. English sentences split into sentence fragments and programmatically constructed at runtime are difficult and sometimes impossible to translate, unless you have implemented multilingual grammar rules, which is rare. Use interpolation sparingly to minimize issues with localization. Interpolation cannot be avoided for values that can only be known at runtime, such as: * Time stamps * User-inputted data {% hint style="info" %} When values are known and available for translation in a resource file, interpolation should be avoided. Use multiple self-contained string values instead. {% endhint %} #### Example Suppose you want to use interpolation to replace the value for `{paymentType}` in the following key ``` { "key": "All fees will be charged to the {{paymentType}} on file for this account." } ``` wherein `{paymentType}` could be 'credit card' or 'PayPal account'. In German the spelling of the word "the" preceding `{paymentType}` must change depending on which value is passed. ``` { "key": "Alle Beträge werden dem {{paymentType}} für dieses Konto in Rechnung gestellt." } ``` The result is some runtime strings will be broken // -> "Alle Beträge werden dem Kreditkarte für dieses Konto in Rechnung gestellt." <- 'dem Kreditkarte' should be 'der Kreditkarte' // -> "Alle Beträge werden dem PayPal-Konto für dieses Konto in Rechnung gestellt." <- 'dem PayPal-Konto' is correct This is just one simple example of a very complex localization problem. Use two separate fully self-contained strings instead: ``` { "key1": "All fees will be charged to the credit card on file for this account." "key2": "All fees will be charged to the PayPal account on file for this account." } ``` --- # Source: https://www.i18next.com/how-to/caching.md # Caching ## Browser caching with local storage With i18next you can configure a cache layer to be used in the browser. It will load and cache resources from [localStorage](https://github.com/i18next/i18next-localstorage-backend) and can be used in combination with the [chained backend](https://github.com/i18next/i18next-chained-backend). ```javascript import i18next from "i18next"; import ChainedBackend from "i18next-chained-backend"; import HttpBackend from "i18next-http-backend"; import LocalStorageBackend from "i18next-localstorage-backend"; i18next .use(ChainedBackend) .init({ fallbackLng: "en", // ... your i18next config backend: { backends: [ LocalStorageBackend, HttpBackend ], backendOptions: [{ expirationTime: 7 * 24 * 60 * 60 * 1000 // 7 days }, { loadPath: '/locales/{{lng}}/{{ns}}.json' }] } }); ``` {% hint style="info" %} More information can be found here:\ [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend)\ [i18next-localstorage-backend](https://github.com/i18next/i18next-localstorage-backend)\ [i18next-http-backend](https://github.com/i18next/i18next-http-backend) {% endhint %} ## Server side caching with filesystem With i18next you can configure a cache layer to be used on server side. It will load and cache resources from the [filesystem](https://github.com/i18next/i18next-fs-backend) and can be used in combination with the [chained backend](https://github.com/i18next/i18next-chained-backend). ```javascript import i18next from "i18next"; import ChainedBackend from "i18next-chained-backend"; import HttpBackend from "i18next-http-backend"; import FsBackend from "i18next-fs-backend"; i18next .use(ChainedBackend) .init({ fallbackLng: "en", // ... your i18next config backend: { backends: [ FsBackend, HttpBackend ], backendOptions: [{ expirationTime: 7 * 24 * 60 * 60 * 1000, // 7 days loadPath: './locales_cache/{{lng}}/{{ns}}.json', addPath: './locales_cache/{{lng}}/{{ns}}.json' // make sure the folders "locales_cache/{{lng}}" exists }, { loadPath: '/locales/{{lng}}/{{ns}}.json' }] } }); ``` {% hint style="info" %} More information can be found here:\ [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend)\ [i18next-fs-backend](https://github.com/i18next/i18next-fs-backend)\ [i18next-http-backend](https://github.com/i18next/i18next-http-backend) {% endhint %} ## React-native caching with AsyncStorage With i18next you can configure a cache layer to be used on react-native. It will load and cache resources from the [AsyncStorage](https://github.com/timbrandin/i18next-async-storage-backend) and can be used in combination with the [chained backend](https://github.com/i18next/i18next-chained-backend). ```javascript import i18next from "i18next"; import ChainedBackend from "i18next-chained-backend"; import HttpBackend from "i18next-http-backend"; import AsyncStorageBackend from "i18next-async-storage-backend"; i18next .use(ChainedBackend) .init({ fallbackLng: "en", // ... your i18next config backend: { backends: [ AsyncStorageBackend, HttpBackend ], backendOptions: [{ expirationTime: 7 * 24 * 60 * 60 * 1000 // 7 days }, { loadPath: '/locales/{{lng}}/{{ns}}.json' }] } }); ``` {% hint style="info" %} More information can be found here:\ [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend)\ [i18next-async-storage-backend](https://github.com/timbrandin/i18next-async-storage-backend)\ [i18next-http-backend](https://github.com/i18next/i18next-http-backend) {% endhint %} ## Server side Next.js caching with filesystem Similar to the normal [server side caching with filesystem](#server-side-caching-with-filesystem), you can use the same approach in a Next.js app in combination with [next-i18next](https://github.com/isaachinman/next-i18next). It will load and cache resources from the [filesystem](https://github.com/i18next/i18next-fs-backend) and can be used in combination with the [chained backend](https://github.com/i18next/i18next-chained-backend). The config file, will probably look similar to this, but for a more complete example have a look [at this example by locize](https://github.com/locize/next-i18next-locize/tree/local-caching#optional-server-side-caching-to-filesystem). ```javascript // next-i18next.config.js const ChainedBackend = require('i18next-chained-backend') const FSBackend = require('i18next-fs-backend/cjs') const HttpBackend = require('i18next-http-backend/cjs') module.exports = { i18n: { defaultLocale: 'en', locales: ['en', 'de'], }, backend: { backends: [ FSBackend, HttpBackend ], backendOptions: [{ // make sure public/locales_cache/en and public/locales_cache/de exists loadPath: './public/locales_cache/{{lng}}/{{ns}}.json', addPath: './public/locales_cache/{{lng}}/{{ns}}.json', expirationTime: 7 * 24 * 60 * 60 * 1000 // 7 days }, { loadPath: '/locales/{{lng}}/{{ns}}.json' }] }, use: [ChainedBackend], ns: ['common', 'footer', 'second-page'], // the namespaces needs to be listed here, to make sure they got preloaded serializeConfig: false, // because of the custom use i18next plugin // debug: true, } ``` {% hint style="info" %} More information can be found here:\ [next-i18next-locize example](https://github.com/locize/next-i18next-locize/tree/local-caching#optional-server-side-caching-to-filesystem)\ [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend)\ [i18next-fs-backend](https://github.com/i18next/i18next-fs-backend)\ [i18next-http-backend](https://github.com/i18next/i18next-http-backend) {% endhint %} {% hint style="danger" %} We suggest not to use multiple backends with the [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend) in combination with saveMissing or updateMissing, because it may happen, that the trigger for this is based on stale data. {% endhint %} --- # Source: https://www.i18next.com/overview/comparison-to-others.md # Comparison to others You now might expect we compare eg. react-i18next to react-intl but that won't happen ;). But we will list why you should trust i18next to be the best choice for internationalization. ## Sustainability i18next was created in late 2011. What does that mean? It's older than most of the libraries you will use nowadays, including your main frontend tech (react, vue, ...). Believe it or not but by the time of writing, the v11.x.x can be dropped in as a replacement for v1 by just adding a minimal compatibility layer. It's important to us not breaking things just for the sake of using new fancy stuff (which does not mean we do not keep up with latest possibilities of development). ## Maturity Based on how long i18next already is available open source, there is no real i18n case that could not be solved with i18next. i18next and its localization service [https://locize.com](https://locize.com/) are used by companies small to very large. ## Extensibility With v2 of i18next we completely rebuild i18next to be as extensible as possible. Doing this i18next can be used in any javascript (and a few non-javascript - .net, elm, iOS, android, ...) environment, with any UI framework, with any i18n format, ... the possibilities are endless. Just have a look at what the community built around the i18next core: * ​[Supported Frameworks​](https://www.i18next.com/overview/supported-frameworks) * ​[Plugins and Utils](https://www.i18next.com/overview/plugins-and-utils)​ ## Richness The regular i18n frameworks work like this: 1. You pass in all translations and the used language 2. You call a function that returns the correct translation based on the translations you passed in and provided values for plural and interpolation. What you don't get by others - but get with i18next * Splitting translations into multiple files. Only load translations needed. * There are plugins to **detect languages** for most environments (browser, native, server). This enables to set priority of where to detect and even enables to cache set languages over requests / visits. * There are endless plugins to **load translation** from server, filesystem, ... these backends also assert that loading gets retried on failure, or that a file does not get loaded twice and callbacks of success are only called once. Those backends can even provide an additional layer for **local caching** eg. in localStorage. * Options what to load and how to fallback depending on language. * Support for [objects and arrays](https://www.i18next.com/translation-function/objects-and-arrays) * Full control over management of the translations stored. * Rich system of events to react on changes important to your application. * Freedom of [i18n formats](https://www.i18next.com/overview/plugins-and-utils#i-18-n-formats) - prefer ICU? Just use i18next-icu plugin. ## But I heard ### i18next is complicated True, i18next's documentation is bigger than that of other i18n frameworks - but that's also a tribute to offering a lot more features that you would have to build yourself otherwise (language detection, translation loading, ...). If you do not need that i18next is as simple as any other i18n framework: {% tabs %} {% tab title="JavaScript" %} ```javascript import i18next from 'i18next';​ i18next.init({ lng: 'de', resources: { de: { translation: { "hello world": "hallo Welt" } } } });​ i18next.t('hello world'); // hallo Welt ``` {% endtab %} {% tab title="TypeScript" %} ```typescript import i18next from 'i18next';​ i18next.init({ lng: 'de', resources: { de: { translation: { "hello world": "hallo Welt" } } } });​ i18next.t($ => $['hello world']); // hallo Welt ``` {% endtab %} {% endtabs %} ### i18next is bloated Hm... ask this in one year again. When your i18n framework needs to catch up with the needs of production systems. We work hard on keeping the code base clean and readable. We add new features which might help a lot of users and not based on we think it's easy to solve. ### i18next is too big Yes, a size of 33kb minified and 9kb gzipped is huge. But like you saw before there is a lot more inside than just the basic i18n functionality. But you could make this smaller by precompiling the translations. We could bring down i18next to 4kb gzipped (good to advertise) but on the other hand your translation files would grow significantly. ## We tell you ### I18next can do more Just two samples of extended functionality you can get: #### a) Ever liked to **dynamically fallback** your error messages to a general info if no specific message is available? translation.json ```javascript { "error": { "unspecific": "Something went wrong.", "404": "The page was not found." } } ``` Sample {% tabs %} {% tab title="JavaScript" %} ```javascript 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" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript const error = '404'; i18next.t($ => $.error[error], { defaultValue: t($ => $.error.unspecific) }) // -> "The page was not found"​ const error = '502'; i18next.t($ => $.error[error], { defaultValue: t($ => $.error.unspecific) }) // -> "Something went wrong" ``` {% endtab %} {% endtabs %} #### b) Or like to say something like **interval plurals**: * many goodies still available * just a few goodies remaining... * no goodies remaining...sorry you're too late Just drop in the [interval-postprocessor](https://github.com/i18next/i18next-intervalPlural-postProcessor)​ ```javascript { key_interval: '(0){no goodies remaining...sorry you`re too late};(1-100){just a few goodies remaining...};(100-inf){many goodies still available};' } ``` ### Works on serverside While some other i18n frameworks run on serverside too there are not many optimized for it. Loading translations only once (think of a render to string in react.js where you create a new instance and inject translations over and over). Also does it keep the set language during async requests or do simultaneous requests create race conditions in setting the right language? ### Learn once - translate everywhere ![Overview of what technologies i18next will integrate with. Some listed are: Electron, Phaser, iOS, Android, Aurelia, Meteor, React Native, Knockout, React, Next.js, Remix, Angular, Ember, jQuery, Vue, Grunt, IntelliJ IDEA, Webpack, NodeJS, Express, Django, Koa, Microsoft .NET, PHP, Ruby Rails, Couchbase, MongoDB, Redis, Firebase, Locize.](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9iS6Wm2hynS5H9Gj7j%2Fuploads%2Fgit-blob-e708561b54722a1662237a53dc8e3794d106fc93%2Fi18next_eco.jpg?alt=media) Should speak for itself. ### We bridge the gap to localization Being honest, internationalization is the smaller pain in getting a site translated. Localization and the translation process are where the real hard work starts. With [https://locize.com](https://locize.com/) we fill this gap and enable a localization workflow as never seen before: {% embed url="" %} --- # Source: https://www.i18next.com/overview/configuration-options.md # Configuration Options `i18next.init(options, callback)` All options for calling [`init()`](https://www.i18next.com/api#init) or [`createInstance()`](https://www.i18next.com/api#createinstance). ## Logging | option | default | description | | ------ | ------- | --------------------------------------------------------------------------------- | | debug | false | logs info level to console output. Helps finding issues with loading not working. | ## Languages, namespaces, resources | option | default | description | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | resources | undefined | resources to initialize with (if not using a [backend plugin](https://www.i18next.com/plugins-and-utils#backends) or not using [`addResourceBundle`](https://www.i18next.com/api#addresourcebundle)) | | lng | undefined | language to use (**overrides language detection**). If set to `'cimode'` the output text will be the key. [*Make sure you use the `'en-US'` format, instead of underscores or similar.*](https://www.i18next.com/how-to/faq#how-should-the-language-codes-be-formatted) | | appendNamespaceToCIMode | false | prefixes the namespace to the returned key when using `lng: 'cimode'` | | fallbackLng | 'dev' | language to use if translations in user language are not available. *Setting it explicitly to `false` will not trigger to load the `fallbackLng` at all.* [See the Fallback docs](https://www.i18next.com/principles/fallback#language-fallback). | | supportedLngs | false | array of allowed languages | | nonExplicitSupportedLngs | false |

if true, will consider variants as supported when the main language is. E.g. en-US will be valid if en is in supportedLngs.

If true and using a backend like i18next-http-backend, this can cause some request errors.

| | load | 'all' | strategy to define which language codes to lookup. Example: given set language is `en-US`: - `'all'` ⇒ `['en-US', 'en', 'dev']` - `'currentOnly'` ⇒ `'en-US'` - `'languageOnly'` ⇒ `'en'` | | preload | false | array of languages to preload. Important on server-side to assert translations are loaded before rendering views. | | lowerCaseLng | false | locale will be fully lowercased; e.g. `en-US` ⇒ `en-us` | | cleanCode | false | main language will be lowercased; e.g. `EN` ⇒ `en`, while leaving full locales like `en-US` | | ns |

'translation'
(setting it to an empty array \[] will not load any namespaces on init)

| string or array of namespaces to load | | defaultNS |

'translation'

(if a ns option and no defaultNS option is defined, the first namespace is used as defaultNS option)
(setting it to false or an empty array \[] will disable this fallback behaviour)

| default namespace used if not passed to the [translation function](https://www.i18next.com/translation-function/essentials) | | fallbackNS | false | string or array of namespaces to lookup key if not found in given namespace. [See NS fallback docs](https://www.i18next.com/principles/fallback#namespace-fallback). | | partialBundledLanguages | false | allows some resources to be set on initialization while others can be loaded using a backend connector | ## Missing keys The missing keys functionality of i18next is very useful during development. If enabled (`saveMissing: true`), it collects the used i18n keys that are not yet part of your translation resources and tries to save them to the used backend *(a backend plugin that offers the create function is necessary for this)*. [In this video](https://youtu.be/SA_9i4TtxLQ?t=1032) you can see how the saveMissing functionality is used. | option | default | description | | ------------------------------ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | saveMissing | false | calls save missing key function on backend if key not found *(only for backends that supports the* [*create function*](https://www.i18next.com/misc/creating-own-plugins#backend)*, i.e.* [*i18next-fs-backend*](https://github.com/i18next/i18next-fs-backend)*,* [*i18next-http-backend*](https://github.com/i18next/i18next-http-backend)*,* [*i18next-locize-backend*](https://github.com/locize/i18next-locize-backend) *etc.)* | | updateMissing | false | experimental: enable to update default values using the `saveMissing` (Works only if `defaultValue` is different from translated value. Only useful on initial development or when keeping code as source of truth not changing values outside of code. Only supported if backend supports it already) | | saveMissingTo | 'fallback' |

'current' or 'all'
By default it uses the configured fallback language to save the missing keys to.
'current' will use the current used/detected language (i18next.language) and 'all' will save it to all languages included in i18next.languages.

| | saveMissingPlurals | true | will save all plural forms instead of only singular if t was called for plurals | | missingKeyHandler | false |

function(lngs, ns, key, fallbackValue, updateMissing, options) { } used for custom missing key handling (needs saveMissing set to true!)

The options are an internal value container similar to the t() options. The fallbackValue argument is the value that is shown if the translations are not provided (usually the defaultValue). The updateMissing argument is set to true if the missingKeyHandler function was invoked because of the updateMissing functionality.

| | parseMissingKeyHandler | noop |

function(key, defaultValue, options) { // return value to display }
The options are an internal value container similar to the t() options.

| | appendNamespaceToMissingKey | false | appends namespace to missing key | | missingInterpolationHandler | noop | `function(text, value) { return 'stringWithAlternativeValueOrUndefined' }` gets called in case a interpolation value is undefined. This method will not be called if the value is an empty string or null | | missingKeyNoValueFallbackToKey | false | Used to not fallback to the key as default value, when using saveMissing functionality. \* i.e. when using with i18next-http-backend this will result in having a key with an empty string value. | ## Translation defaults | option | default | description | | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | postProcess | false | string or array of postProcessors to apply per default | | returnNull | false | allows null values as valid translation | | returnEmptyString | true | allows empty string as valid translation | | returnObjects | false | allows objects as valid translation result | | returnDetails | false | returns an object that includes information about the used language, namespace, key and value | | returnedObjectHandler | noop | `function(key, value, options) {}` gets called if object was passed in as key but `returnObjects` was set to false | | joinArrays | false | char that arrays will be joined by; e.g. ", " | | overloadTranslationOptionHandler | function(args) { return { defaultValue: args\[1] }; }; | default: sets defaultValue | | interpolation | [{...}](https://www.i18next.com/translation-function/interpolation#all-interpolation-options) | see [interpolation](https://www.i18next.com/translation-function/interpolation#all-interpolation-options) | | skipInterpolation | false | Allow translate function to skip interpolation and return raw values instead | |

simplifyPluralSuffix

(used in format < format v4)

| ~~true~~ | ~~will use 'plural' as suffix for languages only having 1 plural form, setting it to false will suffix all with numbers~~ | ## Plugin options | option | default | description | | --------- | --------- | ---------------------------------------------------------------------------------------------------------- | | detection | undefined | options for language detection - [check docs](https://www.i18next.com/plugins-and-utils#language-detector) | | backend | undefined | options for backend - [check docs](https://www.i18next.com/plugins-and-utils#backends) | | cache | undefined | options for a cache layer in backends - [check docs](https://www.i18next.com/plugins-and-utils#backends) | ## Others | option | default | description | | -------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | enableSelector (TypeScript only) | false |

if set to true, pass a selector function as the first argument to t to make a translation query.

if set to "optimize", i18next is capable of handling arbitrarily large translation sets without slowing down IDE performance. Keeping in mind with this setting, translation keys will not be modified, so you'll need to specify the correct key for pluralization or use a tool like @i18next-selector/vite-plugin.

| | initAsync | true | triggers resource loading in `init()` inside a `setTimeout` (default async behaviour). Set it to `false` if your backend loads resources synchronously - that way, calling `i18next.t()` after `init()` is possible without relying on the initialization callback. **This option only works for sync (blocking) loading backend, like** [**i18next-fs-backend**](https://github.com/i18next/i18next-fs-backend)**!** | | keySeparator | `'.'` | char to separate keys. *If working with a flat JSON, it's recommended to set this to `false`.* | | nsSeparator | `':'` | char to split namespace from key | | pluralSeparator | `'_'` | char to split plural from key | | contextSeparator | `'_'` | char to split context from key | | ignoreJSONStructure | true | if a key is not found as nested key, it will try to lookup as flat key | | maxParallelReads | 10 | limits parallel reads to the backend to prevent opening up to thousands of sockets or file descriptors at the same time, leading to `EMFILE` errors if `ulimit -n` is exceeded (`debug: true` must be set to see them). limiting parallelism usually makes loading all items substantially faster than allowing all reads to start before any have finished. | | cacheInBuiltFormats | true | Initializes the internal formatter for the [in-built formats](https://www.i18next.com/translation-function/formatting#built-in-formats) as cached version. Can be set to false for this type of [issues](https://github.com/i18next/i18next/issues/2227). | ## initImmediate Sample using `initImmediate` when using a backend plugin allowing sync (blocking) loads. **This option only works for sync (blocking) loading backend, like** [**i18next-fs-backend**](https://github.com/i18next/i18next-fs-backend#if-set-i18next-initimmediate-option-to-false-it-will-load-the-files-synchronously)**!** {% tabs %} {% tab title="JavaScript" %} ```javascript import i18next from 'i18next'; import Backend from 'i18next-fs-backend'; // not working i18next .use(Backend) .init(); i18next.t('key'); // -> will not return value as init was run async /* execution order of function calls - init - t - loadResources (as called inside timeout) */ // working i18next .use(Backend) .init({ initImmediate: false }); i18next.t('key'); // -> will return value /* execution order of function calls - init - loadResources (as called without timeout) - t */ ``` {% endtab %} {% tab title="TypeScript" %} ```typescript import i18next from 'i18next'; import Backend from 'i18next-fs-backend'; // not working i18next .use(Backend) .init(); i18next.t($ => $.key); // -> will not return value as init was run async /* execution order of function calls - init - t - loadResources (as called inside timeout) */ // working i18next .use(Backend) .init({ initImmediate: false }); i18next.t($ => $.key); // -> will return value /* execution order of function calls - init - loadResources (as called without timeout) - t */ ``` {% endtab %} {% endtabs %} --- # Source: https://www.i18next.com/translation-function/context.md # Context By providing a context you can differ translations. Eg. useful to provide gender specific translations. {% hint style="info" %} 🎓 Check out this topic in the [i18next crash course video](https://youtu.be/SA_9i4TtxLQ?t=653). {% endhint %} ## Basic keys ```javascript { "friend": "A friend", "friend_male": "A boyfriend", "friend_female": "A girlfriend" } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('friend'); // -> "A friend" i18next.t('friend', { context: 'male' }); // -> "A boyfriend" i18next.t('friend', { context: 'female' }); // -> "A girlfriend" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.friend); // -> "A friend" i18next.t($ => $.friend, { context: 'male' }); // -> "A boyfriend" i18next.t($ => $.friend, { context: 'female' }); // -> "A girlfriend" ``` {% endtab %} {% endtabs %} ## Combining with plurals You can pass entire data models in options. keys ```javascript { "friend_male_one": "A boyfriend", "friend_female_one": "A girlfriend", "friend_male_other": "{{count}} boyfriends", "friend_female_other": "{{count}} girlfriends" } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('friend', {context: 'male', count: 1}); // -> "A boyfriend" i18next.t('friend', {context: 'female', count: 1}); // -> "A girlfriend" i18next.t('friend', {context: 'male', count: 100}); // -> "100 boyfriends" i18next.t('friend', {context: 'female', count: 100}); // -> "100 girlfriends" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.friend, {context: 'male', count: 1}); // -> "A boyfriend" i18next.t($ => $.friend, {context: 'female', count: 1}); // -> "A girlfriend" i18next.t($ => $.friend, {context: 'male', count: 100}); // -> "100 boyfriends" i18next.t($ => $.friend, {context: 'female', count: 100}); // -> "100 girlfriends" ``` {% endtab %} {% endtabs %} --- # Source: https://www.i18next.com/misc/creating-own-plugins.md # Creating own Plugins i18next comes with a lot of modules to enhance the features available. There are modules to: * load resources, eg. via xhr or from filesystem (node.js) * cache resources on client, eg. localStorage * detect user language by querystring, navigator, cookie, ... * post processors to further manipulate values, eg. to add sprintf support The plugins need to support following APIs: **HINT:** You can provide a singleton or a prototype constructor (prefered for supporting multiple instances of i18next). ## backend Backend plugins are used to load data for i18next. ```javascript { type: 'backend', init: function(services, backendOptions, i18nextOptions) { /* use services and options */ }, read: function(language, namespace, callback) { /* return resources */ callback(null, { key: 'value' }); /* if method fails/returns an error, call this: */ /* callback(truthyValue, null); */ }, // or new since i18next v22.1.0 // read: function(language, namespace) { // return new Promise((resolve) => { // resolve({ // key: 'value' // }) // }) // }, // optional readMulti: function(languages, namespaces, callback) { /* return multiple resources - useful eg. for bundling loading in one xhr request */ callback(null, { en: { translations: { key: 'value' } }, de: { translations: { key: 'value' } } }); /* if method fails/returns an error, call this: */ /* callback(truthyValue, null); */ }, // or new since i18next-multiload-backend-adapter v2.1.0 // readMulti: function(languages, namespaces) { // return new Promise((resolve) => { // resolve({ // en: { // translations: { // key: 'value' // } // }, // de: { // translations: { // key: 'value' // } // } // }) // }) // }, // only used in backends acting as cache layer save: function(language, namespace, data) { // store the translations }, create: function(languages, namespace, key, fallbackValue) { /* save the missing translation */ } } ``` {% hint style="info" %} Using `readMulti` is only supported when using the {% endhint %} ## languageDetector Language Detector plugins are used to detect language in user land. ```javascript { type: 'languageDetector', async: true, // If this is set to true, your detect function receives a callback function that you should call with your language, useful to retrieve your language stored in AsyncStorage for example init: function(services, detectorOptions, i18nextOptions) { // optional since v22.3.0 /* use services and options */ }, detect: function(callback) { // You'll receive a callback if you passed async true /* return detected language */ // callback('de'); if you used the async flag return 'de'; }, // or new since v22.3.0 // detect: async function () { // you can also return a normal Promise // /* return detected language */ // return 'de'; // // or // // return Promise.resolve('de') // }, cacheUserLanguage: function(lng) { // optional since v22.3.0 /* cache language */ } // or new since v22.3.0, but i18next will not await for it... so it's basically a fire and forget // cacheUserLanguage: async function(lng) { // /* await cache language */ // } } ``` ## post processor Post Processors are used to extend or manipulate the translated values before returning them in `t` function. (Post Processors do not need to be prototype functions) ```javascript { type: 'postProcessor', name: 'nameOfProcessor', process: function(value, key, options, translator) { /* return manipulated value */ return value; } } ``` ## logger Override the built in console logger. (loggers do not need to be prototype functions) ```javascript { type: 'logger', log: function(args) {}, warn: function(args) {}, error: function(args) {} } ``` ## formatter Override the built in [Formatter](https://www.i18next.com/translation-function/formatting). ```javascript { type: 'formatter', init: function(services, detectorOptions, i18nextOptions) {}, add: function(name, fc) {}, addCached: function(name, fc) {}, format: function(value, format, lng, options) { if (!format && value instanceof Date) { return value.toUTCString() } } } ``` ## Helpful tips ### Make sure to set the plugin type If you do not set the plugin type, you may get an error like this. `... No [plugin type] was added via i18next.use. Will not load resources.` If you are creating a class for your plugin, you may set the type like in the following example (the following is an example if you are making a backend plugin): ```javascript class Backend { constructor(services, backendOptions, i18nextOptions){ } // other required methods; // ie. read, create, etc. } Backend.type = "backend"; export default Backend; ``` ### Create a private method to initialize your plugin The constructor of your plugin (if the plugin is of type `backend` or `languageDetector`) will be [called without arguments](https://github.com/i18next/i18next/issues/1379#issuecomment-571913660) if you use the plugin as a class. Using the plugin as a class looks like this: ```javascript import i18n from "i18next"; import { initReactI18next } from "react-i18next"; import i18nBackend from "my-custom-backend"; i18n .use(i18nBackend) .use(initReactI18next) .init({ backend: { // custom options }, // other options }); ``` While using your plugin in this way, you may want to validate the `options` passed into the **backend** property of the `.init` method. A good way to validate them is to have a private method where you initialize your plugin. ```javascript class Backend { constructor(services, backendOptions = {}, i18nextOptions = {}){ this.init(services, backendOptions, i18nextOptions); } init(services, backendOptions, i18nextOptions){ // Validate backendOptions } // other required methods; // ie. read, create, etc. } Backend.type = "backend"; export default Backend; ``` --- # Source: https://www.i18next.com/translation-function/essentials.md # Essentials ## Accessing keys resources with 2 keys: ```javascript { "key": "value of key", "look": { "deep": "value of look deep" } } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('key'); // -> "value of key" i18next.t('look.deep'); // -> "value of look deep" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key); // -> "value of key" i18next.t($ => $.look.deep); // -> "value of look deep" ``` {% endtab %} {% endtabs %} ## Passing a default value You can pass in a default value for cases the key could not be found in translations like: {% tabs %} {% tab title="JavaScript" %} ``` i18next.t('key', 'default value to show'); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key, { defaultValue: 'default value to show' }); ``` {% endtab %} {% endtabs %} {% hint style="info" %} In case you're using the [saveMissing functionality](https://www.i18next.com/overview/configuration-options#missing-keys), it will also pass the defaultValue to your chosen backend, like shown in [this React.js example](https://github.com/locize/react-tutorial). {% endhint %} ## Accessing keys in different namespaces Namespaces are a feature in i18next internationalization framework which allows you to separate translations that get loaded into multiple files. init ```javascript i18next.init({ ns: ['common', 'moduleA'], defaultNS: 'moduleA' }); ``` moduleA.json ```javascript { "name": "Module A" } ``` common.json ```javascript { "button": { "save": "save" } } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('name'); // -> "Module A" // from different namespace (not recommended with namespace prefix when used in combination with natural language keys) i18next.t('common:button.save') // -> "save" // better use the ns option: i18next.t('button.save', { ns: 'common' }) // -> "save" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.name); // -> "Module A" // from different namespace (not recommended with namespace prefix when used in combination with natural language keys) i18next.t($ => $.common.button.save) // -> "save" // better use the ns option: i18next.t($ => $.button.save, { ns: 'common' }) // -> "save" ``` {% endtab %} {% endtabs %} ## Multiple 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: keys ```javascript { "error": { "unspecific": "Something went wrong.", "404": "The page was not found." } } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript // 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" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // const error = '404'; i18next.t($ => $.error[error], { defaultValue: t($ => $.error.unspecific) }); // -> "The page was not found" // const error = '502'; i18next.t($ => $.error[error], { defaultValue: t($ => $.error.unspecific) }); // -> "Something went wrong" ``` {% endtab %} {% endtabs %} ## Overview options `i18next.t(key, options)` | option | description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | defaultValue | defaultValue to return if a translation was not found, you also can define defaults for plurals by adding defaultValue\_other -> \_suffix depends on same [pluralrules](https://www.i18next.com/translation-function/plurals). | | count | count value used for [plurals](https://www.i18next.com/translation-function/plurals) | | context | used for [contexts](https://www.i18next.com/translation-function/context) (eg. male / female) | | replace | object with vars for [interpolation](https://www.i18next.com/translation-function/interpolation) - or put them directly in options | | lng | override language to use | | lngs | override languages to use | | fallbackLng | override language to lookup key if not found see [fallbacks](https://www.i18next.com/principles/fallback) for details, passing `false` will not do a fallback to any language | | ns | override namespaces (string or array) | | keySeparator | override char to separate keys | | nsSeparator | override char to split namespace from key | | returnObjects | accessing an object not a translation string (can be set globally too) | | returnDetails | returns an object that includes information about the used language, namespace, key and value | | joinArrays | char, eg. '\n' that arrays will be joined by (can be set globally too) | | postProcess | string or array of postProcessors to apply see [interval plurals](https://www.i18next.com/translation-function/plurals) as a sample | | interpolation | override [interpolation options](https://www.i18next.com/translation-function/interpolation) | | skipInterpolation | skip interpolation and nesting for this call to t function | | ignoreJSONStructure | if a key is not found as nested key, it will try to lookup as flat key | --- # Source: https://www.i18next.com/how-to/extracting-translations.md # Extracting translations At some point you will come to the question how to get new translation key/values into your namespace (translation) file. ## 1) Adding new strings manually While for sure this is the least efficient method for adding new translations, we know a lot of projects are doing this. There is actually nothing wrong with it beside being some extra work developers could avoid. ## 2) Using an extraction tool Static extraction tools can read through your code files to automatically find and export translation keys. Use the **official ⭐** [**i18next-cli**](https://github.com/i18next/i18next-cli) - a high-performance, all-in-one command-line tool for i18next. It handles key extraction, code linting, locale syncing, and type generation. It's built with modern technologies for maximum speed and accuracy. This is the recommended tool for all i18next projects. [i18next-scanner](http://i18next.github.io/i18next-scanner), [i18next-parser](https://github.com/i18next/i18next-parser) and [babel-plugin-i18next-extract](https://github.com/gilbsgilbs/babel-plugin-i18next-extract) are alternative choices to achieve this goal. *Or try* [*translation-check*](https://github.com/locize/translation-check)*, it shows an overview of your translations in a nice UI. Check which keys are not yet translated.* For more information about extraction tools, see [plugin and utils](https://www.i18next.com/overview/plugins-and-utils#extraction-tools) documentation page. ## 3) Runtime extraction I18next has a setting to send all keys that it was unable to resolve during runtime using the attached backend. In case of the http-backend just set `saveMissing: true` on init: ```javascript import i18n from "i18next"; import detector from "i18next-browser-languagedetector"; import backend from "i18next-http-backend"; import { initReactI18next } from "react-i18next"; i18n .use(detector) .use(backend) .use(initReactI18next) // passes i18n down to react-i18next .init({ fallbackLng: "en", // use en if detected lng is not available saveMissing: true // send not translated keys to endpoint }); export default i18n; ``` Check the [options](https://github.com/i18next/i18next-http-backend#backend-options) for where missing translation gets sent. Using node.js and express? You can get that endpoint for free: ​ This is the most convenient way of working with react-i18next: just develop and run your applications without worrying too much about adding translations to your catalog as those get added automatically. {% hint style="info" %} Wanna have this process on steroids? Just hook up a [locize.com](https://locize.com/) localization project using the provided backend and get both the saveMissing and loading of translations automated in a true continuous localization process. [Check out this tutorial!](https://github.com/locize/react-tutorial) {% endhint %} {% embed url="" %} --- # Source: https://www.i18next.com/principles/fallback.md # Fallback Doing graceful fallbacks is a core principle of i18next. This enables you to display the most accurate content possible, while not repeating content over and over. ## Language fallback ### Variant resolving - fallback from dialects or scripts By default, if a variant (containing region, script, etc) is not found, i18next will look for the same key in the broader version of that language. With this in mind, a common strategy if you're supporting language variants is to write common text inside the pure language, specifying only what differs in the variants. Example: {% tabs %} {% tab title="JavaScript" %} ```javascript // fallback to one language i18next.init({ lng: "en-GB", resources: { "en-GB": { "translation": { "i18n": "Internationalisation" } }, "en": { "translation": { "i18n": "Internationalization", "i18n_short": "i18n" } } } }, () => { i18next.t('i18n'); // -> finds "Internationalisation" i18next.t('i18n_short'); // -> falls back to "en": "i18n" // force using en i18next.t('i18n', { lng: 'en' }); // -> "Internationalization" }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // fallback to one language i18next.init({ lng: "en-GB", resources: { "en-GB": { "translation": { "i18n": "Internationalisation" } }, "en": { "translation": { "i18n": "Internationalization", "i18n_short": "i18n" } } } }, () => { i18next.t($ => $.i18n); // -> finds "Internationalisation" i18next.t($ => $.i18n_short); // -> falls back to "en": "i18n" // force using en i18next.t($ => $.i18n, { lng: 'en' }); // -> "Internationalization" }); ``` {% endtab %} {% endtabs %} ### Fallback to different languages If you can not provide the preferred language for a user, you can specify another language as fallback. This is useful to indicate the main language or, for instance, if you want to keep the fallbacks different per region. ```javascript // fallback to one language i18next.init({ fallbackLng: 'en' }); // fallback ordered i18next.init({ fallbackLng: ['fr', 'en'] }); // fallback depending on user language i18next.init({ fallbackLng: { 'de-CH': ['fr', 'it'], //French and Italian are also spoken in Switzerland '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 i18next.init({ 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 fallbacks.push('dev'); 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, for instance, proper English, including defined terminology. For production use, just set `fallbackLng` to an existing language. ## Namespace fallback i18next by default loads its translations from one file named `translation`. However, you can configure it to load from multiple files, called [*namespaces*](https://www.i18next.com/principles/namespaces). Besides defining multiple namespaces to load from, you also can set fallback namespaces. Thus, if a key to translate isn't found in the given namespace, it will look it up in the indicated fallbacks. app.json ```javascript { "title": "i18next" } ``` common.json ```javascript { "button": { "save": "save" } } ``` Sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.init({ // 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('button.save') // -> "save" (fallback from common) // without fallbackNS you would have to prefix namespace // to access keys in that namespace // and this is not recommended when used in combination with natural language keys i18next.t('common:button.save') // -> "save" // better use the ns option: i18next.t('button.save', { ns: 'common' }) // -> "save" }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.init({ // 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($ => $.button.save) // -> "save" (fallback from common) // switch namespaces with the `ns` option: i18next.t($ => $.button.save, { ns: 'common' }) // -> "save" }); ``` {% endtab %} {% endtabs %} ## Key fallback ### Key not found {% tabs %} {% tab title="JavaScript" %} If a key does not return a value the key acts as fallback: ```javascript i18next.t('notExistingKey'); // -> "notExistingKey" ``` {% endtab %} {% tab title="TypeScript" %} If a key does not return a value the selected path acts as fallback: ```typescript i18next.t($ => $.notExistingKey); // -> "notExistingKey" ``` {% endtab %} {% endtabs %} So you could configure i18next to have the key being the fallback instead of loading a fallback language: {% tabs %} {% tab title="JavaScript" %} de.json ```javascript { "No one says a key can not be the fallback.": "Niemand sagt ein key kann nicht als Ersatz dienen." } ``` ```javascript i18next.init({ 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." ``` {% endtab %} {% tab title="TypeScript" %} de.json ```typescript { "No one says a path can not be the fallback.": "Niemand sagt, dass ein Pfad nicht der Fallback sein kann." } ``` ```typescript i18next.init({ 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, dass ein Pfad nicht der Fallback sein kann" 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." ``` {% endtab %} {% endtabs %} 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 (e.g. 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: translation.json ```javascript { "error": { "unspecific": "Something went wrong.", "404": "The page was not found." } } ``` Sample {% tabs %} {% tab title="JavaScript" %} ```javascript // 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" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // const error = '404'; i18next.t($ => $.error[error], { defaultValue: t($ => $.error.unspecific) }) // -> "The page was not found" // const error = '502'; i18next.t($ => $.error[error], { defaultValue: t($ => $.error.unspecific) }) // -> "Something went wrong" ``` {% endtab %} {% endtabs %} --- # Source: https://www.i18next.com/how-to/faq.md # FAQ ## Misc ### **i18next is awesome. How can I support the project?** *There are a lot of ways to support us. Make a PR for a feature requested. Improve the documentation. Help others to get started. Spread the word.* *Further you could try* [*locize.com*](http://locize.com) *- our localization as a service offering. It's like donating to i18next but with additional benefits for you - like saving hours of time translating your project.* ## Loading issues ### **I don't see my translations!!!** *Try setting* `debug: true` *on init and check the console log. There is rather sure a warning for unable to resolve the loadPath or invalid json. Check if the translation files are accessible via browser.* ## Translation ### **How to translate the resource files?**

https://translate.i18next.com

For a quick and dirty machine translation you may have a look at [this free translator](https://translate.i18next.com).\ But in general we suggest to use a smart Translation Management Service like [locize](https://locize.com) to translate your i18next resources. For professional translations we advice you to work with [human translators](https://docs.locize.com/guides-tips-and-tricks/working-with-translators). Or at least proofread the results coming from machine translations. ### **How do i know which plural suffix i have to use?** *On the* [*plural page*](https://www.i18next.com/translation-function/plurals) *there is a tool to get them.* *Or try* [*translation-check*](https://github.com/locize/translation-check)*, it shows an overview of your translations in a nice UI. It shows also the appropriate plural forms.* *Or you use a smart translation management system, like* [*locize*](https://locize.com)*.* ![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-L9iS6Wm2hynS5H9Gj7j%2F-MX2rpXr6D3UrjwHPOqm%2F-MX2s2PKNH3dqXxCShCx%2Flocize_plurals.png?alt=media\&token=a93a4d64-6c13-4e19-9d1f-c9ae9c898e8f) ### **Why are my plural keys not working?** *Are you seeing this warning in the development console?* > i18next::pluralResolver: Your environment seems not to be Intl API compatible, use an Intl.PluralRules polyfill. Will fallback to the compatibilityJSON v3 format handling. *With v21 we* streamlined the suffix with the one used in the [Intl API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules). *In environments where the* [*Intl.PluralRules*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules) *API is not available (like older Android devices), you may need to* [*polyfill*](https://github.com/eemeli/intl-pluralrules) *the* [*Intl.PluralRules*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules) *API.*\ *In case it is not available it will fallback to the* [*i18next JSON format v3*](https://www.i18next.com/misc/json-format#i-18-next-json-v3) *plural handling. And if your json is already using the new suffixes, your plural keys will probably not be shown.* *tldr;* ```shell npm install intl-pluralrules ``` ```javascript import 'intl-pluralrules' ``` ### How should the language codes be formatted? *Theoretically, you're not bound to any specific language code format, but if you want to make use of all the in built language features, like proper* [*pluralization*](https://www.i18next.com/translation-function/plurals) *and correct* [*fallback resolution*](https://www.i18next.com/principles/fallback#language-fallback)*, we strongly suggest to use the following iso norm (BCP 47 language tag):* `lng-(script)-REGION-(extensions)`\ \ \&#xNAN;*i.e.* * *en, en-US or en-GB* * *zh, zh-HK or zh-Hant-HK* *Other examples are listed here:* [*https://www.iana.org/assignments/language-tags/language-tags.xhtml*](https://www.iana.org/assignments/language-tags/language-tags.xhtml) *And more information about the format can be found here:* [*https://www.w3.org/International/articles/language-tags/*](https://www.w3.org/International/articles/language-tags/) {% hint style="info" %} As soon as you use the dash character `-` the language codes are tried to be formatted with `Intl.getCanonicalLocales`. {% endhint %} ## Process ### **How do I keep overview over my translation progress?** *Try* [*translation-check*](https://github.com/locize/translation-check)*, it shows an overview of your translations in a nice UI. Check which keys are not yet translated.* *If you need more, it might be time to use a* [*translation management tool*](https://locize.com)*.* ### **How to handle with changes in e2e tests?** *For e2e tests a good tactic is to set language to* `cimode` *on init. This will set i18next to always return the key on calling* `i18next.t`*. Want to add the namespace to returned value change* `appendNamespaceToCIMode: true` *on init.* ### **How to use i18next in serverless environments?** Due to how serverless functions work, you cannot guarantee that a cached version of your data is available. Serverless functions are short-lived, and can shut down at any time, purging any in-memory or filesystem cache. This may be an acceptable trade-off, but sometimes it isn't acceptable. Because of this we suggest to not use a remote backend and to download the translations and package them with your serverless function. {% hint style="success" %} Read more about this topic, [here](https://locize.com/blog/i18n-serverless/).[
](https://locize.com/blog/how-does-server-side-internationalization-look-like/)[![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9iS6Wm2hynS5H9Gj7j%2Fuploads%2FWlRIcoHBxh3tLr13Gzz9%2Ftitle.jpg?alt=media\&token=7823c353-0215-4c15-ae40-52f9f1b0cd89)](https://locize.com/blog/i18n-serverless/) {% endhint %} --- # Source: https://www.i18next.com/overview/first-setup-help.md # First setup help * [For which environment are you looking for an i18n solution?](#for-which-environment-are-you-looking-for-an-i-18-n-solution) * [Special handling for serverless environments (AWS lambda, Google Cloud Functions, Azure Functions, etc...)](#special-handling-for-serverless-environments-aws-lambda-google-cloud-functions-azure-functions-etc) * [Do you need a language detector for your environment?](#do-you-need-a-language-detector-for-your-environment) * [Do you want to bundle the translations with your app?](#do-you-want-to-bundle-the-translations-with-your-app) * [Do you want to load the translations separate from your app via http?](#do-you-want-to-load-the-translations-separate-from-your-app-via-http) * [Do you want to manage your translations with an awesome translation management system?](#do-you-want-to-manage-your-translations-with-an-awesome-translation-management-system) ## For which environment are you looking for an i18n solution? [Client](https://react.i18next.com/), [server](https://github.com/i18next/i18next-http-middleware), [browser](https://github.com/i18next/jquery-i18next), [React](https://react.i18next.com), [mobile](https://github.com/i18next/react-i18next/tree/master/example/ReactNativeProject), [desktop](https://github.com/i18next/react-i18next/tree/master/example/react_native_windows), [Node.js](https://github.com/i18next/i18next-fs-backend/blob/master/example/node/index.js), [Deno](https://github.com/i18next/i18next-fs-backend/blob/master/example/deno/index.js)... There are a lot of appropriate libraries. [Have a look at this list.](https://www.i18next.com/overview/supported-frameworks) ### Special handling for serverless environments (AWS lambda, Google Cloud Functions, Azure Functions, etc...) Make use of [i18next-fs-backend](https://github.com/i18next/i18next-fs-backend) ```javascript import i18next from 'i18next'; import Backend from 'i18next-fs-backend'; const backend = new Backend({ // path where resources get loaded from loadPath: '/locales/{{lng}}/{{ns}}.json' }); i18next .use(backend) .init({ // initImmediate: false, // setting initImediate to false, will load the resources synchronously ...opts, ...yourOptions }); // yourOptions should not include backendOptions! ``` or just [import/require](https://www.i18next.com/how-to/add-or-load-translations#add-on-init) your files directly ```javascript import i18next from 'i18next'; import en from './locales/en.json' import de from './locales/de.json' i18next .init({ ...opts, ...yourOptions, resources: { en, de } }); ``` ## Do you need a language detector for your environment? * for example for the browser: [i18next-browser-languageDetector](https://github.com/i18next/i18next-browser-languageDetector) * for example for http server (express, Fastify, etc...): [i18next-http-middleware](https://github.com/i18next/i18next-http-middleware#language-detection) * [there are other plugins here](https://www.i18next.com/overview/plugins-and-utils#language-detector) ## Do you want to bundle the translations with your app? * [you can add translations on init](https://www.i18next.com/how-to/add-or-load-translations#add-on-init) * [you can add translations after init](https://www.i18next.com/how-to/add-or-load-translations#add-after-init) * [you can lazy load translations via dynamic import](https://www.i18next.com/how-to/add-or-load-translations#lazy-load-in-memory-translations) * on server side: [you can load translations from filesystem](https://github.com/i18next/i18next-fs-backend) ## Do you want to load the translations separate from your app via http? * served from your own endpoint: [i18next-http-backend](https://github.com/i18next/i18next-http-backend) * served from a professional CDN of a translation management system: [i18next-locize-backend](https://github.com/locize/i18next-locize-backend) * [there are a lot of other backend possibilities here](https://www.i18next.com/plugins-and-utils#backends) ## Do you want to manage your translations with an awesome translation management system? ### [Ready to take i18next to the next level?](https://www.i18next.com/overview/for-enterprises) --- # Source: https://www.i18next.com/overview/for-enterprises.md # For Enterprises ## Is i18n enough? We believe not. The closer the release date of your product gets the more obvious it gets, that instrumenting your code for localization is not enough. There are more points to address: * How does the translation process work? * How do the source files get to the translators and back? * How do you keep track which parts are already translated and which parts are not - and additional are all target languages fully translated? * How do you deploy new languages after release? * How do you handle versioning? * How do you update / fix typos in translations after deployment? Translation Management Systems are a great help. But most tools out there are built for one-time translation of your documents. Not for continuously translating your application. So there is still a gap between the development and the translation process. > So is there a smart localization management platform? An [i18n(ext) platform](https://www.locize.com/i18next)? ## Locize ![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-L9iS6Wm2hynS5H9Gj7j%2F-L9iS7LlT2W7wFtJH-2n%2F-L9iS9uLqGNjseomOY6O%2Flocize.png?generation=1523345307233719\&alt=media) [Locize](http://locize.com/?utm_source=i18next_com\&utm_medium=gitbook) is a localization as a service platform made by i18next. The close integration of i18next brings a lot of additional value and asserts you an additional level of support and saves you endless time spent on localization. {% embed url="" %} Locize brings you: * A beautiful editor to edit your translations * Enables a continuous localization process * An in-context editor to edit on your own website * Progress reporting * Usage reporting * Plural conversion between languages * Support for versions * Gets your missing keys passed directly to the project * Hosts translation on its CDN and allows for automatic or manual publishing (You still have the option to host translations yourself) Check out how it works => *Together, 'i18next' and '*[*locize*](https://locize.com)*' empower your business to effortlessly reach international audiences. They help you speak the language of your customers, making your business more accessible, relatable, and successful in global markets.* --- # Source: https://www.i18next.com/translation-function/formatting.md # Formatting Starting with **i18next>=21.3.0** you can use the built-in formatting functions based on the [Intl API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl). *You may need to* [*polyfill*](https://formatjs.io/docs/polyfills/) *the Intl API:* * [*Intl.PluralRules*](https://formatjs.io/docs/polyfills/intl-pluralrules) * [*Intl.RelativeTimeFormat*](https://formatjs.io/docs/polyfills/intl-relativetimeformat) * [*Intl.ListFormat*](https://formatjs.io/docs/polyfills/intl-listformat) * [*Intl.DisplayNames*](https://formatjs.io/docs/polyfills/intl-displaynames) * [*Intl.NumberFormat*](https://formatjs.io/docs/polyfills/intl-numberformat) *(ES2020)* * [*Intl.Locale*](https://formatjs.io/docs/polyfills/intl-locale) * [*Intl.getCanonicalLocales*](https://formatjs.io/docs/polyfills/intl-getcanonicallocales) * [*Intl.DateTimeFormat*](https://formatjs.io/docs/polyfills/intl-datetimeformat) *(ES2020)* {% hint style="info" %} 🎓 Check out this topic in the [i18next crash course video](https://youtu.be/SA_9i4TtxLQ?t=557). {% endhint %} ## Basic usage The translation string has the following signature: ```json { "key": "Some format {{value, formatname}}", "keyWithOptions": "Some format {{value, formatname(option1Name: option1Value; option2Name: option2Value)}}" } ``` {% hint style="info" %} Use a "semicolon" delimited list of options. {% endhint %} {% tabs %} {% tab title="JavaScript" %} Passing options to the formatting: 1. In the translation string using `{{value, formatname(options1: options1Value)}}` 2. Using the root level options when calling `t('key', { option1: option1Value })` 3. Using the per value options like: `t('key', { formatParams: { value: { option1: option1Value } })` Samples ```javascript // JSON { "intlNumber": "Some {{val, number}}", "intlNumberWithOptions": "Some {{val, number(minimumFractionDigits: 2)}}" } i18next.t('intlNumber', { val: 1000 }); // --> Some 1,000 i18next.t('intlNumber', { val: 1000.1, minimumFractionDigits: 3 }); // --> Some 1,000.100 i18next.t('intlNumber', { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } }); // --> Some 1,000.100 i18next.t('intlNumberWithOptions', { val: 2000 }); // --> Some 2,000.00 i18next.t('intlNumberWithOptions', { val: 2000, minimumFractionDigits: 3 }); // --> Some 2,000.000 ``` {% endtab %} {% tab title="TypeScript" %} Passing options to the formatting: 1. In the translation string using `{{value, formatname(options1: options1Value)}}` 2. Using the root level options when calling `t($ => $.key, { option1: option1Value })` 3. Using the per value options like: `t($ => $.key, { formatParams: { value: { option1: option1Value } })` Samples ```typescript // JSON { "intlNumber": "Some {{val, number}}", "intlNumberWithOptions": "Some {{val, number(minimumFractionDigits: 2)}}" } i18next.t($ => $.intlNumber, { val: 1000 }); // --> Some 1,000 i18next.t($ => $.intlNumber, { val: 1000.1, minimumFractionDigits: 3 }); // --> Some 1,000.100 i18next.t($ => $.intlNumber, { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } }); // --> Some 1,000.100 i18next.t($ => $.intlNumberWithOptions, { val: 2000 }); // --> Some 2,000.00 i18next.t($ => $.intlNumberWithOptions, { val: 2000, minimumFractionDigits: 3 }); // --> Some 2,000.000 ``` {% endtab %} {% endtabs %} #### Overriding the language to use The language can be overridden by passing it in t.options {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('intlNumber', { val: 1000.1, lng: 'de' }); // or: i18next.t('intlNumber', { val: 1000.1, locale: 'de' }); i18next.t('intlNumber', { val: 1000.1, formatParams: { val: { lng: 'de' } } }); // or: i18next.t('intlNumber', { val: 1000.1, formatParams: { val: { locale: 'de' } } }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.intlNumber, { val: 1000.1, lng: 'de' }); // or: i18next.t($ => $.intlNumber, { val: 1000.1, locale: 'de' }); i18next.t($ => $.intlNumber, { val: 1000.1, formatParams: { val: { lng: 'de' } } }); // or: i18next.t($ => $.intlNumber, { val: 1000.1, formatParams: { val: { locale: 'de' } } }); ``` {% endtab %} {% endtabs %} #### Adding custom format function It's rather simple to add own function: ```javascript // after i18next.init(options); i18next.services.formatter.add('lowercase', (value, lng, options) => { return value.toLowerCase(); }); i18next.services.formatter.add('underscore', (value, lng, options) => { return value.replace(/\s+/g, '_'); }); ``` {% hint style="warning" %} Make sure you add your custom format function **AFTER** the `i18next.init()` call. {% endhint %} There's also an addCached version for optimized performance: ```javascript i18next.services.formatter.addCached('specialformat', (lng, options) => { const formatter = new Intl.NumberFormat(lng, options); return (val) => formatter.format(val); }); ``` #### Using multiple formatters ```json { "key": "Some format {{value, formatter1, formatter2}}" } ``` ## Built-in formats ### Number {% tabs %} {% tab title="JavaScript" %} ```javascript // JSON { "intlNumber": "Some {{val, number}}", "intlNumberWithOptions": "Some {{val, number(minimumFractionDigits: 2)}}" } i18next.t('intlNumber', { val: 1000 }); // --> Some 1,000 i18next.t('intlNumber', { val: 1000.1, minimumFractionDigits: 3 }); // --> Some 1,000.100 i18next.t('intlNumber', { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } }); // --> Some 1,000.100 i18next.t('intlNumberWithOptions', { val: 2000 }); // --> Some 2,000.00 i18next.t('intlNumberWithOptions', { val: 2000, minimumFractionDigits: 3 }); // --> Some 2,000.000 ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // JSON { "intlNumber": "Some {{val, number}}", "intlNumberWithOptions": "Some {{val, number(minimumFractionDigits: 2)}}" } i18next.t($ => $.intlNumber, { val: 1000 }); // --> Some 1,000 i18next.t($ => $.intlNumber, { val: 1000.1, minimumFractionDigits: 3 }); // --> Some 1,000.100 i18next.t($ => $.intlNumber, { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } }); // --> Some 1,000.100 i18next.t($ => $.intlNumberWithOptions, { val: 2000 }); // --> Some 2,000.00 i18next.t($ => $.intlNumberWithOptions, { val: 2000, minimumFractionDigits: 3 }); // --> Some 2,000.000 ``` {% endtab %} {% endtabs %} For options see: ### Currency {% tabs %} {% tab title="JavaScript" %} ```javascript // JSON { "intlCurrencyWithOptionsSimplified": "The value is {{val, currency(USD)}}", "intlCurrencyWithOptions": "The value is {{val, currency(currency: USD)}}", "twoIntlCurrencyWithUniqueFormatOptions": "The value is {{localValue, currency}} or {{altValue, currency}}", } i18next.t('intlCurrencyWithOptionsSimplified', { val: 2000 }); // --> The value is $2,000.00 i18next.t('intlCurrencyWithOptions', { val: 2300 }); // --> The value is $2,300.00 i18next.t('twoIntlCurrencyWithUniqueFormatOptions', { localValue: 12345.67, altValue: 16543.21, formatParams: { localValue: { currency: 'USD', locale: 'en-US' }, altValue: { currency: 'CAD', locale: 'fr-CA' }, }, },); // --> The value is $12,345.67 or 16 543,21 $ CA ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // JSON { "intlCurrencyWithOptionsSimplified": "The value is {{val, currency(USD)}}", "intlCurrencyWithOptions": "The value is {{val, currency(currency: USD)}}", "twoIntlCurrencyWithUniqueFormatOptions": "The value is {{localValue, currency}} or {{altValue, currency}}", } i18next.t($ => $.intlCurrencyWithOptionsSimplified, { val: 2000 }); // --> The value is $2,000.00 i18next.t($ => $.intlCurrencyWithOptions, { val: 2300 }); // --> The value is $2,300.00 i18next.t($ => $.twoIntlCurrencyWithUniqueFormatOptions, { localValue: 12345.67, altValue: 16543.21, formatParams: { localValue: { currency: 'USD', locale: 'en-US' }, altValue: { currency: 'CAD', locale: 'fr-CA' }, }, },); // --> The value is $12,345.67 or 16 543,21 $ CA ``` {% endtab %} {% endtabs %} For options see: ### DateTime {% tabs %} {% tab title="JavaScript" %} ```javascript // JSON { "intlDateTime": "On the {{val, datetime}}", } i18next.t('intlDateTime', { val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) }); // --> On the 12/20/2012 i18next.t('intlDateTime', { val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)), formatParams: { val: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }, }, }); // --> On the Thursday, December 20, 2012 ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // JSON { "intlDateTime": "On the {{val, datetime}}", } i18next.t($ => $.intlDateTime, { val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) }); // --> On the 12/20/2012 i18next.t($ => $.intlDateTime, { val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)), formatParams: { val: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }, }, }); // --> On the Thursday, December 20, 2012 ``` {% endtab %} {% endtabs %} For options see: ### RelativeTime {% tabs %} {% tab title="JavaScript" %} ```javascript // JSON { "intlRelativeTime": "Lorem {{val, relativetime}}", "intlRelativeTimeWithOptions": "Lorem {{val, relativetime(quarter)}}", "intlRelativeTimeWithOptionsExplicit": "Lorem {{val, relativetime(range: quarter; style: narrow;)}}", } i18next.t('intlRelativeTime', { val: 3 }); // --> Lorem in 3 days i18next.t('intlRelativeTimeWithOptions', { val: -3 }); // --> Lorem 3 quarters ago i18next.t('intlRelativeTimeWithOptionsExplicit', { val: -3 }); // --> Lorem 3 qtrs. ago i18next.t('intlRelativeTimeWithOptionsExplicit', { val: -3, style: 'long' }); // --> Lorem 3 quarters ago ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // JSON { "intlRelativeTime": "Lorem {{val, relativetime}}", "intlRelativeTimeWithOptions": "Lorem {{val, relativetime(quarter)}}", "intlRelativeTimeWithOptionsExplicit": "Lorem {{val, relativetime(range: quarter; style: narrow;)}}", } i18next.t($ => $.intlRelativeTime, { val: 3 }); // --> Lorem in 3 days i18next.t($ => $.intlRelativeTimeWithOptions, { val: -3 }); // --> Lorem 3 quarters ago i18next.t($ => $.intlRelativeTimeWithOptionsExplicit, { val: -3 }); // --> Lorem 3 qtrs. ago i18next.t($ => $.intlRelativeTimeWithOptionsExplicit, { val: -3, style: 'long' }); // --> Lorem 3 quarters ago ``` {% endtab %} {% endtabs %} For options see: ### List {% tabs %} {% tab title="JavaScript" %} ```javascript // JSON { "intlList": "A list of {{val, list}}" } i18next.t('intlList', { val: ['locize', 'i18next', 'awesomeness'] }); // --> A list of locize, i18next, and awesomeness ``` {% endtab %} {% tab title="TypeScript" %} ```typescript // JSON { "intlList": "A list of {{val, list}}" } i18next.t($ => $.intlList, { val: ['locize', 'i18next', 'awesomeness'] }); // --> A list of locize, i18next, and awesomeness ``` {% endtab %} {% endtabs %} For options see: ## Legacy format function i18next<21.3.0 You can add formatting using [moment.js](http://momentjs.com/) and [numeral.js](http://numeraljs.com/) or the [intl api](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl). As a sample using momentjs to format dates. keys ```javascript { "key": "The current date is {{date, MM/DD/YYYY}}", "key2": "{{text, uppercase}} just uppercased" } ``` Init i18next with a format function: ```javascript i18next.init({ interpolation: { format: function(value, format, lng) { if (format === 'uppercase') return value.toUpperCase(); if(value instanceof Date) return moment(value).format(format); return value; } } }); ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('key', { date: new Date() }); // -> "The current date is 07/13/2016" i18next.t('key2', { text: 'can you hear me' }); // => "CAN YOU HEAR ME just uppercased" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key, { date: new Date() }); // -> "The current date is 07/13/2016" i18next.t($ => $.key2, { text: 'can you hear me' }); // => "CAN YOU HEAR ME just uppercased" ``` {% endtab %} {% endtabs %} Keep the language on moment in sync with i18next by listening to the change language event: ```javascript i18next.on('languageChanged', function(lng) { moment.locale(lng); }); ``` ## Additional options Prefix/Suffix for interpolation and other options can be overridden in init option: sample ```javascript i18next.init({ interpolation: { ... } }); ``` | option | default | description | | --------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | alwaysFormat | false | used to always call the format function for all interpolated values | | format | noop function |

Passing this function is considered LEGACY in i18next>=21.3.0

format function function format(value, format, lng, edit) {}

| | formatSeparator | ',' | used to separate format from interpolation value | While there are a lot of options going with the defaults should get you covered. ## Custom formatter {% hint style="info" %} Do you want to create some sort of default formatter, that does not need a specific format to be passed via i18n resources? i18next gets you covered also with that... {% endhint %} Create a custom formatter plugin, and pass it to i18next: {% tabs %} {% tab title="JavaScript" %}
const myFormatter = {
  type: 'formatter',
  init(services, backendOptions, i18nextOptions) {}, // of you need some init stuff to be done...
  format(value, format, lng, options) {
    // do whatever you like here... and return the formatted string
    if (!format && value instanceof Date) {
      return value.toUTCString()
    }
  },
  add(name, fc) {
    // handle adding a new format, if you need it
  },
  addCached(name, fc) {
    // handle adding a new cached format, if you need it
  }
}

i18next
  .use(myFormatter)
  .init({
    fallbackLng: "en",
    interpolation: {
      alwaysFormat: true // set alwaysFormat to true
    },
    resources: {
      en: {
        translation: {
          testKeyWithoutFormat: 'On the "{val}"',
        }
      }
    }
  });
  
i18next.t("testKeyWithoutFormat", { val: new Date() }) // On the "Mon, 07 Jul 2025 11:44:50 GMT"
{% endtab %} {% tab title="TypeScript" %}
const myFormatter = {
  type: 'formatter',
  init(services, backendOptions, i18nextOptions) {}, // of you need some init stuff to be done...
  format(value, format, lng, options) {
    // do whatever you like here... and return the formatted string
    if (!format && value instanceof Date) {
      return value.toUTCString()
    }
  },
  add(name, fc) {
    // handle adding a new format, if you need it
  },
  addCached(name, fc) {
    // handle adding a new cached format, if you need it
  }
}

i18next
  .use(myFormatter)
  .init({
    fallbackLng: "en",
    interpolation: {
      alwaysFormat: true // set alwaysFormat to true
    },
    resources: {
      en: {
        translation: {
          testKeyWithoutFormat: 'On the "{val}"',
        }
      }
    }
  });
  
i18next.t($ => $.testKeyWithoutFormat, { val: new Date() }) // On the "Mon, 07 Jul 2025 11:44:50 GMT"
{% endtab %} {% endtabs %} --- # Source: https://www.i18next.com/overview/getting-started.md # Getting started ## Installation i18next can be added to your project using **npm** or **yarn**: ```bash # npm $ npm install i18next --save # yarn $ yarn add i18next ``` The default export is UMD compatible (commonjs, requirejs, global). In the `/dist` folder you may find additional builds for commonjs, es6 modules. Optimized to load i18next in webpack, rollup, ... or node.js. The correct entry points are already configured in the package.json so there should be no extra setup to get the best build option. ## Load in [Deno](https://deno.land/) i18next can be imported like this: ```javascript import i18next from '@i18next/i18next' // when installed via JSR: deno add jsr:@i18next/i18next // or import i18next from 'https://raw.githubusercontent.com/i18next/i18next/master/src/index.js' // or import i18next from 'https://cdn.jsdelivr.net/gh/i18next/i18next/src/index.js' ``` {% hint style="success" %} In [this tutorial blog post](https://locize.com/blog/i18n-for-deno-with-i18next/) you can check out how this works.[
](https://locize.com/blog/i18n-for-deno-with-i18next/)[![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9iS6Wm2hynS5H9Gj7j%2Fuploads%2FOHcKMGaR6YoafoX1Nngu%2Fdeno_i18next.jpg?alt=media\&token=502a156c-49c3-49cb-afed-d1d2facf11ac)](https://locize.com/blog/i18n-for-deno-with-i18next/) {% endhint %} ## Load from CDN You can also directly add a script tag loading i18next from one of the CDNs providing it: **unpkg.com** * * esm or cjs: * * Make sure to use a fixed version in production like [https://unpkg.com/i18next@17.0.0/dist/umd/i18next.js](https://unpkg.com/i18next/dist/umd/i18next.js) as passing no version will redirect to latest version which might contain breaking changes in future. **cdnjs.com** * **jsdelivr.com** * ## Important Caveat Before we dive into the first sample, please note the following: By default, i18next uses a key-based notation to look up translations, which comes with the benefit of [additional structure](https://www.i18next.com/translation-function/essentials) for your translation files. The downside of this is that your keys must not be in natural language — the names of the keys are not used as fallback content and the key names must not include reserved characters `:` and `.` since those are used by i18next. If you prefer using natural language in keys, please read the [fallback guide](https://www.i18next.com/principles/fallback#key-fallback). ## Basic sample Please be aware these samples are just showing basic usage of the core functionality. For production usage please consider using one of our [framework integrations](https://www.i18next.com/overview/supported-frameworks) to get better and simpler integrations (Setting innerHTML is just done to show how it works). {% tabs %} {% tab title="JavaScript" %} ```javascript import i18next from 'i18next'; i18next.init({ lng: 'en', // if you're using a language detector, do not define the lng option debug: true, resources: { en: { translation: { "key": "hello world" } } } }); // initialized and ready to go! // i18next is already initialized, because the translation resources where passed via init function document.getElementById('output').innerHTML = i18next.t('key'); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript import i18next from 'i18next'; i18next.init({ lng: 'en', // if you're using a language detector, do not define the lng option debug: true, resources: { en: { translation: { "key": "hello world" } } } }); // initialized and ready to go! // i18next is already initialized, because the translation resources where passed via init function document.getElementById('output').innerHTML = i18next.t($ => $.key); ``` {% endtab %} {% endtabs %} Or using callback init signature: {% tabs %} {% tab title="JavaScript" %} ```javascript import i18next from 'i18next'; i18next.init({ lng: 'en', // if you're using a language detector, do not define the lng option debug: true, resources: { en: { translation: { "key": "hello world" } } } }, function(err, t) { // initialized and ready to go! document.getElementById('output').innerHTML = i18next.t('key'); }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript import i18next from 'i18next'; i18next.init({ lng: 'en', // if you're using a language detector, do not define the lng option debug: true, resources: { en: { translation: { "key": "hello world" } } } }, function(err, t) { // initialized and ready to go! document.getElementById('output').innerHTML = i18next.t($ => $.key); }); ``` {% endtab %} {% endtabs %} Or using Promises: {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.init({ lng: 'en', // if you're using a language detector, do not define the lng option debug: true, resources: { en: { translation: { "key": "hello world" } } } }).then(function(t) { // initialized and ready to go! document.getElementById('output').innerHTML = i18next.t('key'); }); ``` {% endtab %} {% tab title="TypeScript" %} ```javascript i18next.init({ lng: 'en', // if you're using a language detector, do not define the lng option debug: true, resources: { en: { translation: { "key": "hello world" } } } }).then(function(t) { // initialized and ready to go! document.getElementById('output').innerHTML = i18next.t($ => $.key); }); ``` {% endtab %} {% endtabs %} Or using async/await: {% tabs %} {% tab title="JavaScript" %} ```javascript await i18next.init({ lng: 'en', // if you're using a language detector, do not define the lng option debug: true, resources: { en: { translation: { "key": "hello world" } } } }); // initialized and ready to go! document.getElementById('output').innerHTML = i18next.t('key'); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript await i18next.init({ lng: 'en', // if you're using a language detector, do not define the lng option debug: true, resources: { en: { translation: { "key": "hello world" } } } }); // initialized and ready to go! document.getElementById('output').innerHTML = i18next.t($ => $.key); ``` {% endtab %} {% endtabs %} {% hint style="info" %} if you are [lazy loading the translation resources](https://www.i18next.com/how-to/add-or-load-translations), you may need to wait for i18next to have finished to initialize. {% endhint %} As you might see, this basic sample provides only one language directly added on init… let's extend this to have buttons to change language from English to German: [source code](https://jsfiddle.net/jamuhl/dvk0e8a9/#tabs=js,result,html) {% hint style="info" %} Do you quickly want to translate your resources to other languages?\ Try: [https://translate.i18next.com](https://translate.i18next.com/) {% endhint %} This is a working sample showing translated text. To learn more, have a look at the following extended sample: ## Extended sample The extended sample adds the language detector for our browser and the http-backend to load translation files from this documentation's [i18next-gitbook repo](https://github.com/i18next/i18next-gitbook/tree/master/locales). [source code](https://jsfiddle.net/jamuhl/ferfywyf/525/) You should now have an idea about how to achieve the basic setup. It's time to learn more about: * The translation functions like [interpolation](https://www.i18next.com/translation-function/interpolation), [formatting](https://www.i18next.com/translation-function/formatting) and [plurals](https://www.i18next.com/translation-function/plurals). * Find an [extension for your project](https://www.i18next.com/overview/supported-frameworks), eg. **react-i18next**, **jquery-i18next** and **others**. Using those wrappers around i18next makes using i18next a lot simpler in your project. Most of such modules come with extended examples. * Find out more about the [configuration options](https://www.i18next.com/overview/configuration-options). * Add a [language detector](https://www.i18next.com/overview/plugins-and-utils) to detect the preferred language of your user * Add a [backend plugin](https://www.i18next.com/overview/plugins-and-utils) to load the translations from the server or filesystem * Connect i18next with a smart [Translation Management System](https://locize.com), like in [this React.js example](https://github.com/locize/react-tutorial) --- # Source: https://www.i18next.com/translation-function/interpolation.md # Interpolation Interpolation is one of the most used functionalities in I18N. It allows integrating dynamic values into your translations. Per default, interpolation values get escaped to mitigate XSS attacks. {% hint style="info" %} 🎓 Check out this topic in the [i18next crash course video](https://youtu.be/SA_9i4TtxLQ?t=433). {% endhint %} If the interpolation functionality provided doesn't suit you, you can use [i18next-sprintf-postProcessor](https://github.com/i18next/i18next-sprintf-postProcessor) for sprintf supported interpolation. ## Basic Interpolation is one of the most used functionalities in I18N. Keys Keys, by default, are strings surrounded by curly brackets: ```javascript { "key": "{{what}} is {{how}}" } ``` Sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('key', { what: 'i18next', how: 'great' }); // -> "i18next is great" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key, { what: 'i18next', how: 'great' }); // -> "i18next is great" ``` {% endtab %} {% endtabs %} ## Working with data models You can also pass entire data models as a value for interpolation. Keys ```javascript { "key": "I am {{author.name}}" } ``` Sample {% tabs %} {% tab title="JavaScript" %} ```javascript const author = { name: 'Jan', github: 'jamuhl' }; i18next.t('key', { author }); // -> "I am Jan" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript const author = { name: 'Jan', github: 'jamuhl' }; i18next.t($ => $.key, { author }); // -> "I am Jan" ``` {% endtab %} {% endtabs %} ## Unescape By default, the values get escaped to mitigate XSS attacks. You can toggle escaping off, by either putting `-` before the key, or set the `escapeValue` option to `false` when requesting a translation. Keys ```javascript { "keyEscaped": "no danger {{myVar}}", "keyUnescaped": "dangerous {{- myVar}}" } ``` Sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('keyEscaped', { myVar: '' }); // -> "no danger <img />" i18next.t('keyUnescaped', { myVar: '' }); // -> "dangerous " i18next.t('keyEscaped', { myVar: '', interpolation: { escapeValue: false } }); // -> "no danger " (obviously could be dangerous) ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.keyEscaped, { myVar: '' }); // -> "no danger <img />" i18next.t($ => $.keyUnescaped, { myVar: '' }); // -> "dangerous " i18next.t($ => $.keyEscaped, { myVar: '', interpolation: { escapeValue: false } }); // -> "no danger " (obviously could be dangerous) ``` {% endtab %} {% endtabs %} *Warning:* If you toggle escaping off, escape any user input yourself! ## Additional options Prefix/Suffix for interpolation and other options can be overridden in the init options or by passing additional options to the `t` function: {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.init({ interpolation: { ... } }); i18next.t('key', { interpolation: { ... } }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.init({ interpolation: { ... } }); i18next.t($ => $.key, { interpolation: { ... } }); ``` {% endtab %} {% endtabs %} | option | default | description | | ------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | escape | function | escape function `function escape(str) { return str; }` | | escapeValue | true | escapes passed in values to avoid XSS injection | | useRawValueToEscape | false | If true, then value passed into escape function is not casted to string, use with custom escape function that does its own type-checking | | prefix | "{{" | prefix for interpolation | | suffix | "}}" | suffix for interpolation | While there are a lot of options going with the defaults should get you covered. ## All interpolation options | option | default | description | | ----------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | format | noop function | format function, read [formatting](https://www.i18next.com/translation-function/formatting) for details | | formatSeparator | "," | used to separate format from interpolation value | | escape | function | escape function `function escape(str) { return str; }` | | escapeValue | true | escape passed in values to avoid XSS injection | | useRawValueToEscape | false | If true, then value passed into escape function is not casted to string, use with custom escape function that does its own type-checking | | prefix | "{{" | prefix for interpolation | | suffix | "}}" | suffix for interpolation | | prefixEscaped | undefined | escaped prefix for interpolation (regexSafe) | | suffixEscaped | undefined | escaped suffix for interpolation (regexSafe) | | unescapeSuffix | undefined | suffix to unescaped mode | | unescapePrefix | "-" | prefix to unescaped mode | | nestingPrefix | "$t(" | prefix for [nesting](https://www.i18next.com/translation-function/nesting) | | nestingSuffix | ")" | suffix for [nesting](https://www.i18next.com/translation-function/nesting) | | nestingPrefixEscaped | undefined | escaped prefix for nesting (regexSafe) | | nestingSuffixEscaped | undefined | escaped suffix for nesting (regexSafe) | | nestingOptionsSeparator | "," | separates the options from nesting key | | defaultVariables | undefined | global variables to use in interpolation replacements `defaultVariables: { key: "value" }` | | maxReplaces | 1000 | after how many interpolation runs to break out before throwing a stack overflow | | skipOnVariables |

true

(was false for \

|

Will skip to interpolate the variables, example:

t('key', { a: '$t(nested)' })

this will not resolve the nested key and will use$t(nested) as the variable value.
Another example:

t('key', { a: '{{otherVar}}': otherVar: 'another value' })

this will not resolve the otherVar variable and will use{{otherVar}}as the variable value.

If your interpolation variables are user provided or loaded from an external source, we strongly suggest to keep this option to true.

If you know what you're doing, you can also set this to false.

| ## Implications for localization Checkout the [best practices](https://www.i18next.com/principles/best-practices#implications-of-interpolation-for-localization) on this topic. --- # Source: https://www.i18next.com/misc/json-format.md # JSON Format {% hint style="info" %} Do you prefer the ICU format? Then use the [i18next-icu](https://github.com/i18next/i18next-icu) plugin. {% endhint %} ## i18next JSON v4 ```javascript { "key": "value", "keyDeep": { "inner": "value" }, "keyNesting": "reuse $t(keyDeep.inner)", "keyInterpolate": "replace this {{value}}", "keyInterpolateUnescaped": "replace this {{- value}}", "keyInterpolateWithFormatting": "replace this {{value, format}}", "keyContext_male": "the male variant", "keyContext_female": "the female variant", "keyPluralSimple_one": "the singular", "keyPluralSimple_other": "the plural", "keyPluralMultipleEgArabic_zero": "the plural form 0", "keyPluralMultipleEgArabic_one": "the plural form 1", "keyPluralMultipleEgArabic_two": "the plural form 2", "keyPluralMultipleEgArabic_few": "the plural form 3", "keyPluralMultipleEgArabic_many": "the plural form 4", "keyPluralMultipleEgArabic_other": "the plural form 5", "keyWithArrayValue": ["multiple", "things"], "keyWithObjectValue": { "valueA": "return this with valueB", "valueB": "more text" } } ``` These are the defaults. Nesting and Interpolation formats are configurable. To learn more about the features check the documentation: * [Interpolation](https://www.i18next.com/translation-function/interpolation) * [Formatting](https://www.i18next.com/translation-function/formatting) * [Plurals](https://www.i18next.com/translation-function/plurals) * [Nesting](https://www.i18next.com/translation-function/nesting) * [Objects and Arrays](https://www.i18next.com/translation-function/objects-and-arrays) The only difference to *v3* is the plural suffixes. You may need to [polyfill](https://github.com/eemeli/intl-pluralrules) the [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules) API, in case it is not available it will fallback to the [i18next JSON format v3](#i-18-next-json-v3) plural handling. To convert your existing translations to the new v4 format, have a look at [i18next-v4-format-converter](https://github.com/i18next/i18next-v4-format-converter) or [this web tool](https://i18next.github.io/i18next-v4-format-converter-web/). *(It will only handle keys with the default pluralSeparator `_`)* ## i18next JSON v3 enabled by: ```javascript i18next.init({ compatibilityJSON: 'v3' }); ``` formats: ```javascript { "key": "value", "keyDeep": { "inner": "value" }, "keyNesting": "reuse $t(keyDeep.inner)", "keyInterpolate": "replace this {{value}}", "keyInterpolateUnescaped": "replace this {{- value}}", "keyInterpolateWithFormatting": "replace this {{value, format}}", "keyContext_male": "the male variant", "keyContext_female": "the female variant", "keyPluralSimple": "the singular", "keyPluralSimple_plural": "the plural", "keyPluralMultipleEgArabic_0": "the plural form 0", "keyPluralMultipleEgArabic_1": "the plural form 1", "keyPluralMultipleEgArabic_2": "the plural form 2", "keyPluralMultipleEgArabic_3": "the plural form 3", "keyPluralMultipleEgArabic_4": "the plural form 4", "keyPluralMultipleEgArabic_5": "the plural form 5", "keyWithArrayValue": ["multiple", "things"], "keyWithObjectValue": { "valueA": "return this with valueB", "valueB": "more text" } } ``` The only difference to *v2* is the plural suffixes for languages with multiple plural forms. ## i18next JSON v2 enabled by: ```javascript i18next.init({ compatibilityJSON: 'v2' }); ``` formats: ```javascript { "key": "value", "keyDeep": { "inner": "value" }, "keyNesting": "reuse $t(keyDeep.inner)", "keyInterpolate": "replace this {{value}}", "keyInterpolateUnescaped": "replace this {{- value}}", "keyContext_male": "the male variant", "keyContext_female": "the female variant", "keyPluralSimple": "the singular", "keyPluralSimple_plural": "the plural", "keyPluralMultipleEgArabic_0": "the plural form 0", "keyPluralMultipleEgArabic_1": "the plural form 1", "keyPluralMultipleEgArabic_2": "the plural form 2", "keyPluralMultipleEgArabic_3": "the plural form 3", "keyPluralMultipleEgArabic_11": "the plural form 4", "keyPluralMultipleEgArabic_100": "the plural form 5" } ``` These are the defaults. Nesting and Interpolation formats are configurable. ## i18next JSON v1 enabled by: ```javascript i18next.init({ compatibilityJSON: 'v1' }); ``` formats: ```javascript { "key": "value", "keyDeep": { "inner": "value" }, "keyNesting": "reuse $t(keyDeep.inner)", "keyInterpolate": "replace this __value__", "keyInterpolateUnescaped": "replace this __valueHTML__", "keyContext_male": "the male variant", "keyContext_female": "the female variant", "keyPluralSimple": "the singular", "keyPluralSimple_plural": "the plural", "keyPluralMultipleEgArabic": "the plural form 0", "keyPluralMultipleEgArabic_plural_1": "the plural form 1", "keyPluralMultipleEgArabic_plural_2": "the plural form 2", "keyPluralMultipleEgArabic_plural_3": "the plural form 3", "keyPluralMultipleEgArabic_plural_11": "the plural form 4", "keyPluralMultipleEgArabic_plural_100": "the plural form 5" } ``` These are the defaults. Nesting and Interpolation formats are configurable. --- # Source: https://www.i18next.com/misc/migration-guide.md # Migration Guide ### v25.3.x to v25.4.0 * add new selector API to improve TypeScript IDE performance [2322](https://github.com/i18next/i18next/pull/2322) * To enable it, set `enableSelector: true` in your configuration options * With `enableSelector: "optimize"`, i18next can now handle translation dictionaries of any size, without affecting IDE performance or build times * To assist with the migration, we've published the following packages: * [@i18next-selector/codemod](https://github.com/ahrjarrett/i18next-selector/tree/main/packages/codemod) * [@i18next-selector/vite-plugin](https://github.com/ahrjarrett/i18next-selector/tree/main/packages/vite-plugin) ### v24.x.x to v25.0.0 **This is a potentially breaking release:** * fix multiple `changeLanguage` call that may have result in wrong order in previous versions [1605](https://github.com/i18next/i18next/issues/1605) [2298](https://github.com/i18next/i18next/pull/2298) * adapt `changeLanguage` to always (string or array) use `getBestMatchFromCodes` [2299](https://github.com/i18next/i18next/issues/2299) * `getBestMatchFromCodes` now tries to fallback to language code with same script [2299](https://github.com/i18next/i18next/issues/2299) ### v23.x.x to v24.0.0 * remove support for older environments * remove old i18next [JSON formats](https://www.i18next.com/misc/json-format) * to convert your existing [v3](https://www.i18next.com/json-format#i18next-json-v3) translations to the [v4](https://www.i18next.com/json-format#i18next-json-v4) format, have a look at [i18next-v4-format-converter](https://github.com/i18next/i18next-v4-format-converter) or this [web tool](https://i18next.github.io/i18next-v4-format-converter-web/). * remove support for compatibility to the very first [v1 API](https://www.i18next.com/misc/the-history-of-i18next) ([old docs](https://i18next.github.io/i18next/)) * [`Intl` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) is mandatory now and will not fallback anymore, use a polyfill ([`Intl.PluralRules`](https://github.com/eemeli/intl-pluralrules) and [`Intl.getCanonicalLocales`](https://formatjs.github.io/docs/polyfills/intl-getcanonicallocales/)) if your environment does not support it. * for those who really need the old behaviour, needs to create a compatibility layer similar to [this](https://github.com/i18next/i18next/blob/6b3b06057a3c5aee8e4900ef0731a3cf9254a4fa/test/compatibility/v4/v4Compatibility.js). * renamed `initImmediate` to `initAsync` * fallback to `dev` language if plural rule not found * Dropped support for Node.js < v14 #### TypeScript * Now only `typescript >5` versions are supported. `v4` types are now removed from the codebase. * `jsonFormat` option has been removed. When a new json version will be released you can can use `compatibilityJSON` option. which now only accepts `v4` as value. ### v22.x.x to v23.0.0 #### Redesigned [TypeScript types](https://www.i18next.com/overview/typescript) [This PR](https://github.com/i18next/i18next/pull/1911) redesigned the types to be less complex, faster and easier to maintain.\\ The redesign endeavors to enhance the approach to parsing and inferring keys for the `t` function. Instead of performing a recursive examination of each key-value pair in `resources` associated with specific namespace(s) each time the `t` function is invoked, we generate a comprehensive set of keys from all namespaces just once. Make sure your tsconfig compilerOptions has the [`strict`](https://www.typescriptlang.org/tsconfig#strict) flag or the [`strictNullChecks`](https://www.typescriptlang.org/tsconfig#strictNullChecks) set to `true`. Also use TypeScript v5. #### Codemods To assist with the upgrade from i18n `v22.x.x` to `v23.0.0`, [Codemod](https://github.com/codemod-com/codemod) provides open-source codemods that automatically transform your code to many of the new APIs and patterns. These following codemods are available (see the notes in the "More information" section below): * [`i18next/23/add-namespace-type-annotation`](https://go.codemod.com/i18n-namespace-type-annotation) * [`i18next/23/remove-options`](https://go.codemod.com/i18n-remove-options) * [`i18next/23/replace-keys`](https://go.codemod.com/i18n-replace-keys)
More information: Features and Breaking changes **Features** * When loading multiple namespaces ([react-i18next](https://react.i18next.com)), `t` function will infer and accept the keys for the first namespace. So this pattern will be accepted now: [![Screenshot 2023-02-12 at 9 40 06 PM](https://user-images.githubusercontent.com/12190482/218372236-c7dcc9c5-6c7c-434f-8259-cbba17a03ac6.png)](https://user-images.githubusercontent.com/12190482/218372236-c7dcc9c5-6c7c-434f-8259-cbba17a03ac6.png) * `t` function will now infer and accept the keys for the main namespace (i18next): [![Screenshot 2023-02-12 at 9 48 31 PM](https://user-images.githubusercontent.com/12190482/218373106-ca291bfa-4df0-48bf-b4be-1ca07282373c.png)](https://user-images.githubusercontent.com/12190482/218373106-ca291bfa-4df0-48bf-b4be-1ca07282373c.png) * We're introducing a new type (`returnObjects`) that will infer fewer keys if set to `false`, and all keys and sub-keys if set to `true`. If the option `returnObjects` from `t` function is set to `true`, it'll work the same way: [![Screenshot 2023-02-12 at 9 52 07 PM](https://user-images.githubusercontent.com/12190482/218373749-bba70379-23b3-483d-8cee-241736be43ad.png)](https://user-images.githubusercontent.com/12190482/218373749-bba70379-23b3-483d-8cee-241736be43ad.png) [![Screenshot 2023-02-12 at 9 57 43 PM](https://user-images.githubusercontent.com/12190482/218374305-219b2c51-783a-4753-9df8-450b45f92132.png)](https://user-images.githubusercontent.com/12190482/218374305-219b2c51-783a-4753-9df8-450b45f92132.png) [![Screenshot 2023-02-12 at 10 03 12 PM](https://user-images.githubusercontent.com/12190482/218374963-b1fcbda2-35f5-452a-b4c4-d847d1456a11.png)](https://user-images.githubusercontent.com/12190482/218374963-b1fcbda2-35f5-452a-b4c4-d847d1456a11.png) * `t` function will now infer interpolation values, but it'll only work if the translation files (resources) are placed in a ts file and using `as const` *(like* [*this*](https://github.com/i18next/i18next/blob/master/examples/typescript/i18n/en/ns1.ts)*)* or an [interface in a d.ts file](https://github.com/locize/react-i18next-example-app-ts/blob/main/src/%40types/resources.d.ts) *(can be generated like* [*this*](https://github.com/locize/react-i18next-example-app-ts/blob/751f704984c206076d08638442ae34b3507aa7ad/package.json#L35)*)*, JSON files don't support `as const` to convert objects to be type literals (yet). **Breaking changes** All breaking changes described below are minor ones: 1. Projects with the option `returnObjects` set as `true` by default will also have to set the same option in the `CustomTypeOptions` type. Otherwise, only complete keys will be allowed (`key1.key2.key3...`). ``` // i18next.d.ts import 'i18next'; declare module 'i18next' { interface CustomTypeOptions { returnObjects: true ... ``` 2. Renaming `StringMap` to `$Dictionary`, and we'll no longer export it. `$Dictionary` is an internal helper, and there is no reason to expose it. If needed, you can create a copy and reuse it in your project. 3. `ns` property from `InterpolationOptions` type will be constrained to `Namespace` rather than `string` or `readonly string[]`. Codemod for this Change: ```bash npx codemod i18next/23/add-namespace-type-annotation ``` 4. Renaming `KeysWithSeparator` type to `JoinKeys`, and it will no longer be exposed. Codemod for this Change: ```bash npx codemod i18next/23/replace-keys ``` 5. Renaming `TFuncKey` type to `ParseKeys`. 6. Removing `NormalizeByTypeOptions` type. 7. Renaming `DefaultTFuncReturnWithObject` type to `DefaultTReturn`. It will accept `TOptions` as generic constraint and will no longer be exposed. Codemod for this Change: ```bash npx codemod i18next/23/remove-options ``` 8. Removing `DefaultTFuncReturn` type in favor of `DefaultTReturn`. 9. Removing `NormalizeReturn` type.
{% hint style="info" %} If you encounter any issues, please report them to the Codemod team with `npx codemod feedback` {% endhint %} #### Removed `setDebug` function in internal logger Based on [this discussion](https://github.com/i18next/i18next/issues/1954#issuecomment-1537117407) we decided to remove the setDebug function. #### Changed default value for `returnNull` option to `false` To improve the usage for TypeScript users (in combination with React.js) we decided to set the `returnNull` value to `false` by default.\ More information can be found [here](https://github.com/i18next/i18next/issues/1884). #### Dropped support for old browsers and Node.js < v12 To have smaller builds and faster loads, we now transpile only for modern browsers and runtimes.\ More information can be found [here](https://github.com/i18next/i18next/issues/1948). #### Prefixed ordinal plural keys To help translators, [ordinal plural](#prefixed-ordinal-plural-keys) keys are now prefixed with `_ordinal`. ### v21.x.x to v22.0.0 Since this is a major rewrite for [TypeScript usage](https://www.i18next.com/overview/typescript) we decided to create a major version.\ For JavaScript users v22.0.0 is equivalent to 21.10.0 ### v20.x.x to v21.0.0 #### [json format v4](https://www.i18next.com/json-format#i-18-next-json-v4) - [pluralization](https://www.i18next.com/translation-function/plurals) One of the biggest breaking changes is regarding suffixing plurals.\ This change streamlines the suffix with the one used in the [Intl API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules).\ You may need to [polyfill](https://github.com/eemeli/intl-pluralrules) the [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules) API, in case it is not available it will fallback to the [i18next JSON format v3](https://www.i18next.com/json-format#i-18-next-json-v3) plural handling.\ To enforce old behaviour you can enable `compatibilityJSON = 'v3'` on i18next init call. ```javascript import i18next from 'i18next'; i18next.init({ compatibilityJSON: 'v3' }, (err, t) => { /* resources are loaded */ }); ``` There is also support for [ordinal numbers](https://www.i18next.com/translation-function/plurals#ordinal-plurals) *(referring to the ordering or ranking of things, e.g. "1st", "2nd", "3rd" in English)*.\ Learn more about plurals: To convert your existing translations to the new v4 format, have a look at [i18next-v4-format-converter](https://github.com/i18next/i18next-v4-format-converter) or [this web tool](https://i18next.github.io/i18next-v4-format-converter-web/). *(It will only handle keys with the default pluralSeparator `_`)* #### skipOnVariables = true By default the `skipOnVariables` [option](https://www.i18next.com/translation-function/interpolation#all-interpolation-options) now is set to true.\ To enforce old behaviour you can set `skipOnVariables = false` on i18next init call. ```javascript import i18next from 'i18next'; i18next.init({ interpolation: { skipOnVariables: false } }, (err, t) => { /* resources are loaded */ }); ``` #### natural language detection i18next now automatically tries to detect natural language keys.\ This way there is no need to set `nsSeparator` or `keySeparator` [option](https://www.i18next.com/overview/configuration-options#others) to `false`.\ \&#xNAN;*In case you want to skip this natural language detection, provide a `keySeparator` and/or a `nsSeparator` option.* #### removed deprecated The old [deprecated whitelist options](https://github.com/i18next/i18next/issues/1466) and functions have been definitively removed. * *rename option `whitelist` to `supportedLngs`* * *rename option `nonExplicitWhitelist` to `nonExplicitSupportedLngs`* * *rename function `languageUtils.isWhitelisted` to `languageUtils.isSupportedCode`* #### new resolvedLanguage There is a new [`i18next.resolvedLanguage`](https://www.i18next.com/overview/api#resolvedlanguage) property, that represents the current resolved language. It can be used as primary used language, for example in a language switcher. #### defaultNS If passing the `ns` option, the `defaultNS` will, by default, be set to the first ns passed. ### v19.x.x to v20.0.0 There should not be any breaking change, but regarding of some misuse of i18next that pop up in last minor releases, we opted for a major version this time.\ The relevant change behind the scene for this major version was [ignoreJSONStructure](https://github.com/i18next/i18next/blob/master/CHANGELOG.md#2000). ### v18.x.x to v19.0.0 Typescript use `export default` for esm-first approach [1352](https://github.com/i18next/i18next/pull/1352). No API changes. ### v17.x.x to v18.0.0 * When calling `i18next.changeLanguage()` both `i18next.language` and `i18next.languages` will be set to the new language after calling `loadResources` -> means when accessing `t` function meanwhile you will get still the translations for the previous language instead of the fallback. * **When is this breaking?** this does not break any current test - but if you depend on accessing i18next.language or i18next.dir during language change and expect the new language this will break your app. * Reasoning: In react-i18next we get in a not ready state for loaded translations while we would prefer just waiting for the new language ready and trigger a rerender then - also a triggered rerender outside of the bound events would end in Suspense... * How can I get the language i18next will be set to? `i18next.isLanguageChangingTo` is set to the language called ### v16.x.x to v17.0.0 * removes named exports in index.js to avoid issues in bundlers ### v15.x.x to v16.0.0 * Build process was updated - no API changes * **note:** dist/es -> dist/esm, dist/commonjs -> dist/cjs (individual files -> one bundled file) ### v14.x.x to v15.0.0 * Build process was updated - no API changes ### v13.x.x to v14.0.0 * Breaking changes in typescript typings for details have a look at this [pull request](https://github.com/i18next/i18next/pull/1180). ### v12.x.x to v13.0.0 * typescript definitions now can directly be used from the i18next module - no longer needed to get them from DefinitelyTyped * functions used to return a callback (eg. init, changeLanguage, loadNamespaces) now also return a Promise - while this enables easier handling using async await this also means eg. i18next.init does not return this anylonger and therefore you can't chain calls like `i18next.init().on()` anylonger. ### v11.x.x to v12.0.0 * plural form for hebrew was updated to latest [CLDR](http://www.unicode.org/cldr/charts/33/supplemental/language_plural_rules.html#he). Before it had one plural form. You will have to update your JSON files containing hebrew plurals. Or patch back the plural form to: using the [addRule function](https://github.com/i18next/i18next/blob/master/src/PluralResolver.js#L90).\ \ Learn more about plurals: ### v10.x.x to v11.0.0 * removes plugin of type cache. Can be replace by [i18next-chained-backend](https://github.com/i18next/i18next-chained-backend) example cache for localStorage [i18next-localstorage-backend](https://github.com/i18next/i18next-localstorage-backend#getting-started) * removes the support for multiload (multiRead) in backends - will just use read per language-namespace. You can enable multiRead support in backends again by using [i18next-multiload-backend-adapter](https://github.com/i18next/i18next-multiload-backend-adapter) ### v9.x.x to v10.0.0 brings pt, pt-PT, pt-BR plurals in line with, new pt reflects pt-BR and pt-PT gets a special case for plural handling | code | locale | rule | | ------ | -------------------- | --------------------------- | | pt-PT | Portugal Portuguese | plurals=2; plural=(n != 1); | | pt\_BR | Brazilian Portuguese | plurals=2; plural=(n > 1); | | pt | Portuguese | plurals=2; plural=(n > 1); | ### v8.x.x to v9.0.0 With v9 we removed the compatibility for the v1 API. So the `compatibilityAPI: 'v1'` flag won't do anything anymore. You still can append this manually as we do for our old v1 tests - [learn more](https://github.com/i18next/i18next/blob/master/test/backward/v1.11.1.compat.js#L45-L52). ### v7.x.x to v8.0.0 The `nonExplicitWhitelist` flag was changed to be used in user detected language too, before it was restricted to defined fallback languages only. ``` i18next.init({ fallbackLng: 'en', whitelist: ['de', 'en', 'zh'], nonExplicitWhitelist: true }); // eg. `de-AT` will now pass the whitelist check ``` ### v6.x.x to v7.0.0 We used to resolve nb-NO, nn-NO to no as language part mainly because there was no way to proper define per local fallbacks. With v7.0.0 we removed that to enable default behaviour also for norwegian language. To get back the old behaviour you can define multiple fallbacks like: ``` fallbackLng: { 'nb': ['no', 'en'], 'nn': ['no', 'en'], 'default': ['en'] } ``` Additional starting from 7.0.0 you could use named exports: ``` import { init, t } from 'i18next'; ``` ### v5.x.x to v6.0.0 Return namespace in cimode with appendNamespaceToCIMode option (default now will only return key without namespace - independent of call to t function) [#863](https://github.com/i18next/i18next/issues/863) This change might break your e2e tests if your depending on the cimode (the returned value can now be set to return always only key or ns+key) ### v4.x.x to v5.0.0 Nested keys should not be escaped [#854](https://github.com/i18next/i18next/issues/854) i18next.cloneInstance() calls now init() (before it depended on having called that function with a callback) [#860](https://github.com/i18next/i18next/pull/860) ### v3.x.x to v4.0.0 There is only a small change for webpack2 builds which now targets es build with import/export in place to enable treeshaking (module entrypoint in package.json). Nothing breaking for non webpack2 users. ### v2.x.x to v3.0.0 There is one breaking change regarding suffixing plurals in cases a language has multiple plural forms. Eg. arabic suffixes are now 0, 1, 2, 3, 4, 5 instead of 0, 1, 2, 3, 11, 100. This change streamlines the suffix with the one used in gettext. To enforce old behaviour you can enable `compatibilityJSON = 'v2'` on i18next init call. ```javascript import i18next from 'i18next'; i18next.init({ compatibilityJSON: 'v2' }, (err, t) => { /* resources are loaded */ }); ``` ### v1.11.x to v2.0.0 While v2.0.0 is a full rewrite of the old codebase it should be possible to run in your app without completely rewrite your integration. #### Getting started The new version does not come with backend, cache and user language detection built in. i18next is more a core library that can be extended with modules on demand. This way it can be seamlessly used in browser, node.js or other javascript runtimes. Modules are available on npm, via bower or on github to download. #### browser ```javascript import i18next from 'i18next'; import XHR from 'i18next-xhr-backend'; import Cache from 'i18next-localstorage-cache'; import sprintf from 'i18next-sprintf-postprocessor'; import LanguageDetector from 'i18next-browser-languagedetector'; i18next .use(XHR) .use(Cache) .use(LanguageDetector) .use(sprintf) .init(options, callback); ``` **hint for jquery user:** use additional [jquery-i18next](https://github.com/i18next/jquery-i18next) #### nodejs ```javascript var i18next = require('i18next'), FilesystemBackend = require('i18next-node-fs-backend'), sprintf = require('i18next-sprintf-postprocessor'); i18next .use(FilesystemBackend) .use(sprintf) .init(options, callback); ``` #### nodejs + express ```javascript var express = require('express'); i18next = require('i18next'), FilesystemBackend = require('i18next-node-fs-backend'), sprintf = require('i18next-sprintf-postprocessor'), i18nextMiddleware = require('i18next-express-middleware'); i18next .use(i18nextMiddleware.LanguageDetector) .use(FilesystemBackend) .use(sprintf) .init(options, callback); var app = express(); app.use(i18nextMiddleware.handle(i18next)); // expose req.t with fixed lng app.post('/locales/add/:lng/:ns', i18nextMiddleware.missingKeyHandler(i18next)); // serves missing key route for consumers (browser) app.get('/locales/resources.json', i18nextMiddleware.getResourcesHandler(i18next)); // serves resources for consumers (browser) app.listen(3000); ``` #### Running v2.0.0 with compatibility flags Version 2.0.0 has a compatibility layer built in which allows to run it like v1.11.x. Keep in mind this layer will be removed in future version. ```javascript import i18next from 'i18next'; i18next.init({ compatibilityAPI: 'v1', compatibilityJSON: 'v1', // ...old options from v1 }, (err, t) => { /* resources are loaded */ }); ``` | option | description | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | compatibilityAPI | Will convert init and t options and expose old API functions. Will be removed with future update. | | compatibilityJSON | Will allow to use JSON files in v1 format. Using old interpolation prefix, suffix and no need for singular suffix \[0] for singular in languages with more then just 1 plural form. | #### Not supported any longer in v2.0.0 * **support for older browsers**: Beginning with v2 we target only modern browsers (Chrome, Firefox, ... and IE >= 10). For IE9 you will need to add a es5 shim * **jquery**: use additional [jquery-i18next](https://github.com/i18next/jquery-i18next) * **synchronous loading**: `i18next.init({ getAsync: false });` is not supported any longer - as not encouraged by browsers. * **no conflict:** `i18n.noConflict();` was removed as i18next registers to window\.i18next and no longer to window\.i18n * **indefinite article:** `i18n.t('myKey', { indefinite_article: true })` was removed - as the solution was too limited - reconsidering adding a better solution in a future v2 release --- # Source: https://www.i18next.com/principles/namespaces.md # Namespaces Namespaces are a feature in i18next internationalization framework which allows you to separate translations that get loaded into multiple files. While in a smaller project it might be reasonable to just put everything in one file you might get at a point where you want to break translations into multiple files. Reasons might be: * You start losing the overview having more than 300 segments in a file * Not every translation needs to be loaded on the first page, speed up load time {% hint style="info" %} 🎓 Check out this topic in the [i18next crash course video](https://youtu.be/SA_9i4TtxLQ?t=314). {% endhint %} ## semantic reasons Often you wish to separate some segments out because they belong together. We do this in most of our projects, eg.: * **common.json** -> Things that are reused everywhere, eg. Button labels 'save', 'cancel' * **validation.json** -> All validation texts * **glossary.json** -> Words we want to be reused consistently inside texts ## technical / editorial reasons More often you don't want to load all the translations upfront or at least reduce the amount loaded. This reason often goes hand in hand with the one translation file gets too large and you start losing the overview scrolling through hundreds of text fragments. * namespace per view/page * namespace per application section / feature set (admin area, ...) * namespace per module which gets lazy loaded (single page applications) ## Sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.init({ ns: ['common', 'moduleA', 'moduleB'], defaultNS: 'moduleA' }, (err, t) => { i18next.t('myKey'); // key in moduleA namespace (defined default) i18next.t('common:myKey'); // key in common namespace (not recommended with ns prefix when used in combination with natural language keys) // better use the ns option: i18next.t('myKey', { ns: 'common' }); }); // load additional namespaces after initialization i18next.loadNamespaces('anotherNamespace', (err, t) => { /* ... */ }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.init({ ns: ['common', 'moduleA', 'moduleB'], defaultNS: 'moduleA' }, (err, t) => { i18next.t($ => $.myKey); // key in moduleA namespace (defined default) i18next.t($ => $.myKey, { ns: 'common' }); // key in common namespace }); // load additional namespaces after initialization i18next.loadNamespaces('anotherNamespace', (err, t) => { /* ... */ }); ``` {% endtab %} {% endtabs %} Check the extended sample on the [getting started](https://www.i18next.com/overview/getting-started) page for a running sample. --- # Source: https://www.i18next.com/translation-function/nesting.md # Nesting Nesting allows you to reference other keys in a translation. Could be useful to build glossary terms. ## Basic keys ```javascript { "nesting1": "1 $t(nesting2)", "nesting2": "2 $t(nesting3)", "nesting3": "3", } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('nesting1'); // -> "1 2 3" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.nesting1); // -> "1 2 3" ``` {% endtab %} {% endtabs %} 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 ```javascript { "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 {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('girlsAndBoys', {girls: 3, boys: 2}); // -> "They have 3 girls and 2 boys" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.girlsAndBoys, {girls: 3, boys: 2}); // -> "They have 3 girls and 2 boys" ``` {% endtab %} {% endtabs %} {% hint style="info" %} Make sure the options string is valid JSON and can be parsed using JSON.parse `'sampleKey': 'test $t(nest2, { "changedVarName": "{{var}}" })'` {% endhint %} ## Passing nesting to interpolated keys ```javascript { "key1": "hello world", "key2": "say: {{val}}" } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('key2', {val: '$t(key1)'}); // -> "say: hello world" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key2, {val: '$t(key1)'}); // -> "say: hello world" ``` {% endtab %} {% endtabs %} {% hint style="info" %} If you're using >= v21.0.0 you need to set [skipOnVariables](https://www.i18next.com/misc/migration-guide#skiponvariables-true) to false: ``` interpolation: { skipOnVariables: false } ``` {% endhint %} ## Additional options Prefix/Suffix for nesting and other options can be overridden in init [interpolation options](https://www.i18next.com/interpolation#all-interpolation-options) or by passing additional options to t function: sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.init({ interpolation: { ... } }); i18next.t('key', { interpolation: { ... } }); ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.init({ interpolation: { ... } }); i18next.t($ => $.key, { interpolation: { ... } }); ``` {% endtab %} {% endtabs %} | 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. --- # Source: https://www.i18next.com/translation-function/objects-and-arrays.md # Objects and Arrays ## Objects You can return objects or arrays to be used by third party modules localization: keys ```javascript { "tree": { "res": "added {{something}}" }, "array": ['a', 'b', 'c'] } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('tree', { returnObjects: true, something: 'gold' }); // -> { res: 'added gold' } i18next.t('array', { returnObjects: true }); // -> ['a', 'b', 'c'] ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.tree, { returnObjects: true, something: 'gold' }); // -> { res: 'added gold' } i18next.t($ => $.array, { returnObjects: true }); // -> ['a', 'b', 'c'] ``` {% endtab %} {% endtabs %} The returned value supports interpolation, plurals, nesting, ... `returnObjects` can be set to true on init. ## Arrays You can access array values or join them. keys ```javascript { "arrayJoin": [ "line1", "line2", "line3" ], "arrayJoinWithInterpolation": [ "you", "can", "{{myVar}}" ], "arrayOfObjects": [ { "name": "tom" }, { "name": "steve" } ] } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('arrayJoin', { joinArrays: '+' }); // -> "line1+line2+line3" i18next.t('arrayJoinWithInterpolation', { myVar: 'interpolate', joinArrays: ' ' }); // -> "you can interpolate" i18next.t('arrayOfObjects.0.name'); // -> "tom" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.arrayJoin, { joinArrays: '+' }); // -> "line1+line2+line3" i18next.t($ => $.arrayJoinWithInterpolation, { myVar: 'interpolate', joinArrays: ' ' }); // -> "you can interpolate" i18next.t($ => $.arrayOfObjects[0].name); // -> "tom" ``` {% endtab %} {% endtabs %} The returned value supports interpolation, plurals, nesting, ... `joinArrays` can be set to a value on init. --- # Source: https://www.i18next.com/overview/plugins-and-utils.md # Plugins and Utils > #### Official CLI > > ⭐ [i18next-cli](https://github.com/i18next/i18next-cli) > > The official, high-performance, all-in-one command-line tool for i18next. It handles key extraction, code linting, locale syncing, and type generation. It's built with modern technologies for maximum speed and accuracy. This is the recommended tool for all i18next projects. ![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9iS6Wm2hynS5H9Gj7j%2Fuploads%2Fgit-blob-e708561b54722a1662237a53dc8e3794d106fc93%2Fi18next_eco.jpg?alt=media) ## i18n formats While the i18next format (JSON based) is the preferred solution and widely supported in translation management tools like [locize.com](https://locize.com), you might prefer another exciting format, like: | **name** | **format** | **description** | | --------------------------------------------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [i18next-fluent](https://github.com/i18next/i18next-fluent) | fluent | i18nFormat plugin to use mozilla [fluent format](https://projectfluent.org/) with i18next | | [i18next-icu](https://github.com/i18next/i18next-icu) | ICU | i18nFormat plugin to use ICU format with i18next based on [yahoo/intl-messageformat](https://github.com/formatjs/formatjs/tree/master/packages/intl-messageformat) | | [i18next-polyglot](https://github.com/i18next/i18next-polyglot) | polyglot | i18nFormat plugin to use [airbnb/polyglot.js](https://github.com/airbnb/polyglot.js) format with i18next | | [i18next-shopify](https://github.com/Shopify/i18next-shopify) | Shopify json format | It allows developers to use the same format used by Shopify [apps](https://shopify.dev/docs/apps/checkout/best-practices/localizing-ui-extensions#how-it-works) and [themes](https://shopify.dev/docs/themes/architecture/locales/storefront-locale-files#usage) for localization | *In general, using an i18n format plugin, will remove the i18next specific format functionality, like plurals, interpolation, context, etc... you need to use the format requested in the used i18n format.* ## extraction tools | **name** | **description** | | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [**i18next-cli**](https://github.com/i18next/i18next-cli) | `i18next-cli` is a complete reimagining of the static analysis toolchain for the i18next ecosystem. It consolidates key extraction, type safety generation, locale syncing, linting, and cloud integrations into a single, cohesive, and blazing-fast CLI. | | [i18next-scanner](http://i18next.github.io/i18next-scanner) | Scan your code, extract translation keys/values, and merge them into i18n resource files. | | [i18next-parser](https://github.com/i18next/i18next-parser) | A simple command line and gulp plugin that lets you parse your code and extract the translations keys in it. | | [babel-plugin-i18next-extract](https://github.com/gilbsgilbs/babel-plugin-i18next-extract) | A babel plugin that can extract keys in JSONv4 format. | | [translation-check](https://github.com/locize/translation-check) | Nicely shows an overview of your translations in a UI. Check which keys are not yet translated. | | [i18next-typescript-parser](https://github.com/emersion/i18next-typescript-parser) | Extract i18next keys from a TypeScript codebase. | | [@i18next-selector/vite-plugin](https://github.com/ahrjarrett/i18next-selector/tree/main/packages/vite-plugin) | Vite plugin that watches for edits to your translation files, and uses HMR to generate the appropriate pluralization keys. Specifically made for TypeScript users who turn on `enableSelector: "optimize"` | | [@i18next-selector/codemod](https://github.com/ahrjarrett/i18next-selector/tree/main/packages/codemod) | TypeScript codemod for migrating your codebase from the string-based translation key to the new selector API. Works with `i18next` and `react-i18next`. For users who want to turn on either `enableSelector: true` or `enableSelector: "optimize"`. | ## utils | **util** | **type** | **description** | | ---------------------------------------------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [i18next-gettext-converter](https://github.com/i18next/i18next-gettext-converter) | converter | Converts gettext .mo or .po to 18next json format and vice versa. | | [csv2i18next](https://github.com/tmorozov/csv2i18next) | converter | Convert CSV files to JSON & YAML for i18next.js | | [i18next-json-csv-converter](https://github.com/andraaspar/i18next-json-csv-converter) | converter | Convert between CSV files and JSON format for i18next | | [resx2i18next](https://github.com/rolandpd/resx2i18next) | converter | Convert ResX-files to json resources compatible with i18next | | [i18nextResourceGenerator](https://github.com/DREEBIT/i18nextResourceGenerator) | extractor | Intellij IDEA Plugin for i18next resource generation | | [aurelia-i18next-parser](https://github.com/gooy/aurelia-i18next-parser) | extractor | Extracts i18n keys and values from source files. | | [grunt-i18next](https://github.com/i18next/grunt-i18next) | bundler | bundle language resource files for i18next | | [i18next-gettext-loader](https://github.com/openculinary/i18next-gettext-loader) | bundler | Convert gettext PO files into i18next JSON format during webpack builds | | [i18next-po-loader](https://github.com/queicherius/i18next-po-loader) | bundler | Load gettext PO files as i18next format directly in webpack | | [i18next-loader](https://github.com/kamilglod/i18next-loader) | bundler | webpack loader that can translate your code and generate bundle per each language | | [@alienfast/i18next-loader](https://github.com/alienfast/i18next-loader) | bundler | This webpack loader generates the resources structure necessary for i18next. The structure is webpacked with the client bundle at build time, thus avoiding loading any language resources via extra HTTP requests. | | [vite-plugin-i18next-loader](https://github.com/alienfast/vite-plugin-i18next-loader) | bundler | Vite plugin to client bundle i18next locales composited from one to many json/yaml files from one to many libraries. Zero config HMR support included. | | [webpack i18next-resource-store-loader](https://github.com/atroo/i18next-resource-store-loader) | bundler | This loader generates the resStore config needed for i18next to avoid loading language resources via extra HTTP requests. It generates this config given a directory. | | [ya-i18next-webpack-plugin](https://github.com/Perlmint/ya-i18next-webpack-plugin) | bundler | Yet another i18next webpack plugin. This plugin collects keys from webpack parsing phase, saves missing translations into specified path, copies translation files. | | [rollup-plugin-i18next-conv](https://github.com/perrin4869/rollup-plugin-i18next-conv) | bundler/converter | Import .po files with rollup | | [i18next-static-analysis](https://github.com/Cellule/i18next-static-analysis) | util | analyse statically your code to find calls to i18next and validates them for all your supported languages | | [i18next-json-sync](https://github.com/jwbay/i18next-json-sync) | util | Keep i18next JSON resource files in sync with source language file | | [i18next-locales-sync](https://github.com/felixmosh/i18next-locales-sync) | util | Syncs i18next locale resource files against a primary language. Supports namespaces, plural forms and key sorting. | | [eslint-plugin-i18next](https://github.com/edvardchen/eslint-plugin-i18next) | util | Make sure that all text shown are translated | | [i18next support for JetBrains IDEs](https://plugins.jetbrains.com/plugin/12981-i18n-support/) | IDE integration | Navigation, code completion, highlighting | | [i18next support for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension) | IDE integration | Extract, Visualize, Edit, Lint | | [i18next-hmr](https://github.com/felixmosh/i18next-hmr) | bundler / DX | Webpack / Vite HMR plugin to reload translation resources on client & server | | [translation-check](https://github.com/locize/translation-check) | util / DX | Nicely shows an overview of your translations in a UI. Check which keys are not yet translated. | | [i18next-v4-format-converter](https://github.com/i18next/i18next-v4-format-converter) | converter | Convert old i18next translation resources to the new [i18next v4 json format](https://www.i18next.com/misc/json-format#i-18-next-json-v4). Via CLI or programmatically. | | [i18next-v4-format-converter-web](https://i18next.github.io/i18next-v4-format-converter-web/) | online-converter | Convert old i18next translation resources to the new [i18next v4 json format](https://www.i18next.com/misc/json-format#i-18-next-json-v4) directly in your browser. | | [Intellij idea i18next support plugin](https://github.com/nyavro/i18nPlugin) | | Intellij idea i18next support plugin. | | [i18next-ts-loader](https://github.com/klis87/i18next-ts-loader) | bundler / DX | Webpack loader to fetch locale files with ES6 modules, supporting autocomplete, type checking, HMR and content based hashing | ## services Services that are known to fully support the i18next format (plural handling, ...) and sponsoring or contributing to the development of i18next. | **name** | **description** | | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [locize](http://locize.com) | localization as a service. Solves your localization process using i18next. | | [vaultrice](https://www.vaultrice.com/) | Vaultrice is a globally distributed key-value store with a familiar API. And the [i18next-vaultrice-backend](https://app.gitbook.com/o/-LGP0U4_PJEC15Hx0hOL/s/-LLE0SsGYsMKjrKtCQqp/) can be used as a primary, serverless backend for your translations or as caching layer for your existing i18next backend. | ## backend extenders | **backend** | **description** | | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [chained backend](https://github.com/i18next/i18next-chained-backend) | combine multiple of the existing backends for fallback and caching scenarios | | [i18next-multiload-backend-adapter](https://github.com/i18next/i18next-multiload-backend-adapter) | enable another backend's multiload behaviour of loading multiple lng-ns combinations with one request. This behaviour was removed from i18next >=v11.0.0 and could be enabled again by using this adapter | ## backends | **backend** | **description** | | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [localstorage backend](https://github.com/i18next/i18next-localstorage-backend) | This is a i18next cache layer to be used in the browser. It will load and cache resources from localStorage and can be used in combination with the [chained backend](https://github.com/i18next/i18next-chained-backend). | | [async storage backend](https://github.com/timbrandin/i18next-async-storage-backend) | This is a i18next cache layer to be used in react native. It will load and cache resources from AsyncStorage and can be used in combination with the [chained backend](https://github.com/i18next/i18next-chained-backend). | | [filesystem](https://github.com/i18next/i18next-fs-backend) |

backend layer for i18next used in Node.js and for Deno to load translations from the filesystem.

It can also be used as cache layer in combination with the chained backend, i.e. a chained backend together with the http backendor with the locize backend.

| | [http backend](https://github.com/i18next/i18next-http-backend) | backend layer for i18next using in node.js, in the browser and for deno (will use xhr or fetch) | | [xhr backend](https://github.com/i18next/i18next-xhr-backend) | backend layer for i18next using browsers xhr **deprecated** | | [fetch backend](https://github.com/perrin4869/i18next-fetch-backend) | backend layer for i18next using browsers fetch | | [fluent backend](https://github.com/i18next/i18next-fluent-backend) | backend to load [fluent syntax](https://projectfluent.org/) .ftl files via xhr | | [keys ondemand](https://github.com/kingatlas/i18next-keys-ondemand) | fetch missing keys on demand | | [mongodb backend](https://github.com/laodemalfatih/i18next-node-mongo-backend) | backend layer for i18next used in Node.js & Deno to load translations from the MongoDB. | | [Firestore backend](https://github.com/gregfenton/i18next-node-firestore-backend) | backend layer for i18next used in Node.js & Deno to load translations from Google's Firestore DB. | | [nodejs filesystem](https://github.com/i18next/i18next-fs-backend) | node.js backend layer for i18next using fs module to load resources from filesystem | | [nodejs filesystem (electron)](https://github.com/reZach/i18next-electron-fs-backend) | node.js backend for i18next using fs module to load resources securely in an electron app from filesystem | | [nodejs remote](https://github.com/i18next/i18next-node-remote-backend) | node.js backend layer for i18next using request module to load resources from another server | | [nodejs couchbase](https://github.com/kvaillant/i18next.couchbase) | i18next node.js backend layer for i18next using couchbase | | [Zanata nodejs backend](https://bitbucket.org/tagoh/i18next-node-zanata-backend) | i18next node.js backend layer for [Zanata](http://zanata.org) | | [i18next-firebase-backend](https://github.com/inteligator/i18next-firebase-backend) | i18next Backend Using Firebase | | [i18next-smart-bucket-backend](https://github.com/nekuz0r/i18next-smart-bucket-backend) | i18next backend for smart-bucket | | [locize backend](https://github.com/locize/i18next-locize-backend) | backend layer for [locize.com - localization as a service](http://locize.com) | | [vaultrice backend](https://app.gitbook.com/o/-LGP0U4_PJEC15Hx0hOL/s/-LLE0SsGYsMKjrKtCQqp/) | standalone backend layer or caching layer backed by [Vaultrice](https://www.vaultrice.com/) | | [service backend](https://github.com/timbrandin/i18next-service-backend) | backend layer for external services such as [spacetranslate.com - Simple Translation Service at Scale](https://spacetranslate.com) and [locize.com - localization as a service](http://locize.com). | | [locize nodejs backend](https://github.com/locize/i18next-node-locize-backend) | backend layer for [locize.com - localization as a service](http://locize.com) | | [service node backend](https://github.com/timbrandin/i18next-node-service-backend) | backend layer for external services such as [spacetranslate.com - Simple Translation Service at Scale](https://spacetranslate.com) and [locize.com - localization as a service](http://locize.com). | | [webpack import backend](https://gist.github.com/SimeonC/6a738467c691eef7f21ebf96918cd95f) | Use webpack code splitting to load files as a javascript bundle | | [Transifex backend](https://github.com/transifex/transifex-javascript/tree/master/packages/i18next) | i18next backend for Transifex Native | | [i18next-resources-to-backend](https://github.com/i18next/i18next-resources-to-backend) | This package helps to transform resources to an i18next backend. | ## language detector | **language** **detector** | **description** | | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | [universal (browser + nodejs)](https://github.com/UnlyEd/universal-language-detector) | Language detector that works universally (browser + server) - Meant to be used with a universal framework, such as Next.js | | [browser](https://github.com/i18next/i18next-browser-languageDetector) | language detector used in browser environment for i18next | | [http](https://github.com/i18next/i18next-http-middleware) | language detector for "any" http backend, also for Deno | | [nodejs koa](https://github.com/lxzxl/koa-i18next-detector) | A i18next language detecting plugin for Koa framework. | | [@os-team/i18next-react-native-language-detector](https://gitlab.com/os-team/libs/utils/-/tree/main/packages/i18next-react-native-language-detector) | The i18next language detector, which is used to detect the user's language in React Native. | | [react native localization settings](https://github.com/jakex7/react-native-localization-settings) | language detector for React Native that uses native per-app language API to enable language change in system preferences. | | [react native](https://github.com/DylanVann/i18next-react-native-language-detector) | language detector for React Native. | | [react native Async Storage](https://github.com/0xClpz/i18next-react-native-async-storage) | language detector for React Native that saves the user's choice in Async Storage, used for persistence. | | [electron](https://github.com/neruchev/i18next-electron-language-detector) | language detector for electron apps. | | [CLI](https://github.com/neet/i18next-cli-language-detector) | language detector for CLI. | ## post processors | **post** **processor** | **description** | | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | [sprintf post processor](https://github.com/i18next/i18next-sprintf-postProcessor) | sprintf post processor for i18next. | | [interval plurals](https://github.com/i18next/i18next-intervalPlural-postProcessor) | interval based plurals like. "One Item", "A few items", "A lot of items" | | [i18next-react-postprocessor](https://github.com/orzechowskid/i18next-react-postprocessor) | embed React elements inside your i18next translation strings | | [i18next-korean-postposition-processor](https://github.com/Perlmint/i18next-korean-postposition-processor) | i18next post-processor for processing korean postposition | | [i18next-pseudo](https://github.com/MattBoatman/i18next-pseudo) | i18next post-processor for pseudolocalization of strings | | [i18next-emoji-postprocessor](https://github.com/i18next/i18next-emoji-postprocessor) | i18next postProcessor plugin for Node.js and in the browser that replaces all words with emojis. | ## loggers Only the integrated console logger is available for now. ## Create your own plugin Want to create your own plugins? Learn more [here](https://www.i18next.com/misc/creating-own-plugins). --- # Source: https://www.i18next.com/principles/plugins.md # Plugins i18next [comes with a lot of modules](https://www.i18next.com/overview/plugins-and-utils) to enhance the features available. There are modules to: * [load resources](https://www.i18next.com/overview/plugins-and-utils#backends), eg. via [http fetch](https://github.com/i18next/i18next-http-backend) or from [filesystem](https://github.com/i18next/i18next-fs-backend) (Node.js, Deno) * [cache resources](https://www.i18next.com/how-to/caching) using eg. [i18next-localstorage-backend](https://github.com/i18next/i18next-localstorage-backend) * [detect user language](https://www.i18next.com/overview/plugins-and-utils#language-detector) by querystring, navigator, cookie, … * [post processors](https://www.i18next.com/overview/plugins-and-utils#post-processors) to further manipulate values, eg. to add sprintf support ```javascript import i18next from 'i18next'; import Backend from 'i18next-http-backend'; import LanguageDetector from 'i18next-browser-languagedetector'; import sprintf from 'i18next-sprintf-postprocessor'; i18next .use(Backend) // or any other backend implementation .use(LanguageDetector) // or any other implementation .use(sprintf) // or any other post processor .init(options); ``` For usage details please read the documentation of the plugin (readme file in the repository or npm website). {% hint style="info" %} If you're not sure on why you may need such a plugin, have a look at the [First setup help](https://www.i18next.com/overview/first-setup-help) page. {% endhint %} {% hint style="success" %} [Do you like to create your own plugin?](https://www.i18next.com/misc/creating-own-plugins) {% endhint %} --- # Source: https://www.i18next.com/translation-function/plurals.md # Plurals Plural can be combined with interpolation, context, ... These plurals are streamlined with the one used in the [Intl API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules).\ \=>*You need to* [*polyfill*](https://github.com/eemeli/intl-pluralrules) *the* [*Intl.PluralRules*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules) *API.* {% tabs %} {% tab title="JavaScript" %} {% hint style="danger" %} Note: The variable name must be `count`.\ And it must be present: `i18next.t('key', {count: 1});`\ There will be **no** fallback to the `'key'` value if count is not provided. {% endhint %} {% endtab %} {% tab title="TypeScript" %} {% hint style="danger" %} Note: The variable name must be `count`.\ And it must be present: `i18next.t($ => $.key, {count: 1});`\ There will be **no** fallback to the `'key'` property if count is not provided. {% endhint %} {% endtab %} {% endtabs %} {% hint style="info" %} If you need multiple counts, take a look at [nesting](https://www.i18next.com/nesting#passing-options-to-nestings) {% endhint %} {% hint style="info" %} We provide the ability to have special translation for `{count: 0}`, so that a more natural language can be used. If the count is 0, and a `_zero` entry is present, then it will be used instead of the language plural suffix. {% endhint %} {% hint style="info" %} 🎓 Check out this topic in the [i18next crash course video](https://youtu.be/SA_9i4TtxLQ?t=485). {% endhint %} ## Singular / Plural keys ```javascript { "key_one": "item", "key_other": "items", "keyWithCount_one": "{{count}} item", "keyWithCount_other": "{{count}} items" } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('key', {count: 0}); // -> "items" i18next.t('key', {count: 1}); // -> "item" i18next.t('key', {count: 5}); // -> "items" i18next.t('key', {count: 100}); // -> "items" i18next.t('keyWithCount', {count: 0}); // -> "0 items" i18next.t('keyWithCount', {count: 1}); // -> "1 item" i18next.t('keyWithCount', {count: 5}); // -> "5 items" i18next.t('keyWithCount', {count: 100}); // -> "100 items" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key, {count: 0}); // -> "items" i18next.t($ => $.key, {count: 1}); // -> "item" i18next.t($ => $.key, {count: 5}); // -> "items" i18next.t($ => $.key, {count: 100}); // -> "items" i18next.t($ => $.keyWithCount, {count: 0}); // -> "0 items" i18next.t($ => $.keyWithCount, {count: 1}); // -> "1 item" i18next.t($ => $.keyWithCount, {count: 5}); // -> "5 items" i18next.t($ => $.keyWithCount, {count: 100}); // -> "100 items" ``` {% endtab %} {% endtabs %} {% hint style="warning" %} With [v21.0.0](https://www.i18next.com/misc/migration-guide#json-format-v4-pluralization) a new [JSON format v4](https://www.i18next.com/misc/json-format#i-18-next-json-v4) was introduced that changed the suffixes.\ To convert your existing translations to the new v4 format, have a look at [i18next-v4-format-converter](https://github.com/i18next/i18next-v4-format-converter) or [this web tool](https://i18next.github.io/i18next-v4-format-converter-web/). {% endhint %} ## Languages with multiple plurals Sample uses arabic which has 5 plural forms beside the singular. keys ```javascript { "key_zero": "zero", "key_one": "singular", "key_two": "two", "key_few": "few", "key_many": "many", "key_other": "other" } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('key', {count: 0}); // -> "zero" i18next.t('key', {count: 1}); // -> "singular" i18next.t('key', {count: 2}); // -> "two" i18next.t('key', {count: 3}); // -> "few" i18next.t('key', {count: 4}); // -> "few" i18next.t('key', {count: 5}); // -> "few" i18next.t('key', {count: 11}); // -> "many" i18next.t('key', {count: 99}); // -> "many" i18next.t('key', {count: 100}); // -> "other" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key, {count: 0}); // -> "zero" i18next.t($ => $.key, {count: 1}); // -> "singular" i18next.t($ => $.key, {count: 2}); // -> "two" i18next.t($ => $.key, {count: 3}); // -> "few" i18next.t($ => $.key, {count: 4}); // -> "few" i18next.t($ => $.key, {count: 5}); // -> "few" i18next.t($ => $.key, {count: 11}); // -> "many" i18next.t($ => $.key, {count: 99}); // -> "many" i18next.t($ => $.key, {count: 100}); // -> "other" ``` {% endtab %} {% endtabs %} ## How to find the correct plural suffix? You can use this small utility to get the correct plural suffixes. [source code](https://jsfiddle.net/6bpxsgd4) *Or try* [*translation-check*](https://github.com/locize/translation-check)*, it shows an overview of your translations in a nice UI. It shows also the appropriate plural forms.* #### Or you use a smart translation management system, like [locize](https://locize.com) ![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-L9iS6Wm2hynS5H9Gj7j%2F-MX2rpXr6D3UrjwHPOqm%2F-MX2s2PKNH3dqXxCShCx%2Flocize_plurals.png?alt=media\&token=a93a4d64-6c13-4e19-9d1f-c9ae9c898e8f) ## Ordinal plurals There is also support for ordinal numbers *(referring to the ordering or ranking of things, e.g. "1st", "2nd", "3rd" in English)*. The `ordinal` option (and the \_ordinal suffix) tells the helper to use the ordinal digit to determine the plurality key used. E.g., for "32" the ordinal digit is "2" so `key_two` is used. keys ```javascript // i.e. english { "key_ordinal_one": "{{count}}st place", // 1st, 21st, 31st "key_ordinal_two": "{{count}}nd place", // 2nd, 22nd, 32nd "key_ordinal_few": "{{count}}rd place", // 3rd, 23rd, 33rd "key_ordinal_other": "{{count}}th place" // 4th, 5th, 24th, 11th } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('key', { count: 1, ordinal: true }); // -> "1st place" i18next.t('key', { count: 21, ordinal: true }); // -> "21st place" i18next.t('key', { count: 2, ordinal: true }); // -> "2nd place" i18next.t('key', { count: 11, ordinal: true }); // -> "11th place" i18next.t('key', { count: 32, ordinal: true }); // -> "32nd place" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key, { count: 1, ordinal: true }); // -> "1st place" i18next.t($ => $.key, { count: 21, ordinal: true }); // -> "21st place" i18next.t($ => $.key, { count: 2, ordinal: true }); // -> "2nd place" i18next.t($ => $.key, { count: 11, ordinal: true }); // -> "11th place" i18next.t($ => $.key, { count: 32, ordinal: true }); // -> "32nd place" ``` {% endtab %} {% endtabs %} ## Interval plurals Want to define phrases expressing the number of items lies in a range. Like *a few items* or *a lot of items*. You will need to add a post processor: [i18next-intervalplural-postprocessor](https://github.com/i18next/i18next-intervalplural-postprocessor) ```javascript import i18next from 'i18next'; import intervalPlural from 'i18next-intervalplural-postprocessor'; i18next .use(intervalPlural) .init(i18nextOptions); ``` keys ```javascript { "key1_one": "{{count}} item", "key1_other": "{{count}} items", "key1_interval": "(1)[one item];(2-7)[a few items];(7-inf)[a lot of items];", "key2_one": "{{count}} item", "key2_other": "{{count}} items", "key2_interval": "(1)[one item];(2-7)[a few items];" } ``` sample {% tabs %} {% tab title="JavaScript" %} ```javascript i18next.t('key1_interval', {postProcess: 'interval', count: 1}); // -> "one item" i18next.t('key1_interval', {postProcess: 'interval', count: 4}); // -> "a few items" i18next.t('key1_interval', {postProcess: 'interval', count: 100}); // -> "a lot of items" // not matching into a range it will fallback to // the regular plural form i18next.t('key2_interval', {postProcess: 'interval', count: 1}); // -> "one item" i18next.t('key2_interval', {postProcess: 'interval', count: 4}); // -> "a few items" i18next.t('key2_interval', {postProcess: 'interval', count: 100}); // -> "100 items" ``` {% endtab %} {% tab title="TypeScript" %} ```typescript i18next.t($ => $.key1_interval, {postProcess: 'interval', count: 1}); // -> "one item" i18next.t($ => $.key1_interval, {postProcess: 'interval', count: 4}); // -> "a few items" i18next.t($ => $.key1_interval, {postProcess: 'interval', count: 100}); // -> "a lot of items" // not matching into a range it will fallback to // the regular plural form i18next.t($ => $.key2_interval, {postProcess: 'interval', count: 1}); // -> "one item" i18next.t($ => $.key2_interval, {postProcess: 'interval', count: 4}); // -> "a few items" i18next.t($ => $.key2_interval, {postProcess: 'interval', count: 100}); // -> "100 items" ``` {% endtab %} {% endtabs %} {% hint style="danger" %} Note: The regex for the interval entry has changed in `v3.0.0` of `i18next-intervalPlural-postProcessor` so if you are using the older versions, you need to use the curly braces instead of the bracketes, e.g.: ```javascript "key2_interval": "(1){one item};(2-7){a few items};" ``` {% endhint %} --- # Source: https://www.i18next.com/overview/supported-frameworks.md # Supported Frameworks > **Official CLI** > > ⭐ [i18next-cli](https://github.com/i18next/i18next-cli) > > The official, high-performance, all-in-one command-line tool for i18next. It handles key extraction, code linting, locale syncing, and type generation. It's built with modern technologies for maximum speed and accuracy. This is the recommended tool for all i18next projects. ![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9iS6Wm2hynS5H9Gj7j%2Fuploads%2Fgit-blob-e708561b54722a1662237a53dc8e3794d106fc93%2Fi18next_eco.jpg?alt=media) This list is not officially maintained; information here is contributed by the library maintainers themselves. Consult their GitHub page for details on issues and implementation. Lastly, some of those libraries might stop being updated without further notice, while others warn it in their pages. In the latter scenario, they're tagged as *deprecated* below. | Framework | Home | Extra details | | --------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Flutter | [i18next](https://pub.dev/packages/i18next) | Also supports Flutter's LocalizationsDelegate | | React | [react-i18next](https://github.com/i18next/react-i18next) | A powerful **internationalization** framework for **React** / **React Native** which is based on i18next. | | Svelte | [svelte-i18next](https://github.com/NishuGoel/svelte-i18next) | A Svelte wrapper for i18next | | Next.js | [next-i18next](https://github.com/i18next/next-i18next) | The easiest way to translate your Next.js apps | | Next.js | [ni18n](https://jcquintas.gitbook.io/ni18n/) | An easy to use integration for [Next.js](https://nextjs.org) to enable i18next translations on your application with support for SSR, SSG and Client translation loading. | | Next.js | [next-right-now](https://github.com/UnlyEd/next-right-now) | Flexible production-grade boilerplate with Next.js 9 and Zeit Now, with pre-configured Sentry, cookies, Amplitude, Emotion, FontAwesome, GraphQL/GraphCMS (Apollo), Bootstrap (Reactstrap), **i18next (Locize)**, Jest, Cypress (E2E tests) and CI/CD (GH Actions), with full TypeScript support and support for B2B multi-tenants web apps (monorepo) | | Remix | [remix-i18next](https://github.com/sergiodxa/remix-i18next) | The easiest way to translate your Remix apps. | | AngularJS | [ng-i18next](https://github.com/i18next/ng-i18next) | Angular1/2 provider, directive and filter | | Angular | [ng2-i18next](https://github.com/actimeo/ng2-i18next) *(actimeo)* | Angular2 service and directive | | Angular | [angular-i18next](https://github.com/Romanchuk/angular-i18next) *(Romanchuk)* | Angular 2.0+ integration (service, pipes, events) | | Vue.js | [i18next-vue](https://github.com/i18next/i18next-vue) | Vue 2 and Vue 3+ support | | Vue.js | [vue-i18next](https://github.com/rse/vue-i18next) *(rse)* | | | Vue.js | [vue-i18next2](https://github.com/bluelovers/vue-i18next2) *(bluelovers)* | | | Solid.js | [@mbarzda/solid-i18next](https://github.com/mbarzda/solid-i18next) | | | Omi | [omi-i18n](https://github.com/i18next/omi-i18n) | i18n solution for Omi | | Inferno | [inferno-i18next](https://www.npmjs.com/package/inferno-i18next) | **(deprecated/gone)** Translation utility for Inferno components | | Elm | [elm-i18next](https://github.com/ChristophP/elm-i18next) | | | Node/Deno HTTP server | [http-middleware](https://github.com/i18next/i18next-http-middleware) | Middleware to be used with Node.js web frameworks like Express or Fastify, and also for Deno. | | Express | [i18next-express-middleware](https://github.com/i18next/i18next-express-middleware) | **(deprecated)** Middleware for the Express HTTP server/framework (Node) | | Koa | [koa-i18next-middleware](https://github.com/lxzxl/koa-i18next-middleware) | Middleware for the Koa framework | | Hapi | [hapi-i18next](https://github.com/kenkouot/hapi-i18next) | | | jQuery | [jquery plugin](https://github.com/i18next/jquery-i18next) | Plugin to use i18next on jQuery selectors | | HTML5 | [loc-i18next](https://github.com/mthh/loc-i18next) | Plugin to use the same API as `jquery-i18next`, but with HTML5 selectors | | Aurelia | [aurelia-i18next](https://github.com/aurelia/i18n) | An Aurelia-Wrapper | | Meteor | [i18next-meteor](https://github.com/ckir/i18next-meteor) | i18next repackaged for Meteor | | Polymer | [i18next-element](https://github.com/Polymer/i18next-element) | **(deprecated)** Polymer-friendly interface | | Ember.js | [ember-i18next](https://github.com/OCTRI/ember-i18next) | Integrates i18next into Ember CLI apps | | Ember.js | [ember-cli-i18next](https://github.com/recipher/ember-cli-i18next) | Ember CLI addon | | Knockout.js | [i18next-ko](https://github.com/leMaik/i18next-ko) | KnockoutJS bindings | | Phaser | [phaser-i18next](https://github.com/orange-games/phaser-i18next) | Plugin for the HTML5 game framework | | Construct 3 | [c3-i18next](https://github.com/nagyv/c3-i18next/) | Translation plugin for the Construct 3 game software | | Metalsmith | [metalsmith-i18next](https://github.com/macprog-guy/metalsmith-i18next) | **(deprecated)** Metalsmith plugin to easily create multiple localised branches of your site | | .NET | [I18Next.Net](https://github.com/DarkLiKally/I18Next.Net) | Library based on .NET Standard 2.0 with a rich feature-set like the original i18next, supporting .NET DI and translations; also comes with plugin support | | .NET | [i18next-net](https://github.com/leonardobaggio/i18next-net) | .NET C# class | | PHP | [kopfwelt/i18next-php](https://github.com/Acceptd/i18next-php) | **(deprecated)** Class for basic i18next functionality (2016). There's also a [fork by Mika-](https://github.com/Mika-/i18next-php) (2017) | | PHP | [alpakaio/i18next-php](https://github.com/alpakaio/i18next-php) | Class for basic i18next functionality (2021) | | PHP | [it-tem-papa/i18next-php](https://https/github.com/it-tem-papa/i18next-php) | Class for basic i18next functionality (2023) | | Rails | [i18next-rails](https://github.com/roblander/i18next-rails) | Asset gem containing bundled i18next JavaScript files | | Rails | [rails-asset-localization](https://github.com/nicolai86/rails-asset-localization) | **(deprecated)** Asset pipeline localization using i18next for rails 3.2 & 4 | | Dart | [i18next](https://github.com/nubank/i18next) | An adaptation of i18next standard for Dart with support for Flutter localization techniques. | | Elm | [elm-i18next](https://github.com/ChristophP/elm-i18next) | Functions for working with dynamically loaded translations in Elm. | | iOS | [i18next-ios](https://github.com/i18next/i18next-ios) | | | Android | [i18next-android](https://github.com/i18next/i18next-android) | | | Web Components | [kwc-i18next](https://github.com/successk/kwc-i18next) | Web component interfacing i18next | | Web Components | [i18next-wc](https://github.com/spurreiter/i18next-wc) | Web component interfacing i18next and Intl | | Marko | [marko-i18next](https://github.com/gunjam/marko-i18next) | Components for Marko templates | | Virtual DOM | [i18nextify](https://github.com/i18next/i18nextify) | One-liner script to enable i18next on any site not using its own Virtual DOM | | Handlebars | [handlebars-i18next](https://github.com/UUDigitalHumanitieslab/handlebars-i18next) | Helper that lets you translate inside your templates | | Handlebars | [handlebars-i18n](https://github.com/fwalzel/handlebars-i18n) | Adds the features of i18next and Intl to Handlebars | | lit-html/lit-element | [lit-i18n](https://github.com/colscott/lit-i18n) | i18next translations using lit-html directives | | Solid | [solid-i18next](https://github.com/mbarzda/solid-i18next) | Small library which covers i18next for Solid applications | | Astro | [astro-i18next](https://github.com/yassinedoghri/astro-i18next) | An astro integration of i18next + some utility components to help you translate your astro websites! | | Astro | [@gutenye/astro-i18next](https://github.com/gutenye/astro-i18next) | An Astro integration for i18next with fast to load, emit zero JS. | ``` | ``` \| Go | [go-i18next](https://github.com/yuangwei/go-i18next) | Go implementation of i18next | ## Supported Environments i18next supports the two most recent versions of evergreen browsers (Chrome, Firefox, Safari, etc). It also runs in Node and Deno. --- # Source: https://www.i18next.com/misc/testimonials.md # Testimonials

<<How we translated the Avocode website written in Next.js with the i18next package

...>>

https://locize.com/customers.html#avocodeavocode.jpg

<<...

Using i18next as our international framework enables us to use the same technology around our whole software stack, regardless the actual backend or framework we use. locize is the icing on the cake – it made translation management unspeakably easier.

...>

https://locize.com/customers.html#logiscoollogiscool.jpg

<<...

We have separated help pages for en, ja, zh, zh-TW. i18next automatically switched the link to appropriated lang help’s page

....>>

https://locize.com/customers.html#worldshoppingworldshopping.jpg

<<Using locize and its tools (i18next) saves us a LOT of time by not thinking about the texts and focusing on development only.

...>>

https://locize.com/customers.html#fidelifideli.jpg

<<...

We used i18next with React and were translating JSON files by hand, which was really cumbersome.

...>>

https://locize.com/customers.html#realadvisorrealadvisor.jpg

<<...

Switching to locize was pretty straightforward, thanks to i18next and the possiblity to import JSON files in the admin dashboard.

...>>

https://locize.com/customers.html#photogramphotogram.jpg

<<...

Support was also very reactive and fixed a bug in under 1 hour after it was reported. I would recommend for use with i18next on a React.js platform.>>

https://locize.com/customers.html#beelancebeelance.jpg

<<...

We use i18next as an internationalization framework. locize being perfectly integrated with the framework become a really good translation management tool for us.

...>>

https://locize.com/customers.html#2captcha2captcha.jpg

<<...

Using i18next in conjunction with react-i18next (there’s an Angular, Vue and even jQuery support, among others) will help you maintain expressive code that’s i18n ready.

...>>

https://dutzi.party/utilizing-i18next/dutzi.jpg
--- # Source: https://www.i18next.com/misc/the-history-of-i18next.md # The history of i18next ## How all began - back in 2011 All started back in 2011 when we were in search for an internationalization library that meets our demand - allowing to run both on server side [Node.js](https://nodejs.org) and on our client side single page applications. ![The first i18next landing page in 2011: http://i18next.github.io/i18next/](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-L9iS6Wm2hynS5H9Gj7j%2F-MWdOmt-kPMV5ayeSJS0%2F-MWdRrI6y185C4fZ2oAj%2Fi18next%20first%20website.jpg?alt=media\&token=1e021050-74ca-4ba5-b635-731acc9c8b6a) I18next was born and fastly grown to one of the most used frameworks for translating web applications and in [Node.js](https://nodejs.org). The response of the community was amazing and a fast growing [ecosystem](https://www.i18next.com/overview/supported-frameworks) established itself around i18next. ![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9iS6Wm2hynS5H9Gj7j%2Fuploads%2FkRlGe60RN6IqsPGmslP0%2Fi18next-logo.png?alt=media\&token=68e76524-d839-448d-9c25-3dbd0fb0e902) ## V2 With v2 of i18next, released in 2015, we completely rebuild i18next to be as extensible as possible. {% hint style="success" %} Since v1 all newer releases can be dropped in as a replacement for v1 by just adding a minimal compatibility layer. The v1 API is still actively tested, [here](https://github.com/i18next/i18next/blob/master/test/backward/v1.11.1.compat.js). {% endhint %} Shortly after the i18next v2 release in 2015, another big community driven i18next extension was released: [react-i18next](https://react.i18next.com/). ![https://www.npmtrends.com/react-i18next-vs-i18next](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9iS6Wm2hynS5H9Gj7j%2Fuploads%2Fh3Q20Tp231ybELcD2Xux%2Fimage.png?alt=media\&token=9e88cdb9-4d74-4986-b8ca-6e87e0d1f73f) ## Internationalization (i18n) is not enough Our community provided us with great feedback. Out of that response and our own experiences we learnt providing instrumentation for doing proper internationalization just is not enough. Helping developers to get their applications translated is great - but there is more to it. * How do you integrate any translation services / agencies? * How do you keep track of new or removed content? * How do you handle proper versioning? * How do you deploy translation changes without deploying your complete application? * and a lot more... ### [locize](https://locize.com) to the rescue Having created the foundation with i18next it was a long journey to [**localization as a service**](https://locize.com). * [Easy to integrate](https://docs.locize.com/integration/instrumenting-your-code#i-18-next) * Continuous deployment? [Continuous localization](https://locize.com/how-it-works.html#continouslocalization) with a [CDN](https://docs.locize.com/whats-inside/cdn-content-delivery-network)! * Manage the translation files with ease * [Order professional translations](https://docs.locize.com/guides-tips-and-tricks/working-with-translators/localistars) * Analytics & Statistics * [Profit from a content delivery network](https://docs.locize.com/whats-inside/cdn-content-delivery-network) * [Versioning of your translations](https://docs.locize.com/more/versioning) * [Automatic and On-Demand Machine Translation](https://docs.locize.com/whats-inside/auto-machine-translation) * [Risk free: Take your data with you](https://docs.locize.com/more/general-questions/how-is-locize-different-from-the-alternatives#service-lock-in) * [Transparent and fair pricing](https://locize.com/pricing.html) * and a lot more... ![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-L9iS6Wm2hynS5H9Gj7j%2F-MWdUEyoy5QeqajUerTJ%2F-MWdWZZN7y942v91ZzRA%2Ftransform%20your%20localization%20process%20small.png?alt=media\&token=5e17754f-57c6-4cdb-86cb-0c779590776c) {% hint style="success" %} 🙏 **The best way to directly support the future of i18next is to use** [**locize**](https://locize.com)**.** 💙 {% endhint %} > *<\>* [read the full interview](https://www.websiteplanet.com/blog/interview-locize/). --- # Source: https://www.i18next.com/principles/translation-resolution.md # Translation Resolution The process of translating keys is the heart of i18next, and as such this document should serve as a guide to the overall process by which i18next attempts to translate your keys into the appropriate content for a given location, be it on a specific page and/or for a user in a particular region of the world. ## Core Elements ### Keys A key is not unlike a key in any object structure, like JSON or a dictionary in Python. A key is a specific set of text that, when looked up, provides a corresponding value. #### Example: ``` "key": "value" ``` This example shows the very core concept of what a key is capable of expressing, but the ability to express this formally is very important, as it allows us to expand its utility going forward. Keys are a very powerful way of specifying the different forms of an element, be it a piece of text or other forms of content, into its potential variations. For more information on all of the different ways keys can be used, please see the documentation for the [translation function](https://www.i18next.com/translation-function/essentials). ### Languages A language is what you would expect: the idiom to be used for translating a key. When we look for a key, we specify a language with it, so that we know which version of the key to use. The important thing to note about this is that *if a key is not found, you can* [*gracefully fall back to a parent language or a default one*](https://www.i18next.com/principles/fallback). In i18next, a language is a particular value which can be known as a "code". A language code can be expressed in variety of ways, but they generally look something like the following example: #### Example: ``` "en-US" ``` Long story short, you'll either use a "pure language" code, such as `en` or `de` for English and German, or a language + a variant identification, such as `pt-BR` for the Brazilian Portuguese, `es-419` for Latin American Spanish, or `zh-cmn-Hant-HK` which is Chinese in the Mandarin variation, written in the Traditional script, as used in Hong Kong. For more information on the subject, it is recommended to read up on [IETF Language Codes](https://en.wikipedia.org/wiki/IETF_language_tag). ### Namespaces A namespace can be thought of as logical groupings of different sets of translations. For instance, you might have a 3 sections of your app, each with many individual pages in them, but only 2 sections share similar content. If that's the case, instead of loading all of the keys for all 3 sections, you can instead load keys from a "shared" set of translations and break up the other sections into much smaller sets of keys, loading them as needed. In a given namespace you could have a set of languages, each with its own set of keys. #### Example ``` "common" // Things that are reused everywhere, like "Confirm" and "Cancel" on buttons "validation" // All validation text, like "email address not valid" in a form "glossary" // Words we want to be reused consistently, like key words in your app ``` For more information on the concept of namespaces and how you might want to use them, please see their [documentation](https://www.i18next.com/principles/namespaces). ## Resolution Order By default, when translating a key, i18next tries the first combination of your **namespace**, **language**, and **key**. However, if that does not work, i18next attempts to [gracefully fallback](https://www.i18next.com/principles/fallback) to a different combination in order to provide the most relevant translation for a piece of content. The core idea is to try to find a key that exists, from *most specific to least specific*. Here is the process that it uses by default: #### 1. Similar Keys If the specific key is not found, i18next tries to match the key you are looking for with a similar key, looking for a key that best fits the **plural** form, **context**, and **singular** form in that order. #### 2. Languages If a key is not found, i18next then walks through the list of languages, which consists of the **current language(s)** and the **fallback language(s)**. #### 3. Namespaces If no language matches, i18next walks through the list of namespaces, which similarly to languages, consists of the **current namespace(s)** and the **fallback namespace(s)**. #### 4. Fallback Keys If that key is still not found, i18n will walk through this process with the **fallback key(s)**, if specified. #### 5. Key Not Found If the key is still not found, i18n will then return the **key itself**, that being the first key specified if you also specified fallback keys. For more information on each method of fallback, please see the [fallback documentation](https://www.i18next.com/principles/fallback). --- # Source: https://www.i18next.com/overview/typescript.md # TypeScript {% hint style="info" %} Note: TypeScript support has improved significantly in v25.4 with the `enableSelector` option. As of v25.4, this option is off by default, but will be set to `true` by default in v26, with tentative plans to deprecate type-level support for the "string-based" (non-selector) API in v27. {% endhint %} i18next has embedded type definitions. If you want to enhance IDE Experience and prevent errors (such as type coercion), you should follow the instructions below in order to get the t function fully-type safe (keys and return type). {% hint style="info" %} This is an optional feature and may affect the **compilation time** depending on your project's size. If you opt not to leverage the type enhancements suggested here, you can ignore this section. {% endhint %} {% hint style="info" %} Make sure your tsconfig compilerOptions has the [`strict`](https://www.typescriptlang.org/tsconfig#strict) flag or the [`strictNullChecks`](https://www.typescriptlang.org/tsconfig#strictNullChecks) set to `true`.\ The newest i18next versions only support **TypeScript v5**. Older TypeScript versions are not supported any longer with `i18next > v23`.\ ⚠ *To use it with TypeScript v4, use `i18next@22.5.1`.* {% endhint %} {% hint style="warning" %} If your project spans multiple i18next instances with different translation resources, it might take a little extra work to set up type-safe translations. For each instance you'll need to create a separate `tsconfig.json` and `i18next.d.ts` file. See [i18next/i18next-monorepo](https://github.com/i18next/i18next-monorepo) for an example. {% endhint %} {% hint style="success" %} [Here](https://locize.com/blog/i18next-typescript/) you'll find a simple guide on how to best use TypeScript for i18next.\ Discover how to unleash the full potential of i18next in your TypeScript applications by mastering type-safe translations, ensuring accurate localization and eliminating runtime errors.\ [![](https://286188001-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9iS6Wm2hynS5H9Gj7j%2Fuploads%2FfAvnEUKGMGt0fFNY4PYs%2Ftitle.jpg?alt=media\&token=02f1d2c4-fbb1-4bb7-9ff4-a6312cd40ef4)](https://locize.com/blog/i18next-typescript/) {% endhint %} {% embed url="" %} ## Create a declaration file TypeScript definitions for i18next can be extended by using [Type Augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) and [Merging Interfaces](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces). So the first step is creating a declaration file (`i18next.d.ts`), for example: ```typescript // import the original type declarations import "i18next"; // import all namespaces (for the default language, only) import ns1 from "locales/en/ns1.json"; import ns2 from "locales/en/ns2.json"; declare module "i18next" { // Extend CustomTypeOptions interface CustomTypeOptions { // custom namespace type, if you changed it defaultNS: "ns1"; // custom resources type resources: { ns1: typeof ns1; ns2: typeof ns2; }; // other } } ``` Or, if you want to include all namespaces at once, you can use our preferred approach: **`i18n.ts`** ```typescript export const defaultNS = "ns1"; export const resources = { en: { ns1, ns2, }, } as const; i18n.use(initReactI18next).init({ lng: "en", ns: ["ns1", "ns2"], defaultNS, resources, }); ``` **`i18next.d.ts`** ```typescript import { resources, defaultNS } from "./i18n"; declare module "i18next" { interface CustomTypeOptions { defaultNS: typeof defaultNS; resources: typeof resources["en"]; } } ``` **We recommend creating a `@types` directory under `src` or above it and placing all your type declarations there. E.g.: `@types/i18next.d.ts`** ### Some examples * [various examples](https://github.com/locize/i18next-typescript-examples) *(from simple i18next only to react-i18next prod ready)* * [react-i18next](https://github.com/i18next/react-i18next/tree/master/example/react-typescript) * [next-i18next](https://github.com/i18next/next-i18next/tree/master/examples/simple) * [next-13-app-dir-i18next-example-ts](https://github.com/i18next/next-13-app-dir-i18next-example-ts) * [react-i18next-example-app-ts](https://github.com/locize/react-i18next-example-app-ts) ### Custom Type Options We provide a few options that can improve TypeScript for `i18next`. All options come with default values, and if you want to change them, you just need to add them under `CustomTypeOptions` interface in your i18next type declaration file (`i18next.d.ts`). | option | default | description | | ------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | enableSelector | false |

if set to true, pass a selector function as the first argument to t to make a translation query.

if set to "optimize", i18next is capable of handling arbitrarily large translation sets without slowing down IDE performance. Keeping in mind with this setting, translation keys will not be modified, so you'll need to specify the correct key for pluralization or use a tool like @i18next-selector/vite-plugin.

| | defaultNS | 'translation' | Default namespace. This is more practical in React applications, so when you call `useTranslation()` hooks without passing the namespace, it will infer the types for the `translation` namespace. | | resources | object | Resources to initialize with. This is the most important option that is used to infer the appropriate keys and return types. | | fallbackNS | false | Fallback namespace. string or array of namespaces to lookup key if not found in given namespace. [See NS fallback docs](https://www.i18next.com/principles/fallback#namespace-fallback). | | keySeparator | '.' | Char to separate keys. | | nsSeparator | ':' | Char to split namespace from key | | pluralSeparator | '\_' | Char to split namespace from key | | contextSeparator | '\_' | Char to split context from key | | returnNull | true | Allows null values as valid translation. | | returnObjects | false | Allows objects as valid translation result | | compatibilityJSON | 'v4' | Only 'v4' is supported. Enable plurals keys support. See [Plurals docs](https://www.i18next.com/translation-function/plurals). | | allowObjectInHTMLChildren | false | Flag that allows HTML elements to receive objects. This is only useful for React applications where you pass objects to HTML elements so they can be replaced to their respective interpolation values (mostly with Trans component) | | interpolationPrefix | '{{' | Prefix for interpolation | | interpolationSuffix | '}}' | Suffix for interpolation | | strictKeyChecks | false | Flag that enables strict key checking even if a `defaultValue` has been provided. This ensures all calls of `t` function don't accidentally use implicitly missing keys. | ## Testing ### Mocking the selector function For testing purposes, you might find yourself wanting to mock the `t` function. `i18next` exports a function called `keyFromSelector` to make this easier. Here's an example of how you can use it: ```typescript import { keyFromSelector } from "i18next"; const mockT = (selector: ($: Record) => any) => keyFromSelector(selector); const mockTranslation = mockT($ => $.abc.def); console.log(mockTranslation); // => "abc.def" ``` ## Troubleshooting ### Intellisense not working Try to update the used TypeScript version *(>= v5 is recommended)*. ### Out of memory (OOM) errors {% hint style="warning" %} This problem does not occur when `enableSelector` is set to `"optimize"`. If possible, we recommend you first attempt to upgrade to the selector API and setting this option. To make the migration smoother, we've published the following packages: * [@i18next-selector/codemod](https://github.com/ahrjarrett/i18next-selector/tree/main/packages/codemod) * [@i18next-selector/vite-plugin](https://github.com/ahrjarrett/i18next-selector/tree/main/packages/vite-plugin) {% endhint %} Running typechecking with key validation might result in OOM errors. This can be facilitated by additional factors like: * large codebase with a lot of namespace with hundreds of keys * running typechecking alongside other tools like `ESLint` combined with `typescript-eslint` {% hint style="info" %} When having this kind of error consider to: * If you are on a large codebase consider split the typecheck / lint process in separate tasks * Split the code in multiple packages (monorepo) * Use Node `--max-old-space-size` option to increase Node memory E.g.: ```shell export NODE_OPTIONS=\"--max_old_space_size=10240\" && tsc ``` {% endhint %} {% hint style="warning" %} If you report a OOM error, please provide an easy way to reproduce the issue using: * online sandbox * example repository {% endhint %} ### Not working interpolation values `t` function infers interpolation values, but it'll only work if the translation files (resources) are placed in a ts file and using `as const` *(like* [*this*](https://github.com/i18next/i18next/blob/master/examples/typescript/i18n/en/ns1.ts)*)* or an [interface in a d.ts file](https://github.com/locize/react-i18next-example-app-ts/blob/main/src/%40types/resources.d.ts) *(can be generated like* [*this*](https://github.com/locize/react-i18next-example-app-ts/blob/751f704984c206076d08638442ae34b3507aa7ad/package.json#L35)*)*, JSON files don't support `as const` to convert objects to be type literals (yet). ### `Type 'HTMLAttributes' is not assignable to type...` This happens when [`skipLibCheck`](https://www.typescriptlang.org/tsconfig#skipLibCheck) is disabled. Setting `skipLibCheck` in tsconfig to `true` will remove this issue. ### Type error - template literal {% hint style="info" %} Note: this problem only occurs when `enableSelector` is set to `false` {% endhint %} If you face this issue: > Argument of type 'string' is not assignable to parameter of type ... When using the following approach (template literal with an expression): ```typescript // with i18next i18next.t(`${expression}.title`); // with react-i18next const { t } = useTranslation(); t(`${expression}.title`); ``` Or: ```typescript // with react-i18next const { t } = useTranslation(`${ns}Default`); ``` TypeScript will lose the literal value, and it will infer the `key` as string, which will cause to throw the error above. In this case, you will need to assert the template string `as const`, like this: ```typescript // with i18next i18next.t(`${expression}.title` as const); // with react-i18next const { t } = useTranslation(); t(`${expression}.title` as const); ``` For now, this is the only possible workaround. This is a TypeScript limitation that will be address at some point in the future. ### Type error - excessively deep and possibly infinite {% hint style="info" %} Note: this problem does not occur when `enableSelector` is set to `"optimize"` {% endhint %} If you face this issue whenever calling the `t` function: > TS2589: Type instantiation is excessively deep and possibly infinite. That probably means you did not set up your type declaration correctly, so review your configuration or check [here](https://github.com/i18next/react-i18next/issues?q=is%3Aissue+Type+instantiation+is+excessively+deep+and+possibly+infinite) for some similar cases that may help you. If needed, you can always open an issue on Github to get some help from us. ### Tagged Template Literal (`react-i18next` only) {% hint style="info" %} Note: this problem only applies when `enableSelector` is set to `false` {% endhint %} If you are using the tagged template literal syntax for the `t` function, like this: ```typescript t`key1.key2`; ``` The `keys` and `return` type inference will not work, because [TemplateStringsArray](https://github.com/microsoft/TypeScript/issues/33304) does not accept generic types yet. You can use Tagged Template Literal syntax, but it will accept any string as argument. ### Customize `t` function return when `returnObjects` is set to `true` but `CustomTypeOptions.resources` is not used (>= v23) When no `resources` are defined inside `CustomTypeOptions` and `returnObject` options is set to `true` `t` function returns a `$SpecialObject` type: ```typescript type $SpecialObject = object | Array; ``` Due to his anatomy it can be easily casted to a better defined type as you can see from the following examples: #### Example with object {% tabs %} {% tab title="v25.4+" %} ```typescript const tResult = t($ => $.myTypeKey, { returnObjects: true }) as { title: string, text: string }; expectTypeOf(tResult).toEqualTypeOf<{ title: string; text: string }>(); ``` {% endtab %} {% tab title="v25.3 and before" %} ```typescript const tResult = t('myTypeKey', { returnObjects: true }) as { title: string, text: string }; expectTypeOf(tResult).toEqualTypeOf<{ title: string; text: string }>(); ``` {% endtab %} {% endtabs %} #### Example with array {% tabs %} {% tab title="v25.4+" %} ```typescript const tResult = t($ => $.myTypeKey, { returnObjects: true }) as Array; expectTypeOf(tResult).toEqualTypeOf>(); ``` {% endtab %} {% tab title="v25.3 and before" %} ```typescript const tResult = t('myTypeKey', { returnObjects: true }) as Array; expectTypeOf(tResult).toEqualTypeOf>(); ``` {% endtab %} {% endtabs %} #### Example without casting using type parameters {% tabs %} {% tab title="v25.4+" %} ```typescript type MyCustomReturn = { title:string; text: string }; const tResult = t($ => $.myKey, { returnObjects: true }); expectTypeOf(tResult).toEqualTypeOf(); ``` {% endtab %} {% tab title="v25.3 and before" %} ```typescript type MyCustomReturn = { title:string; text: string }; const tResult = t('myKey', { returnObjects: true }); expectTypeOf(tResult).toEqualTypeOf(); ``` {% endtab %} {% endtabs %} ## Troubleshooting (< 23) {% hint style="info" %} The following problems should not be present since v23.0.0 {% endhint %} ### Slow compilation time In order to fully type the `t` function, we recursively map all nested keys from your primary locale files or objects. Depending on the number of keys your project have, the compilation time could be noticeably affected. If this is negatively influencing your productivity, this feature might not be the best choice for you. If needed, you can always open an issue on Github to get some help from us. ### Argument of type 'DefaultTFuncReturn' is not assignable to parameter of type xyz `t` function can return `null`, this behaviour is [set by default](https://www.i18next.com/configuration-options#translation-defaults), if you want to change it, set `returnNull` type to `false`. ```typescript // i18next.d.ts import 'i18next'; declare module 'i18next' { interface CustomTypeOptions { returnNull: false; ... } } ``` I also recommend updating your [i18next configuration](https://www.i18next.com/overview/configuration-options) to behave accordantly: ```javascript i18next.init({ returnNull: false, // ... }); ```