i18n libraries
When we are to support i18n with React, we can narrow it down to the following three.
React-intl
12.5k stars on Github
A part of Format.js. The open-source library developed by Yahoo.
React-i18next
5.6k stars on Github
i18n framework for React.
LinguiJS
3.1k stars on Github
i18n framework. it seems most lightweight within these three.
After considering flexibility and simplicity, React-i18next seems to be well-balanced and very good, so I’ll use that one this time.
For a Gatsby project
If you are to use Gatsby, there is already a wonderful plugin as always.
gatsby-plugin-react-i18next
Seamless integration with react-i18next
This plugin helps to create a static file on SSR for each language, and also sets the proper URL for each language.
For example, https://sample.com/en/profile
for an English page and https://sample.com/ja/profile
for a Japanese page.
But this time, for me, this plugin seems too much because it is enough by enabling users to switch languages on the client side without changing URL. So I’m gonna use React-i18next to support i18n with Gatsby.
Make a sample component
I assume we already have a project.
Then let’s make a small component to test i18n.
// index.js
import React from 'react'
export const Index = () => {
return (
<div>
<h1>Have a nice day!</h1>
<ul>
<li><button>EN</button></li>
<li><button>DE</button></li>
<li><button>JA</button></li>
</ul>
</div>
)
}
Translation files
Prepare translation files arbitrary place.
*
└── locales/
├── en/
│ └── translation.json
│
├── de/
│ └── translation.json
│
└── ja/
└── translation.json
We can write translations using json format. Make sure the same sentence has the same key.
Nested json object is supported.
en/translation.json
{
"topPage": {
"greeting": "Have a nice day"
}
}
de/translation.json
{
"topPage": {
"greeting": "Schönen tag noch"
}
}
ja/translation.json
{
"topPage": {
"greeting": "よい1日を"
}
}
React-i18next
first, Install.
npm install --save react-i18next i18next
or
yarn add react-i18next i18next
Make i18n.js
file on arbitrary place then init i18n.
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
i18n
.use(initReactI18next)
.init({
resources: { // Import translations you made from certain path.
en: {
translation: require('../../static/locales/en/translation.json')
},
de: {
translation: require('../../static/locales/de/translation.json')
},
ja: {
translation: require('../../static/locales/ja/translation.json')
}
},
debug: process.env.NODE_ENV === "development",
fallbackLng: 'en', // Set default language
interpolation: {
escapeValue: false,
},
})
export default i18n
Then pass i18n to whole app.
We use I18nextProvider
to wrap the app.
import React from 'react'
import ReactDOM from 'react-dom'
import { I18nextProvider } from 'react-i18next'
import i18n from './src/providers/i18n'
const App =() => {
return (
<I18nextProvider i18n={i18n}>
<Index />
</I18nextProvider>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
For Gatsby, gatsby-browser.js
and gatsby-ssr.js
are the place to do this.
// gatsby-wrapper.js
import React from 'react'
import { I18nextProvider } from 'react-i18next'
import i18n from './src/providers/i18n'
export const rootWrapper = ({ element }) => (
<>
<I18nextProvider i18n={i18n}>
{element}
</I18nextProvider>
</>
)
// gatsby-ssr.js
import { rootWrapper } from './gatsby-wrapper'
export const wrapRootElement = rootWrapper
// gatsby-browser.js
import { rootWrapper } from './gatsby-wrapper'
export const wrapRootElement = rootWrapper
Switch languages
Translating with i18next is quite simple, we just need to enclose the key string with t() function which comes from special hooks.
If you want to change the language, just use i18n.changeLanguage() passing the language as an argument.
// index.js
import React from 'react'
import { useTranslation } from 'react-i18next'
export const Index = () => {
const { t, i18n } = useTranslation()
const changeLang = (lang) => {
i18n.changeLanguage(lang)
}
return (
<Div>
<h1>{t('topPage.greeting')}</h1>
<ul>
<li><button onClick={() => changeLang('en')}>EN</button></li>
<li><button onClick={() => changeLang('de')}>DE</button></li>
<li><button onClick={() => changeLang('ja')}>JA</button></li>
</ul>
</Div>
)
}
Detect user language
i18next has another useful feature that detects the user’s language settings and automatically changes the language. To enable this, just install two dedicated packages and load them at init.
npm install --save i18next-http-backend i18next-browser-languagedetector
or
yarn add i18next-http-backend i18next-browser-languagedetector
// i18n.js
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import Backend from 'i18next-http-backend' // new
import LanguageDetector from 'i18next-browser-languagedetector' //new
i18n
.use(Backend) // new
.use(LanguageDetector) // new
.use(initReactI18next)
.init({
resources: {
en: {
translation: require('../../static/locales/en/translation.json')
},
de: {
translation: require('../../static/locales/de/translation.json')
},
ja: {
translation: require('../../static/locales/ja/translation.json')
}
},
debug: process.env.NODE_ENV === "development",
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
})
export default i18n
Done!
We can support i18n quite easily by using React-i18next.