How to set the document language in React Router v7
Declare page language for browsers and screen readers
Problem
Web pages need to declare their primary language to browsers and assistive technologies. Without an explicit language declaration, screen readers default to the user's system language, which can produce incorrect pronunciation when the content language differs. Browsers cannot offer accurate translation features because they must guess the source language. Search engines struggle to confidently index pages for the correct language audience, reducing discoverability for users searching in that language.
Solution
Set the lang attribute on the root <html> element to declare the document's primary language. This attribute accepts a valid language code that tells browsers, screen readers, and search engines what language the content uses. When the language is declared explicitly, assistive technologies can apply correct pronunciation rules, browsers can offer appropriate translation options, and search engines can index the page for the right language audience.
Steps
1. Determine the current locale
The root route in app/root.tsx is responsible for rendering the root HTML document. If your application uses locale-based routing (such as /:locale/... patterns), extract the locale from route parameters. Otherwise, use a default locale.
import { useParams } from "react-router";
export default function Root() {
const params = useParams();
const locale = params.locale || "en";
return (
<html lang={locale}>
<head>
<meta charSet="utf-8" />
</head>
<body>
<h1>Content</h1>
</body>
</html>
);
}
This reads the locale from the URL if present and falls back to English when no locale parameter exists.
2. Map locale codes to language tags
If your application uses custom locale identifiers that differ from standard language tags, create a mapping function to convert them to valid BCP 47 language codes.
function getLanguageTag(locale: string): string {
const languageMap: Record<string, string> = {
en: "en",
"en-US": "en-US",
es: "es",
fr: "fr",
de: "de",
ja: "ja",
"zh-CN": "zh-Hans",
"zh-TW": "zh-Hant",
};
return languageMap[locale] || "en";
}
This ensures the lang attribute receives a valid language tag even when your routing uses simplified locale codes.
3. Apply the language tag to the HTML element
Use the mapped language tag as the value for the lang attribute on the <html> element in your root component.
import { useParams } from "react-router";
function getLanguageTag(locale: string): string {
const languageMap: Record<string, string> = {
en: "en",
es: "es",
fr: "fr",
de: "de",
};
return languageMap[locale] || "en";
}
export default function Root() {
const params = useParams();
const locale = params.locale || "en";
const lang = getLanguageTag(locale);
return (
<html lang={lang}>
<head>
<meta charSet="utf-8" />
</head>
<body>
<h1>Content</h1>
</body>
</html>
);
}
The lang attribute now reflects the current locale, updating automatically when users navigate between language-specific routes.