How can we universally detect and resolve the user's language within a React/Next.js application using an Apollo client HOC?

Currently, I am developing an I18n module utilizing the Next.js framework (v5).

The challenge I am facing is determining the user's default language universally in order to display the UI in that language.

While it is relatively simple to resolve the language from the browser, I am struggling with doing so on the server side and passing that value to a Higher Order Component (HOC) wrapping my Page component. This information is essential for specifying the locale in request headers to fetch content in the desired language.

I have successfully resolved the user's language from the server by using the 'accept-language' header in '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'}

Despite this working well, I now need to access the 'mostPreferredLanguage' within my HOC wrapping the Page component. However, as the HOC code is executed before the 'getInitialProps' function, accessing 'req.headers' from the HOC itself seems impossible.

HOC implementation:

export default withData(
  compose(
    withRedux(configureStore),
    withLoanAdvisor,
    graphql(institutionPagesData, {
      options: (props) => {
        return {
          context: {
            headers: {
              'gcms-locale': 'FR', // How can I consistently retrieve the user's language here?
              'gcms-locale-no-default': false
            },
          },
        };
      },
    }),
  )(SchoolPage));

Possible Solutions

Redux

One solution I am considering is leveraging Redux. Though I attempted its implementation, I encountered limitations since Redux cannot be used on the server side.

The concept behind using Redux was to resolve the language in 'getInitialProps' and store it in Redux, then connecting to the store before executing my 'graphql()' HOC query. This would make the language available in the 'props' of the 'graphql' HOC, enabling me to run the query with the correct headers.

Unfortunately, the lack of availability of Redux on the server side hindered this approach, and initializing it through '_document.js' resulted in server crashes. Refer to this link for more information.

Cookies

An alternative method I explored was using cookies. While successful in reading cookies from both the browser and server, I faced challenges in writing them on the server side within the '_document.js' 'getInitialProps' function. The reason for this limitation remains unclear, and existing examples did not provide much assistance.

Answer №1

One way to access getInitialProps from HOCs is by following the usual restrictions such as no children components and only using it in pages. An example of this pattern could be:

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() {
      // Remove userAgent from props
      const { userAgent, ...props } = this.props || {};
      return (
        <WrappedComponent
          {...props}
          {...this.state}
          isMobile={this.state.windowWidth <= deviceWidth.mobile}
          isTablet={this.state.windowWidth <= deviceWidth.tablet}
        />
      );
    }
  };
};

To explore more examples, refer to Next.js's documentation or check out samples like https://github.com/zeit/next.js/blob/3e51ddb8af55b6438aa3aeb382081b9a1c86f325/examples/with-lingui/components/withLang.js.

(Remember to use hoistNonReactStatics if planning to utilize getInitialProps within components wrapped by the HOC.)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Striking a balance between innovation and backward compatibility in the realm of Web Design/Development

Creating websites is my passion, and I enjoy optimizing them for various platforms, devices, and browsers. However, lately, I've been feeling frustrated. I'm tired of facing limitations in implementing my creative ideas due to outdated technolog ...

Having difficulty entering text in the modal text box and updating it with a new state

Within my render method, I am utilizing the following model: { showEditModal && <Modal toggleModal={this.togglePageModal} pageModal={true}> <h2 style={{ textAlign: "center", width: "100%" }}> ...

Why is Jasmine throwing an error when I try to use getElementsByTagName(...)?

HTML: <ul id="listONE"> <li class="{{isSel}}" ng-repeat="person in people" ng-click="selPersonToChange(this)">{{person.name +" - "+ person.city}}</li> </ul> A snippet from my script.js using AngularJS (1.3.1): mymod.control ...

Retrieving a Table Row from a TableView in Titanium Mobile

Does anyone know where the actual tableViewRows are stored within a TableView? When inspecting the TableView, I can see the headings for the Rows but not the Rows themselves. Can someone point me in the right direction to find where these Rows are contai ...

What is the best way to utilize the oninput function in Jade?

input(type='range', id= 'inputSlider', min='0', max='255', value='50', step='1', oninput=showValue(this.value)) span#outputText 50 script. var socket = io.connect(); socket.on(& ...

Switch color in Material-UI based on props

Utilizing code inspired by the Material-UI documentation on customizing the switch, you can customize the switch color to be blue: import React from 'react' import Switch from '@material-ui/core/Switch' import {withStyles} from '@ ...

Tips for customizing the border radius style of the menu in Vuetify's v-autocomplete component

I am looking to customize the appearance of the drop-down list in the v-autocomplete component by adding a border-radius style, as depicted in the image below. The current design I have achieved closely resembles the visual shown below. Previously, I app ...

Positioning the filters in jQuery Datatables

I'm currently working with jQuery datatables and I'm attempting to align the filter/search box on the same row as the header of the container holding the datatable. Attached is a screenshot for reference: https://i.stack.imgur.com/nzbIl.png He ...

What is the procedure for utilizing Javascript to redirect a user on a website back to the login page if necessary?

Is there a way to redirect a website user back to the login page if they try to access a secure page without logging in first? I'm looking to implement this using JavaScript and cookies. Any suggestions or ideas on how to achieve this seamlessly for t ...

When using Vuejs2, the list of autosize textareas connected to an expanding array of objects does not properly update their values

After binding https://github.com/jackmoore/autosize to textareas within a v-for loop, I've noticed an unexpected data persistence issue while expanding the array linked to that list: While inputs on the left side move downward as intended, new textar ...

VUE JS - My methods are triggering without any explicit invocation from my side

I've encountered a frustrating problem with Vue JS >.<. My methods are being triggered unexpectedly. I have a button that is supposed to execute a specific method, but this method gets executed along with other methods, causing annoyance... Her ...

Is it possible to utilize a slot within a Vue.js loop?

I am encountering an issue with a template that is utilizing v-for to loop through. The template includes a named slot where the name is dynamically assigned within the loop. However, no content is displaying as expected. Can someone help me identify wha ...

Organizing JSON keys based on their values using Typescript

In the context of a main JSON structure represented below, I am interested in creating two separate JSONs based on the ID and Hobby values. x = [ {id: "1", hobby: "videogames"}, {id: "1", hobby: "chess"}, {id: "2", hobby: "chess ...

Combine multiple key values from an array of objects into a single array

I have a set of key and value pairs that I need to filter based on whether the values are in an array or not, and then combine them into a single array. const holiday_expenses = { food: [{name: "abc", place: "xyz"}], travel: [{name: ...

Utilizing ES6 promises in node.js to send a null response

I'm looking for assistance on how to execute a query using ES6 native promises in node.js. The code I have below is what I've been working with: let arr= []; conn.query('select * from table1', (err, b) => { for (let i = 0; i ...

What is the reason for the error that is being caused by using arrow functions in my code

I'm currently working on a React application, but I keep running into errors that are causing issues. Here is the code snippet in question: import React from 'react'; import { Link } from 'react-router-dom'; const LINKS = [ { to ...

Issue with HTML5 Canvas y-axis dimensions

I am attempting to create a basic animated HTML canvas with a moving block controlled by WASD keys. I encountered an issue where drawing a 5x5 rectangle appeared to be 5x10 on the canvas. Upon inspecting my code and logging the position of the element, I d ...

Connecting a Database with NestJS and TypeORM: A step-by-step guide to establish a connection with TypeORM and ensure easy access to

Could someone please explain how to create a DB instance using TypeORM? I want it to be accessible like this service, but the Connection class is deprecated. import { Inject, Injectable } from '@nestjs/common'; import { Connection, Repository } ...

What can be done to ensure that two separate react-native Picker components do not interfere with each other's

Encountering an issue with two Pickers in a react-native View. Whenever I select a value in one Picker, it causes the other Picker to revert back to its initial item in the list. It seems like the onValueChange function is being triggered for both Pickers ...

Having trouble retrieving data from the table with AJAX and CodeIgniter

I am currently developing a comprehensive HRM+CRM system (Human Resource Management and Customer Relation Management). I have encountered an issue while trying to generate an invoice for each customer. I am struggling to resolve this problem and would appr ...