This post is last in the series of react i18n integration.
In the previous post we went over how our TranslationServiceProvider
exposes API method for our components to consume.
Now a ideal place for TranslationServiceProvider
would be inside the root component. When our application is getting initialised, react-i18n exposes ready
boolean flag which can be accessed using the useTranslation
hook.
import React from "react";
import "./styles.css";
import "antd/dist/antd.css";
import { Spin } from "antd";
import { useTranslation } from "react-i18next";
import { Router } from "react-router-dom";
import { TranslationServiceProvider } from "./providers/TranslationServiceProvider";
import { AppRoutes } from "./routes/index";
import { createHashHistory } from "history";
import "./i18n";
const BrowserHistory = createHashHistory();
export default function App() {
const { ready } = useTranslation();
return (
<>
{!ready ? (
<Spin className="suspense-spinner" size="large" />
) : (
<TranslationServiceProvider>
<Router history={BrowserHistory}>
<AppRoutes />
</Router>
</TranslationServiceProvider>
)}
</>
);
}
Once we have encapsulated our main component with TranslationServiceProvider
we should now be able to access all the API method provided by TranslationServiceProvider
.
If you remember in the previous post I'd mentioned different ways to consume provider methods for
class
based andfunctional
component. We will have a look at those in this post.
when we say we want to translate textual contents embedded inside our components, we essentially mean to say, if there's any way can link or bind the textual content inside the component with the one mentioned in the .json
file.
react-i18n
let's us do that with a set of helper function namely
- t (
t
short form for translate) -
<Trans></Trans>
(to translate contents with html tag) -
<Translation></Translation>
(comes handy when translating a standalone texts that are not inside any components)
Let's have a look how we'd inject this helper methods in our class
and functional
component
import { withTranslation } from 'react-i18next';
import { TranslationServiceHelper } from 'HOC/TranslationServiceHelper';
class ToBeTranslated extends React.pureComponent{
render() {
const { t, currentLanguage } = this.props;
return (
<p>{t('helloworld')}</p>
)
}
}
ToBeTranslated = withTranslation()(ToBeTranslated);
export default compose(TranslationServiceHelper)(ToBeTranslated);
In the above example if you can see ()
empty parenthesis adjacent to withTranslation
. The empty parentheses is where you specify which the namespace should the component look into for resolving the translations. if no namespace is mentioned in withTranslation
, default namespace is used for lookup.
Alternatively we can also define the namespace to look for inside the t
helper function.
The helloworld
inside the t
helper function is the key
inside the json file that binds the translated content.
render() {
const { t, currentLanguage } = this.props;
return (
<p>{t('home:helloworld')}</p>
)
}
The above is how you'd for class
components, what if I have a functional component. Well, in that case we can make use of useTranslation
hook.
import { useTranslation } from 'react-i18next';
const ToBeTranslated = ({}) => {
const { t } = useTranslation('home');
return (
<p>{t('helloworld')}</p>
)
}
export default ToBeTranslated
The t
helper function suffices for only textual content, what if you have to translate below content.
<div>
It's
<span style={{color:'red'}}>free</span>
Forever!
</div>
Translating the above content is one thing, but how do we define keys for above contents inside json
file
"key": "Sus <1>GRATIS</1> Siempre!"
see how <1></1>
is substituted instead of . For every html
tag we have incrementing numbers inside the json
file. <1></1>
, <2></2>
.
For translation we can use Trans
component provided by react-i18n
.
<Trans i18nKey="key">
{"It's"}
<span style=style={{color:'red'}}>FREE </span>
Forever!
</Trans>
Bonus
If you plan to scale i18n
in your application by including multiple locales
, you may wish to load translation based on route
. Instead of downloading all the translations
in one go it makes sense to download them based on routes.
Let's start by adding useEffect
to watch for location
useEffect(() => {
const pathNameTerms = locationPath.includes("/terms");
const pathNameHome = locationPath.includes("/home");
if (pathNameTerms) {
props.loadNameSpaces("terms");
} else if (pathNameHome) {
props.loadNameSpaces("home");
}
}, [props.location]);
The above peace of code watched for route changes and loads appropriate namespace. It also changes the default namespace to terms
and home
respectively.
That's it for this series. You can see the above lessons in action below. You can also find the github repo containing all codes mentioned in this series here
Top comments (0)