In this article I will show you how to translate your React app with React-i18next and give a few examples that you may find useful!
I am using joy ui in this example, but I won't show any configuration for it because it is out of scope. You can see the full code in this code sandbox.
I am also assuming that you already have a react project up and running.
Setup
First of we need to add the react-i18next
package and its dependencies:
npm install react-i18next i18next i18next-http-backend i18next-browser-languagedetector
You do not strictly need i18next-http-backend
and i18next-browser-languagedetector
, however in my experience, almost every React app with translations will want to use these tools sooner or later.
Create config and add i18next provider
Now we need to create a i18n.ts
file where we will configure the i18n instance:
// /src/i18n.ts
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import Backend from 'i18next-http-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
i18n
.use(Backend) // default import from /public/locales/[lang]/[namespace].json
.use(LanguageDetector) // Detect browser language
.use(initReactI18next)
.init({
fallbackLng: 'en', // Our default language
debug: true, // Only use this in dev mode
interpolation: {
escapeValue: false // We don't need this for React
}
})
export default i18n
Next we need to provide this config to our entire React app using the I18nextProvider
:
// /src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { I18nextProvider } from 'react-i18next'
import i18n from './i18n' // import i18n config
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<I18nextProvider i18n={i18n} defaultNS={'translation'}>
<App />
</I18nextProvider>
</React.StrictMode>
)
Add the translations files
English translation:
// /public/locales/en/translation.json
{
"hello": "Hello World!"
}
Dutch translation:
// /public/locales/nl/translation.json
{
"hello": "Hallo wereld!"
}
Typescript
For extra convenience, we can add a react-i18next.d.ts
file so the compiler will know which translation keys are available in our app. This way we get autocomplete for translation keys and it will let us know when we are using a translation key that doesn't exist:
// /src/react-i18next.d.ts
import 'react-i18next'
import translation from 'locales/en/translation.json'
declare module 'react-i18next' {
interface Resources {
translation: typeof translation
}
}
declare module 'react-i18next' {
interface CustomTypeOptions {
defaultNS: 'translation'
resources: {
translation: typeof translation
}
}
}
Using translations
To translate a part of our app, we just import that useTranslation
hook and let it know which translation key to use:
// /src/App.tsx
import { useTranslation } from 'react-i18next'
import { Typography } from '@mui/joy'
function App(){
const { t } = useTranslation()
return <Typography>{t('hello')}</Typography>
}
More complex scenario's
Variables and pluralization
You might be thinking, what if some part of my text is a variable? Do I have to split the text out into chunks before and after the variable and translate them seperately? The answer is: nope, I18next has you covered!
// translation.json
{
"welcome_one": "Welcome {{name}}, you have {{count}} message.",
"welcome_other": "Welcome {{name}}, you have {{count}} messages.",
}
// /src/App.tsx
import { useTranslation } from 'react-i18next'
import { Typography } from '@mui/joy'
function App(){
const { t } = useTranslation()
const [name, setName] = useState('')
const [count, setCount] = useState(1)
// ...
return <Typography>{t('welcome', { count, name })}</Typography>
}
You can do a lot of other fancy stuff with i18next as well like context aware translations.
Custom React components
Sometimes you have some text with a link for example, or you may even want to use a custom React component inside a piece of translated text. For this you have to use the Trans
component.
// translations.json
{
"custom_link": "Translate some text with a custom <1>link</1>."
}
Note the <1>
placeholder that tells i18next where to expect a custom element.
// /src/App.tsx
import { Link } from '@mui/joy'
import { Trans } from 'react-i18next'
function App(){
return <Trans i18nKey="custom_link">
Translate some text with a custom <Link href="#link">link</Link>.
</Trans>
}
Adding a language switcher
Building a language switcher with i18next is very simple, all we have to do is make some buttons and call the i18n.changeLanguage
method with the language that we want to switch to:
// /src/App.tsx
import { Typography, IconButton } from '@mui/joy'
import { useTranslation, Trans } from 'react-i18next'
function App(){
const { t, i18n } = useTranslation()
return <>
<Typography>{t('hello')}</Typography>
<IconButton onClick={() => i18n.changeLanguage('en')} size="sm" variant={i18n.language ==='en' ? 'solid' : 'soft'}>EN</IconButton>
<IconButton onClick={() => i18n.changeLanguage('nl')} size="sm" variant={i18n.language ==='nl' ? 'solid' : 'soft'}>NL</IconButton>
</>
}
Top comments (1)
Hi, I am having issues with getting the autocomplete to work, even when running your sandbox. When I run it in VS Code and start typing a key in the t() function no suggestions are given. Do you have any idea what could cause this?