I'm working with i18NextJs
in a Next.js 14
that uses the App router
and next-i18n-router
. My NotFound pages
, both the custom and default ones, are not working as expected. I'm seeing an error about missing <html>
and <body>
tags in my RootLayout
component, but I can’t seem to resolve it. I've tried several adjustments, but nothing seems to work.
Got this error message:
Missing required html tags The following tags are missing in the Root Layout: <html>, <body>. Read more at https://nextjs.org/docs/messages/missing-root-layout-tags
Error image:
Server error log:
✓ Compiled /favicon.ico in 77ms
⚠ ./middleware.ts
Unable to parse config export in source file
The exported configuration object in a source file need to have a very specific format from which some properties can be statically parsed at compiled-time.
layout.tsx
it hasn’t used 'use client'
interface RootLayoutProps {
children: React.ReactNode;
params: {
locale: string;
};
}
export default function RootLayout({
children,
params: { locale },
}: Readonly<RootLayoutProps>) {
if (!i18nConfig.locales.includes(locale)) {
notFound();
}
return (
<html lang={locale} className="light scroll-smooth" dir={dir(locale)}>
<body
className={`${poppins.variable} font-poppins text-[15px] text-slate-900 dark:text-white dark:bg-slate-900`}
>
{children}
</body>
</html>
);
}
Also, tried this:
export default function RootLayout({
children,
params: { locale },
}: Readonly<RootLayoutProps>) {
if (!i18nConfig.locales.includes(locale)) {
notFound();
}
return (
<html lang={locale} className="light scroll-smooth" dir={dir(locale)}>
<body
className={`${poppins.variable} font-poppins text-[15px] text-slate-900 dark:text-white dark:bg-slate-900`}
>
{children}
</body>
</html>
);
}
i18nConfig.ts
const i18nConfig = {
locales: ["en", "ar"],
defaultLocale: "en",
prefixDefault: true,
};
export default i18nConfig;
i18n.ts
import { createInstance } from "i18next";
import { initReactI18next } from "react-i18next/initReactI18next";
import resourcesToBackend from "i18next-resources-to-backend";
import i18nConfig from "@/i18nConfig";
export default async function initTranslations(
locale: any,
namespaces: any,
i18nInstance: any,
resources: any
) {
i18nInstance = i18nInstance || createInstance();
i18nInstance.use(initReactI18next);
if (!resources) {
i18nInstance.use(
resourcesToBackend(
(language: any, namespace: any) =>
import(`@/locales/${language}/${namespace}.json`)
)
);
}
await i18nInstance.init({
lng: locale,
resources,
fallbackLng: i18nConfig.defaultLocale,
supportedLngs: i18nConfig.locales,
defaultNS: namespaces[0],
fallbackNS: namespaces[0],
ns: namespaces,
preload: resources ? [] : i18nConfig.locales,
});
return {
i18n: i18nInstance,
resources: i18nInstance.services.resourceStore.data,
t: i18nInstance.t,
};
}
middleware.tsx
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { i18nRouter } from "next-i18n-router";
import i18nConfig from "./i18nConfig";
export function middleware(request: NextRequest) {
const response = i18nRouter(request, i18nConfig);
return response;
}
export const config = {
matcher: ["/((?!api|static|.*\\..*|_next).*)", { source: "/" }],
};
Files & Folders Arch.
package.json
"dependencies": {
"i18next": "^23.16.4",
"i18next-resources-to-backend": "^1.2.1",
"next-i18n-router": "^5.5.1",
"react-i18next": "^15.1.0",
"next": "14.2.16"
}
How can I resolve this issue?
To solve using Catch-all Segments. [...notFound]
under the [locale]
directory. it will catch any invalid routes, such as /en/some-unknown-path
, and properly return a 404 / Custome NotFound Page.
files and folders arch.
- app
|- [locale]
|- [...notFound]
|- page.tsx // catch-all segment
|- layout.tsx // layout component for different locales
- middleware.ts // middleware for handling localization
page.tsx:
import { notFound } from "next/navigation";
const CatchAll = () => {
return notFound();
};
export default CatchAll;