Cómo recordar la selección de idioma entre sesiones en React Router v7
Almacenar la elección explícita de idioma del usuario
Problema
Cuando un usuario selecciona explícitamente un idioma, esa elección refleja su preferencia y debería anular cualquier detección automática. Sin persistencia, esta selección desaparece cuando el navegador se cierra o la sesión termina. En la siguiente visita, la aplicación comienza de nuevo, obligando al usuario a seleccionar su idioma otra vez. Esta repetición indica que la aplicación no respeta sus preferencias, creando fricción y disminuyendo la confianza.
Solución
Almacenar la elección de idioma del usuario en una ubicación persistente como una cookie cuando realicen una selección. En visitas posteriores, verificar esta preferencia almacenada antes de recurrir a los encabezados del navegador u otros métodos de detección. Si se encuentra un idioma almacenado válido, redirigir automáticamente al usuario a la ruta de ese idioma. Esto asegura que su elección explícita tenga prioridad y persista a través de las sesiones.
Pasos
1. Crear una cookie para almacenar la preferencia de idioma
Definir una cookie que contendrá el idioma seleccionado por el usuario con un tiempo de expiración largo.
import { createCookie } from "react-router";
export const languagePreference = createCookie("language-preference", {
maxAge: 31536000,
httpOnly: false,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
});
Esta cookie persiste durante un año y es accesible para el código del lado del cliente para leer la preferencia.
2. Añadir una acción para almacenar la selección de idioma
Crear una acción que maneje los envíos del formulario de selección de idioma y almacene la elección en la cookie.
import { redirect } from "react-router";
import type { Route } from "./+types/root";
import { languagePreference } from "./cookies";
export async function action({ request }: Route.ActionArgs) {
const formData = await request.formData();
const selectedLanguage = formData.get("language");
if (typeof selectedLanguage === "string") {
return redirect(`/${selectedLanguage}`, {
headers: {
"Set-Cookie": await languagePreference.serialize(selectedLanguage),
},
});
}
return redirect("/");
}
Cuando el usuario envía su elección de idioma, esta acción la almacena en la cookie y lo redirige a la ruta de idioma apropiada.
3. Crear un componente de selección de idioma
Construye un componente de formulario que permita a los usuarios elegir su idioma preferido.
import { Form } from "react-router";
export function LanguageSelector({
currentLanguage,
}: {
currentLanguage: string;
}) {
return (
<Form method="post">
<select
name="language"
defaultValue={currentLanguage}
onChange={(e) => e.currentTarget.form?.requestSubmit()}
>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
<option value="de">Deutsch</option>
</select>
</Form>
);
}
Este componente se envía automáticamente cuando el usuario cambia la selección, activando la acción que almacena la preferencia.
4. Verificar la preferencia almacenada en el cargador raíz
Añade lógica al cargador de la ruta raíz que verifique si hay una preferencia de idioma almacenada y redirija en consecuencia.
import { redirect } from "react-router";
import type { Route } from "./+types/root";
import { languagePreference } from "./cookies";
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const cookieHeader = request.headers.get("Cookie");
const storedLanguage = await languagePreference.parse(cookieHeader);
if (url.pathname === "/" && storedLanguage) {
return redirect(`/${storedLanguage}`);
}
return null;
}
Cuando un usuario visita la ruta raíz, este cargador verifica si existe una preferencia de idioma almacenada y los redirige a su ruta de idioma elegida si existe.
5. Validar el idioma almacenado contra los locales soportados
Asegúrate de que la preferencia almacenada sea válida antes de usarla para la redirección.
import { redirect } from "react-router";
import type { Route } from "./+types/root";
import { languagePreference } from "./cookies";
const SUPPORTED_LANGUAGES = ["en", "es", "fr", "de"];
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const cookieHeader = request.headers.get("Cookie");
const storedLanguage = await languagePreference.parse(cookieHeader);
if (
url.pathname === "/" &&
storedLanguage &&
SUPPORTED_LANGUAGES.includes(storedLanguage)
) {
return redirect(`/${storedLanguage}`);
}
return null;
}
Esta validación evita redireccionar a rutas de idioma inválidas o no soportadas si el valor de la cookie ha sido manipulado o si los idiomas soportados han cambiado desde que se almacenó la preferencia.