QuiiBz / next-international

Type-safe internationalization (i18n) for Next.js
https://next-international.vercel.app
MIT License
1.2k stars 52 forks source link

next-international requires manual reload to change the language #346

Closed Abbosbek-cloud closed 4 months ago

Abbosbek-cloud commented 5 months ago

next-international requires reload to change the language After adding next-international to my next application it requires manual reload to change the language even I have already changed the language using useChangeLanguage hook.

Expected behavior I expected to change page's locale immediately when user interacts with change language buttons.

About:

Additional context Using next-international with pages directory of nextjs.

Abbosbek-cloud commented 5 months ago

next.config.json

const withPlugins = require('next-compose-plugins');
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
  openAnalyzer: false,
});

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  distDir: '.next',
  i18n: {
    locales: ['ru', 'uz'],
    defaultLocale: 'uz',
  },
  crossOrigin: 'use-credentials',
  images: {
    remotePatterns: [...],
  },
};

module.exports = withPlugins([withBundleAnalyzer], nextConfig);

_app.tsx

import { I18nProvider } from 'locales';
import { Page } from 'types/page';
import { AppProps } from 'next/app';
import Router from 'next/router';
import nProgress from 'nprogress';
import { FC, Fragment, useEffect, useState } from 'react';
import MuiThemeProvider from 'theme';
import { CurrencyProvider } from 'utils/context/CurrencyContext';
import Head from 'next/head';
import ErrorBoundary from 'utils/context/ErrorBoundary';
import { Hydrate, QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import { ReduxProvider } from 'utils/redux/Provider';
import { ToastContainer } from 'react-toastify';

// styles
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import 'react-toastify/dist/ReactToastify.css';

type OrientWebAppProps = AppProps & {
  Component: Page;
};

Router.events.on('routeChangeStart', () => nProgress.start());
Router.events.on('routeChangeComplete', () => nProgress.done());
Router.events.on('routeChangeError', () => nProgress.done());

nProgress.configure({
  showSpinner: false,
});

export const OrientWebApp: FC<OrientWebAppProps> = ({ Component, pageProps, router }) => {
  const [queryClient] = useState(
    new QueryClient({
      defaultOptions: {
        queries: {
          retry: false,
          refetchOnWindowFocus: false,
        },
      },
    })
  );

  const getLayout = Component.getLayout ?? ((page: React.ReactNode) => page);

  useEffect(() => {
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles && jssStyles.parentElement) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
    unregister();
  }, []);

  function unregister() {
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.getRegistrations().then(function (registrations) {
        for (const registration of registrations) {
          registration.unregister();
        }
      });
    }
  }

  return (
    <Fragment>
      <Head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      </Head>
      <ErrorBoundary>
        <CurrencyProvider>
          <QueryClientProvider client={queryClient}>
            <Hydrate state={pageProps.dehydratedState}>
              <ReduxProvider>
                <I18nProvider locale={pageProps.locale}>
                  <MuiThemeProvider>{getLayout(<Component {...pageProps} />)}</MuiThemeProvider>
                </I18nProvider>
                <ToastContainer />
              </ReduxProvider>
              <ReactQueryDevtools initialIsOpen={false} />
            </Hydrate>
          </QueryClientProvider>
        </CurrencyProvider>
      </ErrorBoundary>
    </Fragment>
  );
};

export default OrientWebApp;

_document.tsx

import createEmotionCache from 'theme/createEmotionCache';
import { CacheProvider } from '@emotion/react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import createEmotionServer from '@emotion/server/create-instance';
import React from 'react';
import { AppProps } from 'next/app';

export default class OrientMotorsDocument extends Document {
  render() {
    return (
      <Html lang="uz">
        <Head>
          <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
          <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
          <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />

          <meta name="apple-mobile-web-app-capable" content="yes" />
          <meta name="apple-mobile-web-app-status-bar-style" content="black" />
          <meta name="theme-color" content="#000000" />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

OrientMotorsDocument.getInitialProps = async (ctx) => {
  const originalRenderPage = ctx.renderPage;
  const cache = createEmotionCache();
  const { extractCriticalToChunks } = createEmotionServer(cache);

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App: React.ComponentType<AppProps>) => (props: AppProps) => {
        return (
          <CacheProvider value={cache}>
            <App {...props} />
          </CacheProvider>
        );
      },
    });

  const initialProps = await Document.getInitialProps(ctx);

  const emotionStyles = extractCriticalToChunks(initialProps.html);
  const emotionStyleTags = emotionStyles.styles?.map((style) => (
    <style
      data-emotion={`${style.key} ${style.ids.join(' ')}`}
      key={style.key} // eslint-disable-next-line react/no-danger
      dangerouslySetInnerHTML={{
        __html: style.css,
      }}
    />
  ));
  return {
    ...initialProps,
    styles: [...React.Children.toArray(initialProps.styles), ...emotionStyleTags],
  };
};
QuiiBz commented 5 months ago

Seems like a regression of https://github.com/QuiiBz/next-international/pull/314. Will check asap

Abbosbek-cloud commented 4 months ago

Seems like a regression of #314. Will check asap

I will wait for your response after checking this one!

FleetAdmiralJakob commented 4 months ago

I have the same problem here: https://weather-app-git-move-to-next-830f94-creative-programming-group.vercel.app/settings

Just press the buttons and then you see that the cached locales are not changing.

Code: https://github.com/The-Creative-Programming-Group/Weather-App/pull/213

QuiiBz commented 4 months ago

Fix released in https://github.com/QuiiBz/next-international/releases/tag/1.2.4!

Abbosbek-cloud commented 4 months ago

Fix released in https://github.com/QuiiBz/next-international/releases/tag/1.2.4!

Thank you, bro!