Reputation: 185
I am building a website, which has two languages, so I persist the selected language on cookie and retrieve it in the getInitialProps at _app file then pass it as a context API value. and I keep the cookie with sync to language state through the useEffect. the _app.js file look like this.
import React, { useState, useEffect } from 'react';
import nextCookie from 'next-cookies';
import * as Cookie from 'js-cookie';
import Head from 'next/head';
import { ThemeProvider } from 'emotion-theming';
import Layout from '../components/Common/Layout';
import GlobalStyle from '../components/GlobalStyle';
import { languageState, languageDispatch } from '../hooks/useLanguage';
function MyApp({ Component, pageProps, initialLanguage = 'ar' }) {
const [language, setLanguage] = useState(initialLanguage);
const changeLanuage = () => {
setLanguage((prev) => (prev == 'en' ? 'ar' : 'en'));
};
useEffect(() => {
Cookie.set('language', language);
}, [language]);
return (
<languageDispatch.Provider value={changeLanuage}>
<languageState.Provider value={language}>
<ThemeProvider theme={theme}>
<Layout>
<Head>
<link rel="shortcut icon" href="/svg/favicon.ico" />
</Head>
<Component {...pageProps} />
<GlobalStyle rtl={rtl} />
</Layout>
</ThemeProvider>
</languageState.Provider>
</languageDispatch.Provider>
);
}
MyApp.getInitialProps = async ({ ctx }) => {
const { language } = cookies(ctx);
return { initialLanguage: language };
};
in the development mode and deploying on now, it works perfectly with each page refresh. However, when I export it as static and deploy it on Netlify, with each refresh the language returns to its initial value ("ar").
Is there a better way to implement it, if no, what's wrong with the above implementation?
Upvotes: 1
Views: 4023
Reputation: 185
After making some research, I figure out that when statically exporting NextJS's project while using getInitialProps or getStaticProps, NextJS will create the static HTML pages with initial-values - in this case, "ar" - so whenever you refresh the page the content will arrive with its initial-values, so in my previous approach, I was changing the cookie just at runtime. However, at the build-time, it was the initial-value "ar".
here's snippet code of the out/index.html
<script id="__NEXT_DATA__" type="application/json">
{
"props": { "initialLanguage": "ar" },
"page": "/",
"query": {},
"buildId": "RmU4iA8jACDFdZr30Xqjo",
"nextExport": true,
"isFallback": false
}
</script>
so I knew some approach to solve this issue, namely,
upload NextJS as SSR, not SSG.
duplicate pages per language, e.g. "/en", "/ar".
save initial-value in localStorage and is useEffect change it, but you need to handle loading state while rendering the component and read the localStorage.
use a third-party package.
So, the approach that I have gone through was to create two pages per language.
so the folder structure become somthing like that.
pages
--[lang]
--index.js
--other.js
--index.js
and here's the pages/index.js
import Home from '../components/Home';
import Head from '../components/Common/Head';
import { useRouter } from 'next/router';
import getInitialLocale from '../locale/getInitialLocale';
import Spinner from '../components/Common/Spinner/Spinner';
const Index = () => {
const router = useRouter();
React.useEffect(() => {
const href = `/${getInitialLocale()}`;
router.push({ pathname: href });
}, []);
return (
<div>
<Head title="Home" />
<h1 style={{ fontSize: '3rem' }}>Welcome to Here</h1>
</div>
);
};
export default Index;
If I did something wrong, or if you have better suggestions, comment here, please?
Upvotes: 0