Recently, we migrated our sub-project from react-localization
to i18next
. During that migration, the main goal was to keep the previous behavior of setting and changing language in our app.
Storing language in a route path is a commonly used practice for the Nextjs framework. But for our project, that was an inappropriate solution. Our main application allows businesses to generate QR codes for their customers with a link to the sub-application where the end user can leave feedback regarding service quality and satisfaction. All QR codes had already been printed, and new ones would cost a fortune for the business. The previous version of the sub-app used to be built on the base of CRA, and only half a year ago, it was migrated to Nextjs. So, we were looking for library or libraries which could provide us with non-route-based internationalization and API similar to react-i8next
. We found ni18n
. This is a library specifically designed for use with Nextjs. ni18n
provides a simple and flexible way to add i18n functionality to Nextjs projects, including support for server-side rendering and other advanced features.
Let’s install all necessary dependencies to start working on our project.
npm install i18next react-i18next ni18n
The next step is to expand the existing next.config.js
with the default i18n config.
Basically, we need only a few fields for a quick start. locales
is required to show all the locales we want to support in the app, and defaultLocale
will be used when visiting a non-locale prefixed path (for us, it’s just the default language).
// next.config.js
module.exports = {
...yourNextConfig,
i18n: {
defaultLocale: 'GB',
locales: ['GB', 'UA', 'PT'],
},
};
Then we are required to create a new file in the root or utils/plugins/etc. directory named ni18n.config.js
. supportedLngs
- names which show us supported languages, and ns
- namespaces, which we can use in some cases.
// ni18n.config.js
export const ni18nConfig = {
supportedLngs: ['GB', 'UA', 'PT'],
ns: ['namespace-name'],
};
A few more things left. Our application requires I18nextProvider
, so let’s wrap the App
with the high-order component imported from i18n
.
It will initialize the i18next
instance and provide it as a context for all the children.
// pages/_app.jsx
import { appWithI18Next } from 'ni18n';
import { ni18nConfig } from '../ni18n.config';
const App = ({ Component, pageProps }) => <Component {...pageProps} />;
export default appWithI18Next(App, ni18nConfig);
And the last preparation step before we started using translation into our components is a filling of translation files. The important thing - keep the following file structure.
./public
└── locales
├── GB
│ ├── namespace-name.json // { "key1": "Test" }
│
├── UA
│ ├── namespace-name.json // { "key1": "Тест" }
│
├── PT
├── namespace-name.json // { "key1": "Teste" }
Finally, we’ve done with the setup and are ready to start integration of the i18n feature into components. Let’s take a look at the example in ComponentName.jsx
.
We extract the t
function from useTranslation
hook which will return translated string for the selected language. Looks simple, doesn’t it?
// ComponentName.jsx
import { useTranslation } from 'react-i18next';
export const MyComponent = () => {
const { t } = useTranslation();
return (
<div>{t('key1')}</div>
);
};
If you store user language in DB, don’t forget to create a context with React.Context
or any other solution to wrap pages and set the language in useEffect
. Below, I’ll show you a simple snippet of how it could be implemented.
// ContextName.jsx
const I18nProvider = ({ children, data }) => {
const { i18n } = useTranslation();
const { language = 'GB' } = data;
useEffect(() => {
i18n.changeLanguage(language);
}, [language]);
return (
<I18nContext.Provider>
{children}
</I18nContext.Provider>
);
};
That’s it. I hope it helped you to save some time, as always. In the future, we are going to migrate the existing i18n approach to route based. The reason is pretty simple - a unification of all our applications. I’ll definitely describe it in one of my next articles.