Reputation: 81
I have a problem with Next.js 14 project, which uses app router. I use [lang] folder to localize my app. So, I have all my pages, including page.tsx and layout.tsx inside of [lang] folder. This way, I get locale passed to all of my pages like this:
export default function Home({ params }: { params: { lang: string } }) {
const s = dictionary[params.lang];
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<p>{s.home.title}</p>
</main>
);
}
This is my middleware.ts file:
let locales = ["en", "de"];
export let defaultLocale = "en";
function getLocale(request: Request): string {
const headers = new Headers(request.headers);
const acceptLanguage = headers.get("accept-language");
if (acceptLanguage) {
headers.set("accept-language", acceptLanguage.replaceAll("_", "-"));
}
const headersObject = Object.fromEntries(headers.entries());
const languages = new Negotiator({ headers: headersObject }).languages();
return match(languages, locales, defaultLocale);
}
// Without /locale in path
export function middleware(request: NextRequest) {
let locale = getLocale(request) ?? defaultLocale;
const pathname = request.nextUrl.pathname;
const newUrl = new URL(`/${locale}${pathname}`, request.nextUrl);
return NextResponse.rewrite(newUrl);
}
export const config = {
matcher: [
// Skip all internal paths (_next)
"/((?!_next|api|favicon.ico|robots.txt|sitemap.xml).*)",
// Optional: only run on root (/) URL
// '/'
],
};
My folder structure is:
my-app/
├─ ...
├─ public/
│ ├─ favicon.ico
│ ├─ robots.txt
├─ src/
│ ├─ app/
│ │ ├─ [lang]/
│ │ │ ├─ page.tsx
│ │ │ ├─ layout.tsx
│ │ │ ├─ not-found.tsx
│ ├─ api/
├─ ...
The problem is, when I put not-found.tsx inside of a [lang] folder, it does not work. On unknown route I get default 404 page. But, when I put it outside of [lang], in app folder directly, it does work, but I do not get locale, and I get the page without layout. The workaround would be to create yet another layout.tsx in app directory, but again without the possibility to localize it, which is just bad user experience.
I tried to copy not-found.tsx into [lang] folder to be able to get app locale to localize my content. According to Next.js documentation, this should work out of the box.
Has anyone encountered a problem like this?
Upvotes: 2
Views: 1042
Reputation: 1
There's a way to render your custom not-found.tsx. Except the not-found.tsx file itself, you have to catch unknown routes too. You can define a catch-all route that explicitly calls the notFound function.
import {notFound} from 'next/navigation';
export default function CatchAllPage() {
notFound();
}
After this change, all requests that are matched within the [locale] segment will render the not-found page when an unknown route is encountered (e.g. /en/unknown).
Upvotes: 0
Reputation: 4956
This answer documents my solution for the same issue, you might find it suitable or not.
First of all, put your main not-found.tsx
localized at app/[lang]/not-found.tsx
.
At the root, create a app/layout.tsx
that doesn't do anything except returning its children
prop:
import { type ReactNode } from "react";
export default function GlobalLayout({ children }: { children: ReactNode }) {
return children;
}
not-found.tsx
:Here you have two options:
"use client";
import { redirect, usePathname } from "next/navigation";
import { defaultLocale } from "@/config/constants";
export default function NotFound() {
const pathname = usePathname();
redirect(`/${defaultLocale}${pathname}`);
}
Upvotes: 1