Linking between localized pages
Keeping users in their selected language
Problem
When language codes are part of the URL, creating internal links becomes complex. A simple link like <a href="/about"> is wrong, as it breaks the localized route, sending a user from /fr/contact to /about instead of /fr/about. This pulls the user out of their selected language.
Solution
Create a custom, wrapper component around the Next.js Link component. This new component will use the useParams hook to get the current language from the URL and automatically prepend it to any href it receives, ensuring all internal links are correctly localized.
Steps
1. Create a LocalizedLink component
Create a new file app/components/LocalizedLink.tsx. This must be a client component to use the useParams hook.
// app/components/LocalizedLink.tsx
'use client';
import Link from 'next/link';
import { useParams } from 'next/navigation';
import type { ComponentProps } from 'react';
type LinkProps = ComponentProps<typeof Link>;
export default function LocalizedLink({ href, ...rest }: LinkProps) {
const params = useParams();
const lang = params.lang as string;
let localizedHref = href;
// Check if href is a string and needs prefixing
if (typeof href === 'string' && href.startsWith('/')) {
localizedHref = `/${lang}${href}`;
} else if (
typeof href === 'object' &&
href !== null &&
href.pathname?.startsWith('/')
) {
// Re-create the object with a prefixed pathname
localizedHref = {
...href,
pathname: `/${lang}${href.pathname}`,
};
}
// Absolute URLs or other cases are passed through
return <Link href={localizedHref} {...rest} />;
}
This component imports the standard Link props. It checks if href is a string (like /about) or an object (like { pathname: '/about' }) and intelligently prepends the current lang (e.g., es) to it.
2. Use the component on your pages
Now, in your pages, import LocalizedLink instead of the standard next/link. You can use it just as you would the normal Link component, but without worrying about the language prefix.
// app/[lang]/page.tsx
import LocalizedLink from '@/app/components/LocalizedLink';
export default function Home({ params }: { params: { lang: string } }) {
return (
<div>
<h1>Home page</h1>
<p>Current language: {params.lang}</p>
<nav>
<ul>
<li>
{/* This will render as /en/about or /es/about, etc. */}
<LocalizedLink href="/about">About page</LocalizedLink>
</li>
<li>
{/* This also works */}
<LocalizedLink href={{ pathname: '/contact' }}>
Contact page
</LocalizedLink>
</li>
</ul>
</nav>
</div>
);
}
Using <LocalizedLink href="/about"> now correctly renders a link to /{current_lang}/about, keeping the user within their selected language as they navigate your site.