├── .gitbook └── assets │ ├── Screen Shot 2018-07-30 at 10.25.19.png │ ├── Screen Shot 2018-09-30 at 16.58.18 (1).png │ ├── Screen Shot 2018-09-30 at 16.58.18.png │ ├── dashboard.png │ ├── gatsby-i18next.jpg │ ├── general-locize-screen.png │ ├── next-13-app-dir-i18n.jpg │ ├── next-i18next.jpg │ ├── next-ssg.jpeg │ ├── pill.jpeg │ ├── preview.jpg │ ├── remix-localization.jpg │ ├── screen-shot-2018-07-30-at-10.25.19.png │ ├── screen-shot-2018-09-30-at-16.58.18.png │ ├── title width (1).jpg │ ├── title width.jpg │ ├── title-width.jpg │ └── title1.png ├── .gitignore ├── README.md ├── SUMMARY.md ├── assets ├── README.md ├── favicon.ico ├── img │ ├── README.md │ └── dashboard.png └── js │ ├── README.md │ └── custom.js ├── book.json ├── getting-started.md ├── guides ├── multiple-translation-files.md ├── quick-start.md └── the-drawbacks-of-other-i18n-solutions.md ├── latest ├── i18next-instance.md ├── i18nextprovider.md ├── migrating-v9-to-v10.md ├── ssr.md ├── trans-component.md ├── translation-render-prop.md ├── typescript.md ├── usetranslation-hook.md ├── using-with-hooks.md └── withtranslation-hoc.md ├── legacy-v9 ├── i18next-instance.md ├── i18nextprovider.md ├── interpolate.md ├── namespacesconsumer.md ├── overview.md ├── serverside-rendering.md ├── step-by-step-guide.md ├── trans-component.md ├── withi18n.md └── withnamespaces.md ├── methods.md ├── misc ├── testing.md ├── using-with-fluent-format.md └── using-with-icu-format.md └── styles ├── README.md └── website.css /.gitbook/assets/Screen Shot 2018-07-30 at 10.25.19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/Screen Shot 2018-07-30 at 10.25.19.png -------------------------------------------------------------------------------- /.gitbook/assets/Screen Shot 2018-09-30 at 16.58.18 (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/Screen Shot 2018-09-30 at 16.58.18 (1).png -------------------------------------------------------------------------------- /.gitbook/assets/Screen Shot 2018-09-30 at 16.58.18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/Screen Shot 2018-09-30 at 16.58.18.png -------------------------------------------------------------------------------- /.gitbook/assets/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/dashboard.png -------------------------------------------------------------------------------- /.gitbook/assets/gatsby-i18next.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/gatsby-i18next.jpg -------------------------------------------------------------------------------- /.gitbook/assets/general-locize-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/general-locize-screen.png -------------------------------------------------------------------------------- /.gitbook/assets/next-13-app-dir-i18n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/next-13-app-dir-i18n.jpg -------------------------------------------------------------------------------- /.gitbook/assets/next-i18next.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/next-i18next.jpg -------------------------------------------------------------------------------- /.gitbook/assets/next-ssg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/next-ssg.jpeg -------------------------------------------------------------------------------- /.gitbook/assets/pill.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/pill.jpeg -------------------------------------------------------------------------------- /.gitbook/assets/preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/preview.jpg -------------------------------------------------------------------------------- /.gitbook/assets/remix-localization.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/remix-localization.jpg -------------------------------------------------------------------------------- /.gitbook/assets/screen-shot-2018-07-30-at-10.25.19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/screen-shot-2018-07-30-at-10.25.19.png -------------------------------------------------------------------------------- /.gitbook/assets/screen-shot-2018-09-30-at-16.58.18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/screen-shot-2018-09-30-at-16.58.18.png -------------------------------------------------------------------------------- /.gitbook/assets/title width (1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/title width (1).jpg -------------------------------------------------------------------------------- /.gitbook/assets/title width.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/title width.jpg -------------------------------------------------------------------------------- /.gitbook/assets/title-width.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/title-width.jpg -------------------------------------------------------------------------------- /.gitbook/assets/title1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/.gitbook/assets/title1.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ## What is react-i18next? 4 | 5 | react-i18next is a powerful **internationalization** framework for [**React**](https://reactjs.org) / [**React Native**](https://reactnative.dev/) which is based on [**i18next**](https://www.i18next.com). Check out the [history of i18next](https://www.i18next.com/misc/the-history-of-i18next) and [when react-i18next was introduced](https://www.i18next.com/misc/the-history-of-i18next#v2). 6 | 7 | {% hint style="info" %} 8 | You should read the [i18next](https://www.i18next.com) documentation. The [configuration options](https://www.i18next.com/overview/configuration-options) and translation functionalities like [plurals](https://www.i18next.com/translation-function/plurals), [formatting](https://www.i18next.com/translation-function/formatting), [interpolation](https://www.i18next.com/translation-function/interpolation), ... are documented there. 9 | {% endhint %} 10 | 11 | The module provides multiple components eg. to assert that needed translations get loaded or that your content gets rendered when the language changes. 12 | 13 | {% hint style="warning" %} 14 | Managing JSON files manually?\ 15 | When your project grows, streamline your workflow with [locize](https://locize.com), the official TMS built by the creators of i18next. [**Try it for free!**](https://www.locize.com/i18next) 16 | {% endhint %} 17 | 18 | {% embed url="https://www.youtube.com/watch?t=705s&v=SA_9i4TtxLQ" %} 19 | 20 | react-i18next is optimally suited for **server-side rendering**. It provides extra extension point to work with next.js, for e.g. [Learn more](legacy-v9/serverside-rendering.md). 21 | 22 | As react-i18next depends on [i18next](http://i18next.com) you can use it in any other UI framework and on the server-side (node.js, .net, ...) too. Like the React philosophy - just: 23 | 24 | > **Learn once - translate everywhere**. 25 | 26 | {% hint style="success" %} 27 | Check out [this video](https://youtu.be/37rcHVcQ6t0) and the corresponding [blog post](https://www.locize.com/blog/how-to-easily-add-i18n-to-your-software) about "Vite + React + TypeScript" with i18next. 28 | 29 | 30 | {% endhint %} 31 | 32 | {% hint style="success" %} 33 | [Here](https://locize.com/blog/react-i18next/) you'll find a simple tutorial on how to best use react-i18next.\ 34 | Some basics of i18next and some cool possibilities on how to optimize your localization workflow.[\ 35 | ](https://locize.com/blog/react-i18next/) 36 | {% endhint %} 37 | 38 | {% hint style="info" %} 39 | **Using Next.js?**\ 40 | [Here](https://locize.com/blog/next-i18next/) you'll find a blog post on how to best use [next-i18next](https://github.com/i18next/next-i18next) with [client side translation download](https://github.com/i18next/next-i18next#client-side-loading-of-translations-via-http) and SEO optimization. 41 | 42 | [![](.gitbook/assets/next-i18next.jpg)](https://locize.com/blog/next-i18next/)\ 43 | \ 44 | **Using Next.js with the new App Router?**\ 45 | Then [this article](https://www.locize.com/blog/i18n-next-app-router) is what you are looking for! 46 | 47 | [![](https://cdn.prod.website-files.com/67a323e323a50df7f24f0a94/67f268673fcfae53e5d4697c_i18n-next-app-router.jpg)](https://www.locize.com/blog/i18n-next-app-router) 48 | {% endhint %} 49 | 50 | {% hint style="info" %} 51 | **Using Remix?**\ 52 | [Here](https://github.com/locize/locize-remix-i18next-example) you'll find a simple example and [here a step by step tutorial](https://locize.com/blog/remix-i18n/) on how to best use remix-i18next. 53 | 54 | [![](.gitbook/assets/remix-localization.jpg)](https://locize.com/blog/remix-i18n/) 55 | {% endhint %} 56 | 57 | {% hint style="info" %} 58 | **Using Gatsby?**\ 59 | [Here](https://github.com/locize/locize-gatsby-example) you can find an example and an appropriate [blog post](https://locize.com/blog/gatsby-i18n/). 60 | 61 | [![](.gitbook/assets/gatsby-i18next.jpg)](https://locize.com/blog/gatsby-i18n/) 62 | {% endhint %} 63 | 64 | ## What does my code look like 65 | 66 | **Before:** Your React code would have looked something like: 67 | 68 | ```jsx 69 | ... 70 |
Just simple content
71 |
72 | Hello {name}, you have {count} unread message(s). Go to messages. 73 |
74 | ... 75 | ``` 76 | 77 | **After:** With the `Trans` component just change it to: 78 | 79 | ```jsx 80 | ... 81 |
{t('simpleContent')}
82 | 83 | Hello {{name}}, you have {{count}} unread message(s). Go to messages. 84 | 85 | ... 86 | ``` 87 | 88 | If you prefer not using semantic keys but text - [that's also possible](https://www.i18next.com/principles/fallback.html#key-fallback). 89 | 90 | ## On top: [Localization as a service](https://locize.com) 91 | 92 | i18next supports translation management tools such as [locize.com](http://locize.com/?utm_source=react_i18next_com\&utm_medium=gitbook). 93 | 94 | {% hint style="success" %} 95 | [Here](https://github.com/locize/react-tutorial) you can find a step by step guide, which will unleash the full power of i18next in combination with locize.\ 96 | See how your developer experience with this localization workflow [could look like](https://youtu.be/osScyaGMVqo).\ 97 | There's also the possibility to have an [even more focused developer experience](https://youtu.be/VfxBpSXarlU), with the help of the [auto-machinetranslation workflow](https://docs.locize.com/whats-inside/auto-machine-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)). 98 | {% endhint %} 99 | 100 | {% embed url="https://www.youtube.com/watch?v=TFV_vhJs5DY" %} 101 | 102 | [Learn more about the enterprise offering](https://www.i18next.com/overview/for-enterprises) 103 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [Introduction](README.md) 4 | * [Getting started](getting-started.md) 5 | 6 | ## Guides 7 | 8 | * [Drawbacks of other i18n solutions](guides/the-drawbacks-of-other-i18n-solutions.md) 9 | * [Quick start](guides/quick-start.md) 10 | * [Multiple Translation Files](guides/multiple-translation-files.md) 11 | * [Extracting translations](https://www.i18next.com/how-to/extracting-translations) 12 | 13 | ## latest 14 | 15 | * [Step by step guide](latest/using-with-hooks.md) 16 | * [i18next instance](latest/i18next-instance.md) 17 | * [useTranslation (hook)](latest/usetranslation-hook.md) 18 | * [withTranslation (HOC)](latest/withtranslation-hoc.md) 19 | * [Translation (render prop)](latest/translation-render-prop.md) 20 | * [Trans Component](latest/trans-component.md) 21 | * [I18nextProvider](latest/i18nextprovider.md) 22 | * [SSR (additional components)](latest/ssr.md) 23 | * [Migrating v9 to v10](latest/migrating-v9-to-v10.md) 24 | * [TypeScript](latest/typescript.md) 25 | 26 | ## Misc 27 | 28 | * [Using with ICU format](misc/using-with-icu-format.md) 29 | * [Using with fluent format](misc/using-with-fluent-format.md) 30 | * [Testing](misc/testing.md) 31 | 32 | ## legacy v9 33 | 34 | * [Step by step guide (v9)](legacy-v9/step-by-step-guide.md) 35 | * [Overview (v9)](legacy-v9/overview.md) 36 | * [i18next instance (v9)](legacy-v9/i18next-instance.md) 37 | * [I18nextProvider (v9)](legacy-v9/i18nextprovider.md) 38 | * [withI18n (v9)](legacy-v9/withi18n.md) 39 | * [withNamespaces (v9)](legacy-v9/withnamespaces.md) 40 | * [NamespacesConsumer (v9)](legacy-v9/namespacesconsumer.md) 41 | * [Trans Component (v9)](legacy-v9/trans-component.md) 42 | * [Interpolate (v9)](legacy-v9/interpolate.md) 43 | * [SSR (v9)](legacy-v9/serverside-rendering.md) 44 | 45 | *** 46 | 47 | * [🌐 localization as a service](https://locize.com) 48 | * [🎓 i18next crash course](https://youtu.be/SA\_9i4TtxLQ?t=705) 49 | * [💾 GitHub Repository](https://github.com/i18next/react-i18next) 50 | -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/assets/README.md -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/assets/favicon.ico -------------------------------------------------------------------------------- /assets/img/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/assets/img/README.md -------------------------------------------------------------------------------- /assets/img/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/assets/img/dashboard.png -------------------------------------------------------------------------------- /assets/js/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/assets/js/README.md -------------------------------------------------------------------------------- /assets/js/custom.js: -------------------------------------------------------------------------------- 1 | var target = window.location.hash; 2 | 3 | window.location.hash = ""; 4 | 5 | $(document).ready(function() { 6 | setTimeout(function() { 7 | document.location.hash = target; 8 | }, 50); 9 | }); -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "addcssjs", "edit-link", "theme-api", "jsfiddle", "custom-favicon", "simple-page-toc", "anchors", "hints" ], 3 | "pluginsConfig": { 4 | "edit-link": { 5 | "base": "https://github.com/i18next/react-i18next-gitbook/edit/master/", 6 | "label": "Edit" 7 | }, 8 | "theme-api": { 9 | "languages": [ 10 | { 11 | "lang": "js", 12 | "name": "js", 13 | "default": true 14 | } 15 | ], 16 | "split": true 17 | }, 18 | "jsfiddle":{ 19 | "type": "script", 20 | "tabs": ["result","js"], 21 | "height": "500", 22 | "width": "500" 23 | }, 24 | "favicon": "assets/favicon.ico", 25 | "simple-page-toc": { 26 | "maxDepth": 3, 27 | "skipFirstH1": true 28 | }, 29 | "addcssjs": { 30 | "js": ["assets/js/custom.js"] 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | ## Installation 4 | 5 | ### Install using npm 6 | 7 | react-i18next can be added to your project using **npm**: 8 | 9 | ```bash 10 | # npm 11 | $ npm install react-i18next i18next --save 12 | ``` 13 | 14 | In the `/dist` folder you find specific builds for `commonjs`, `es6 modules`,... 15 | 16 | {% hint style="info" %} 17 | The module is optimized to load by webpack, rollup, ... The correct entry points are already configured in the package.json. There should be no extra setup needed to get the best build option. 18 | {% endhint %} 19 | 20 | ### Load from CDN 21 | 22 | You can also add a script tag to load react-i18next from one of the CDNs providing it, eg.: 23 | 24 | **unpkg.com** 25 | 26 | * [https://unpkg.com/react-i18next/react-i18next.js](https://unpkg.com/react-i18next/react-i18next.js) 27 | * [https://unpkg.com/react-i18next/react-i18next.min.js](https://unpkg.com/react-i18next/react-i18next.min.js) 28 | 29 | ## Translation "how to" 30 | 31 | {% hint style="info" %} 32 | You should read the [i18next](https://www.i18next.com) documentation at some point as we do not repeat all the [configuration options](https://www.i18next.com/overview/configuration-options) and translation functionalities like [plurals](https://www.i18next.com/translation-function/plurals), [formatting](https://www.i18next.com/translation-function/formatting), [interpolation](https://www.i18next.com/translation-function/interpolation), ... here. 33 | {% endhint %} 34 | 35 | You have two options to translate your content: 36 | 37 | ### Simple content 38 | 39 | Simple content can easily be translated using the provided `t` function. 40 | 41 | **Before:** 42 | 43 | ```jsx 44 |
Just simple content
45 | ``` 46 | 47 | **After:** 48 | 49 | ```jsx 50 |
{t('simpleContent')}
51 | ``` 52 | 53 | {% hint style="info" %} 54 | You will get the t function by using the [useTranslation](latest/usetranslation-hook.md) hook or the [withTranslation](latest/withtranslation-hoc.md) hoc. 55 | {% endhint %} 56 | 57 | ### JSX tree 58 | 59 | Sometimes you might want to include html formatting or components like links into your translations. (Always try to get the best result for your translators - the final string to translate should be a complete sentence). 60 | 61 | **Before:** Your react code would have looked something like: 62 | 63 | ```jsx 64 |
65 | Hello {name}, you have {count} unread message(s). Go to messages. 66 |
67 | ``` 68 | 69 | **After:** With the trans component just change it to: 70 | 71 | ```jsx 72 | 73 | Hello {{name}}, you have {{count}} unread message. Go to messages. 74 | 75 | ``` 76 | 77 | {% hint style="info" %} 78 | Learn more about the Trans Component [here](latest/trans-component.md) 79 | {% endhint %} 80 | 81 | ## Basic sample 82 | 83 | This basic sample tries to add i18n in a one file sample. 84 | 85 | ```javascript 86 | import React from "react"; 87 | import { createRoot } from 'react-dom/client'; 88 | import i18n from "i18next"; 89 | import { useTranslation, initReactI18next } from "react-i18next"; 90 | 91 | i18n 92 | .use(initReactI18next) // passes i18n down to react-i18next 93 | .init({ 94 | // the translations 95 | // (tip move them in a JSON file and import them, 96 | // or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui) 97 | resources: { 98 | en: { 99 | translation: { 100 | "Welcome to React": "Welcome to React and react-i18next" 101 | } 102 | } 103 | }, 104 | lng: "en", // if you're using a language detector, do not define the lng option 105 | fallbackLng: "en", 106 | 107 | interpolation: { 108 | escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape 109 | } 110 | }); 111 | 112 | function App() { 113 | const { t } = useTranslation(); 114 | 115 | return

{t('Welcome to React')}

; 116 | } 117 | 118 | // append app to dom 119 | const root = createRoot(document.getElementById('root')); 120 | root.render( 121 | 122 | ); 123 | ``` 124 | 125 | #### RESULT: 126 | 127 | ![Preview of content](<.gitbook/assets/Screen Shot 2018-09-30 at 16.58.18 (1).png>) 128 | 129 | {% hint style="info" %} 130 | This sample while very simple does come with some [drawbacks](guides/the-drawbacks-of-other-i18n-solutions.md) to getting the full potential from using react-i18next you should read the extended [step by step guide](latest/using-with-hooks.md). 131 | {% endhint %} 132 | 133 | ### Do you like to read a more complete step by step tutorial? 134 | 135 | {% hint style="success" %} 136 | [Here](https://locize.com/blog/react-i18next/) you'll find a simple tutorial on how to best use react-i18next.\ 137 | Some basics of i18next and some cool possibilities on how to optimize your localization workflow.[\ 138 | ](https://locize.com/blog/react-i18next/) 139 | {% endhint %} 140 | -------------------------------------------------------------------------------- /guides/multiple-translation-files.md: -------------------------------------------------------------------------------- 1 | # Multiple Translation Files 2 | 3 | One of the advantages of react-i18next is based on i18next it supports the separation of translations into multiple files - which are called namespaces in i18next context -> as you're accessing keys from a namespace defining that as a prefix: 4 | 5 | So while this takes the translation from the defined default namespace: 6 | 7 | ```javascript 8 | i18next.t('look.deep'); 9 | ``` 10 | 11 | This will lookup the key in a namespace (file) called common.json: 12 | 13 | ```javascript 14 | i18next.t('common:look.deep'); // not recommended with ns prefix when used in combination with natural language keys 15 | // better use the ns option: 16 | i18next.t('look.deep', { ns: 'common' }) 17 | ``` 18 | 19 | In order to use multiple namespaces/translation files, you need to specify it when calling [`useTranslation`](https://react.i18next.com/latest/usetranslation-hook) : 20 | 21 | ```javascript 22 | const { t } = useTranslation(['translation', 'common']); 23 | ``` 24 | 25 | [`withTranslation`](https://react.i18next.com/latest/withtranslation-hoc): 26 | 27 | ```javascript 28 | withTranslation(['translation', 'common'])(MyComponent); 29 | ``` 30 | 31 | or [`Translation`](https://react.i18next.com/latest/translation-render-prop): 32 | 33 | ```javascript 34 | 35 | { 36 | (t) =>

{t('look.deep', { ns: 'common' })}

37 | } 38 |
39 | ``` 40 | 41 | ## Separating translation files 42 | 43 | In i18next you have a lot of options to add translations on init, in your code calling API methods or using one of the backend implementation. For a detailed write up check out the ["Add or load translation guide on i18next.com"](https://www.i18next.com/how-to/add-or-load-translations). 44 | 45 | With react-i18next you can use any of the components passing down the `t` function to your components to load namespaces: 46 | 47 | * [useTranslation (hook)](../latest/usetranslation-hook.md) 48 | * [withTranslation (HOC)](../latest/withtranslation-hoc.md) 49 | * [Translation (render prop)](../latest/translation-render-prop.md) 50 | 51 | All take arguments to define which namespaces to load and will Suspense rendering until those got loaded. 52 | 53 | So you do not need to load all translations upfront enabling you to create huge react based applications without slowing down loading of the first page cause all translations need to be loaded upfront (hello other i18n implementations). 54 | 55 | ## Manage your translations with a management GUI 56 | 57 | ### [**locize**](https://locize.com) is the perfect translation management tool for your [**i18next**](https://www.i18next.com) project 58 | 59 | #### ➡️ [i18next](https://www.i18next.com/) + [locize](https://locize.com/) = [true continuous localization](https://locize.com/how-it-works.html#continouslocalization) 60 | 61 | [Here](https://github.com/locize/react-tutorial) you can find a step by step guide, which will unleash the full power of i18next in combination with locize.\ 62 | See how your developer experience with this localization workflow [could look like](https://youtu.be/osScyaGMVqo).\ 63 | There's also the possibility to have an [even more focused developer experience](https://youtu.be/VfxBpSXarlU), with the help of the [auto-machinetranslation workflow](https://docs.locize.com/whats-inside/auto-machine-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)). 64 | 65 | {% embed url="https://youtu.be/osScyaGMVqo" %} 66 | 67 | {% embed url="https://youtu.be/VfxBpSXarlU" %} 68 | 69 | -------------------------------------------------------------------------------- /guides/quick-start.md: -------------------------------------------------------------------------------- 1 | # Quick start 2 | 3 | ## Install needed dependencies 4 | 5 | We expect you having an existing react application - if not give [Vite](https://vite.dev/guide/#scaffolding-your-first-vite-project) (`npm create vite@latest`) or similar a try. 6 | 7 | Install both react-i18next and i18next packages: 8 | 9 | ```bash 10 | npm install react-i18next i18next --save 11 | ``` 12 | 13 | Why do you need i18next package? i18next is the core that provides all translation functionality while react-i18next gives some extra power for using with react. 14 | 15 | #### Do you directly want to see an example? 16 | 17 | Check out this basic [react example](https://github.com/i18next/react-i18next/tree/master/example/react) with a [browser language-detector](https://github.com/i18next/i18next-browser-languageDetector) and a [http backend](https://github.com/i18next/i18next-http-backend) to load translations from. 18 | 19 | #### Do you like to read a more complete step by step tutorial? 20 | 21 | {% hint style="success" %} 22 | [Here](https://locize.com/blog/react-i18next/) you'll find a simple tutorial on how to best use react-i18next.\ 23 | Some basics of i18next and some cool possibilities on how to optimize your localization workflow.[\ 24 | ![](<../.gitbook/assets/title width (1).jpg>)](https://locize.com/blog/react-i18next/) 25 | {% endhint %} 26 | 27 | ## Configure i18next 28 | 29 | Create a new file `i18n.js` beside your `index.js` containing following content: 30 | 31 | ```javascript 32 | import i18n from "i18next"; 33 | import { initReactI18next } from "react-i18next"; 34 | 35 | // the translations 36 | // (tip move them in a JSON file and import them, 37 | // or even better, manage them separated from your code: https://react.i18next.com/guides/multiple-translation-files) 38 | const resources = { 39 | en: { 40 | translation: { 41 | "Welcome to React": "Welcome to React and react-i18next" 42 | } 43 | }, 44 | fr: { 45 | translation: { 46 | "Welcome to React": "Bienvenue à React et react-i18next" 47 | } 48 | } 49 | }; 50 | 51 | i18n 52 | .use(initReactI18next) // passes i18n down to react-i18next 53 | .init({ 54 | resources, 55 | lng: "en", // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources 56 | // you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage 57 | // if you're using a language detector, do not define the lng option 58 | 59 | interpolation: { 60 | escapeValue: false // react already safes from xss 61 | } 62 | }); 63 | 64 | export default i18n; 65 | ``` 66 | 67 | {% hint style="info" %} 68 | The file does not need to be named `i18n.js`, it can be any other filename. Just make sure you import it accordingly. 69 | {% endhint %} 70 | 71 | The interesting part here is by `i18n.use(initReactI18next)` we pass the i18n instance to react-i18next which will make it available for all the components via the context api. 72 | 73 | Then import that in `index.js`: 74 | 75 | ```javascript 76 | import React, { Component } from "react"; 77 | import { createRoot } from 'react-dom/client'; 78 | import './i18n'; 79 | import App from './App'; 80 | 81 | // append app to dom 82 | const root = createRoot(document.getElementById('root')); 83 | root.render( 84 | 85 | ); 86 | ``` 87 | 88 | {% hint style="info" %} 89 | If you need to access the `t` function or the `i18next` instance from outside of a React component you can simply import your `./i18n.js` and use the exported i18next instance: 90 | 91 |
import i18next from './i18n'
 92 | 
 93 | i18next.t('my.key')
 94 | 
95 | 96 | \ 97 | Also read about this [here](https://www.locize.com/blog/how-to-use-i18next-t-outside-react-components) and [here](https://github.com/i18next/react-i18next/issues/1236#issuecomment-762039023). 98 | {% endhint %} 99 | 100 | ## Translate your content 101 | 102 | ### Using the hook 103 | 104 | Using the hook in functional components is one of the options you have. 105 | 106 | The `t` function is the main function in i18next to translate content. Read the [documentation](https://www.i18next.com/translation-function/essentials) for all the options. 107 | 108 | ```jsx 109 | import React from 'react'; 110 | 111 | // the hook 112 | import { useTranslation } from 'react-i18next'; 113 | 114 | function MyComponent () { 115 | const { t, i18n } = useTranslation(); 116 | return

{t('Welcome to React')}

117 | } 118 | ``` 119 | 120 | Learn more about the hook [useTranslation](../latest/usetranslation-hook.md). 121 | 122 | ### Using the HOC 123 | 124 | Using higher order components is one of the most used method to extend existing components by passing additional props to them. 125 | 126 | The `t` function is the main function in i18next to translate content. Read the [documentation](https://www.i18next.com/translation-function/essentials) for all the options. 127 | 128 | ```jsx 129 | import React from 'react'; 130 | 131 | // the hoc 132 | import { withTranslation } from 'react-i18next'; 133 | 134 | function MyComponent ({ t }) { 135 | return

{t('Welcome to React')}

136 | } 137 | 138 | export default withTranslation()(MyComponent); 139 | ``` 140 | 141 | Learn more about the higher order component [withTranslation](../latest/withtranslation-hoc.md). 142 | 143 | ### Using the render prop 144 | 145 | The render prop enables you to use the `t` function inside your component. 146 | 147 | ```jsx 148 | import React from 'react'; 149 | 150 | // the render prop 151 | import { Translation } from 'react-i18next'; 152 | 153 | export default function MyComponent () { 154 | return ( 155 | 156 | { 157 | t =>

{t('Welcome to React')}

158 | } 159 |
160 | ) 161 | } 162 | ``` 163 | 164 | Learn more about the render prop [Translation](../latest/translation-render-prop.md). 165 | 166 | ### Using the Trans component 167 | 168 | The Trans component is the best way to translate a JSX tree in one translation. This enables you to eg. easily translate text containing a link component or formatting like ``. 169 | 170 | ```jsx 171 | import React from 'react'; 172 | import { Trans } from 'react-i18next'; 173 | 174 | export default function MyComponent () { 175 | return

Welcome to React

176 | } 177 | 178 | // the translation in this case should be 179 | "<0>Welcome to React": "<0>Welcome to React and react-i18next" 180 | ``` 181 | 182 | Don't worry if you do not yet understand how the Trans component works in detail. Learn more about it [here](../latest/trans-component.md). 183 | 184 | ## Next steps 185 | 186 | Depending on your learning style, you can now read the more in-depth [step by step](../latest/using-with-hooks.md) guide and learn how to load translations using xhr or how to change the language. 187 | 188 | Prefer having code to checkout? Directly dive into our examples: 189 | 190 | * [Example react](https://github.com/i18next/react-i18next/tree/master/example/react) 191 | 192 | > **Would you like to visually check the progress state of your translations?** 193 | > 194 | > _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._\ 195 | > [![](../.gitbook/assets/preview.jpg)](https://github.com/locize/translation-check) 196 | -------------------------------------------------------------------------------- /guides/the-drawbacks-of-other-i18n-solutions.md: -------------------------------------------------------------------------------- 1 | # Drawbacks of other i18n solutions 2 | 3 | Let's make the sample using our own base i18n framework [i18next](https://i18next.com). Like all other solutions, some come with [drawbacks](the-drawbacks-of-other-i18n-solutions.md#the-drawbacks). These will be highlighted after samples. 4 | 5 | ## Using a pure javascript i18n framework 6 | 7 | ```javascript 8 | import React, { Component } from "react"; 9 | import { createRoot } from 'react-dom/client'; 10 | import i18n from "i18next"; 11 | 12 | // translation catalog 13 | const resources = { 14 | en: { 15 | translation: { 16 | "welcome": "Welcome to React and react-i18next" 17 | } 18 | } 19 | }; 20 | 21 | // initialize i18next with catalog and language to use 22 | i18n.init({ 23 | resources, 24 | lng: "en" 25 | }); 26 | 27 | class App extends Component { 28 | render() { 29 | return

{i18n.t('welcome')}

; 30 | } 31 | } 32 | 33 | // append app to dom 34 | const root = createRoot(document.getElementById('root')); 35 | root.render( 36 | 37 | ); 38 | ``` 39 | 40 | ## More react adapted "react-i18n" 41 | 42 | The above is basically how every i18n framework for react works. The translations and language get set when initiated and a translation function is made available. You could easily extend this hiding the i18n.init inside a provider and pass down the function by context to another component to translate strings. 43 | 44 | So let's make this more visible with some pseudo code: 45 | 46 | ```javascript 47 | import React, { Component } from "react"; 48 | import { createRoot } from 'react-dom/client'; 49 | import { I18nProvider, FormattedString } from "i18nLib"; 50 | 51 | // import translation catalog 52 | import resources from './catalog-en.json'; 53 | 54 | class App extends Component { 55 | render() { 56 | return

; 57 | } 58 | } 59 | 60 | // append app to dom 61 | const root = createRoot(document.getElementById('root')); 62 | root.render( 63 | 64 | , 65 | 66 | ); 67 | ``` 68 | 69 | ## The drawbacks 70 | 71 | Before we come to the drawbacks let's highlight some advantages of those solutions above - they are very simple to get started. 72 | 73 | ### Changing the language 74 | 75 | Can you easily change the language? Get the translations in other language loaded? Does the language change trigger a rerender? 76 | 77 | That's what the [withTranslation](../latest/withtranslation-hoc.md) higher order component or [useTranslation](../latest/usetranslation-hook.md) hook do! 78 | 79 | ### Scale and split your translations into multiple files 80 | 81 | When your project gets bigger you do not only want code splitting but you also like to load translations on demand to avoid loading all translations upfront which would result in bad load times for your website. 82 | 83 | With loading translations asynchronous there comes another problem - does your framework handle the pending state during loading translation? 84 | 85 | That's what the [withTranslation](../latest/withtranslation-hoc.md) higher order component or [useTranslation](../latest/usetranslation-hook.md) hook do! 86 | 87 | ### Can you translate combined jsx nodes in one sentence 88 | 89 | Let's take following content: 90 | 91 | ```javascript 92 |

93 | Hello {name}, you have 94 | {count} unread message(s). 95 |

96 | ``` 97 | 98 | In most frameworks you will end having to split this into multiple translation strings. But for your translators it would make sense to have this as one sentence to translate like eg.: 99 | 100 | ``` 101 | Hello <1>{name}, you have <3>{count} unread message(s). 102 | ``` 103 | 104 | You can do this using the [Trans component](../latest/trans-component.md). 105 | -------------------------------------------------------------------------------- /latest/i18next-instance.md: -------------------------------------------------------------------------------- 1 | # i18next instance 2 | 3 | The instance is an initialized i18next instance. In the following code snippet, we add a backend to load translations from server and a language detector for detecting user language. 4 | 5 | > You can learn more about [i18next](http://i18next.com) and [plugins](https://www.i18next.com/plugins-and-utils.html#plugins) on the i18next website. 6 | 7 | ```javascript 8 | import i18n from 'i18next'; 9 | import Backend from 'i18next-http-backend'; 10 | import LanguageDetector from 'i18next-browser-languagedetector'; 11 | import { initReactI18next } from 'react-i18next'; 12 | 13 | 14 | i18n 15 | .use(Backend) 16 | .use(LanguageDetector) 17 | .use(initReactI18next) // bind react-i18next to the instance 18 | .init({ 19 | fallbackLng: 'en', 20 | debug: true, 21 | 22 | interpolation: { 23 | escapeValue: false, // not needed for react!! 24 | }, 25 | 26 | // react i18next special options (optional) 27 | // override if needed - omit if ok with defaults 28 | /* 29 | react: { 30 | bindI18n: 'languageChanged', 31 | bindI18nStore: '', 32 | transEmptyNodeValue: '', 33 | transSupportBasicHtmlNodes: true, 34 | transKeepBasicHtmlNodesFor: ['br', 'strong', 'i'], 35 | useSuspense: true, 36 | } 37 | */ 38 | }); 39 | 40 | 41 | export default i18n; 42 | ``` 43 | 44 | All additional options for react in init options: 45 | 46 | | options | default | description | 47 | | -------------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 48 | | bindI18n | 'languageChanged' |

which events trigger a rerender, can be set to false or string of events
separated by ""

| 49 | | bindI18nStore | '' | define which events on [resourceStore](https://www.i18next.com/overview/api#store-events) should trigger a rerender | 50 | | transEmptyNodeValue | '' | how to treat failed lookups in Trans component | 51 | | transSupportBasicHtmlNodes | true |

convert eg. <br/> found in translations to a react component of type br
See Trans component

| 52 | | transKeepBasicHtmlNodesFor | \['br', 'strong', 'i', 'p'] |

Which nodes not to convert in defaultValue generation in the Trans component.
See Trans component

| 53 | | useSuspense | true | If using Suspense or not | 54 | | keyPrefix | undefined | the optional `keyPrefix` will be automatically applied to the returned `t` function in [useTranslation](usetranslation-hook.md#optional-keyprefix-option) for example. | 55 | 56 | For more initialization options have look at the [docs](https://www.i18next.com/overview/configuration-options). 57 | -------------------------------------------------------------------------------- /latest/i18nextprovider.md: -------------------------------------------------------------------------------- 1 | # I18nextProvider 2 | 3 | ## What it does 4 | 5 | The I18nextProvider does take an i18next instance via prop i18n and passes that down using the context API. 6 | 7 | ```jsx 8 | import { I18nextProvider } from 'react-i18next'; 9 | import i18n from './i18n'; 10 | import App from './App'; 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ## When to use? 18 | 19 | You will need to use the provider if you need to support multiple i18next instances - eg. if you provide a component library ([like this example](https://github.com/i18next/react-i18next/tree/master/example/react-component-lib)) or in scenarios for [SSR (ServerSideRendering)](ssr.md). Additionally, you have the ability to manage the default namespace(s) by passing defaultNS. 20 | 21 | ## I18nextProvider props 22 | 23 | | _**name**_ | **type (**_**default)**_ | _**description**_ | 24 | | ------------- | ------------------------------ | ----------------------------------------------------------------------------------------- | 25 | | **i18n** | object (undefined) | pass i18next instance the provider will pass it down to translation components by context | 26 | | **defaultNS** | string \| string[] (undefined) | pass defaultNS to manage the default namespace(s) | 27 | -------------------------------------------------------------------------------- /latest/migrating-v9-to-v10.md: -------------------------------------------------------------------------------- 1 | # Migrating v9 to v10 2 | 3 | v10 is a complete rewrite, taking the chance to clean up some complexity added from v1 to v9. 4 | 5 | This means you will need to test your application more cautiously before release. 6 | 7 | {% hint style="info" %} 8 | This is a specific migration guide regarding the complete react-i18next rewrite in v10.\ 9 | If you're looking for general release notes, please have a look in the [CHANGELOG](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md) file. 10 | {% endhint %} 11 | 12 | ## New in v10 13 | 14 | The most obvious change is the hook function for use inside functional components: 15 | 16 | ```jsx 17 | import React from 'react'; 18 | import { useTranslation } from 'react-i18next'; 19 | 20 | export function MyComponent() { 21 | const [t, i18n] = useTranslation(); 22 | 23 | return

{t('my translated text')}

24 | } 25 | ``` 26 | 27 | ## Components without replacement 28 | 29 | The Interpolation component (which was marked as deprecated for a long time and replaced by the Trans Component) was removed finally. You will need to replace it with the Trans Component. 30 | 31 | ## Migration 32 | 33 | Replace your components like described below. If you don't have to use `Suspense` in your existing App you can set `useSuspense: false` in react.init options.react: 34 | 35 | ```javascript 36 | i18n.init({ 37 | react: { 38 | useSuspense: false 39 | } 40 | }); 41 | ``` 42 | 43 | ## I18nextProvider changes 44 | 45 | The `I18nextProvider` no longer provides as many properties as before. Make the necessary changes in your codebase after migrating. 46 | 47 | ```javascript 48 | // New props 49 | { 50 | i18n, 51 | defaultNS, 52 | } 53 | 54 | // Old props 55 | { 56 | i18n, 57 | defaultNS, 58 | reportNS, 59 | lng: i18n && i18n.language, 60 | t: i18n && i18n.t.bind(i18n), 61 | } 62 | ``` 63 | 64 | ## Components v9 -> v10 65 | 66 | | Type | <= v7 (v8) | v9 (v8) | v10 | 67 | | ------------------- | ------------------ | ------------------ | ---------------- | 68 | | hook | | - | useTranslation | 69 | | HOC | translate | withNamespaces | withTranslation | 70 | | render prop | I18n | NamespacesConsumer | Translation | 71 | | i18next plugin | reactI18nextModule | reactI18nextModule | initReactI18next | 72 | | Provider | I18nextProvider | I18nextProvider | I18nextProvider | 73 | | Complex Translation | Trans | Trans | Trans | 74 | | Interpolations | Interpolate | Interpolate | Trans | 75 | -------------------------------------------------------------------------------- /latest/ssr.md: -------------------------------------------------------------------------------- 1 | # SSR (additional components) 2 | 3 | ## Using [Next.js](https://nextjs.org/) App Router? 4 | 5 | Then check out [this article](https://www.locize.com/blog/i18n-next-app-router) describing how to best internationalize it with i18next. 6 | 7 | [![](https://cdn.prod.website-files.com/67a323e323a50df7f24f0a94/67f268673fcfae53e5d4697c_i18n-next-app-router.jpg)](https://www.locize.com/blog/i18n-next-app-router) 8 | 9 | ## Using [Next.js](https://nextjs.org/)? 10 | 11 | You should have a look at [next-i18next](https://github.com/i18next/next-i18next) which extends react-i18next to bring it to next.js the easiest way. 12 | 13 | > With `next-i18next@v8.0.0` and `Next.js v10`, next-i18next has done a major rewrite of the package, leveraging the built-in [internationalized routing](https://nextjs.org/docs/advanced-features/i18n-routing) provided by Next.js. 14 | > 15 | > [Here](https://github.com/locize/next-i18next-locize) you can also find a next-i18next app example in combination with locize, that offers 2 different approaches. 16 | > 17 | > `next-i18next@v5.0.0` supports `Next.js v9.5` in [**Serverless** mode](https://nextjs.org/blog/next-8#serverless-nextjs) (as of [July 2020](https://github.com/isaachinman/next-i18next/issues/274#issuecomment-664616304)). If your goal is to use earlier versions of Next.js with Serverless, then you should have a look at ["Next Right Now"](https://github.com/UnlyEd/next-right-now), which is a Next.js 9 boilerplate with built-in `i18next`, `react-i18next` and Locize. 18 | > 19 | > **Looking for an optimized Next.js translations setup?**\ 20 | > [Here](https://locize.com/blog/next-i18next/) you'll find a blog post on how to best use next-i18next with client side translation download and SEO optimization. 21 | > 22 | > [![](../.gitbook/assets/next-i18next.jpg)](https://locize.com/blog/next-i18next/) 23 | > 24 | > *** 25 | > 26 | > **Using SSG / `next export`?**\ 27 | > [Here](https://locize.com/blog/next-i18n-static/) you'll find a simple tutorial on how to best use next-i18next in a SSG environment.\ 28 | > [](https://locize.com/blog/next-i18n-static/) 29 | 30 | ## Using [Remix](https://remix.run)? 31 | 32 | You should have a look at [remix-i18next](https://github.com/sergiodxa/remix-i18next) which extends react-i18next to bring it to Remix the easiest way. 33 | 34 | > [Here](https://github.com/locize/locize-remix-i18next-example) you'll find a simple example and [here a step by step tutorial](https://locize.com/blog/remix-i18n/) on how to best use remix-i18next. 35 | > 36 | > [![](../.gitbook/assets/remix-localization.jpg)](https://locize.com/blog/remix-i18n/) 37 | 38 | ## Using [Gatsby](https://www.gatsbyjs.com/)? 39 | 40 | You should have a look at [gatsby-plugin-react-i18next](https://github.com/microapps/gatsby-plugin-react-i18next) which extends react-i18next to bring it to Gatsby the easiest way. 41 | 42 | > [Here](https://github.com/locize/locize-gatsby-example) you'll find a simple example and [here a step by step tutorial](https://locize.com/blog/gatsby-i18n/) on how to best use [gatsby-plugin-react-i18next](https://github.com/microapps/gatsby-plugin-react-i18next). 43 | > 44 | > [![](../.gitbook/assets/gatsby-i18next.jpg)](https://locize.com/blog/gatsby-i18n/) 45 | 46 | ## Setting the i18next instance based on req 47 | 48 | Use the [I18nextProvider](i18nextprovider.md) to inject the i18next instance for example bound to the http i18n instance on the request object using [i18next-http-middleware](https://github.com/i18next/i18next-http-middleware). 49 | 50 | ```jsx 51 | 52 | 53 | 54 | ``` 55 | 56 | ## Passing initial translations / initial language down to client 57 | 58 | To avoid asynchronous loading of translation on the client side (and the possible Suspense out of that) you will need to pass down initialLanguage (will call changeLanguage on i18next) and initialI18nStore (will prefill translations in i18next store). 59 | 60 | ### using the useSSR hook 61 | 62 | ```jsx 63 | import React from 'react'; 64 | import { useSSR } from 'react-i18next'; 65 | 66 | export function InitSSR({ initialI18nStore, initialLanguage }) { 67 | useSSR(initialI18nStore, initialLanguage); 68 | 69 | return 70 | } 71 | ``` 72 | 73 | ### using the withSSR HOC 74 | 75 | ```jsx 76 | import React from 'react'; 77 | import { withSSR } from 'react-i18next'; 78 | import App from './App'; 79 | 80 | const ExtendedApp = withSSR()(App); 81 | 82 | 83 | ``` 84 | 85 | The ExtendedApp in this case will also have the composed `ExtendedApp.getInitialProps()` 86 | -------------------------------------------------------------------------------- /latest/trans-component.md: -------------------------------------------------------------------------------- 1 | # Trans Component 2 | 3 | ## Important note 4 | 5 | While `` gives you a lot of power by letting you interpolate or translate complex React elements, the truth is: in most cases you don't even need it. 6 | 7 | **As long you have no React/HTML nodes integrated into a cohesive sentence** (text formatting like `strong`, `em`, link components, maybe others), **you won't need it** - most of the times you will be using the good old `t` function. 8 | 9 | You may be looking directly for the [Trans props](https://react.i18next.com/latest/trans-component#trans-props). 10 | 11 | {% hint style="warning" %} 12 | It does ONLY interpolation. It does not rerender on language change or load any translations needed. Check [`useTranslation` hook](usetranslation-hook.md) or [`withTranslation` HOC](withtranslation-hoc.md) for those cases. 13 | {% endhint %} 14 | 15 | ```javascript 16 | import React from 'react'; 17 | import { Trans, useTranslation } from 'react-i18next' 18 | 19 | function MyComponent() { 20 | const { t } = useTranslation('myNamespace'); 21 | 22 | return Hello World; 23 | } 24 | ``` 25 | 26 | {% hint style="info" %} 27 | Have a look at the [i18next documentation](https://www.i18next.com) for details on the the `t` function: 28 | 29 | * [essentials](https://www.i18next.com/translation-function/essentials.html) 30 | * [interpolation](https://www.i18next.com/translation-function/interpolation.html) 31 | * [formatting](https://www.i18next.com/translation-function/formatting.html) 32 | * [plurals](https://www.i18next.com/translation-function/plurals.html) 33 | {% endhint %} 34 | 35 | ## Samples 36 | 37 | ### Using with React components 38 | 39 | So you learned there is no need to use the Trans component everywhere (the plain `t` function will just do fine in most cases). 40 | 41 | This component enables you to nest any React content to be translated as one cohesive string. It supports both plural and interpolation. The `` component will automatically use the most relevant `t()` function (from the [context instance](https://react.i18next.com/latest/i18nextprovider) or the global instance), unless overridden via the `i18n` or `t` props. 42 | 43 | _Let's say you want to create following HTML output:_ 44 | 45 | > Hello **Arthur**, you have 42 unread messages. [Go to messages](../legacy-v9/trans-component.md). 46 | 47 | **Before:** Your untranslated React code would have looked something like: 48 | 49 | ```javascript 50 | function MyComponent({ person, messages }) { 51 | const { name } = person; 52 | const count = messages.length; 53 | 54 | return ( 55 | <> 56 | Hello {name}, you have {count} unread message(s). Go to messages. 57 | 58 | ); 59 | } 60 | ``` 61 | 62 | **After:** With the Trans component just change it to: 63 | 64 | ```javascript 65 | import { Trans } from 'react-i18next'; 66 | 67 | function MyComponent({ person, messages }) { 68 | const { name } = person; 69 | const count = messages.length; 70 | 71 | return ( 72 | 73 | Hello {{name}}, you have {{count}} unread message. Go to messages. 74 | 75 | ); 76 | } 77 | ``` 78 | 79 | _Your en.json (translation strings) will look like:_ 80 | 81 | ```javascript 82 | "nameTitle": "This is your name", 83 | "userMessagesUnread_one": "Hello <1>{{name}}, you have {{count}} unread message. <5>Go to message.", 84 | "userMessagesUnread_other": "Hello <1>{{name}}, you have {{count}} unread messages. <5>Go to messages.", 85 | ``` 86 | 87 | {% hint style="info" %} 88 | [**saveMissing**](https://www.i18next.com/overview/configuration-options#missing-keys) will send a valid `defaultValue` based on the component children.\ 89 | Also, The `i18nKey` is optional, in case you already use text as translation keys. 90 | {% endhint %} 91 | 92 | ### Alternative usage which lists the components (v11.6.0) 93 | 94 | ```javascript 95 | fallbacks to defaults if not provided 97 | defaults="hello beautiful {{what}}" // optional defaultValue 98 | values={{ what: 'world'}} 99 | components={{ italic: , bold: }} 100 | /> 101 | ``` 102 | 103 | This format is useful if you want to interpolate the same node multiple times. Another advantage is the simpler named tags, which avoids the trouble with index guessing - however, this can also be achieved with `transSupportBasicHtmlNodes`, see the next section. 104 | 105 | {% hint style="warning" %} 106 | Existing self-closing HTML tag names are reserved keys and won't work. Examples: `link: `, `img: `, `media: ` 107 | {% endhint %} 108 | 109 | {% hint style="info" %} 110 | Make sure you also adapt your translation resources to include the _named tags_ (``) instead of the _indexed tags_ (`<0>`)! 111 | {% endhint %} 112 | 113 | ### Overriding React component props (v11.5.0) 114 | 115 | In some cases you may want to override the props of a given component based on the active language. 116 | 117 | This can be achieved by providing prop values inside of your translations. Such values will override whatever has been passed to the component present in the `components` prop of the `Trans` component. 118 | 119 | In the example below we want our custom link component to have a different `href` value based on the active language. This is how our custom link component is being used: 120 | 121 | ```javascript 122 | 126 | }} 127 | /> 128 | ``` 129 | 130 | with the following being our translation message: 131 | 132 | ```json 133 | "myKey": "This is a link to example.com." 134 | ``` 135 | 136 | This setup will render the following JSX: 137 | 138 | ```html 139 | This is a link to example.com. 140 | ``` 141 | 142 | This approach also works with listed components: 143 | 144 | ```javascript 145 | ]} 148 | /> 149 | ``` 150 | 151 | With this then making up our translation message: 152 | 153 | ```json 154 | "myKey": "This is a <0 href=\"https://example.com/\">link to example.com." 155 | ``` 156 | 157 | ### Usage with simple HTML elements like \
and others (v10.4.0) 158 | 159 | There are two options that allow you to have basic HTML tags inside your translations, instead of numeric indexes. However, this only works for elements without additional attributes (like `className`), having none or a single text children. 160 | 161 | Examples of elements that will be readable in translation strings: 162 | 163 | * `
` 164 | * `bold` 165 | * `

some paragraph

` 166 | 167 | Examples that will be converted to indexed nodes: 168 | 169 | * ``: no attributes allowed 170 | * `{{name}}`: only text nodes allowed 171 | * `bold italic`: no nested elements, even simple ones 172 | 173 | ```jsx 174 | 175 | Hello {{name}}. See my profile 176 | 177 | // JSON -> "welcomeUser": "Hello {{name}}. <1>See my profile" 178 | 179 | 180 | Some newlines
would be
fine 181 |
182 | // JSON -> "multiline": "Some newlines
would be
fine" 183 | ``` 184 | 185 | Here is what can be configured in `i18next.options.react` that affect this behaviour: 186 | 187 | | Option | Default | Description | 188 | | ------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 189 | | `transSupportBasicHtmlNodes` | `true` | Enables keeping the name of simple nodes (e.g. `
`) in translations instead of indexed keys | 190 | | `transKeepBasicHtmlNodesFor` | `['br', 'strong', 'i', 'p']` | Which nodes are allowed to be kept in translations during `defaultValue` generation of ``. | 191 | | `transWrapTextNodes` (v11.10.0) | `''` | Wrap text nodes in a user-specified element. e.g. set it to `span`. By default, text nodes are not wrapped. Can be used to work around a well-known Google Translate issue with React apps. See [facebook/react#11538](https://github.com/facebook/react/issues/11538). | 192 | 193 | ### Interpolation 194 | 195 | You can pass in variables to get interpolated into the translation string by using objects containing those key:values. 196 | 197 | ```jsx 198 | const person = { name: 'Henry', age: 21 }; 199 | const { name, age } = person; 200 | 201 | 202 | Hello {{ name }}. // <- = {{ "name": name }} 203 | 204 | // Translation string: "Hello {{name}}" 205 | 206 | 207 | 208 | Hello {{ firstname: person.name }}. 209 | 210 | // Translation string: "Hello {{firstname}}" 211 | ``` 212 | 213 | ### Plural 214 | 215 | You will need to pass the `count` prop: 216 | 217 | ```jsx 218 | const messages = ['message one', 'message two']; 219 | 220 | 221 | You have {{ count: messages.length }} messages. 222 | 223 | 224 | // Translation strings: 225 | // "newMessages": "You have one message." 226 | // "newMessages_plural": "You have {{count}} messages." 227 | ``` 228 | 229 | ### Using with lists (v10.5.0) 230 | 231 | You can still use `Array.map()` to turn dynamic content into nodes, using an extra option on a wrapping element: 232 | 233 | ```jsx 234 | 235 | My dogs are named: 236 |
    237 | {['rupert', 'max'].map(dog => (
  • {dog}
  • ))} 238 |
239 |
240 | // JSON -> "list_map": "My dogs are named: <1>" 241 | ``` 242 | 243 | Setting `i18nIsDynamicList` on the parent element will assert the `nodeToString` function creating the string for `saveMissing` will not contain children. 244 | 245 | ### Alternative usage (components array) 246 | 247 | Some use cases, such as the ICU format, might be simpler by just passing content as props: 248 | 249 | ```javascript 250 | fallbacks to defaults if not provided 252 | defaults="hello <0>{{what}}" // optional defaultValue 253 | values={{ what: 'world'}} 254 | components={[univers]} 255 | /> 256 | ``` 257 | 258 | {% hint style="info" %} 259 | `<0>` -> 0 is the index of the component in the components array 260 | {% endhint %} 261 | 262 | E.g. this format is needed when using [ICU as translation format](https://github.com/i18next/i18next-icu) as it is not possible to have the needed syntax as children (invalid jsx). 263 | 264 | ## How to get the correct translation string? 265 | 266 | Guessing replacement tags _(<0>\)_ of your component is rather difficult. There are four options to get those translations directly generated by i18next: 267 | 268 | 1. use React Developer Tools to inspect the `` component instance and look at the `props.children` array for array index of the tag in question. 269 | 2. use `debug = true` in `i18next.init()` options and watch your console for the missing key output 270 | 3. use the [saveMissing feature](https://www.i18next.com/configuration-options#missing-keys) of i18next to get those translations pushed to your backend or handled by a custom function. 271 | 4. understand how those numbers get generated from child index: 272 | 273 | **Sample JSX:** 274 | 275 | ```javascript 276 | 277 | Hello {{name}}, you have {{count}} unread message. Go to messages. 278 | 279 | ``` 280 | 281 | **Resulting translation string:** 282 | 283 | ``` 284 | "Hello <1>{{name}}, you have {{count}} unread message. <5>Go to message." 285 | ``` 286 | 287 | **The complete the node tree**: 288 | 289 | ```javascript 290 | Trans.children = [ 291 | 'Hello ', // 0: only a string 292 | { children: [{ name: 'Jan' }] }, // 1: with child object for interpolation 293 | ', you have ', // 2: only a string 294 | { count: 10 }, // 3: plain object for interpolation 295 | ' unread messages. ', // 4: only a string 296 | { children: ['Go to messages'] }, // 5: with a string child 297 | '.' // 6: yep, you guessed: another string 298 | ] 299 | ``` 300 | 301 | **Rules:** 302 | 303 | * child is a string: nothing to wrap; just take the string 304 | * child is an object: nothing to do; it's used for interpolation 305 | * child is an element: wrap it's children in `` where `x` is the index of that element's position in the `children` list; handle its children with the same rules (starting `element.children` index at 0 again) 306 | 307 | ## Trans props 308 | 309 | All properties are optional, although you'll need to use `i18nKey` if you're not using natural language keys (text-based). 310 | 311 | | _**name**_ | _**type (default)**_ | _**description**_ | 312 | | ---------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 313 | | `i18nKey` | `string (undefined)` |

If you prefer to use text as keys you can omit this, and the translation will be used as key. Can contain the namespace by prepending it in the form 'ns:key' (depending on i18next.options.nsSeparator)

But this is not recommended when used in combination with natural language keys, better use the dedicated ns parameter: <Trans i18nKey="myKey" ns="myNS"></Trans>

| 314 | | `ns` | `string (undefined)` | Namespace to use. May also be embedded in `i18nKey` but not recommended when used in combination with natural language keys, see above. | 315 | | `t` | `function (undefined)` | `t` function to use instead of the global `i18next.t()` or the `t()` function provided by the nearest [provider](https://react.i18next.com/latest/i18nextprovider). | 316 | | `count` | `integer (undefined)` | Numeric value for pluralizable strings | 317 | | `context` | `string (undefined)` | Value used for the [context feature](https://www.i18next.com/translation-function/context). | 318 | | `tOptions` | `object (undefined)` | Extra options to pass to `t()` (e.g. `context`, `postProcessor`, ...) | 319 | | `parent` | `node (undefined)` | A component to wrap the content into (can be globally set on `i18next.init`). **Required for React < v16** | 320 | | `i18n` | `object (undefined)` | i18next instance to use if not provided by context | 321 | | `defaults` | `string (undefined)` | Use this instead of using the children as default translation value (useful for ICU) | 322 | | `values` | `object (undefined)` | Interpolation values if not provided in children | 323 | | `components` | `array[nodes] (undefined)` | Components to interpolate based on index of tag | 324 | | `shouldUnescape` | `boolean (false)` | HTML encoded tags like: `< & >` should be unescaped, to become: `< & >` | 325 | 326 | ### i18next options 327 | 328 | ```javascript 329 | i18next.init({ 330 | // ... 331 | react: { 332 | // ... 333 | hashTransKey: function(defaultValue) { 334 | // return a key based on defaultValue or if you prefer to just remind you should set a key return false and throw an error 335 | }, 336 | defaultTransParent: 'div', // a valid react element - required before react 16 337 | transEmptyNodeValue: '', // what to return for empty Trans 338 | transSupportBasicHtmlNodes: true, // allow
and simple html elements in translations 339 | transKeepBasicHtmlNodesFor: ['br', 'strong', 'i'], // don't convert to <1> if simple react elements 340 | transWrapTextNodes: '', // Wrap text nodes in a user-specified element. 341 | // i.e. set it to 'span'. By default, text nodes are not wrapped. 342 | // Can be used to work around a well-known Google Translate issue with React apps. See: https://github.com/facebook/react/issues/11538 343 | // (v11.10.0) 344 | } 345 | }); 346 | ``` 347 | 348 | {% hint style="warning" %} 349 | Please be aware if you are using **React 15 or below**, you are required to set the `defaultTransParent` option, or pass a `parent` via props. 350 | {% endhint %} 351 | 352 | {% hint style="danger" %} 353 | **Are you having trouble when your website is ran through Google Translate?**\ 354 | Google Translate seems to manipulate the DOM and makes React quite unhappy!\ 355 | **There's a work around:** you can wrap text nodes with`` using `transWrapTextNodes: 'span'`. 356 | 357 | _If you want to know more about the Google Translate issue with React, have a look at_ [_this_](https://github.com/facebook/react/issues/11538#issuecomment-390386520)_._ 358 | {% endhint %} 359 | -------------------------------------------------------------------------------- /latest/translation-render-prop.md: -------------------------------------------------------------------------------- 1 | # Translation (render prop) 2 | 3 | ## What it does 4 | 5 | The `Translation` is a render prop and gets the `t` function and `i18n` instance to your component. 6 | 7 | ```jsx 8 | import React from 'react'; 9 | import { Translation } from 'react-i18next'; 10 | 11 | export function MyComponent() { 12 | return ( 13 | 14 | { 15 | (t, { i18n }) =>

{t('my translated text')}

16 | } 17 |
18 | ) 19 | } 20 | ``` 21 | 22 | While you most time only need the t function to translate your content you also get the i18n instance to eg. change the language. 23 | 24 | ```javascript 25 | i18n.changeLanguage('en-US'); 26 | ``` 27 | 28 | {% hint style="info" %} 29 | The `Translation` render prop will trigger a [Suspense](https://reactjs.org/docs/code-splitting.html#suspense) if not ready (eg. pending load of translation files). You can set `useSuspense` to false if prefer not using Suspense. 30 | {% endhint %} 31 | 32 | ## When to use? 33 | 34 | Use the `Translation` render prop inside **any component (class or function)** to access the translation function or i18n instance. 35 | 36 | ## Translation params 37 | 38 | ### Loading namespaces 39 | 40 | ```jsx 41 | // load a specific namespace 42 | // the t function will be set to that namespace as default 43 | 44 | { 45 | (t) =>

{t('my translated text')}

// will be looked up from namespace ns1 46 | } 47 |
48 | 49 | // load multiple namespaces 50 | // the t function will be set to first namespace as default 51 | 52 | { 53 | (t) =>

{t('my translated text')}

// will be looked up from namespace ns1 54 | } 55 |
56 | ``` 57 | 58 | ### Overriding the i18next instance 59 | 60 | ```jsx 61 | // passing in an i18n instance 62 | // use only if you do not like the default instance 63 | // set by i18next.use(initReactI18next) or the I18nextProvider 64 | import i18n from './i18n'; 65 | 66 | 67 | { 68 | (t, { i18n }) =>

{t('my translated text')}

// will be looked up from namespace ns1 69 | } 70 |
71 | ``` 72 | 73 | -------------------------------------------------------------------------------- /latest/typescript.md: -------------------------------------------------------------------------------- 1 | # TypeScript 2 | 3 | {% hint style="warning" %} 4 | Make sure you update to **react-i18next >= 13.0.0** and **i18next >= 23.0.1** and follow the instructions [here](https://www.i18next.com/overview/typescript). 5 | {% endhint %} 6 | 7 | -------------------------------------------------------------------------------- /latest/usetranslation-hook.md: -------------------------------------------------------------------------------- 1 | # useTranslation (hook) 2 | 3 | ## What it does 4 | 5 | It gets the `t` function and `i18n` instance inside your functional component. 6 | 7 | ```jsx 8 | import React from 'react'; 9 | import { useTranslation } from 'react-i18next'; 10 | 11 | export function MyComponent() { 12 | const { t, i18n } = useTranslation(); // not passing any namespace will use the defaultNS (by default set to 'translation') 13 | // or const [t, i18n] = useTranslation(); 14 | 15 | return

{t('my translated text')}

16 | } 17 | ``` 18 | 19 | While most of the time you only need the `t` function to translate your content, you can also get the i18n instance (in order to change the language). 20 | 21 | ```javascript 22 | i18n.changeLanguage('en-US'); 23 | ``` 24 | 25 | {% hint style="info" %} 26 | The `useTranslation` hook will trigger a [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html) if not ready (eg. pending load of translation files). You can set `useSuspense` to false if prefer not using Suspense. 27 | {% endhint %} 28 | 29 | ## When to use? 30 | 31 | Use the `useTranslation` hook inside your **functional components** to access the translation function or i18n instance. 32 | 33 | {% hint style="success" %} 34 | In [this tutorial](https://locize.com/blog/react-i18next/) you'll find some ways on how to use this useTranslation hook. 35 | 36 | You'll also see how to use it when you need to work with [multiple namespaces](https://locize.com/blog/react-i18next/#multiple-namespaces).[\ 37 | ](https://locize.com/blog/react-i18next/) 38 | {% endhint %} 39 | 40 | ## useTranslation params 41 | 42 | ### Loading namespaces 43 | 44 | ```javascript 45 | // load a specific namespace 46 | // the t function will be set to that namespace as default 47 | const { t, i18n } = useTranslation('ns1'); 48 | t('key'); // will be looked up from namespace ns1 49 | 50 | // load multiple namespaces 51 | // the t function will be set to first namespace as default 52 | const { t, i18n } = useTranslation(['ns1', 'ns2', 'ns3']); 53 | t('key'); // will be looked up from namespace ns1 54 | t('key', { ns: 'ns2' }); // will be looked up from namespace ns2 55 | ``` 56 | 57 | ### Overriding the i18next instance 58 | 59 | ```javascript 60 | // passing in an i18n instance 61 | // use only if you do not like the default instance 62 | // set by i18next.use(initReactI18next) or the I18nextProvider 63 | import i18n from './i18n'; 64 | const { t, i18n } = useTranslation('ns1', { i18n }); 65 | ``` 66 | 67 | ### Optional keyPrefix option 68 | 69 | > available in react-i18next version >= 11.12.0 70 | > 71 | > depends on i18next version >= 20.6.0 72 | 73 | ```javascript 74 | // having JSON in namespace "translation" like this: 75 | /*{ 76 | "very": { 77 | "deeply": { 78 | "nested": { 79 | "key": "here" 80 | } 81 | } 82 | } 83 | }*/ 84 | // you can define a keyPrefix to be used for the resulting t function 85 | const { t } = useTranslation('translation', { keyPrefix: 'very.deeply.nested' }); 86 | const text = t('key'); // "here" 87 | ``` 88 | 89 | {% hint style="warning" %} 90 | Do **not** use the `keyPrefix` option if you want to use keys with prefixed namespace notation: 91 | 92 | i.e. 93 | 94 | ```javascript 95 | const { t } = useTranslation('translation', { keyPrefix: 'very.deeply.nested' }); 96 | const text = t('ns:key'); // this will not work 97 | ``` 98 | {% endhint %} 99 | 100 | ### Optional lng option 101 | 102 | > available in react-i18next version >= 12.3.1 103 | 104 | ```javascript 105 | // you can pass a language to be used for the resulting t function 106 | const { t } = useTranslation('translation', { lng: 'de' }); 107 | const text = t('key'); // "hier" 108 | ``` 109 | 110 | ### Not using Suspense 111 | 112 | ```javascript 113 | // additional ready will state if translations are loaded or not 114 | const { t, i18n, ready } = useTranslation('ns1', { useSuspense: false }); 115 | ``` 116 | 117 | {% hint style="info" %} 118 | Not using Suspense you will need to handle the not ready state yourself by eg. render a loading component as long `!ready` . Not doing so will result in rendering your translations before they loaded which will cause save missing be called although translations exists (just yet not loaded). 119 | {% endhint %} 120 | -------------------------------------------------------------------------------- /latest/using-with-hooks.md: -------------------------------------------------------------------------------- 1 | # Step by step guide 2 | 3 | ## Install needed dependencies 4 | 5 | We expect you to have an existing react application supporting [hooks](https://reactjs.org/docs/hooks-intro.html) (at least v16.7.0-alpha of react and react-dom). 6 | 7 | Install both react-i18next and i18next packages: 8 | 9 | ```bash 10 | npm install react-i18next i18next --save 11 | 12 | # if you'd like to detect user language and load translation 13 | npm install i18next-http-backend i18next-browser-languagedetector --save 14 | ``` 15 | 16 | ### Configure i18next 17 | 18 | I18next is the core of the i18n functionality while react-i18next extends and glues it to react. 19 | 20 | Create a new file `i18n.js` beside your `index.js` containing following content: 21 | 22 | ```javascript 23 | import i18n from 'i18next'; 24 | import { initReactI18next } from 'react-i18next'; 25 | 26 | import Backend from 'i18next-http-backend'; 27 | import LanguageDetector from 'i18next-browser-languagedetector'; 28 | // don't want to use this? 29 | // have a look at the Quick start guide 30 | // for passing in lng and translations on init 31 | 32 | i18n 33 | // load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales) 34 | // learn more: https://github.com/i18next/i18next-http-backend 35 | // want your translations to be loaded from a professional CDN? => https://github.com/locize/react-tutorial#step-2---use-the-locize-cdn 36 | .use(Backend) 37 | // detect user language 38 | // learn more: https://github.com/i18next/i18next-browser-languageDetector 39 | .use(LanguageDetector) 40 | // pass the i18n instance to react-i18next. 41 | .use(initReactI18next) 42 | // init i18next 43 | // for all options read: https://www.i18next.com/overview/configuration-options 44 | .init({ 45 | fallbackLng: 'en', 46 | debug: true, 47 | 48 | interpolation: { 49 | escapeValue: false, // not needed for react as it escapes by default 50 | } 51 | }); 52 | 53 | 54 | export default i18n; 55 | ``` 56 | 57 | The interesting part here is by `i18n.use(initReactI18next)` we pass the i18n instance to react-i18next which will make it available for all the components. 58 | 59 | Then import that in `index.js`: 60 | 61 | ```javascript 62 | import React, { Component } from "react"; 63 | import { createRoot } from 'react-dom/client'; 64 | import App from './App'; 65 | 66 | // import i18n (needs to be bundled ;)) 67 | import './i18n'; 68 | 69 | const root = createRoot(document.getElementById('root')); 70 | root.render( 71 | 72 | ); 73 | ``` 74 | 75 | {% hint style="info" %} 76 | If you need to access the `t` function or the `i18next` instance from outside of a React component you can simply import your `./i18n.js` and use the exported i18next instance: 77 | 78 | ``` 79 | import i18next from './i18n' 80 | 81 | i18next.t('my.key') 82 | ``` 83 | {% endhint %} 84 | 85 | ### Translate your content 86 | 87 | #### Using the useTranslation hook 88 | 89 | You can use the hook inside your functional components like: 90 | 91 | ```jsx 92 | import React, { Suspense } from 'react'; 93 | import { useTranslation } from 'react-i18next'; 94 | 95 | function MyComponent() { 96 | const { t, i18n } = useTranslation(); 97 | 98 | return

{t('Welcome to React')}

99 | } 100 | 101 | // i18n translations might still be loaded by the http backend 102 | // use react's Suspense 103 | export default function App() { 104 | return ( 105 | 106 | 107 | 108 | ); 109 | } 110 | ``` 111 | 112 | The useTranslation hook function takes one options argument. You can either pass in a namespace or an array of namespaces to load. 113 | 114 | ```javascript 115 | const { t, i18n } = useTranslation('common'); 116 | 117 | const { t, i18n } = useTranslation(['page1', 'common']); 118 | ``` 119 | 120 | #### Translation Files 121 | 122 | Create a new file `public/locales//translation.json` with the following sample content. 123 | 124 | ``` 125 | { 126 | "title": "Welcome to react using react-i18next", 127 | "description": { 128 | "part1": "To get started, edit <1>src/App.js and save to reload.", 129 | "part2": "Switch language between english and german using buttons above." 130 | } 131 | } 132 | ``` 133 | 134 | Files are plain JSON you can checkout the full sample [here](https://github.com/i18next/react-i18next/tree/master/example/react/public/locales). 135 | 136 | {% hint style="info" %} 137 | Please note the t function will be either bound to the default namespace defined on i18next init or to the first one passed in arguments. 138 | {% endhint %} 139 | 140 | {% content-ref url="../guides/multiple-translation-files.md" %} 141 | [multiple-translation-files.md](../guides/multiple-translation-files.md) 142 | {% endcontent-ref %} 143 | 144 | #### Using the withTranslation HOC 145 | 146 | There might be some legacy cases where you are still forced to use classes. Don't worry, we still provide a hoc to cover these cases: 147 | 148 | ```jsx 149 | import React, { Component, Suspense } from 'react'; 150 | import { withTranslation } from 'react-i18next'; 151 | 152 | class LegacyComponentClass extends Component { 153 | render() { 154 | const { t } = this.props; 155 | 156 | return ( 157 |

{t('Welcome to React')}

158 | ) 159 | } 160 | } 161 | const MyComponent = withTranslation()(LegacyComponentClass) 162 | 163 | // i18n translations might still be loaded by the http backend 164 | // use react's Suspense 165 | export default function App() { 166 | return ( 167 | 168 | 169 | 170 | ); 171 | } 172 | ``` 173 | 174 | The withTranslation hook function takes one options argument. You can either pass in a namespace or a array of namespaces to load. 175 | 176 | ```javascript 177 | withTranslation('common')(LegacyComponentClass); 178 | 179 | withTranslation(['page1', 'common'])(LegacyComponentClass); 180 | ``` 181 | 182 | #### Using the Trans component 183 | 184 | The Trans component is the best way to translate a JSX tree in one translation. This enables you to eg. easily translate text containing a link component or formatting like ``. 185 | 186 | ```jsx 187 | import React from 'react'; 188 | import { Trans } from 'react-i18next'; 189 | 190 | export default function MyComponent () { 191 | return Welcome to React 192 | } 193 | 194 | // the translation in this case should be 195 | "Welcome to <1>React": "Welcome to <1>React and react-i18next" 196 | ``` 197 | 198 | Don't worry if you do not yet understand how the Trans component works in detail. Learn more about it [here](trans-component.md). 199 | 200 | ## See the sample 201 | 202 | Prefer having code to checkout? Directly dive into our example: 203 | 204 | * [using hooks with react-i18next](https://github.com/i18next/react-i18next/tree/master/example/react) 205 | 206 | ### Do you like to read a more complete step by step tutorial? 207 | 208 | {% hint style="success" %} 209 | [Here](https://locize.com/blog/react-i18next/) you'll find a simple tutorial on how to best use react-i18next.\ 210 | Some basics of i18next and some cool possibilities on how to optimize your localization workflow.[\ 211 | ![](<../.gitbook/assets/title width (1).jpg>)](https://locize.com/blog/react-i18next/) 212 | {% endhint %} 213 | -------------------------------------------------------------------------------- /latest/withtranslation-hoc.md: -------------------------------------------------------------------------------- 1 | # withTranslation (HOC) 2 | 3 | ## What it does 4 | 5 | The `withTranslation` is a classic HOC (higher order component) and gets the `t` function and `i18n` instance inside your component via props. 6 | 7 | ```jsx 8 | import React from 'react'; 9 | import { withTranslation } from 'react-i18next'; 10 | 11 | function MyComponent({ t, i18n }) { 12 | return

{t('my translated text')}

13 | } 14 | 15 | export default withTranslation()(MyComponent); 16 | ``` 17 | 18 | While you most time only need the t function to translate your content you also get the i18n instance to eg. change the language. 19 | 20 | ```javascript 21 | i18n.changeLanguage('en-US'); 22 | ``` 23 | 24 | {% hint style="info" %} 25 | The `withTranslation` HOC will trigger a [Suspense](https://reactjs.org/docs/code-splitting.html#suspense) if not ready (eg. pending load of translation files). You can set `useSuspense` to false if prefer not using Suspense. 26 | {% endhint %} 27 | 28 | ## When to use? 29 | 30 | Use the `withTranslation` HOC to wrap **any component (class or function)** to access the translation function or i18n instance. 31 | 32 | ## withTranslation params 33 | 34 | ### Loading namespaces 35 | 36 | ```javascript 37 | // load a specific namespace 38 | // the t function will be set to that namespace as default 39 | withTranslation('ns1')(MyComponent); 40 | 41 | // inside your component MyComponent 42 | this.props.t('key'); // will be looked up from namespace ns1 43 | 44 | // load multiple namespaces 45 | // the t function will be set to first namespace as default 46 | withTranslation(['ns1', 'ns2', 'ns3'])(MyComponent); 47 | 48 | // inside your component MyComponent 49 | this.props.t('key'); // will be looked up from namespace ns1 50 | this.props.t('key', { ns: 'ns2' }); // will be looked up from namespace ns2 51 | ``` 52 | 53 | ### Overriding the i18next instance 54 | 55 | ```javascript 56 | // passing in an i18n instance 57 | // use only if you do not like the default instance 58 | // set by i18next.use(initReactI18next) or the I18nextProvider 59 | import i18n from './i18n'; 60 | 61 | const ExtendedComponent = withTranslation('ns1')(MyComponent); 62 | 63 | 64 | ``` 65 | 66 | ### Not using Suspense 67 | 68 | ```javascript 69 | // use tReady prop in MyComponent to check if translations 70 | // are already loaded or not 71 | const ExtendedComponent = withTranslation()(MyComponent); 72 | 73 | 74 | ``` 75 | 76 | {% hint style="info" %} 77 | Not using Suspense you will need to handle the not ready state yourself by eg. render a loading component as long `!props.tReady` . Not doing so will result in rendering your translations before they loaded which will cause save missing be called although translations exist (just yet not loaded). 78 | {% endhint %} 79 | 80 | ## How to 81 | 82 | ### use ref (>= v10.6.0) 83 | 84 | You can use forwardRefs like: 85 | 86 | ```jsx 87 | const Wrapped = withTranslation('translation', { withRef: true })(MyComponent); 88 | 89 | // then pass a ref in your render method like 90 | const myRef = React.createRef(); 91 | ; 92 | 93 | // use myRef.current to access it 94 | ``` 95 | 96 | ### hoist non-react statics 97 | 98 | The HOC does not hoist statics itself so you might append those statics manually or by using a module. 99 | 100 | Use [hoist-non-react-statics](https://github.com/mridgway/hoist-non-react-statics) yourself: 101 | 102 | ```jsx 103 | import React, { Component } from 'react'; 104 | import { withTranslation } from 'react-i18next'; 105 | import hoistStatics from 'hoist-non-react-statics'; 106 | 107 | class MyComponent extends Component { 108 | static ... 109 | } 110 | 111 | export default hoistStatics(withTranslation()(MyComponent), MyComponent); 112 | ``` 113 | 114 | Or simply hoist the one/two statics yourself: 115 | 116 | ```jsx 117 | import React, { Component } from 'react'; 118 | import { withTranslation } from 'react-i18next'; 119 | import hoistStatics from 'hoist-non-react-statics'; 120 | 121 | class MyComponent extends Component { 122 | static ... 123 | } 124 | 125 | const Extended = withTranslation()(MyComponent); 126 | Extended.static = MyComponent.static; 127 | 128 | export default Extended; 129 | ``` 130 | 131 | ### use TypeScript with class components 132 | 133 | To get proper type annotations while using TypeScript, import the interface `WithTranslation` and extend it with your own props interface. 134 | 135 | ``` 136 | import React, { Component } from 'react'; 137 | import { withTranslation, WithTranslation } from 'react-i18next'; 138 | 139 | class MyComponent extends Component { 140 | render() { 141 | return
{this.props.t('My translated text')}
142 | } 143 | } 144 | 145 | interface IProps extends WithTranslation { 146 | prop: any; 147 | } 148 | 149 | interface IState { 150 | state: any; 151 | } 152 | 153 | export default withTranslation()(MyComponent); 154 | ``` 155 | -------------------------------------------------------------------------------- /legacy-v9/i18next-instance.md: -------------------------------------------------------------------------------- 1 | # i18next instance (v9) 2 | 3 | The instance is an initialized i18next instance. In the following code snippet, we add a backend to load translations from server and a language detector for detecting user language. 4 | 5 | > You can learn more about [i18next](http://i18next.com) and [plugins](https://www.i18next.com/plugins-and-utils.html#plugins) on the i18next website. 6 | 7 | {% hint style="info" %} 8 | The instance could be passed to the [I18nextProvider](i18nextprovider.md) or directly to the [translate hoc](broken-reference). 9 | 10 | The **reactI18nextModule** used below is an alternative to using the [I18nextProvider](i18nextprovider.md) and asserts that components ([render prop](broken-reference), [hoc](broken-reference)) lower in the element tree get access to the i18n instance. 11 | {% endhint %} 12 | 13 | ```javascript 14 | import i18n from 'i18next'; 15 | import XHR from 'i18next-xhr-backend'; 16 | import LanguageDetector from 'i18next-browser-languagedetector'; 17 | import { reactI18nextModule } from 'react-i18next'; 18 | 19 | 20 | i18n 21 | .use(XHR) 22 | .use(LanguageDetector) 23 | .use(reactI18nextModule) // if not using I18nextProvider 24 | .init({ 25 | fallbackLng: 'en', 26 | debug: true, 27 | 28 | interpolation: { 29 | escapeValue: false, // not needed for react!! 30 | }, 31 | 32 | // react i18next special options (optional) 33 | react: { 34 | wait: false, 35 | bindI18n: 'languageChanged loaded', 36 | bindStore: 'added removed', 37 | nsMode: 'default' 38 | } 39 | }); 40 | 41 | 42 | export default i18n; 43 | ``` 44 | 45 | All additional options for react in init options: 46 | 47 | | _**options**_ | _**default**_ | _**description**_ | 48 | | ------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 49 | | wait | false | assert all provided namespaces are loaded before rendering the component (can be set [globally](i18next-instance.md) too); note that rendering will not be blocked again when dynamically updating `ns` on the [render prop component](broken-reference) after initial mount | 50 | | nsMode | 'default' | _default:_ namespaces will be loaded an the first will be set as default or _fallback:_ namespaces will be used as fallbacks used in order provided | 51 | | bindI18n | 'languageChanged loaded' | which events trigger a rerender, can be set to false or string of events | 52 | | bindStore | 'added removed' | which events on store trigger a rerender, can be set to false or string of events | 53 | 54 | For more initialization options have look at the [docs](https://www.i18next.com/configuration-options.html). 55 | -------------------------------------------------------------------------------- /legacy-v9/i18nextprovider.md: -------------------------------------------------------------------------------- 1 | # I18nextProvider (v9) 2 | 3 | The provider is responsible to pass the i18next instance passed in by props down to all the [withNamespaces](withnamespaces.md) hocs or [NamespacesConsumer](namespacesconsumer.md) render prop using react context api. 4 | 5 | ```javascript 6 | import React from 'react'; 7 | import ReactDOM from 'react-dom'; 8 | import { I18nextProvider } from 'react-i18next'; 9 | 10 | import App from './App'; // your entry page 11 | import i18n from './i18n'; // initialized i18next instance 12 | 13 | ReactDOM.render( 14 | 15 | 16 | , 17 | document.getElementById('app') 18 | ); 19 | ``` 20 | 21 | For the i18n instance have a look at the [i18next instance page](i18next-instance.md). 22 | 23 | As an alternative you can use the [reactI18nextModule](i18next-instance.md) in the i18n instance. 24 | 25 | ## The I18nextProvider props: 26 | 27 | | _**name**_ | **type (**_**default)**_ | _**description**_ | 28 | | ---------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------- | 29 | | **i18n** | object (undefined) | pass i18next instance the provider will pass it down to translation components by context | 30 | | defaultNS | string (undefined) | optionally pass down a default namespace to your translate HOC, I18n render prop (without having to specify it there) | 31 | | initialI18nStore | object (undefined) | pass in initial translations (useful for [serverside rendering](serverside-rendering.md)) | 32 | | initialLanguage | string (undefined) | pass in initial language (useful for [serverside rendering](serverside-rendering.md)) | 33 | -------------------------------------------------------------------------------- /legacy-v9/interpolate.md: -------------------------------------------------------------------------------- 1 | # Interpolate (v9) 2 | 3 | {% hint style="danger" %} 4 | Deprecated: We highly recommend having a look at the new [trans component](trans-component.md) as it provides a better experience. 5 | 6 | This component will be remove in the next major version v9.0.0!! 7 | {% endhint %} 8 | 9 | The interpolate component enables you to interpolate react components into translation strings (eg. to use links). 10 | 11 | the key: 12 | 13 | ```javascript 14 | { 15 | "interpolateSample": "you can interpolate {{value}} or {{component}} via interpolate component!" 16 | } 17 | ``` 18 | 19 | sample: 20 | 21 | ```javascript 22 | import React from 'react'; 23 | import { translate, Interpolate } from 'react-i18next'; 24 | 25 | function TranslatableView(props) { 26 | const { t } = props; 27 | 28 | let interpolateComponent = a interpolated component; 29 | 30 | return ( 31 |
32 | 33 | {/* 34 | => 35 | 36 | you can interpolate "some string" or a interpolated component via interpolate component! 37 | 38 | */} 39 |
40 | ) 41 | } 42 | ``` 43 | 44 | You can use [formatting](https://www.i18next.com/formatting.html) as in i18next. 45 | 46 | **props**: 47 | 48 | * i18nKey: the key to lookup 49 | * options: [options](http://i18next.com/docs/options/#t-options) to use for translation (exclude interpolation variables!) 50 | * parent: optional component to wrap translation into (default 'span') 51 | * useDangerouslySetInnerHTML: allows use of raw html tags in translation values 52 | * dangerouslySetInnerHTMLPartElement: optional component to wrap parts of translation values into (default 'span'), used with `useDangerouslySetInnerHTML={true}` only 53 | * i18n: i18next instance to use if not provided via context (using hoc or render props) 54 | * t: t function to use if not provided via context (using hoc or render props) 55 | * ...props: values to interpolate into found translation (eg. `my value with {{replaceMe}} interpolation`) 56 | 57 | ## using useDangerouslySetInnerHtml 58 | 59 | Allows having html tags inside the translation with a restriction as those get wrapped in spans. You can't have a interpolation value inside a html tag. 60 | 61 | the key: 62 | 63 | ```javascript 64 | { 65 | "interpolateSample": "you can interpolate {{value}} or {{component}} via interpolate component!" 66 | } 67 | ``` 68 | 69 | sample: 70 | 71 | ```javascript 72 | import React from 'react'; 73 | import { translate, Interpolate } from 'react-i18next'; 74 | 75 | function TranslatableView(props) { 76 | const { t } = props; 77 | 78 | let interpolateComponent = a interpolated component; 79 | 80 | return ( 81 |
82 | 83 | {/* 84 | => 85 | 86 | you can interpolate "some string" or a interpolated component via interpolate component! 87 | 88 | */} 89 |
90 | ) 91 | } 92 | ``` 93 | 94 | ## Alternatives 95 | 96 | a) Use standard interpolation of i18next and dangerously insert that: 97 | 98 | ```javascript 99 |
100 | ``` 101 | 102 | b) use markdown, eg. [react-remarkable](https://github.com/acdlite/react-remarkable) and pass markdown formatted content from translations to the markdown component. 103 | -------------------------------------------------------------------------------- /legacy-v9/namespacesconsumer.md: -------------------------------------------------------------------------------- 1 | # NamespacesConsumer (v9) 2 | 3 | {% hint style="info" %} 4 | Was introduced in v8.0.0. Not available in older versions. 5 | {% endhint %} 6 | 7 | The NamespacesConsumer is a so called render prop. The component passes the [**t** function](https://www.i18next.com/overview/api#t) to child function and triggers loading the translation files defined. Further it asserts the component gets rerendered on language change or on changes to the translations themselves. 8 | 9 | {% hint style="info" %} 10 | To learn more about using the **t** function have a look at i18next documentation: 11 | 12 | * [essentials](https://www.i18next.com/translation-function/essentials) 13 | * [interpolation](https://www.i18next.com/translation-function/interpolation) 14 | * [formatting](https://www.i18next.com/translation-function/formatting) 15 | * [plurals](https://www.i18next.com/translation-function/plurals) 16 | * ... 17 | {% endhint %} 18 | 19 | ## Sample usage 20 | 21 | ```javascript 22 | import React from 'react'; 23 | import { NamespacesConsumer } from 'react-i18next'; 24 | 25 | function TranslatableView() { 26 | return ( 27 | 31 | { 32 | (t, { i18n, ready }) => ( 33 |
34 |

{t('keyFromDefault')}

35 |

{t('anotherNamespace:key.from.another.namespace', { /* options t options */ })}

36 |
37 | ) 38 | } 39 |
40 | ) 41 | } 42 | ``` 43 | 44 | ## NamespacesConsumer props 45 | 46 | | _**options**_ | _**type (default)**_ | _**description**_ | 47 | | ------------------ | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 48 | | **wait** | boolean (false) |

assert all provided namespaces are loaded before rendering the component (can be set globally too).

Note that rendering will not be blocked again when dynamically updating the ns prop after initial mount.

In most cases you like to set this to true. If not handling not ready by evaluating ready.

| 49 | | nsMode | string ('default') |

default: namespaces will be loaded and the first will be set as default

fallback: namespaces will be used as fallbacks used in order provided

| 50 | | bindI18n | string ('languageChanged loaded') | which events trigger a rerender, can be set to false or string of events | 51 | | bindStore | string ('added removed') | which events on store trigger a rerender, can be set to false or string of events | 52 | | omitBoundRerenders | boolean (true) | Does not trigger rerenders while state not ready - avoiding unneeded renders on init | 53 | | i18n | object (undefined) | pass i18next via options (useful for [next.js usage](https://github.com/i18next/react-i18next/tree/v9.x.x/example/nextjs)) | 54 | | initialI18nStore | object (undefined) | pass in initial translations (useful for [next.js usage](https://github.com/i18next/react-i18next/tree/v9.x.x/example/nextjs/pages/index.js#L29)) | 55 | | initialLanguage | string (undefined) | pass in initial language (useful for [next.js usage](https://github.com/i18next/react-i18next/tree/v9.x.x/example/nextjs/pages/index.js)) | 56 | -------------------------------------------------------------------------------- /legacy-v9/overview.md: -------------------------------------------------------------------------------- 1 | # Overview (v9) 2 | 3 | react-i18next depends on i18next to provide the localization features. So there are two main things flowing through your render tree: 4 | 5 | 1. The [i18next instance](i18next-instance.md) (short **i18n**) 6 | 2. The [translation function](https://www.i18next.com/overview/api#t) (short **t**) 7 | 8 | {% hint style="info" %} 9 | While we primary rely on react context to pass down **i18n** and **t** the components are built to also accept those via props, options or in case of i18n via internal context / reactI18nextModule. 10 | {% endhint %} 11 | 12 | ## Components 13 | 14 | | Component | Props | Provides | Consumes | 15 | | ----------------------------------------------------------------------------------------------------------- | ------------------- | ------------------- | --------------- | 16 | | [I18nextProvider](i18nextprovider.md) | **i18n,** defaultNS | **i18n,** defaultNs | | 17 | | [NamespacesConsumer](namespacesconsumer.md) is a render prop | | **t**, i18n | i18n | 18 | | [withNamespaces](withnamespaces.md) hoc | | **t**, i18n | i18n | 19 | | [Trans Component](trans-component.md) is used to translate JSX nodes where just using **t** is insufficient | | | **t**, **i18n** | 20 | 21 | This means your tree will look something like this _(assuming you use the options I18nextProvider):_ 22 | 23 | {% hint style="info" %} 24 | **I18nextProvider** --> **NamespacesConsumer** or **withNamespaces HOC** --> **Trans** or using **t** in your component 25 | {% endhint %} 26 | 27 | ```javascript 28 | import { I18nextProvider, NamespacesConsumer, Trans, withNamespaces } from 'react-i18next'; 29 | import i18n from `./i18n`; // the initialized i18next instance 30 | 31 | export default function App () { 32 | return ( 33 | 34 | 35 | { 36 | t =>

{t('key')}

37 | } 38 |
39 | 40 |
41 | ) 42 | } 43 | 44 | function MyComponent({ t }) { 45 | return ( 46 | 47 | Hello {{name}}, you have {{count}} unread message. Go to messages. 48 | 49 | ) 50 | } 51 | 52 | const MyComponentWithHoc = withNamespaces()(MyComponent); 53 | ``` 54 | 55 | ## Getting the t function 56 | 57 | To get the **t** function (providing the translation functionality) down to your component you have two options: 58 | 59 | 1. Using the [withNamespaces](withnamespaces.md) hoc 60 | 2. Using the [NamespacesConsumer](namespacesconsumer.md) render prop 61 | 62 | ## Getting the i18n function into the flow 63 | 64 | You have the following options to pass the [i18next instance](i18next-instance.md) to the hoc, render prop and Trans component: 65 | 66 | ### Use the [provider](i18nextprovider.md) 67 | 68 | ```javascript 69 | import React from 'react'; 70 | import ReactDOM from 'react-dom'; 71 | import { I18nextProvider } from 'react-i18next'; 72 | 73 | import App from './App'; // your entry page 74 | import i18n from './i18n'; // initialized i18next instance 75 | 76 | ReactDOM.render( 77 | 78 | 79 | , 80 | document.getElementById('app') 81 | ); 82 | ``` 83 | 84 | ### Use the reactI18nextModule 85 | 86 | ```javascript 87 | import i18n from 'i18next'; 88 | import { reactI18nextModule } from 'react-i18next'; 89 | 90 | 91 | i18n 92 | .use(reactI18nextModule) // if not using I18nextProvider 93 | .init({ /* options */ }); 94 | 95 | export default i18n; 96 | ``` 97 | -------------------------------------------------------------------------------- /legacy-v9/serverside-rendering.md: -------------------------------------------------------------------------------- 1 | # SSR (v9) 2 | 3 | ## Using next.js? 4 | 5 | You should have a look at [next-i18next](https://github.com/isaachinman/next-i18next) which extends react-i18next to bring it to next.js the easiest way. 6 | 7 | ## Samples 8 | 9 | To learn more you should have a look at our samples: 10 | 11 | * [razzle (sample provided by react-i18next)](https://github.com/i18next/react-i18next/tree/v9.x.x/example/razzle-ssr) 12 | * [simpleblack's boilerplate](https://github.com/simpleblack/react-redux-universal-hot-example) 13 | 14 | {% hint style="info" %} 15 | The usage of the `reactI18nextModule` for holding the i18n instance is not a valid option (the instance would be set globally). Always use the I18nextProvider like done in the samples above. 16 | {% endhint %} 17 | 18 | For further information see this [issue](https://github.com/i18next/react-i18next/issues/375). 19 | 20 | ## Pass language and translations down to client 21 | 22 | Both the [i18nextProvider](i18nextprovider.md) and [translate hoc](serverside-rendering.md) allow to pass in `initialI18nStore` and `initialLanguage`. By doing so the translations won't be loaded and initial clientside render will avoid any flickering or rerender by checksum mismatch. 23 | 24 | For details check the docs of those components or **have a look at the examples above**. 25 | 26 | ## loadNamespaces helper 27 | 28 | **loadNamespaces**: Function that will pre-load all namespaces used by your components. Works well with `react-router` `match` function 29 | 30 | **props**: 31 | 32 | * components: Components that need to have namespaces loaded. 33 | * i18n: the i18n instance to load translations into 34 | 35 | ```javascript 36 | import { I18nextProvider, loadNamespaces } from 'react-i18next'; 37 | import { match } from 'react-router'; 38 | 39 | match({...matchArguments}, (error, redirectLocation, renderProps) => { 40 | loadNamespaces({ ...renderProps, i18n: i18nInstance }) 41 | .then(()=>{ 42 | // All i18n namespaces required to render this route are loaded 43 | }) 44 | }); 45 | ``` 46 | 47 | ## use the i18next-express-middleware 48 | 49 | When using [i18next-express-middleware](https://github.com/i18next/i18next-express-middleware), you can use `req.i18n` as the `i18next` instance for `I18nextProvider` it will assert no request conflicts happen (each request gets it's cloned instance of i18next): 50 | 51 | ```javascript 52 | import { I18nextProvider } from 'react-i18next'; 53 | import i18n from './i18next'; // your own initialized i18next instance 54 | import App from './app'; 55 | 56 | app.use((req, res) => { 57 | const component = ( 58 | 59 | 60 | 61 | ); 62 | 63 | // render as desired now ... 64 | }); 65 | ``` 66 | -------------------------------------------------------------------------------- /legacy-v9/step-by-step-guide.md: -------------------------------------------------------------------------------- 1 | # Step by step guide (v9) 2 | 3 | {% hint style="warning" %} 4 | This guide is based on an older react-i18next version! Please have a look at [this detailed guide](https://locize.com/blog/react-i18next/) for a newer version. 5 | {% endhint %} 6 | 7 | Let's start with the sample created in the [quick start guide](../guides/quick-start.md) and extend it to be of more use. 8 | 9 | {% hint style="info" %} 10 | react-i18next will run in any environment without you having to do changes to your babel or webpack setup. 11 | {% endhint %} 12 | 13 | ## Initial situation based on quick start 14 | 15 | We have installed the needed i18n packages react-i18next and i18next: 16 | 17 | ```bash 18 | npm install react-i18next@legacy i18next --save 19 | ``` 20 | 21 | Added following files: 22 | 23 | **translation.json** (/public/locales/en/translation.json) 24 | 25 | ```javascript 26 | { 27 | "Welcome to React": "Welcome to React and react-i18next" 28 | } 29 | ``` 30 | 31 | **i18n.js** (/src/i18n.js) 32 | 33 | ```javascript 34 | import i18n from "i18next"; 35 | import { reactI18nextModule } from "react-i18next"; 36 | 37 | import translationEN from '../public/locales/en/translation.json'; 38 | 39 | // the translations 40 | const resources = { 41 | en: { 42 | translation: translationEN 43 | } 44 | }; 45 | 46 | i18n 47 | .use(reactI18nextModule) // passes i18n down to react-i18next 48 | .init({ 49 | resources, 50 | lng: "en", 51 | 52 | keySeparator: false, // we do not use keys in form messages.welcome 53 | 54 | interpolation: { 55 | escapeValue: false // react already safes from xss 56 | } 57 | }); 58 | 59 | export default i18n; 60 | ``` 61 | 62 | Make sure to import `i18n.js` in **index.js**: 63 | 64 | ```javascript 65 | import React, { Component } from "react"; 66 | import ReactDOM from "react-dom"; 67 | import './i18n'; 68 | import App from './App'; 69 | 70 | // append app to dom 71 | ReactDOM.render( 72 | , 73 | document.getElementById("root") 74 | ); 75 | ``` 76 | 77 | Have **App.js** using the `t` function for translation: 78 | 79 | ```jsx 80 | import React from 'react'; 81 | 82 | // the hoc 83 | import { withNamespaces } from 'react-i18next'; 84 | 85 | function App ({ t }) { 86 | return

{t('Welcome to React')}

87 | } 88 | 89 | export default withNamespaces()(App); 90 | ``` 91 | 92 | ## 1) Adding more languages 93 | 94 | ### a) Add an additional language file 95 | 96 | **translation.json** (/public/locales/**de**/translation.json) 97 | 98 | ```javascript 99 | { 100 | "Welcome to React": "Willkommen bei react und react-i18next" 101 | } 102 | ``` 103 | 104 | ### b) Add the additional translations on init 105 | 106 | in i18n.js: 107 | 108 | ```javascript 109 | // ... 110 | import translationEN from '../public/locales/en/translation.json'; 111 | import translationDE from '../public/locales/de/translation.json'; 112 | 113 | // the translations 114 | const resources = { 115 | en: { 116 | translation: translationEN 117 | }, 118 | de: { 119 | translation: translationDE 120 | } 121 | }; 122 | 123 | // ... 124 | ``` 125 | 126 | ### c) Auto detect the user language 127 | 128 | As the language is set on `i18n.init` you either could create some custom code setting the needed language or just use one of the provided language detectors coming with i18next. 129 | 130 | For browser usage there is the [i18next-browser-languageDetector](https://github.com/i18next/i18next-browser-languageDetector) which detects language based on: 131 | 132 | * cookie 133 | * localStorage 134 | * navigator 135 | * querystring (append `?lng=LANGUAGE` to URL) 136 | * htmlTag 137 | * path 138 | * subdomain 139 | 140 | ```bash 141 | npm install i18next-browser-languagedetector --save 142 | ``` 143 | 144 | Using it before i18n.init is all needed to get this to work: 145 | 146 | ```javascript 147 | import i18n from "i18next"; 148 | import detector from "i18next-browser-languagedetector"; 149 | import { reactI18nextModule } from "react-i18next"; 150 | 151 | import translationEN from '../public/locales/en/translation.json'; 152 | import translationDE from '../public/locales/de/translation.json'; 153 | 154 | // the translations 155 | const resources = { 156 | en: { 157 | translation: translationEN 158 | }, 159 | de: { 160 | translation: translationDE 161 | } 162 | }; 163 | 164 | i18n 165 | .use(detector) 166 | .use(reactI18nextModule) // passes i18n down to react-i18next 167 | .init({ 168 | resources, 169 | fallbackLng: "en", // use en if detected lng is not available 170 | 171 | keySeparator: false, // we do not use keys in form messages.welcome 172 | 173 | interpolation: { 174 | escapeValue: false // react already safes from xss 175 | } 176 | }); 177 | 178 | export default i18n; 179 | ``` 180 | 181 | Now we already are able to set language based on the browsers set language or by appending `?lng=LANGUAGE` to the URL. 182 | 183 | ### d) Let the user toggle the language 184 | 185 | Call [i18n.changeLanguage](https://www.i18next.com/overview/api#changelanguage) is all needed to do. 186 | 187 | ```jsx 188 | import React from 'react'; 189 | import i18n from './i18n'; 190 | import { withNamespaces } from 'react-i18next'; 191 | 192 | function App ({ t }) { 193 | const changeLanguage = (lng) => { 194 | i18n.changeLanguage(lng); 195 | } 196 | 197 | return ( 198 |
199 | 200 | 201 |

{t('Welcome to React')}

202 |
203 | ) 204 | } 205 | 206 | export default withNamespaces()(App); 207 | ``` 208 | 209 | {% hint style="info" %} 210 | It's essential to have at least your outer page level / container component wrapped with the [withNamespaces](withnamespaces.md) or [NamespacesConsumer](namespacesconsumer.md) as those are bound to the [languageChanged event](https://www.i18next.com/overview/api#onlanguagechanged) and trigger a needed rerender. 211 | {% endhint %} 212 | 213 | ## 2) Lazy loading translations 214 | 215 | We haven't yet started splitting translations into multiple files (which is highly recommended for larger projects) but we already see that adding more languages would result in bundling unneeded translations into the application. 216 | 217 | > Why not just use dynamic imports to load the language needed? 218 | 219 | This for sure works but comes with one drawback. If you have a change in your translations you will need to rebuild your application and deploy that. 220 | 221 | This might not be a problem when starting but at some point you will learn localization is a complete different beast than just adding i18n to your code. You will keep translations as separated from your code as you can - so developers and translators can work as independent as possible. 222 | 223 | ### a) Adding lazy loading for translations 224 | 225 | This will be simpler than you think. All needed to be done is adding another package called [i18next-http-backend](https://github.com/i18next/i18next-http-backend) and using that. 226 | 227 | ```bash 228 | npm install i18next-http-backend --save 229 | ``` 230 | 231 | **i18n.js** 232 | 233 | ```javascript 234 | import i18n from "i18next"; 235 | import detector from "i18next-browser-languagedetector"; 236 | import backend from "i18next-http-backend"; 237 | import { reactI18nextModule } from "react-i18next"; 238 | 239 | // translations are already at 240 | // '../public/locales/en/translation.json' 241 | // which is the default for the xhr backend to load from 242 | 243 | i18n 244 | .use(detector) 245 | .use(backend) 246 | .use(reactI18nextModule) // passes i18n down to react-i18next 247 | .init({ 248 | fallbackLng: "en", // use en if detected lng is not available 249 | 250 | keySeparator: false, // we do not use keys in form messages.welcome 251 | 252 | interpolation: { 253 | escapeValue: false // react already safes from xss 254 | } 255 | }); 256 | 257 | export default i18n; 258 | ``` 259 | 260 | {% hint style="info" %} 261 | i18next implementation is smart enough to only load needed languages and comes with intelligent deduplications so even multiple load requests for files in different code locations result in one request while notifying all needed requester. 262 | {% endhint %} 263 | 264 | ### b) Loading multiple translation files 265 | 266 | Lets assume your project started to grow and you like to split translations into multiple files. 267 | 268 | Without configuration i18next will always load one file (namespace) named `translation`. Learn more about namespaces [here](https://www.i18next.com/principles/namespaces). 269 | 270 | You can load them on i18n.init or in code like: 271 | 272 | ```javascript 273 | i18n.init({ 274 | ns: ['common', 'moduleA', 'moduleB'], 275 | defaultNS: 'moduleA' 276 | }, (err, t) => { 277 | i18n.t('myKey'); // key in moduleA namespace (defined default) 278 | i18n.t('common:myKey'); // key in common namespace 279 | }); 280 | 281 | // load additional namespaces after initialization 282 | i18n.loadNamespaces('anotherNamespace', (err, t) => { /* ... */ }); 283 | ``` 284 | 285 | But that will load all upfront or in some custom code where you would need to handle manually that the translations were loaded. So there is a better way. 286 | 287 | #### Use the withNamespaces hoc 288 | 289 | As you might guess the withNamespaces hocs role is to lazy load the needed namespaces. 290 | 291 | **page2.json Add more translation files:** (/public/locales/en/page2.json) 292 | 293 | ```javascript 294 | { 295 | "Welcome on page2": "Welcome on page2" 296 | } 297 | ``` 298 | 299 | **Page2.js** (/src/Page2.js) 300 | 301 | ```jsx 302 | import React from 'react'; 303 | 304 | // the hoc 305 | import { withNamespaces } from 'react-i18next'; 306 | 307 | function Page2 ({ t }) { 308 | return

{t('Welcome on page2')}

309 | } 310 | 311 | export default withNamespaces('page2')(Page2); 312 | ``` 313 | 314 | ### c) Handle rendering while translations are not yet loaded 315 | 316 | In the above `Page2` you will notice the initial render will trigger the load for `page2.json` but also render the page without the translations ready. There will be a rerender when the translations where loaded resulting in the page flickering. 317 | 318 | #### Using the prop tReady 319 | 320 | tReady will be set to true when translations are loaded so you can eg. suspend rendering and show a Spinner or another placeholder: 321 | 322 | ```jsx 323 | import React from 'react'; 324 | 325 | // the hoc 326 | import { withNamespaces } from 'react-i18next'; 327 | 328 | function Page2 ({ t, tReady }) { 329 | // just to add some more here we load an additional namespace 330 | // common for "common" used texts and use that namespace 331 | // be prefixing it in front of the key "common:" 332 | if (!tReady) return

{t('common:loading')}

333 | 334 | return

{t('Welcome on page2')}

335 | } 336 | 337 | export default withNamespaces(['page2', 'common'])(Page2); 338 | ``` 339 | 340 | #### Set the global wait option 341 | 342 | You can configure the withNamespaces / NamespacesConsumer to not render the content until needed namespaces are loaded. 343 | 344 | **i18n.js:** 345 | 346 | ```javascript 347 | import i18n from "i18next"; 348 | import detector from "i18next-browser-languagedetector"; 349 | import backend from "i18next-http-backend"; 350 | import { reactI18nextModule } from "react-i18next"; 351 | 352 | i18n 353 | .use(detector) 354 | .use(backend) 355 | .use(reactI18nextModule) // passes i18n down to react-i18next 356 | .init({ 357 | fallbackLng: "en", // use en if detected lng is not available 358 | 359 | keySeparator: false, // we do not use keys in form messages.welcome 360 | 361 | interpolation: { 362 | escapeValue: false // react already safes from xss 363 | }, 364 | 365 | // react-i18next options 366 | react: { 367 | wait: true 368 | } 369 | }); 370 | 371 | export default i18n; 372 | ``` 373 | 374 | Now `Page2` will be blank until the needed translation files were loaded. 375 | 376 | {% hint style="info" %} 377 | You can set the wait option either globally for all instances or individually like: 378 | 379 | `withNamepaces('page2', { wait: true })(Page2);` 380 | {% endhint %} 381 | 382 | ## 3) Sidequest: natural vs. keybased catalog 383 | 384 | ### a) natural keys 385 | 386 | Until now we had organised translation and keys in natural language. 387 | 388 | ```jsx 389 |

{t('Welcome on page2')}

390 | ``` 391 | 392 | Having translation files like: 393 | 394 | ```javascript 395 | { 396 | "Welcome on page2": "Welcome on page2" 397 | } 398 | ``` 399 | 400 | This was possible by setting `keySeparator: false` on `i18n.init` 401 | 402 | The upside of this the code can be more readable but the content of the key might get soon rather different from the value it reflects. You could even go a step further by disabling any fallback language and [using the key as fallback](https://www.i18next.com/principles/fallback#key-fallback) - but be aware if you have a typo in the key acting as fallback value you will need to change it. 403 | 404 | ### b) keybased catalog 405 | 406 | Some i18n frameworks organise having more technical keys allowing those to be even structured into hierarchies. This is the default in i18next too - so removing `keySeparator: false` on `i18n.init` would enable having catalogs and `t` usage like: 407 | 408 | ```javascript 409 | { 410 | "titles": { 411 | "page2": "Welcome on page2" 412 | } 413 | } 414 | ``` 415 | 416 | accessed like: 417 | 418 | ```jsx 419 |

{t('titles.page2')}

420 | ``` 421 | 422 | If you prefer natural or keybased is a matter of taste...both can be used with react-i18next. Just avoid mixing those styles. 423 | 424 | ## 4) HOCs are dead - long lives the render props 425 | 426 | We won't open a debate over which is better as in our opinion both have their use case and there is no reason to just use one of the two options. 427 | 428 | So you already saw before that you can use the [withNamespaces](withnamespaces.md) to decorate your component to pass the `t` function down. 429 | 430 | The same works with [a render prop](namespacesconsumer.md): 431 | 432 | ```jsx 433 | import React from 'react'; 434 | 435 | // the render prop 436 | import { NamespacesConsumer } from 'react-i18next'; 437 | 438 | export default function Page2 () { 439 | ( 440 | 441 | { 442 | (t, { i18n, ready }) => ( 443 | ready ? 444 |

{t('Welcome on page2')}

: 445 |

{t('common:loading')}

446 | ) 447 | } 448 |
449 | ) 450 | } 451 | ``` 452 | 453 | ## 5) Translate JSX nodes as one string 454 | 455 | Let's translate this: 456 | 457 | > Translating content with **formatting** or a [link](step-by-step-guide.md#5-translate-jxs-nodes-as-one-string) is a pain. 458 | 459 | For this your JSX might look like: 460 | 461 | ```jsx 462 |

463 | Translating content with 464 | formatting 465 | or a 466 | link 467 | is a pain. 468 |

469 | ``` 470 | 471 | So naive approach using the `t` function would result in 472 | 473 | ```jsx 474 |

475 | { t('Translating content with ') } 476 | t('formatting') 477 | { t(' or a ') } 478 | t('link') 479 | { t(' is a pain.') } 480 |

481 | ``` 482 | 483 | So you end up with 5 keys in your translation file and your translator has no idea about how these 5 keys relate to each other. Further what happens in other languages where the order needs to be changed?!? 484 | 485 | So you won't have luck with this approach. 486 | 487 | ### Using the Trans component 488 | 489 | The [Trans component](trans-component.md) enables you to keep this as one sentence by replacing the JSX nodes with indexed pseudo tags. 490 | 491 | ```jsx 492 | import { Trans } from 'react-i18next'; 493 | 494 | // ... 495 | 496 |

497 | 498 | Translating content with 499 | formatting 500 | or a 501 | link 502 | is a pain. 503 | 504 |

505 | ``` 506 | 507 | Resulting in JSON: 508 | 509 | ```javascript 510 | { 511 | "Translating content with <1>formatting or a <3>link is a pain.": 512 | "Translating content with <1>formatting or a <3>link is a pain." 513 | } 514 | ``` 515 | 516 | The `<1>`, `<3>` pseudo tags are based on the index of appearance in `nodes.children`: 517 | 518 | ```jsx 519 | 520 | Translating content with // index 0 521 | formatting // index 1 522 | or a // index 2 523 | link // index 3 524 | is a pain. // index 4 525 | 526 | ``` 527 | 528 | The Trans component also supports interpolation and plurals just read the [full documentation](trans-component.md) of that component. 529 | -------------------------------------------------------------------------------- /legacy-v9/trans-component.md: -------------------------------------------------------------------------------- 1 | # Trans Component (v9) 2 | 3 | ## Important note 4 | 5 | While the Trans components gives you a lot of power by letting you interpolate or translate complexer react elements. 6 | 7 | The truth is - In most cases you won't need it. **As long you have no react nodes you like to be integrated into a translated text** (text formatting, like `strong`, `i`, ...) **or adding some link component - you won't need it.** 8 | 9 | All can be done by using the `t` function you get by the [translate hoc](trans-component.md) or [I18n render prop](trans-component.md). 10 | 11 | {% hint style="info" %} 12 | Using the **t** function have a look at i18next documentation: 13 | 14 | * [essentials](https://www.i18next.com/translation-function/essentials) 15 | * [interpolation](https://www.i18next.com/translation-function/interpolation) 16 | * [formatting](https://www.i18next.com/translation-function/formatting) 17 | * [plurals](https://www.i18next.com/translation-function/plurals) 18 | * ... 19 | {% endhint %} 20 | 21 | ## Sample 22 | 23 | So you learned there is no need to use the Trans component everywhere (the plain t function will just do fine in most cases). 24 | 25 | This component enables you to nest any react content to be translated as one string. Supports both plural and interpolation. 26 | 27 | _Let's say you want to create following html output:_ 28 | 29 | > Hello **Arthur**, you have 42 unread messages. [Go to messages](trans-component.md). 30 | 31 | **Before:** Your react code would have looked something like: 32 | 33 | ```javascript 34 |
35 | Hello {name}, you have {count} unread message(s). Go to messages. 36 |
37 | ``` 38 | 39 | **After:** With the trans component just change it to: 40 | 41 | ```javascript 42 | 43 | Hello {{name}}, you have {{count}} unread message. Go to messages. 44 | 45 | ``` 46 | 47 | _Your en.json (translation strings) will look like:_ 48 | 49 | ```javascript 50 | "userMessagesUnread": "Hello <1>{{name}}, you have {{count}} unread message. <5>Go to message.", 51 | "userMessagesUnread_plural": "Hello <1>{{name}}, you have {{count}} unread messages. <5>Go to messages.", 52 | ``` 53 | 54 | {% hint style="info" %} 55 | [**saveMissing**](https://www.i18next.com/overview/configuration-options#missing-keys) will send a valid defaultValue 56 | {% endhint %} 57 | 58 | ### Alternative usage 59 | 60 | Depending on using [ICU as translation format](https://github.com/i18next/i18next-icu) it is not possible to have the needed syntax as children (invalid jsx). You can alternatively use the component like: 61 | 62 | ```javascript 63 | univers
]} 67 | /> 68 | ``` 69 | 70 | ## How to get the correct translation string? 71 | 72 | Guessing replacement tags _(<0>\)_ of your component right is rather difficult. There are two options to get those translations directly generated by i18next. 73 | 74 | 1. use `debug = true` in i18next init call and watch your console for the missing key output 75 | 2. use the [saveMissing feature](https://www.i18next.com/configuration-options#missing-keys) of i18next to get those translations pushed to your backend or handled by a custom missing key handler. 76 | 3. understand how those numbers get generated from child index: 77 | 78 | **jsx:** 79 | 80 | ```javascript 81 | 82 | Hello {{name}}, you have {{count}} unread message. Go to messages. 83 | 84 | ``` 85 | 86 | **results in string:** 87 | 88 | ``` 89 | "Hello <1>{{name}}, you have {{count}} unread message. <5>Go to message." 90 | ``` 91 | 92 | **based on** the node tree**:** 93 | 94 | ```javascript 95 | Trans.children = [ 96 | 'Hello ', // index 0: only a string 97 | { children: [{ name: 'Jan' }] }, // index 1: element strong -> child object for interpolation 98 | ', you have', // index 2: only a string 99 | { count: 10 }, // index 3: just object for interpolation 100 | ' unread messages. ', // index 4 101 | { children: [ 'Go to messages' ] }, // index 5: element link -> child just a string 102 | '.' 103 | ] 104 | ``` 105 | 106 | {% hint style="info" %} 107 | **Rules:** 108 | 109 | * child is a string => nothing to wrap just take the string 110 | * child is an object => nothing to do it's used for interpolation 111 | * child is an element: wrap it's children in \\ where i is the index of that element position in children and handle it's children with same rules (starting element.children index at 0 again) 112 | {% endhint %} 113 | 114 | ## Trans props 115 | 116 | | _**name**_ | _**type (default)**_ | _**description**_ | 117 | | ---------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------- | 118 | | i18nKey | string (undefined) | is optional if you prefer to use text as keys you can omit that and the translation will be used as a key. | 119 | | count | integer (undefined) | optional count if you use a plural | 120 | | parent | node (undefined) | a component to wrap the content into (default none, can be globally set on i18next.init) -> needed for **react < v16** | 121 | | i18n | object (undefined) | i18next instance to use if not provided via context (using hoc or render props) | 122 | | t | function (undefined) | t function to use if not provided via context (using hoc or render props) | 123 | | defaults | string (undefined) | use this instead of default content in children (useful when using ICU) | 124 | | values | object (undefined) | interpolation values if not provided in children | 125 | | components | array\[nodes] (undefined) | components to interpolate based on index of tag <0>\, ... | 126 | 127 | ## Additional options on i18next.init 128 | 129 | ```javascript 130 | i18next.init({ 131 | // ... 132 | react: { 133 | // ... 134 | hashTransKey: function(defaultValue) { 135 | // return a key based on defaultValue or if you prefer to just remind you should set a key return false and throw an error 136 | }, 137 | defaultTransParent: 'div' // a valid react element - required before react 16 138 | } 139 | }); 140 | ``` 141 | 142 | {% hint style="warning" %} 143 | Please be aware if you are using **React 15 or below**, you need to set the `defaultTransParent` or `parent` in props. 144 | {% endhint %} 145 | -------------------------------------------------------------------------------- /legacy-v9/withi18n.md: -------------------------------------------------------------------------------- 1 | # withI18n (v9) 2 | 3 | {% hint style="info" %} 4 | Was introduced in v8.0.0. Not available in older versions. 5 | {% endhint %} 6 | 7 | `withI18n` is a basic higher order component which passes mainly the `t` function down to the wrapped component. 8 | 9 | ```jsx 10 | import React, { Component } from "react"; 11 | import { withI18n } from "react-i18next"; 12 | 13 | class MyComponent extends Component { 14 | render() { 15 | const { t } = this.props; 16 | 17 | return

{t('Welcome to React')}

; 18 | } 19 | } 20 | export default withI18n()(MyComponent); 21 | ``` 22 | 23 | {% hint style="danger" %} 24 | This component won't trigger a rerender on language change. The passed down `t` function will be the same as calling `i18n.t` directly and not be bound to a specific namespace or even trigger a load of a namespace. 25 | 26 | If you do **not pass in translations** on `i18n.init` we highly encourage using the [withNamespaces](withnamespaces.md) hoc. 27 | {% endhint %} 28 | -------------------------------------------------------------------------------- /legacy-v9/withnamespaces.md: -------------------------------------------------------------------------------- 1 | # withNamespaces (v9) 2 | 3 | {% hint style="info" %} 4 | Was introduced in v8.0.0. Not available in older versions. 5 | {% endhint %} 6 | 7 | The withNamespaces [hoc](https://reactjs.org/docs/higher-order-components.html) is responsible for passing the [**t** function](https://www.i18next.com/overview/api#t) to your component. It enables all the translation functionality provided by i18next. Further, it asserts your component gets re-rendered on language change or changes to the translation catalog itself (loaded translations). 8 | 9 | ```javascript 10 | withNamespaces(namespaces, options)(MyComponent); 11 | ``` 12 | 13 | {% hint style="info" %} 14 | To learn more about using the **t** function have a look at i18next documentation: 15 | 16 | * [essentials](https://www.i18next.com/essentials.html) 17 | * [interpolation](https://www.i18next.com/interpolation.html) 18 | * [formatting](https://www.i18next.com/formatting.html) 19 | * [plurals](https://www.i18next.com/plurals.html) 20 | * ... 21 | {% endhint %} 22 | 23 | ## Sample 24 | 25 | ```javascript 26 | import React from 'react'; 27 | import { withNamespaces } from 'react-i18next'; 28 | 29 | function TranslatableView(props) { 30 | const { t, tReady } = props; 31 | // tReady is true if translations were loaded. 32 | // Use wait option to not render before loaded 33 | // or render placeholder yourself if not tReady=false 34 | 35 | return ( 36 |
37 |

{t('keyFromDefault')}

38 |

{t('anotherNamespace:key.from.another.namespace', { /* options t options */ })}

39 |
40 | ) 41 | } 42 | 43 | export default withNamespaces([ 44 | 'defaultNamespace', 45 | 'anotherNamespace' 46 | ], { /* additional options see below */ })(TranslatableView); 47 | 48 | // or: short for only loading one namespace: 49 | export default withNamespaces('defaultNamespace')(TranslatableView); 50 | 51 | // or: short for using defaultNS defined in i18next 52 | export default withNamespaces()(TranslatableView); 53 | 54 | // or: using a function to return namespaces based on props 55 | export default withNamespaces((props) => props.namespaces)(TranslatableView); 56 | ``` 57 | 58 | If not using the [reactI18nextModule](i18next-instance.md) this hoc should be nested inside a [I18nextProvider](i18nextprovider.md). Alternatively you can pass the i18next instance via prop `i18n`. 59 | 60 | ## Using with TypeScript 61 | 62 | To help you using TypeScript and the @withNamespaces decorator here is a trival example: 63 | 64 | ```jsx 65 | import * as React from 'react'; 66 | import { withNamespaces, WithNamespaces } from 'react-i18next'; 67 | 68 | class MyComponent extends React.PureComponent { 69 | public render() { 70 | const { t } = this.props; 71 | return ( 72 | 73 | {t('my-component-content')} 74 | 75 | ); 76 | } 77 | } 78 | export default withNamespaces()(MyComponent); 79 | ``` 80 | 81 | 82 | 83 | ## Set defaults for all used withNamespaces 84 | 85 | Most time you like to change those values for every component. 86 | 87 | Set those on i18next init: 88 | 89 | ```javascript 90 | i18n.init({ 91 | // ... other options 92 | react: { 93 | wait: false, 94 | withRef: false, 95 | bindI18n: 'languageChanged loaded', 96 | bindStore: 'added removed', 97 | nsMode: 'default' 98 | } 99 | }); 100 | ``` 101 | 102 | ## withNamespaces options: 103 | 104 | ```javascript 105 | export default withNamespaces( 106 | 'defaultNamespace', 107 | { wait: true } // <-- options 108 | )(TranslatableView); 109 | ``` 110 | 111 | | _**option**_ | _**type (default)**_ | _**description**_ | 112 | | ------------------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 113 | | **wait** | boolean (false) |

assert all provided namespaces are loaded before rendering the component (can be set globally too)

In most cases you like to set this to true. If not handling not ready by evaluating tReady.

| 114 | | nsMode | string ('default') |

default: namespaces will be loaded an the first will be set as default or

fallback: namespaces will be used as fallbacks used in order provided

| 115 | | innerRef | function or object (undefined) |

either pass in a object React.createRef or a ref function like (c) => this.myRef = c;

read more

| 116 | | bindI18n | string ('languageChanged loaded') | which events trigger a rerender, can be set to false or string of events | 117 | | bindStore | string ('added removed') | which events on store trigger a rerender, can be set to false or string of events | 118 | | omitBoundRerenders | boolean (true) | Does not trigger rerenders while state not ready - avoiding unneeded renders on init | 119 | | i18n | object (undefined) | pass i18next via options (useful for [next.js usage](https://github.com/i18next/react-i18next/tree/v9.x.x/example/nextjs) | 120 | | usePureComponent | boolean (false) | use shallowEqual on props change if set to true | 121 | 122 | ## withNamespaces props: 123 | 124 | | _**name**_ | _**type (default)**_ | _**description**_ | 125 | | ---------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------ | 126 | | i18n | object (undefined) | pass i18next instance by props instead of having it on context | 127 | | initialI18nStore | object (undefined) | pass in initial translations (useful for [next.js usage](https://github.com/i18next/react-i18next/tree/v9.x.x/example/nextjs)) | 128 | | initialLanguage | object (undefined) | pass in initial language (useful for [next.js usage](https://github.com/i18next/react-i18next/tree/v9.x.x/example/nextjs)) | 129 | -------------------------------------------------------------------------------- /methods.md: -------------------------------------------------------------------------------- 1 | # Defining Methods 2 | 3 | Methods allow you to smoothly display code examples in different languages. 4 | 5 | {% method %} 6 | ## My first method 7 | 8 | My first method exposes how to print a message in JavaScript and Go. 9 | 10 | {% sample lang="js" %} 11 | Here is how to print a message to `stdout` using JavaScript. 12 | 13 | ```js 14 | console.log('My first method'); 15 | ``` 16 | 17 | {% sample lang="go" %} 18 | Here is how to print a message to `stdout` using Go. 19 | 20 | ```go 21 | fmt.Println("My first method") 22 | ``` 23 | 24 | {% common %} 25 | Whatever language you are using, the result will be the same. 26 | 27 | ```bash 28 | $ My first method 29 | ``` 30 | {% endmethod %} 31 | -------------------------------------------------------------------------------- /misc/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | For testing purpose of your component you should export the pure component without extending with the withTranslation hoc and test that: 4 | 5 | ```javascript 6 | export MyComponent; 7 | export default withTranslation('ns')(MyComponent); 8 | ``` 9 | 10 | In the test, test the myComponent export passing a t function mock: 11 | 12 | ```javascript 13 | import { MyComponent } from './myComponent'; 14 | 15 | key} /> 16 | ``` 17 | 18 | Or use [https://github.com/kadirahq/react-stubber](https://github.com/kadirahq/react-stubber) to stub i18n functionality: 19 | 20 | ```javascript 21 | const tDefault = (key) => key; 22 | const StubbableInterpolate = mayBeStubbed(Interpolate); 23 | const stubInterpolate = function () { 24 | stub(StubbableInterpolate, (props, context) => { 25 | const t = (context && context.t) || tDefault; 26 | return ({t(props.i18nKey)}); 27 | }); 28 | }; 29 | ``` 30 | 31 | Or mock it like: 32 | 33 | ```javascript 34 | jest.mock('react-i18next', () => ({ 35 | // this mock makes sure any components using the translate HoC receive the t function as a prop 36 | withTranslation: () => Component => { 37 | Component.defaultProps = { ...Component.defaultProps, t: (i18nKey) => i18nKey }; 38 | // or with TypeScript: 39 | //Component.defaultProps = { ...Component.defaultProps, t: (i18nKey: string) => i18nKey }; 40 | return Component; 41 | }, 42 | })); 43 | ``` 44 | 45 | Or, when using the `useTranslation` hook instead of `withTranslation`, mock it like: 46 | 47 | ```javascript 48 | jest.mock('react-i18next', () => ({ 49 | // this mock makes sure any components using the translate hook can use it without a warning being shown 50 | useTranslation: () => { 51 | return { 52 | t: (i18nKey) => i18nKey, 53 | // or with TypeScript: 54 | //t: (i18nKey: string) => i18nKey, 55 | i18n: { 56 | changeLanguage: () => new Promise(() => {}), 57 | }, 58 | }; 59 | }, 60 | initReactI18next: { 61 | type: '3rdParty', 62 | init: () => {}, 63 | } 64 | })); 65 | ``` 66 | 67 | or, you can also spy the `t` function: 68 | 69 |
// implementation
 70 | import React from 'react';
 71 | import { useTranslation } from 'react-i18next';
 72 | 
 73 | export default function CustomComponent() {
 74 |   const { t } = useTranslation();
 75 | 
 76 |   return <div>{t('some.key', { some: 'variable' })}</div>;
 77 | }
 78 | 
 79 | // test
 80 | import React from 'react';
 81 | import { mount } from 'enzyme';
 82 | import UseTranslationWithInterpolation from './UseTranslationWithInterpolation';
 83 | import { useTranslation } from 'react-i18next';
 84 | 
 85 | jest.mock('react-i18next', () => ({
 86 |   useTranslation: jest.fn(),
 87 | }));
 88 | 
 89 | it('test render', () => {
 90 |   const useTranslationSpy = useTranslation;
 91 |   const tSpy = jest.fn((str) => str);
 92 |   useTranslationSpy.mockReturnValue({
 93 |     t: tSpy,
 94 |     i18n: {
 95 |       changeLanguage: () => new Promise(() => {}),
 96 |     },
 97 |   });
 98 | 
 99 |   const mounted = mount(<UseTranslationWithInterpolation />);
100 | 
101 |   // console.log(mounted.debug());
102 |   expect(mounted.contains(<div>some.key</div>)).toBe(true);
103 | 
104 |   // If you want you can also check how the t function has been called,
105 |   // but basically this is testing your mock and not the actual code.
106 |   expect(tSpy).toHaveBeenCalledTimes(1);
107 |   expect(tSpy).toHaveBeenLastCalledWith('some.key', { some: 'variable' });
108 | });
109 | 
110 | 111 | {% hint style="success" %} 112 | You can find a full sample for testing with jest here: [https://github.com/i18next/react-i18next/tree/master/example/test-jest](https://github.com/i18next/react-i18next/tree/master/example/test-jest) 113 | {% endhint %} 114 | 115 | ## Testing without stubbing 116 | 117 | Alternatively, you could also test I18next without stubbing anything, by providing the correct configuration and fully wrapping your container in the provider. 118 | 119 | ### Example configuration for testing 120 | 121 | ```javascript 122 | import i18n from 'i18next'; 123 | import { initReactI18next } from 'react-i18next'; 124 | 125 | i18n 126 | .use(initReactI18next) 127 | .init({ 128 | lng: 'en', 129 | fallbackLng: 'en', 130 | 131 | // have a common namespace used around the full app 132 | ns: ['translationsNS'], 133 | defaultNS: 'translationsNS', 134 | 135 | debug: true, 136 | 137 | interpolation: { 138 | escapeValue: false, // not needed for react!! 139 | }, 140 | 141 | resources: { en: { translationsNS: {} } }, 142 | }); 143 | 144 | export default i18n; 145 | ``` 146 | 147 | ### Example test using this configuration 148 | 149 | ```javascript 150 | import React from 'react'; 151 | import { Provider } from 'react-redux'; 152 | import { mount } from 'enzyme'; 153 | import { I18nextProvider } from 'react-i18next'; 154 | import configureStore from 'redux-mock-store'; 155 | import ContactTable from './ContactTable'; 156 | import actionTypes from '../constants'; 157 | import i18n from '../i18nForTests'; 158 | 159 | const mockStore = configureStore([]); 160 | const store = mockStore({ contacts: [ ] }); 161 | 162 | it('dispatches SORT_TABLE', () => { 163 | const enzymeWrapper = mount( 164 | 165 | 166 | 167 | 168 | 169 | ); 170 | enzymeWrapper.find('.sort').simulate('click'); 171 | const actions = store.getActions(); 172 | expect(actions).toEqual([{ type: actionTypes.SORT_TABLE }]); 173 | }); 174 | ``` 175 | 176 | As translations aren't provided, `this.props.i18n.language` will be `undefined`. In case your application relies on that value you can mock resources by adding these lines to the object passed to init: 177 | 178 | ``` 179 | i18n 180 | .init({ 181 | ... 182 | fallbackLng: 'en', 183 | resources: { 184 | en: {}, 185 | de: {} 186 | } 187 | }) 188 | ``` 189 | 190 | Now in your component `this.props.i18n.language` will return `en`. 191 | -------------------------------------------------------------------------------- /misc/using-with-fluent-format.md: -------------------------------------------------------------------------------- 1 | # Using with fluent format 2 | 3 | i18next itself is flexible enough to support multiple existing i18next formats beside it's own. 4 | 5 | {% hint style="info" %} 6 | Find the full working sample here: 7 | 8 | [https://github.com/i18next/react-i18next/tree/master/example/react-fluent](https://github.com/i18next/react-i18next/tree/master/example/react-fluent) 9 | {% endhint %} 10 | -------------------------------------------------------------------------------- /misc/using-with-icu-format.md: -------------------------------------------------------------------------------- 1 | # Using with ICU format 2 | 3 | i18next itself is flexible enough to support multiple existing i18next formats beside its own. So also the ICU format, thanks to [i18next-icu](https://github.com/i18next/i18next-icu). 4 | 5 | {% hint style="info" %} 6 | Find the full working sample [here](https://github.com/i18next/react-i18next/tree/master/example/react-icu). 7 | {% endhint %} 8 | 9 | ![](<../.gitbook/assets/Screen Shot 2018-07-30 at 10.25.19.png>) 10 | 11 | ## Extend the i18n instance with ICU module 12 | 13 | To enable ICU format you will need to include the [i18next-icu](https://github.com/i18next/i18next-icu) module into your [i18next instance](../legacy-v9/i18next-instance.md). 14 | 15 | ```javascript 16 | import i18n from 'i18next'; 17 | import ICU from 'i18next-icu'; 18 | import Backend from 'i18next-http-backend'; 19 | import LanguageDetector from 'i18next-browser-languagedetector'; 20 | import { reactI18nextModule } from 'react-i18next'; 21 | 22 | i18n 23 | .use(ICU) 24 | .use(Backend) 25 | .use(LanguageDetector) 26 | .use(reactI18nextModule) // if not using I18nextProvider 27 | .init({ 28 | fallbackLng: 'en', 29 | debug: true, 30 | 31 | interpolation: { 32 | escapeValue: false, // not needed for react!! 33 | }, 34 | 35 | // react i18next special options (optional) 36 | react: { 37 | bindI18n: 'languageChanged loaded', 38 | bindStore: 'added removed', 39 | nsMode: 'default' 40 | } 41 | }); 42 | 43 | 44 | export default i18n; 45 | ``` 46 | 47 | ## Use the ICU format 48 | 49 | ### using t function 50 | 51 | ```javascript 52 | import React, { Component } from 'react'; 53 | import { useTranslation } from 'react-i18next'; 54 | 55 | function MyComponent() { 56 | const { t, i18n } = useTranslation(); 57 | // or const [t, i18n] = useTranslation(); 58 | 59 | return
{t('icu', { numPersons: 500 })}
60 | } 61 | 62 | // ... 63 | 64 | // json 65 | "icu": "{numPersons, plural, =0 {no persons} =1 {one person} other {# persons}}", 66 | 67 | // result: 68 |
500 persons
69 | ``` 70 | 71 | ### using the Trans Component 72 | 73 | As is including plain ICU syntax inside a JSX node will result in invalid JSX as the ICU format uses curly brackets that are reserved by JSX. 74 | 75 | So the default option is to use the [Trans Component](../legacy-v9/trans-component.md) just with props like: 76 | 77 | ```javascript 78 | import { Trans } from 'react-i18next'; 79 | 80 | const user = 'John Doe'; 81 | 82 | dummyChild
]} 86 | values={{ user }} 87 | /> 88 | 89 | // json 90 | "icu_and_trans": "We invited <0>{user}." 91 | 92 | // result 93 | We invited John Doe. 94 | ``` 95 | 96 | While this works the resulting JSX is very verbose - guess we could do better. 97 | 98 | ### using babel macros (Trans, Plural, Select) 99 | 100 | {% hint style="info" %} 101 | Thanks to using [kentcdodds/babel-plugin-macros](https://github.com/kentcdodds/babel-plugin-macros) we could use some babel magic to transpile nicer looking jsx to above Trans markup. 102 | 103 | Check [https://github.com/kentcdodds/babel-plugin-macros/blob/master/other/docs/user.md](https://github.com/kentcdodds/babel-plugin-macros/blob/master/other/docs/user.md) for setting babel-plugin-macros up. 104 | 105 | Using create-react-app? Make sure you are using react-scripts v2 as it includes the macro plugin. 106 | 107 | ``` 108 | $ # Create a new application 109 | $ npx create-react-app 110 | $ # Upgrade an existing application 111 | $ yarn upgrade react-scripts@2 112 | ``` 113 | {% endhint %} 114 | 115 | ```javascript 116 | import { Trans } from 'react-i18next/icu.macro'; 117 | 118 | const user = 'John Doe'; 119 | 120 | 121 | We invited {user}. 122 | 123 | ``` 124 | 125 | The macro will add the needed import for Trans Component and generate the correct Trans component for you. 126 | 127 | The correct string for translations will be shown in the browser console output as a missing string (if set debug: true on i18next init) or submitted via saveMissing (have saveMissing set true and a i18next backend supporting saving missing keys). 128 | 129 | If linting or other code analysis tools are complaining or failing because of the invalid JSX syntax, you can use the `defaults` prop instead of putting your message as a child, and it will be parsed and updated to the correct format. 130 | 131 | ```javascript 132 | import { Trans } from 'react-i18next/icu.macro'; 133 | 134 | const user = 'John Doe'; 135 | 136 | 140 | ``` 141 | 142 | This will be converted by the macro into: 143 | 144 | ```javascript 145 | import { Trans } from 'react-i18next'; 146 | 147 | const user = 'John Doe'; 148 | 149 | {user}]} 154 | /> 155 | ``` 156 | 157 | The defaults parsing supports the `@babel/react` preset, so any expressions that require more complex parsing may not work. 158 | 159 | **More samples:** 160 | 161 | ```markup 162 | // basic interpolation 163 | Welcome, { name }! 164 | 165 | // interpolation and components 166 | Welcome, { name }! 167 | 168 | 169 | // number formatting 170 | Trainers: { trainersCount, number } 171 | Trainers: { trainersCount, number }! 172 | 173 | 174 | // date formatting 175 | Caught on { catchDate, date, short } 176 | Caught on { catchDate, date, short }! 177 | 178 | 179 | You have { unread, number } messages 180 | 181 | ``` 182 | 183 | #### Tagged Template for ICU 184 | 185 | To support complex interpolations, `react-i18next` provides additional imports from the `icu.macro`. These provide a way to represent translations closer to the ICU messageformat syntax, but in a manner that is compatible with React and strictly typed in typescript. 186 | 187 | For example, to format a number: 188 | 189 | ```javascript 190 | import { Trans } from "react-i18next/icu.macro"; 191 | 192 | const num = 1; 193 | 194 | 195 | Incremented {num, number} times 196 | 197 | ``` 198 | 199 | the above syntax, although valid javascript, will error when using a linting tool like eslint. Instead, we can do this: 200 | 201 | ```javascript 202 | import { Trans, number } from "react-i18next/icu.macro"; 203 | 204 | const num = 1; 205 | 206 | 207 | Incremented {number`${num}`} times 208 | 209 | ``` 210 | 211 | This results in the translation string `Incremented {num, number} times` 212 | 213 | Supported interpolators are `number`, `date`, `time`, `select`, `plural`, and `selectOrdinal`. 214 | 215 | More complex skeletons can also be represented: 216 | 217 | ```javascript 218 | import { Trans, number } from "react-i18next/icu.macro"; 219 | 220 | const awesomePercentage = 100; 221 | 222 | 223 | It's awesome {number`${awesomePercentage}, ::percent`} of the time 224 | 225 | ``` 226 | 227 | This results in the translation string `It's awesome {awesomePercentage, number, ::percent} of the time`. 228 | 229 | **Complex interpolations with plural/select/selectOrdinal** 230 | 231 | The `plural` and `select` and `selectOrdinal` interpolations support more advanced syntax. For instance, it is possible to interpolate both React elements and other interpolations: 232 | 233 | ```javascript 234 | import { Trans, plural, number } from "react-i18next/icu.macro"; 235 | 236 | const awesomePercentage = 100; 237 | 238 | 239 | {plural`${awesomePercentage}, 240 | =0 { It's ${never} awesome } 241 | =100 { It is ${ALWAYS} awesome! } 242 | other { It's awesome {number`${awesomePercentage}, ::percent`} of the time }`} 243 | 244 | ``` 245 | 246 | This will result in the translation string `{awesomePercentage, plural, =0 { It's <0>never</0> awesome } =100 { It is <1>ALWAYS</1> awesome! } =100 { It's awesome {awesomePercentage, number, ::percent} of the time }}` 247 | 248 | It possible to nest any interpolated type, including nested `plural`, `select`, or `selectOrdinal`. 249 | 250 | **Typescript support for interpolated template strings** 251 | 252 | The `number`, `plural`, and `selectOrdinal` functions will error if a non-number typed variable is interpolated. 253 | 254 | ```javascript 255 | import { Trans, number } from "react-i18next/icu.macro"; 256 | 257 | // type error below - awesomePercentage must be a number 258 | const awesomePercentage = "100"; 259 | 260 | 261 | It's awesome {number`${awesomePercentage}, ::percent`} of the time 262 | 263 | ``` 264 | 265 | The `date` and `time` functions will error if a non-Date object is interpolated. 266 | 267 | ```javascript 268 | import { Trans, date } from "react-i18next/icu.macro"; 269 | 270 | // type error below - awesomePercentage must be a number 271 | const notADate = "100"; 272 | 273 | 274 | What time is it? it's {date`${notADate}`} o'clock 275 | 276 | ``` 277 | 278 | Finally, the `select` function will error if a non-string is interpolated. 279 | 280 | ```javascript 281 | import { Trans, select } from "react-i18next/icu.macro"; 282 | 283 | // type error below - awesomePercentage must be a number 284 | const notAString = 100; 285 | 286 | 287 | {select`${notAString} oops { you have to pass in a string } other { oh well }`} 288 | 289 | ``` 290 | 291 | ### Alternative syntax for select and plural 292 | 293 | It is also possible to display `select` and `plural` and `selectOrdinal` using Elements `Select`, `Plural` and `SelectOrdinal`. All of them have full type safety in typescript. 294 | 295 | #### Select 296 | 297 | There is no way to directly add the needed ICU format inside a JSX child - so we had to add another component that gets transpiled to needed Trans component: 298 | 299 | ```javascript 300 | import { Select } from 'react-i18next/icu.macro'; 301 | 302 | // simple select 303 | He avoids bugs.} 320 | female={She avoids bugs.} 321 | other={They avoid bugs.} 322 | /> 323 | ``` 324 | 325 | #### Plural 326 | 327 | ```javascript 328 | import { Plural } from 'react-i18next/icu.macro'; 329 | 330 | // simple plural 331 | 338 | ``` 339 | 340 | ```javascript 341 | import { Plural } from 'react-i18next/icu.macro'; 342 | 343 | // plural with inner components 344 | There is no item.} 348 | one={There is # item.} 349 | other={There are # items.} 350 | /> 351 | ``` 352 | 353 | #### SelectOrdinal 354 | 355 | ```javascript 356 | import { SelectOrdinal } from 'react-i18next/icu.macro'; 357 | 358 | // simple SelectOrdinal 359 | 367 | ``` 368 | 369 | ```javascript 370 | import { SelectOrdinal } from 'react-i18next/icu.macro'; 371 | 372 | // SelectOrdinal with inner components 373 | You are #st in line} 377 | two={You are #nd in line} 378 | few={You are #rd in line} 379 | other={You are #th in line} 380 | $7={You are the lucky #th in line} 381 | /> 382 | ``` 383 | 384 | {% hint style="info" %} 385 | The needed plural forms can be looked up in the official unicode cldr table: [http://www.unicode.org/cldr/charts/33/supplemental/language_plural_rules.html](http://www.unicode.org/cldr/charts/33/supplemental/language_plural_rules.html) 386 | 387 | In addition to the plural forms you can specify results for given number values like show above: 388 | 389 | `0="show if zero"` 390 | 391 | in ICU it would be `=0 {show if zero}` but `=` is not allowed to be leading char in attributes so we replaced it with `$` 392 | {% endhint %} 393 | -------------------------------------------------------------------------------- /styles/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i18next/react-i18next-gitbook/51221cce402b0021face38f726e02e1495a7075f/styles/README.md -------------------------------------------------------------------------------- /styles/website.css: -------------------------------------------------------------------------------- 1 | /* header */ 2 | h1, h2, h3, h4, h5, h6 { 3 | color: #00695C; 4 | } 5 | 6 | h2, h3, h4, h5, h6 { 7 | color: #00796B; 8 | } 9 | 10 | h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { 11 | position: relative; 12 | text-decoration: none; 13 | color: #00695C 14 | } 15 | 16 | h1 a { 17 | color: #00695C 18 | } 19 | 20 | h2 a, h3 a, h4 a, h5 a, h6 a { 21 | color: #00796B 22 | } 23 | 24 | .markdown-section a, a, a:active, a:hover, a:focus, a:visited { 25 | color: #26A69A; 26 | } 27 | 28 | h2, h3, h4, h5 { 29 | position: relative; 30 | } 31 | 32 | h2 > a:before, h3 > a:before, h4 > a:before, h5 > a:before { 33 | color: #efefef; 34 | position: absolute; 35 | left: -20px; 36 | content: "#"; 37 | } 38 | 39 | h2 > a:hover:before, h3 > a:hover:before, h4 > a:hover:before, h5 > a:hover:before { 40 | position: absolute; 41 | left: -20px; 42 | content: "#"; 43 | } 44 | 45 | /* active link in summary */ 46 | .book-summary ul.summary li.active>a { 47 | color: #26A69A; 48 | } 49 | 50 | /* brand */ 51 | .brand-container { 52 | padding: 5px 15px; 53 | } 54 | 55 | /* page */ 56 | .page-wrapper { 57 | padding-bottom: 20px; 58 | } 59 | 60 | /* page toc */ 61 | .markdown-section > * { 62 | z-index: 1; 63 | } 64 | .markdown-section > ul:first-child { 65 | z-index: 3000; 66 | position: relative; 67 | list-style-type: none; 68 | border: solid 1px #eee; 69 | padding: 10px; 70 | background: #fafafa; 71 | display: inline-block; 72 | min-width: 300px; 73 | float: right; 74 | margin-left: 40px; 75 | } 76 | .book-header { 77 | z-index: 4000; 78 | } 79 | 80 | /* workaround for non working initial top position - initial load scrolls title up 50px */ 81 | .book-body { 82 | top: 50px; 83 | } 84 | .body-inner { 85 | min-height: 100%; 86 | } 87 | .page-inner { 88 | margin-top: 0; 89 | } --------------------------------------------------------------------------------