Cómo mantener el idioma en los enlaces de navegación en React Router v7
Mantén el idioma en la navegación interna
Problema
Cuando la información del idioma está codificada en la ruta de la URL, cada enlace de navegación debe preservar ese idioma para mantener una experiencia de usuario consistente. Si un usuario navega por la versión francesa de tu sitio y hace clic en un enlace a /about, espera permanecer en francés y navegar a /fr/about. Sin enlaces conscientes del idioma, los usuarios son llevados al idioma predeterminado a mitad de sesión, rompiendo su contexto de navegación y obligándolos a cambiar de idioma manualmente de nuevo. Esto crea fricción y socava la experiencia localizada.
Codificar el prefijo del idioma en cada enlace es propenso a errores y hace que el código base sea frágil. A medida que los usuarios navegan por la aplicación, el idioma activo puede cambiar, y actualizar manualmente cientos de enlaces se vuelve insostenible.
Solución
Crea un componente Link personalizado que lea automáticamente el idioma actual de la URL y lo anteponga a todas las rutas de navegación internas. Al envolver el componente Link de React Router, centralizas el manejo del idioma en un solo lugar. El wrapper extrae el parámetro de idioma de la ruta actual y asegura que cada ruta de destino lo incluya, de modo que la navegación preserve la elección de idioma del usuario sin intervención manual.
Este enfoque mantiene las definiciones de enlaces limpias y agnósticas al idioma en toda tu aplicación, mientras garantiza que el contexto del idioma viaje con cada clic.
Pasos
1. Crea un componente wrapper de Link consciente del idioma
Construye un componente personalizado que use useParams para extraer el idioma actual de la URL y envuelva el componente Link de React Router para anteponer el idioma a la ruta de destino.
import { Link, useParams } from "react-router";
import type { LinkProps } from "react-router";
export function LocaleLink({ to, ...props }: LinkProps) {
const { locale } = useParams<{ locale: string }>();
const localizedTo =
typeof to === "string"
? `/${locale}${to.startsWith("/") ? to : `/${to}`}`
: {
...to,
pathname: `/${locale}${to.pathname?.startsWith("/") ? to.pathname : `/${to.pathname}`}`,
};
return <Link to={localizedTo} {...props} />;
}
Este componente lee el parámetro de locale de la ruta actual y automáticamente lo añade como prefijo a cualquier ruta que pases a la prop to, manejando tanto formas de cadena como de objeto.
2. Usa el componente LocaleLink en toda tu aplicación
Reemplaza los componentes Link estándar con LocaleLink donde necesites navegación que preserve el locale.
import { LocaleLink } from "./LocaleLink";
export function Navigation() {
return (
<nav>
<LocaleLink to="/">Home</LocaleLink>
<LocaleLink to="/about">About</LocaleLink>
<LocaleLink to="/products">Products</LocaleLink>
</nav>
);
}
Cuando un usuario en /fr/products hace clic en el enlace About, navega a /fr/about. El prefijo de locale se añade automáticamente sin saturar la definición del enlace.
3. Maneja casos especiales para rutas absolutas y enlaces externos
Extiende el wrapper para detectar cuando una ruta ya incluye el locale o apunta a una URL externa, evitando la duplicación de prefijos o romper la navegación externa.
import { Link, useParams } from "react-router";
import type { LinkProps } from "react-router";
export function LocaleLink({ to, ...props }: LinkProps) {
const { locale } = useParams<{ locale: string }>();
if (!locale) {
return <Link to={to} {...props} />;
}
const isExternal =
typeof to === "string" &&
(to.startsWith("http://") || to.startsWith("https://"));
const alreadyLocalized =
typeof to === "string" && to.startsWith(`/${locale}/`);
if (isExternal || alreadyLocalized) {
return <Link to={to} {...props} />;
}
const localizedTo =
typeof to === "string"
? `/${locale}${to.startsWith("/") ? to : `/${to}`}`
: {
...to,
pathname: `/${locale}${to.pathname?.startsWith("/") ? to.pathname : `/${to.pathname}`}`,
};
return <Link to={localizedTo} {...props} />;
}
Esto protege contra la duplicación de prefijos si una ruta ya comienza con el locale y deja pasar las URL externas sin cambios, asegurando que el componente funcione de manera confiable en todos los escenarios de navegación.