DEV Community

loading...
Cover image for Binding translations to views

Binding translations to views

devabhijeet profile image Abhijeet Yadav ・3 min read

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 and functional 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

Discussion

pic
Editor guide