28

I am trying to translate my application using react-i18next. I know how to use it with simple const components, but not within a class.

I'm working with the I18nextProvider. This is my App.js file.

import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { I18nextProvider } from 'react-i18next';
import i18next from 'i18next';
// eslint-disable-next-line import/no-extraneous-dependencies
import { hot } from 'react-hot-loader';
import 'bootstrap/dist/css/bootstrap.css';
import '../../scss/app.scss';
import Router from './Router';
import store from './store';
import ScrollToTop from './ScrollToTop';
import { config as i18nextConfig } from '../../translations';

i18next.init(i18nextConfig);

class App extends Component {
  constructor() {
    super();
    this.state = {
      loading: true,
      loaded: false,
    };
  }

  componentDidMount() {
    window.addEventListener('load', () => {
      this.setState({ loading: false });
      setTimeout(() => this.setState({ loaded: true }), 500);
    });
  }

  render() {
    const { loaded, loading } = this.state;
    return (
      <Provider store={store}>
        <BrowserRouter basename="/easydev">
          <I18nextProvider i18n={i18next}>
            <ScrollToTop>
              {!loaded &&
                <div className={`load${loading ? '' : ' loaded'}`}>
                  <div className="load__icon-wrap">
                    <svg className="load__icon">
                      <path fill="#4ce1b6" d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z" />
                    </svg>
                  </div>
                </div>
              }
              <div>
                <Router />
              </div>
            </ScrollToTop>
          </I18nextProvider>
        </BrowserRouter>
      </Provider>
    );
  }
}

export default hot(module)(App);

Now using it within a const based component is quite easy. Here is an example:

import React from 'react';
import { Card, CardBody, Col } from 'reactstrap';
import HeartOutlineIcon from 'mdi-react/HeartOutlineIcon';
import { translate } from 'react-i18next';
import PropTypes from 'prop-types';

const InfoCard = ({ t }) => (
  <Col md={12} xl={3} lg={6} sm={12} xs={12}>
    <Card>
      <CardBody className="dashboard__health-chart-card">
        <div className="card__title">
          <h5 className="bold-text">{t('dashboard_fitness.heartrate')}</h5>
        </div>
        <div className="dashboard__health-chart">
          <div className="dashboard__health-chart-info">
            <HeartOutlineIcon style={{ fill: '#ff4861' }} />
            <p className="dashboard__health-chart-number">96</p>
            <p className="dashboard__health-chart-units">b/min</p>
          </div>
        </div>
      </CardBody>
    </Card>
  </Col>
);

InfoCard.propTypes = {
  t: PropTypes.func.isRequired,
};

export default translate('common')(InfoCard);

As you can see I just import the translate from the react-i18next and I'm almost ready to go with the t function.

How can I achieve the same within a class component? I want to implement it in this class:

/* eslint-disable react/no-typos */
import React, { PureComponent } from 'react';
import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';
import { translate } from 'react-i18next';

import MenuDownIcon from 'mdi-react/ChevronDownIcon';
import MagnifyIcon from 'mdi-react/MagnifyIcon';

class TradesTableControls extends PureComponent {
  constructor() {
    super();
    this.state = {
      rows: 10,
    };
  }

  changeRowAmount = (rows) => {
    switch (rows) {
      case 10:
        this.setState({ rows: 10 });
        break;
      case 25:
        this.setState({ rows: 25 });
        break;
      case 50:
        this.setState({ rows: 50 });
        break;
      case 100:
        this.setState({ rows: 100 });
        break;
      default:
        this.setState({ rows: 10 });
        break;
    }
  };

  render() {
    return (
      <div className="trades-table__controls-wrap">
        <div className="trades-table__controls">
          <UncontrolledDropdown>
            <DropdownToggle className="icon icon--right" outline size="sm">
              <p>
                {t('history.controls.show')}
                {this.state.rows}
                {t('history.controls.results')}
                <MenuDownIcon />
              </p>
            </DropdownToggle>
            <DropdownMenu className="dropdown__menu">
              <DropdownItem onClick={() => this.changeRowAmount(10)}>10</DropdownItem>
              <DropdownItem onClick={() => this.changeRowAmount(25)}>25</DropdownItem>
              <DropdownItem onClick={() => this.changeRowAmount(50)}>50</DropdownItem>
              <DropdownItem onClick={() => this.changeRowAmount(100)}>100</DropdownItem>
            </DropdownMenu>
          </UncontrolledDropdown>
        </div>
        <div className="trades-table__controls-right">
          <div className="trades-table__control-search">
            <input placeholder="Search" />
            <div className="trades-table__control-search-icon"><MagnifyIcon /></div>
          </div>
        </div>
      </div>
    );
  }
}

export default translate('common')(TradesTableControls);

I'm quite new to React and ES6, but I was unable to find the solution online. Would really appreciate any help!

Thanks!

6 Answers6

25

Currently (ie 2021) the docs suggest the packaged HOC withTranslation():

import React from 'react';
import { withTranslation } from 'react-i18next';

class MyComponent extends Component {
  return <p>{this.props.t('key')}</p>
}

export default withTranslation()(MyComponent);

If you like to use namespaces then export:

export default withTranslation('namespace')(MyComponent);

Ref: official docs.

pico_prob
  • 1,105
  • 10
  • 14
14

Just like t is available as props in a functional component, you can access it from props in a class component after wrapping TradesTableComponent with translate HOC. All you need to do is destructure it from props in render method like

const { t } = this.props;

Relevant code

render() {
    const { t } = this.props;
    return (
      <div className="trades-table__controls-wrap">
        <div className="trades-table__controls">
          <UncontrolledDropdown>
            <DropdownToggle className="icon icon--right" outline size="sm">
              <p>
                {t('history.controls.show')}
                {this.state.rows}
                {t('history.controls.results')}
                <MenuDownIcon />
              </p>
            </DropdownToggle>
            <DropdownMenu className="dropdown__menu">
              <DropdownItem onClick={() => this.changeRowAmount(10)}>10</DropdownItem>
              <DropdownItem onClick={() => this.changeRowAmount(25)}>25</DropdownItem>
              <DropdownItem onClick={() => this.changeRowAmount(50)}>50</DropdownItem>
              <DropdownItem onClick={() => this.changeRowAmount(100)}>100</DropdownItem>
            </DropdownMenu>
          </UncontrolledDropdown>
        </div>
        <div className="trades-table__controls-right">
          <div className="trades-table__control-search">
            <input placeholder="Search" />
            <div className="trades-table__control-search-icon"><MagnifyIcon /></div>
          </div>
        </div>
      </div>
    );
  }
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
11

Here's a working example of how to use translation in a class-based component in React Native.

import { withTranslation } from 'react-i18next';
class PersonalScreen extends React.Component {
  render() {
    const { t } = this.props;
    return (
      <Text>{t('Translate this text')}</Text>
    )
  }
}

export default withTranslation()(PersonalScreen)
cmcodes
  • 1,559
  • 19
  • 24
  • 1
    I used the answer from @Mathissimo, but extracting t from this.props I didn't need to change anything in JSX, very good! - `const { t } = this.props;` – Fernando Tholl Nov 20 '20 at 17:28
3

You can import "t" or i18next from i18next then you can use that t or i18next instance directly in your any class or in any file in the project.

import React from 'react';
import i18next, { t } from 'i18next';
...
class Screen extends Component {
  ...
  render() {
    return (
        <View>
          <Text>{t('your_translate_text_key')}</Text>
          <Text>{i18next.t('your_translate_text_key')}</Text>
        </View>
    )
  }
}

export default Screen;
Vishal Pawar
  • 1,447
  • 8
  • 10
2

The recommended way is to use the withTranslate HOC, Another way is to use the render props, by passing a callback function with translation param in the props.children of Translation component

import React from 'react';

// the render prop
import { Translation } from 'react-i18next';

export default function MyComponent () {
  return (
    <Translation>
      {
        t => <h1>{t('Welcome to React')}</h1>
      }
    </Translation>
  )
}
Viraj Singh
  • 1,951
  • 1
  • 17
  • 27
0

Here is an Example of how to use i18next + React + Typescript with class definitions https://gitlab.com/damjan89/i18next-typescript-example

liquid boy
  • 145
  • 1
  • 6
  • 2
    @liquid_boy Normally, we are asked to provide the answer directly in our posts on StackOverflow. We can provide a link directing to a page with more details, but the gist of the solution should be in the post. Also, following that link I found a project with all the basic stuff to do localization, but there is no example in the component itself. The last bit is missing. – Jean-François Beauchamp Aug 14 '20 at 15:00
  • 1
    I needed this package in a class which I was using to make API related functions. From the above repo, I have found this code which helped me. `import i18next from 'i18next';` `i18next.t('someKey');` Thanks – shery089 Dec 21 '21 at 10:09