How to maintain locale in navigation links in Next.js (Pages Router) v16

Maintain locale across internal navigation

Problem

When a web application encodes language preference in the URL path, every internal link must preserve that language context throughout the user's session. Without explicit locale handling, links written as bare paths can inadvertently drop the language prefix, causing users to lose their selected language mid-navigation. This disrupts the localized experience and forces users to repeatedly select their preferred language.

Solution

Ensure that every internal navigation link automatically includes the current locale by reading it from the router context. Next.js Pages Router provides built-in locale support through its routing system, where the active locale is available via the useRouter hook. By default, the Link component preserves the current locale during client-side transitions, but understanding this behavior and applying it consistently across the application ensures seamless locale-aware navigation.

Steps

1. Access the current locale from the router

The useRouter hook provides locale (the currently active locale), locales (all configured locales), and defaultLocale (the configured default locale).

import { useRouter } from "next/router";

export default function Navigation() {
  const router = useRouter();
  const currentLocale = router.locale;

  return (
    <nav>
      <p>Current locale: {currentLocale}</p>
    </nav>
  );
}

This component reads the active locale from the router, making it available for use in navigation logic.

When no locale prop is provided to Link, the currently active locale is used during client-transitions.

import Link from "next/link";

export default function Navigation() {
  return (
    <nav>
      <Link href="/about">About</Link>
      <Link href="/products">Products</Link>
      <Link href="/contact">Contact</Link>
    </nav>
  );
}

These links automatically maintain the current locale. If the user is viewing /fr/products, clicking "About" navigates to /fr/about.

For cases where you need explicit control or want to make locale handling more visible, create a wrapper component that explicitly passes the current locale.

import Link from "next/link";
import { useRouter } from "next/router";
import { ReactNode } from "react";

interface LocaleLinkProps {
  href: string;
  children: ReactNode;
}

export function LocaleLink({ href, children }: LocaleLinkProps) {
  const { locale } = useRouter();

  return (
    <Link href={href} locale={locale}>
      {children}
    </Link>
  );
}

This component makes locale preservation explicit and can be extended with additional locale-specific logic if needed.

4. Handle programmatic navigation with locale preservation

When using router methods directly, you can specify the locale via the transition options, or preserve all routing information including the locale by passing the href parameter as an object.

import { useRouter } from "next/router";

export default function NavigationButton() {
  const router = useRouter();
  const { pathname, asPath, query, locale } = router;

  const handleNavigate = () => {
    router.push({ pathname: "/dashboard", query }, asPath, { locale });
  };

  return <button onClick={handleNavigate}>Go to Dashboard</button>;
}

This pattern ensures programmatic navigation maintains the current locale and any existing query parameters.

Use the standard Link component throughout your application, relying on its built-in locale preservation behavior.

import Link from "next/link";

export default function ProductCard({ productId }: { productId: string }) {
  return (
    <article>
      <h2>Product {productId}</h2>
      <Link href={`/products/${productId}`}>View Details</Link>
      <Link href="/products">Back to Products</Link>
    </article>
  );
}

Both static and dynamic routes automatically include the current locale prefix, keeping users in their selected language as they navigate through the application.