Binding translations to views
Tags: react, i18n, localisation, translation
Published: 2020-06-30 15:23:57

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.

```sh
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

```sh
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.

```sh
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.

```sh
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.

```sh
<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

```sh
"key": "Sus <1>GRATIS</1> Siempre!"
```
see how `<1></1>` is substituted instead of <span></span>. 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`.

```sh
<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`

```sh
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](https://github.com/devAbhijeet/react-i18n-app)

{% codesandbox blue-brook-xgg5v %}