Reputation: 4848
I implemented a next-intl
for multi-language support. So my paths look like www.next.com/de
or www.next.com/en
I'm using NextJS 14
.
<NextLink href="/support-us">{t("About us")}</NextLink>
And when I want to navigate to for example /support-us
it must navigate me to /en/support-us
instead I get to /support-us
so it throws an error.
NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
Here is my code.
middleware.ts
import createMiddleware from "next-intl/middleware";
import { locales } from "./i18n";
export default createMiddleware({
// A list of all locales that are supported
locales,
// Used when no locale matches
defaultLocale: "en",
});
export const config = {
// Match only internationalized pathnames
matcher: ["/", "/(en|it|de|nl|fr|sv|es|nb|pt|pl)/:path*"],
};
i18next
import { notFound } from "next/navigation";
import { getRequestConfig } from "next-intl/server";
interface Language {
symbol: string;
name: string;
}
export const supportedLanguages: Language[] = [
{ symbol: "EN", name: "English" },
{ symbol: "DE", name: "Deutsch" },
];
const languageSymbolsLowercase: string[] = supportedLanguages.map((lang) =>
lang.symbol.toLowerCase()
);
const initialLocales: string[] = [];
const combinedLocales: string[] = [
...initialLocales,
...languageSymbolsLowercase,
];
export const locales: string[] = combinedLocales;
export default getRequestConfig(async ({ locale }) => {
if (!locales.includes(locale)) notFound();
return {
messages: (await import(`../messages/${locale}.json`)).default,
};
});
Upvotes: 5
Views: 3981
Reputation: 11
None of the answers above worked for my app(next v15.1.2), but adding this configuration to the middleware worked for me:
import createMiddleware from 'next-intl/middleware';
import {routing} from './i18n/routing';
export default createMiddleware(routing);
export const config = {
matcher: [
// Enable a redirect to a matching locale at the root
'/',
// Set a cookie to remember the previous locale for
// all requests that have a locale prefix
'/(de|en)/:path*',
// Enable redirects that add missing locales
// (e.g. `/pathnames` -> `/en/pathnames`)
'/((?!_next|_vercel|.*\\..*).*)'
]
};
Found this on the sorce code of the App Router Example
Upvotes: 1
Reputation: 1
Or you could simply add a navigation.ts
file:
import {createSharedPathnamesNavigation} from 'next-intl/navigation';
import {locales} from './i18n'
export const {Link, redirect, usePathname, useRouter} =
createSharedPathnamesNavigation({locales,/* ... */});
and use that exported Link
:
import { Link } from "@/src/navigation"
<Link href="/support-us">{t("About us")}</Link>
Upvotes: 0
Reputation: 734
You should simply add the path to your middleware matchers.
middlewere.ts
import createMiddleware from "next-intl/middleware";
import { locales } from "./i18n";
export default createMiddleware({
// A list of all locales that are supported
locales,
// Used when no locale matches
defaultLocale: "en",
});
export const config = {
// Match only internationalized pathnames
matcher: ["/", "/(en|it|de|nl|fr|sv|es|nb|pt|pl)/:path*", "/support-us"],
};
So you just added "/support-us" to the matcher array
Upvotes: 0
Reputation: 4848
At the end I had to add a navigation file
as mentioned in the next-intl documentation in there it exports a Link
component which solves the problem and navigates to /[locale]/support-us
for example /en/support-us
here is my navigation
file
import {
createLocalizedPathnamesNavigation,
Pathnames,
} from "next-intl/navigation";
import { locales } from "./i18n";
export const localePrefix = "always"; // Default
export const pathnames = {
"/support-us": "/support-us",
} satisfies Pathnames<typeof locales>;
export const { Link, redirect, usePathname, useRouter, getPathname } =
createLocalizedPathnamesNavigation({ locales, localePrefix, pathnames });
And use the Link
exported in the navigation file
import { Link as NavLink } from "@navigation"
<NavLink href="/support-us">{t("support us")}</NavLink>
Upvotes: 4
Reputation: 1071
To explicitly include the locale in your paths, you can use the useRouter
hook from next/navigation
(in nextjs 14
) to access the current locale, and then prepend it to your paths.
Here's how you could adjust your <NextLink>
usage to incorporate the current locale:
"use client"
import { useRouter } from 'next/navigation';
const SupportUs = () => {
const router = useRouter();
const { locale } = router;
return (
<NextLink href={`/${locale}/support-us`}>{t("About us")}</NextLink>
);
};
UPDATE: I tried to simulate your use case on my end, and I think you can achieve your desired result on the server side by adjusting your middleware.ts
file. You won't need to modify your component/page file though.
So, below is the updated middleware.ts
that I tried to revise:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import createMiddleware from 'next-intl/middleware';
import { locales } from './i18n';
// Your existing createMiddleware setup
const intlMiddleware = createMiddleware({
locales,
defaultLocale: 'en',
});
export default function middleware(req: NextRequest) {
// Attempt to retrieve the locale from the previous URL
const referer = req.headers.get('referer');
let refererLocale = '';
if (referer) {
// Extract the locale from the URL path in the Referer header
const pathLocaleMatch = referer.match(/\/\/[^/]+\/([^/]+)/);
if (pathLocaleMatch && locales.includes(pathLocaleMatch[1])) {
refererLocale = pathLocaleMatch[1];
}
}
// Fallback to the default locale if no valid locale was found in the Referer
const effectiveLocale = refererLocale || 'en';
// Check if the current request's URL already includes a locale
const hasLocale = locales.some(locale => req.nextUrl.pathname.startsWith(`/${locale}`));
if (!hasLocale) {
// If not, redirect to the same URL but with the effective locale prefixed
const url = req.nextUrl.clone();
url.pathname = `/${effectiveLocale}${url.pathname}`;
return NextResponse.redirect(url);
}
// Proceed with the next-intl middleware if the locale is already present
return intlMiddleware(req);
}
export const config = {
// Match only internationalized pathnames
matcher: ['/', '/(en|it|de|nl|fr|sv|es|nb|pt|pl)/:path*'],
};
I hope this could resolve your issue in a better approach.
Upvotes: 1