How to implement locale-based routing in React Router v7
Configure routing with locale segments
Problem
When building a multilingual application, one fundamental decision shapes everything else: how will the application know which language to display? Without an explicit mechanism, the URL /about becomes ambiguous—it could represent content in any language. Users cannot share links to specific language versions, and search engines struggle to understand which version belongs to which audience. This ambiguity creates problems for both user experience and discoverability.
Solution
Put a language identifier directly into the URL path, such as /en/about or /fr/about. This makes every path unique to a specific language, removing the ambiguity for both users and search engines. By defining routes with a locale parameter as the first segment, the application can extract the locale from the URL and use it to determine which language content to display. This approach ensures that every URL unambiguously identifies both the page and its language.
Steps
1. Define routes with a locale parameter
Configure your routes in app/routes.ts to include a locale parameter as the first segment of each path.
import { type RouteConfig, route, index } from "@react-router/dev/routes";
export default [
route(":locale", "./localized-layout.tsx", [
index("./home.tsx"),
route("about", "./about.tsx"),
route("contact", "./contact.tsx"),
]),
] satisfies RouteConfig;
The colon prefix makes locale a dynamic segment that will be parsed from the URL and provided as a parameter to route components. This configuration creates routes like /en, /en/about, /fr/contact, where the first segment is always the locale.
2. Create a layout component to extract the locale
Child routes are rendered through the Outlet component in the parent route. Create a layout that extracts the locale parameter and renders nested routes.
import { Outlet, useParams } from "react-router";
export default function LocalizedLayout() {
const { locale } = useParams();
return (
<div>
<nav>
<a href={`/${locale}`}>Home</a>
<a href={`/${locale}/about`}>About</a>
<a href={`/${locale}/contact`}>Contact</a>
</nav>
<Outlet />
</div>
);
}
The useParams hook retrieves the dynamic segment value from the URL. The layout uses this locale to construct navigation links and passes rendering control to child routes via Outlet.
3. Access the locale in page components
Use the useParams hook in any route component to access the locale parameter.
import { useParams } from "react-router";
export default function About() {
const { locale } = useParams();
return (
<div>
<h1>About Us</h1>
<p>Current locale: {locale}</p>
</div>
);
}
Every component rendered within the localized layout can extract the locale from the URL. This value can then be used to load the appropriate translations, format dates and numbers, or make any other locale-specific decisions.
4. Use Link components for client-side navigation
Replace anchor tags with Link components to enable navigation with client-side routing.
import { Outlet, useParams, Link } from "react-router";
export default function LocalizedLayout() {
const { locale } = useParams();
return (
<div>
<nav>
<Link to={`/${locale}`}>Home</Link>
<Link to={`/${locale}/about`}>About</Link>
<Link to={`/${locale}/contact`}>Contact</Link>
</nav>
<Outlet />
</div>
);
}
The Link component handles routing on the client side and prevents the web page from reloading, enabling smooth navigation between pages. Each link includes the locale parameter to maintain the language context across navigation.