platforms icon indicating copy to clipboard operation
platforms copied to clipboard

i18n locales 404 issues

Open Smart387doo opened this issue 3 years ago • 2 comments

Hello. I have issues with i18n locales. I currently have only 2 locales, but when turned on in next.config all paths renders as 404 when deployed to Vercel. Locally everything works as expected.

I have tried several approaches, tried to add basePath as someone suggested like for example:

url.pathname = `${basePath}/_sites/${currentHost}${pathname}`;
    return NextResponse.rewrite(url);

It did nothing, basically.

Tried to add locale too as someone suggested, for example:

url.pathname = `${basePath}/${locale}/_sites/${currentHost}${pathname}`;
    return NextResponse.rewrite(url);

and it somewhat works. Default locale works, but on some pages secondary locale gives 404 still, like:

subdomain.domain.something/secondarylocale subdomain.domain.something/secondarylocale/somepage

if I add en, which is default locale it works:

subdomain.domain.something/en subdomain.domain.something/en/somepage

Full _middleware:

import { NextResponse } from "next/server";

import type { NextRequest } from "next/server";

export default function middleware(req: NextRequest) {
  // Clone the request url
  const url = req.nextUrl.clone();

  // Get pathname of request (e.g. /blog-slug)
  const { pathname, basePath } = req.nextUrl;
  const locale = req.nextUrl.locale;

  // Get hostname of request (e.g. demo.xy.com)
  const hostname = req.headers.get("host");
  if (!hostname)
    return new Response(null, {
      status: 400,
      statusText: "No hostname found in request headers",
    });

  // Only for demo purposes – remove this if you want to use your root domain as the landing page
  // if (
  //   hostname === "xy.com" ||
  //   hostname === "platforms.vercel.app"
  // ) {
  //   return NextResponse.redirect("https://demo.xy.com");
  // }

  const PUBLIC_FILE = /\.(.*)$/;

  const currentHost =
    process.env.NODE_ENV === "production" && process.env.VERCEL === "1"
      ? // You have to replace ".xy.com" with your own domain if you deploy this example under your domain.
        // You can use wildcard subdomains on .vercel.app links that are associated with your Vercel team slug
        // in this case, our team slug is "platformize", thus *.platformize.vercel.app works
        hostname.replace(`.xy.com`, "")
      : hostname.replace(`.localhost:3000`, "");

  console.log(
    "req",
    locale,
    // "end",
    "basePath",
    basePath,
    "end",
    process.env.NODE_ENV,
    process.env.VERCEL,
    "host",
    req.headers.get("host"),
    "current host",
    currentHost
  );

  if (pathname.startsWith(`/_sites`))
    return new Response(null, {
      status: 404,
    });

  if (
    !pathname.includes(".") &&
    !pathname.startsWith("/api") &&
    !PUBLIC_FILE.test(req.nextUrl.pathname)
  ) {
    if (currentHost == "app") {
      if (
        pathname === "/login" &&
        (req.cookies["next-auth.session-token"] ||
          req.cookies["__Secure-next-auth.session-token"])
      ) {
        url.pathname = `${basePath}/${locale}`;
        return NextResponse.redirect(url);
      } else if (!pathname) {
        url.pathname = `${basePath}/${locale}/_sites/${currentHost}`;
        return NextResponse.rewrite(url);
      }

      url.pathname = `${basePath}/${locale}/app${pathname}`;
      return NextResponse.rewrite(url);
    }

    if (hostname === "localhost:3000" || hostname === "xy.com") {
      url.pathname = `${basePath}/${locale}/home${pathname}`;
      return NextResponse.rewrite(url);
    }

    url.pathname = `${basePath}/${locale}/_sites/${currentHost}${pathname}`;
    return NextResponse.rewrite(url);
  }
}

Smart387doo avatar May 22 '22 12:05 Smart387doo

im having the exact same issue when using i18n

wuichen avatar Jun 15 '22 12:06 wuichen

Well if you log stuff, you will see strange behavior, it does not add locale to the URL for default locale, but does for other ones.

If you do:

url.pathname = `/${locale}/_sites/${currentHost}${pathname}`;

then your default one will work, but you'll get 404 on all others. And reason is that other locales are added twice, once by you, and once by system. I solved it by adding this:

const { pathname, locale, defaultLocale } = req.nextUrl;
.
.
.
if (currentHost == "app") {
      if (
        pathname === "/login" &&
        (req.cookies["next-auth.session-token"] ||
          req.cookies["__Secure-next-auth.session-token"])
      ) {
        url.pathname = `/${locale}`;
        return NextResponse.redirect(url);
      }

      url.pathname = `/${locale}/app${pathname}`;
      return NextResponse.rewrite(url);
    }

    if (hostname === "localhost:3000" || hostname === "yourdomain.something") {
      url.pathname = `/${locale}/home${pathname}`;
      return NextResponse.rewrite(url);
    }

    if (locale === defaultLocale) {
      url.pathname = `/${locale}/_sites/${currentHost}${pathname}`;
      return NextResponse.rewrite(url);
    }

    url.pathname = `/_sites/${currentHost}${pathname}`;
    return NextResponse.rewrite(url);
  }

Hope it helps

Smart387doo avatar Jun 15 '22 13:06 Smart387doo

Hey guys! Sorry for the late response but this should've been fixed in the latest version of Next.js. Feel free to reference this issue here: https://github.com/vercel/next.js/issues/36563

steven-tey avatar Aug 12 '22 16:08 steven-tey

The problem still exists:

nextjs version

"next": "13.2.4",

middleware code:

import { NextRequest, NextResponse } from "next/server";

export const config = {
  matcher: [
    "/((?!api/|_next/|_static/|/|[\\w-]+\\.\\w+).*)",
  ],
};

export default async function middleware(req: NextRequest) {
  const url = req.nextUrl;

  const hostname = req.headers.get("host") || "demo.localhost:3000";

  const path = url.pathname;

  return NextResponse.rewrite(
    new URL(`/_sites/${currentHost}${path}`, req.url)
  );
}

nextconfig code

/**
 * @format
 * @type {import('next').NextConfig}
 */

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

const nextConfig = {
	reactStrictMode: true,
	poweredByHeader: false,
	i18n: {
		localeDetection: false,
		locales: ['en', 'cn', 'jp', 'it', 'tw', 'kr', 'hk', 'fr'],
		defaultLocale: 'cn',
	}
};

module.exports = withBundleAnalyzer(nextConfig);

The problem still exists

eugle avatar Apr 04 '23 11:04 eugle