QuiiBz / next-international

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

Using Cloudflare Pages forgets the selected language #397

Open Eusebiotrigo opened 7 months ago

Eusebiotrigo commented 7 months ago

Describe the bug I have a language switcher like:

  const changeLocale = useChangeLocale();
  const currentLocale = useCurrentLocale();

  const handleLocaleChange = (event: ChangeEvent<HTMLSelectElement>) => {
    const selectedLocale = event.target.value as (typeof i18n.locales)[number];
    changeLocale(selectedLocale);
  };

  return (
    <select value={currentLocale} className={"uppercase"} onChange={e => handleLocaleChange(e)}>
      {i18n.locales.map(locale => (
        <option key={`${locale}_lang_key`} value={locale}>
          {locale}
        </option>
      ))}
    </select>
  );
}

And it does in fact switches the language adding the /en or /de in the placeholder /:locale.

But when I navigate to any other URL in the webapp, the language goes back to the default...

The middleware that I have is:

import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
import { i18n } from "locales/i18n";
import { createI18nMiddleware } from "next-international/middleware";
import { NextResponse } from "next/server";

/** Regex to check if current path equals to a public file */
const PUBLIC_FILE = /\.(.*)$/;
/** Ignore non-page paths */
const shouldProceed = (pathname: string) => {
  return !(pathname.startsWith("/_next") || pathname.includes("/api/") || PUBLIC_FILE.test(pathname));
};

const I18nMiddleware = createI18nMiddleware({
  locales: i18n.locales,
  defaultLocale: i18n.defaultLocale as (typeof i18n.locales)[number],
});

const isProtectedRoute = createRouteMatcher(["/"]);

export default clerkMiddleware((auth, req) => {
  const { pathname } = req.nextUrl;

  if (!shouldProceed(pathname)) return;

  if (pathname.includes("/:locale/")) {
    const locale = pathname.split("/")[1];
    const replacedPathname = pathname.replace("/:locale/", "");
    return NextResponse.redirect(
      new URL(
        `/${
          (i18n.locales.includes(locale as (typeof i18n.locales)[number]) ?? locale) || i18n.defaultLocale
        }/${replacedPathname}`,
        req.url,
      ),
    );
  }

  if (isProtectedRoute(req)) {
    auth().protect();
  }

  return I18nMiddleware(req);
});

export const config = {
  matcher: ["/((?!.*\\..*|_next).*)", "/(trpc)(.*)"],
};

All this works in my local instance on my laptop (works on my machine (TM)), but when I deploy the application to Cloudflare Pages, using their @cloudflare/next-on-pages, it behaves as the described behaviour.

About (please complete the following information):

Additional context I know that we need to use the runtime edge for the applications deployed on Cloudflare Pages.

  export const runtime = "edge";

I'd be happy to add a video, or building a minimun reproducible project (will take me some more time).

Eusebiotrigo commented 6 months ago

I have deployed the example for the app router in https://next-international-cloudflare.pages.dev/ and the code is in https://github.com/Eusebiotrigo/next-international-cloudflare

I'd just like to know if this is because of the library (certainly not...) or because of cloudflare's edge-runtime.

Eusebiotrigo commented 6 months ago

Thread in CF Discord: https://discord.com/channels/595317990191398933/1232710382762852352