user 007
user 007

Reputation: 911

Next.js server side redirection overrides the locale

In some of my pages I'm using getServerSideProps to make API calls and redirect the user if necessary. The web APP I'm building is multilingual and I need to always show the user the correct language.

The homepage / uses getServerSideProps and redirects the user either to the profile or the login page. For that I do the following:

    return {
      redirect: {
        permanent: false,
        destination: someLogic ? `${context.locale}/login` : `${context.locale}/profile`,
      },
    };

now the profile and user pages use getServerSideProps too, to check if there's a valid session and redirect the user if necessary. For instance the user will try access the profile page when he's session is expired, he will then be redirected to the login page. if I set the destination property to /login the locale property will be overriden and the user will get the default language and be redirected to domain/login. If I set it to ${context.locale}/login and the page that was originally called is domain/fr-FR/profile then the user will be redirected to domain/fr-FR/fr-FR/login

Client side redirecting with router.push or router.replace is working fine and returning the correct urls.

To my understanding I can't get the absolute URL from the context of the getServerSideProps to check if the locale is already set, how can I then solve this problem?

I'm currently using next 10.0.4 and this is my next.config.js :

module.exports = {
  i18n: {
    locales: ['de-DE', 'en-US', 'fr-FR', 'nl-NL', 'it-IT'],
    defaultLocale: 'en-US',
    localDetection: true,
  }
}

Upvotes: 6

Views: 10172

Answers (2)

juliomalves
juliomalves

Reputation: 50278

The locale is being applied twice because you're setting the destination path without a leading /. Simply adding a / at the beginning should fix your issue.

return {
    redirect: {
        permanent: false,
        destination: someLogic ? `/${context.locale}/login` : `/${context.locale}/profile`
        //                        ^                            ^
    }
};

Upvotes: 0

Adam Morsi
Adam Morsi

Reputation: 499

I had the same issue and solved it following the next steps:

  • Pass the context to getServerSideProps:
    export const getServerSideProps = async (context) => {
  • Get locale from the context:
    const { locale } = context;

  • Use template literals to concatenate the current locale with the required destination:
    return {
                redirect: {
                destination: `/${locale}${getLoginPageUrl()}`,
                permanent: false,
            },
        };

Here is the whole code of my guard:

    export function withAuthServerSideProps(getServerSidePropsFunc) {
        return async (context) => {
            const {
                req: { cookies },
                query: { city },
                locale,
            } = context;
    
            if (!cookies.userToken) {
                return {
                    redirect: {
                        destination: `/${locale}${getLoginPageUrl(city ? city : '')}`,
                        permanent: false,
                    },
                };
            }
            if (getServerSidePropsFunc) {
                return { props: { data: await getServerSidePropsFunc(context) } };
            }
            return { props: {} };
        };
    }

And here is an example of how I use it:

    export const getServerSideProps = withAuthServerSideProps(async (context) => {
        const res = await ProductsService.fetchOrderDetails({
                id: 'b324015f-bf3f-4862-9817-61b954278168',
            });
    
        if (!res.data) {
            return {
                notFound: true,
            };
        }
    
        return {
            props: {
                orderDetails: res.data,
            },
        };
    });

Please keep in mind that if you use this guard your props will be in data, so for example in order for me to access the orderDetails from the previous code in my page I have to make the following:

    const OrderConfirmed = ({ data }) => (
        <OrderConfirmedPageWrapper orderDetails={data?.props?.orderDetails} />
    );

I'm currently using "next": "10.0.6", here is my next.config.js:

    i18n: {
            locales: [
                'en-kw',
                'ar-kw',
                'en-sa',
                'ar-sa',
                'en-qa',
                'ar-qa',
                'en-bh',
                'ar-bh',
                'en-ae',
                'ar-ae',
                'en-gb',
                'ar-gb',
                'catchAll',
            ],
            defaultLocale: 'catchAll',
        },

Upvotes: 3

Related Questions