How to add namespaces in React i18next
Is your translation file getting to big for your React project?
Do you need a way to split your translation JSON file into multiple smaller files?
Let me show you how to accomplish that with react-i18next
NPM module.
Setup translation files
In this example, I’m going to create 2 json files
{
"greet": "Hi there, it's Ruben here!"
}
{
"greet": "Hi there, I like cats! How about yourself?"
}
Setup i18n configuration file
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import commonTranslationEN from "../public/locales/en/common.json";
import moduleATranslationEN from "../public/locales/en/moduleA.json";
const resources = {
en: {
// Namspaces
common: commonTranslationEN,
moduleA: moduleATranslationEN
}
};
i18n
// passes i18n down to react-i18next
.use(initReactI18next)
.init({
resources,
// Set default namespace
defaultNS: "common",
lng: "en",
interpolation: {
// react already safes from xss
escapeValue: false
}
});
export default i18n;
Let’s do a breakdown of what’s happening here.
First I’m importing a couple i18n libraries, and I’m also importing the translation files.
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import commonTranslationEN from "../public/locales/en/common.json";
import moduleATranslationEN from "../public/locales/en/moduleA.json";
Pretty easy stuff!
Setup React i18n resources
The next step I’m taking is to create an object that maps my translations files to the desired namespace.
const resources = {
en: {
// Namspaces
common: commonTranslationEN,
moduleA: moduleATranslationEN
}
};
In my en
property, I’m creating common
, and moduleA
as namespaces.
And I’m attaching a translation JSON object to them.
Choose default namespace
In the i18n.init()
function, I’m passing the resources map, and I’m setting a default namespace.
i18n
.init({
resources,
// Set default namespace
defaultNS: "common",
// other configs...
});
Now that the configuration has been completed, I’m going to create a React component to utilize react-i18next
with it’s namespaces.
Use props.t() function in React component
import * as React from "react";
import { render } from "react-dom";
import "./i18n";
import { withTranslation } from "react-i18next";
const App = withTranslation()(props => {
const [showCatGreetMssg, setShowCatGreetMssg] = React.useState(false);
const handleClick = () => setShowCatGreetMssg(true);
return (
<>
<h1>
{!showCatGreetMssg ? props.t("greet") : props.t("moduleA:greet")}
</h1>
<button onClick={handleClick}>Change message</button>
</>
);
});
render(<App />, document.getElementById("root"));
React code breakdown!
Before I begin calling my greet messages, I have to import a few files first.
import "./i18n";
import { withTranslation } from "react-i18next";
In the code example above, I’m importing my i18n configuration file.
I’m also importing one of react-i18next
utility functions, withTranslation
.
withTranslation()(Component);
withTranslation
is a HOC (higher order component) function type.
When you use the withTranslation utility function, withTranslation will pass the translate function via React props, props.t()
.
<h1>
{!showCatGreetMssg ? props.t("greet") : props.t("moduleA:greet")}
</h1>
In the code snippet above you’ll the code utilize the translate function, and passing a string value in 2 different formats.
// Uses default namespace common
props.t("greet") // Hi there, it's Ruben here!
// Calling namespace "<namespace_identifier>:<message_identifier>"
props.t("moduleA:greet") // Hi there, I like cats! How about yourself?
If I didn’t set a default namespace in my i18n file the first props.t()
call would have not work.
I would have to use it as such:
props.t("common:greet")
Conclusion
Creating namespaces for your i18n locales will help alleviate the pain of having a large translation file.
react-i18next
makes it easy to setup namespaces and to call them into your React application.
I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!