2

I'm using apollo for authentication of my nextJS application. Now I need to add i18n support and I'm facing some basic problems:

Mainly the problem is to handle class Index extends React.Component, which is how my page and the components looks like vs. the function version used in the example.

In the documentation there is this example how to implement i18next to a page of the application:

import React from 'react';
import Link from 'next/link';
import { translate } from 'react-i18next';
import i18n from '../i18n';

function Index({ t, initialI18nStore }) {
  return (
    <div>
      {t('welcome')}
      <p>{t('common:integrates_react-i18next')}</p>
       <Link href="/page2"><a>{t('link.gotoPage2')}</a></Link>
    </div>
  );
}

const Extended = translate(['home', 'common'], { i18n, wait: process.browser })(Index);

// Passing down initial translations
// use req.i18n instance on serverside to avoid overlapping requests set the language wrong
Extended.getInitialProps = async ({ req }) => {
  if (req && !process.browser) return i18n.getInitialProps(req, ['home', 'common']);
  return {};
};

export default Extended;

But my page is using class Index extends React.Component. So I don't know how to implement t and initialI18nStore into my component. Also I do not understand how to add the getInitialProps into my existing one:

Page

import React from 'react'
import cookie from 'cookie'
import { withApollo, compose } from 'react-apollo'

import withData from '../lib/withData'
import redirect from '../lib/redirect'
import checkLoggedIn from '../lib/checkLoggedIn'

class Index extends React.Component {
  static async getInitialProps (context, apolloClient) {
    const { loggedInUser } = await checkLoggedIn(context, apolloClient)

    if (!loggedInUser.user) {
      // If not signed in, send them somewhere more useful
      redirect(context, '/signin')
    }

    return { loggedInUser }
  }

  render () {
    return (
      <div>
        Hello {this.props.loggedInUser.user.name}!<br />
        <button onClick={this.signout}>Sign out</button>
      </div>
    )
  }
};

export default compose(
  withData,
  withApollo
)(Index)

1 Answer 1

1
+50

To play along with nextJS way of getting the initial props and initialise the initialI18nStore store. We need to place the initialI18nStore and t fetching logic in your getInitialProps. Initialise a new i18nProps object and populate it when the condition is met, then return your logged in user along with the i18nProps using the spread operator.

Once that is done, you need to have the language mapping .json files similar to how the documentation example does. Create a index.json in all the languages you want the translations in. Eg: en/index.json containing English mapping, hi/index.json containing Hindi mapping etc.

NOTE: You need to import i18n.js in your component like the documentation example did. This is where the module is https://github.com/i18next/react-i18next/blob/master/example/nextjs/i18n.js

Index.js

class Index extends React.Component {
  static async getInitialProps (context, apolloClient) {
    let i18nProps = {}

    if (context.req && !process.browser) {        
      i18nProps = i18n.getInitialProps(context.req, ['index']);
    }

    const { loggedInUser } = await checkLoggedIn(context, apolloClient)

    if (!loggedInUser.user) {
      redirect(context, '/signin')
    }

    return { loggedInUser, ...i18nProps }
  }

  render () {
    // Ternary conditional just to ensure the availability of initialI18nStore object in props.
    return (
      this.props.initialI18nStore
        ?
        <div>
          {this.props.t('hello') + this.props.loggedInUser.user.name} !<br />
          <button onClick={this.signout}{this.props.t('signOut')}</button>
        </div>
        :
        <div>
          Hello {this.props.loggedInUser.user.name}!<br />
          <button onClick={this.signout}>Sign out</button>
        </div>
    )
  }
};

const ExtendedIndex = translate(['index'], { i18n, wait: process.browser })(Index)

export default compose(
  withData,
  withApollo
)(ExtendedIndex)

en/index.json for English

{
  "hello": "Hello",
  // Instead of name, your json should have the names of your users
  // if you intend on internationalising names as well
  "name": "Name"
  "signOut": "Sign Out"
}

hi/index.json for Hindi

{
  "hello": "नमस्ते",
  "name": "नाम"
  "signOut": "साइन आउट"
}
Sign up to request clarification or add additional context in comments.

7 Comments

Two problems with that: t is not defined in the return of render() and TypeError: i18n.getInitialProps is not a function
Replace it with this.props.t. and the documentation example has import i18n from '../i18n' You need to get that module similarly. Check the updated snippet.
I already imported the i18n.js in my server.js and in my page file. I still get the error TypeError: i18n.getInitialProps is not a function.
But your component needs to know about the i18n module. Which is why it is throwing that error. Just add an import to i18n.js relative to your component. They do the same in the example. github.com/i18next/react-i18next/blob/master/example/nextjs/…
The third line of your code (i18n = {}) throws the error Module build failed: SyntaxError: "i18n" is read-only after importing i18n to the component.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.