简体   繁体   中英

Next.js/React - How to universally resolve the user language, from an Apollo client HOC?

I'm working on a I18n module using the Next.js framework (v5).

In order to display the UI on the user's default language, I'm trying to figure out what that language is, universally .

Resolving the language from the browser is "fairly simple", but I'm having a hard time figuring out how to do that on the server side, while providing that value to a HOC that wraps my Page, so that I can specify in my request headers the locale to use, in order to fetch content in that language.

I figured out how to resolve the user's language from the server, using the accept-language header, in the pages/_documents.js :

  static getInitialProps(props) {
    const { req, res, renderPage, isServer = false } = props;
    const cookies = new Cookies();

    if (isServer) {
      const headers = req.headers;
      const acceptedUserLanguages = acceptLanguageParser.parse(headers['accept-language']);
      const mostPreferredLanguage = get(acceptedUserLanguages, '[0]', {});
      // {code: 'en', region: 'GB'}

This works fine.

But, I need to access this mostPreferredLanguage within my HOC that wraps the Page component, and I really don't know how to do that, because the HOC code is executed before the getInitialProps function. And I don't have access to req.headers from the HOC itself, as far as I know.

HOC implementation:

export default withData(
  compose(
    withRedux(configureStore),
    withLoanAdvisor,
    graphql(institutionPagesData, {
      options: (props) => {
        return {
          context: {
            headers: {
              'gcms-locale': 'FR', // How do I universally get the user language here? I don't have access to request.headers there
              'gcms-locale-no-default': false
            },
          },
        };
      },
    }),
  )(SchoolPage));

Potential solutions

Redux

I've been thinking about using Redux . I tried to implement it but got blocked as it doesn't seem possible to use Redux on the server side.

The idea with Redux was to use getInitialProps to resolve the language and store it in redux, then I'd connect to the store before running my graphql() HOC query, therefore making the language available in the props of the graphql HOC, so that I could run the query with the correct headers.

But as mentioned, Redux isn't available on the server side and trying to initialise it through _document.js crashes the server. See https://github.com/zeit/next.js/issues/3990#issuecomment-372159451

Cookies

I also tried using cookies, but while I was successful reading cookies from both browser/server, I wasn't able to write them on the server side inside the _document.js getInitialProps function. I don't know why though, and existing examples didn't help me out.

You can access getInitialProps from HOCs - the restrictions on getInitialProps apply as usual (no children components, only pages ), but it's quite common pattern, eg:

const withSize = (WrappedComponent) => {
  return class extends React.Component {
    static async getInitialProps({ req }) {
      const ua = req ? req.headers['user-agent'] : navigator.userAgent;
      const userAgent = uaParser(ua);

      return { userAgent };
    }

    // ... implementation

    render() {
      // userAgent meant to be removed from props
      const { userAgent, ...props } = this.props || {};
      return (
        <WrappedComponent
          {...props}
          {...this.state}
          isMobile={this.state.windowWidth <= deviceWidth.mobile}
          isTablet={this.state.windowWidth <= deviceWidth.tablet}
        />
      );
    }
  };
};

See nextjs's examples for further examples, eg https://github.com/zeit/next.js/blob/3e51ddb8af55b6438aa3aeb382081b9a1c86f325/examples/with-lingui/components/withLang.js .

(Don't forget to hoistNonReactStatics if you want to use getInitialProps yet in the components wrapped by the HOC.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM