Cómo recordar la selección de idioma entre sesiones en TanStack Start v1

Almacenar la elección explícita de idioma del usuario

Problema

Cuando un usuario selecciona explícitamente un idioma, esa elección representa una preferencia deliberada que debería persistir más allá de la sesión actual del navegador. Sin persistencia, la aplicación olvida esta preferencia en cada visita, obligando a los usuarios a volver a seleccionar su idioma repetidamente. Esto crea fricción y señala que la aplicación no respeta las elecciones del usuario, degradando la experiencia general y potencialmente causando que los usuarios abandonen el sitio antes de completar las tareas que pretendían realizar.

Solución

Almacenar la elección de idioma del usuario en una cookie persistente cuando realizan una selección explícita. En visitas posteriores, verificar esta preferencia almacenada antes de recurrir a métodos de detección automática como los encabezados del navegador. Si se encuentra un idioma almacenado válido, redirigir al usuario desde la raíz del sitio a la ruta de ese idioma, asegurando que lleguen directamente a su configuración regional preferida sin pasos adicionales.

Pasos

1. Crear una función de servidor para almacenar la preferencia de idioma

Las funciones de servidor te permiten definir lógica exclusiva del servidor que puede ser llamada desde cualquier parte de tu aplicación. Define una función que escriba la configuración regional seleccionada en una cookie.

import { createServerFn } from "@tanstack/react-start";
import { setCookie } from "@tanstack/react-start/server";

const LOCALE_COOKIE = "user_locale";
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365;

export const saveLocalePreference = createServerFn({ method: "POST" })
  .validator((locale: string) => locale)
  .handler(async ({ data }) => {
    setCookie(LOCALE_COOKIE, data, {
      maxAge: COOKIE_MAX_AGE,
      path: "/",
      sameSite: "lax",
    });
    return { success: true };
  });

Esta función de servidor utiliza setCookie de @tanstack/react-start/server para almacenar la preferencia de configuración regional, haciéndola disponible en futuras solicitudes.

2. Llama a la función de guardado cuando el usuario selecciona un idioma

En tu componente de selector de idioma, invoca la función del servidor después de que el usuario haga una selección.

import { useNavigate } from "@tanstack/react-router";
import { saveLocalePreference } from "./locale-preference";

export function LanguageSwitcher({ currentLocale }: { currentLocale: string }) {
  const navigate = useNavigate();

  const handleLocaleChange = async (newLocale: string) => {
    await saveLocalePreference({ data: newLocale });
    navigate({ to: `/${newLocale}` });
  };

  return (
    <select
      value={currentLocale}
      onChange={(e) => handleLocaleChange(e.target.value)}
    >
      <option value="en">English</option>
      <option value="es">Español</option>
      <option value="fr">Français</option>
    </select>
  );
}

Esto asegura que la preferencia se guarde antes de navegar al nuevo idioma.

3. Crea una función de servidor para leer la preferencia almacenada

Define una función que recupere el idioma almacenado desde la cookie.

import { createServerFn } from "@tanstack/react-start";
import { getCookie } from "@tanstack/react-start/server";

const LOCALE_COOKIE = "user_locale";

export const getStoredLocale = createServerFn({ method: "GET" }).handler(
  async () => {
    const stored = getCookie(LOCALE_COOKIE);
    return stored || null;
  },
);

La función getCookie de @tanstack/react-start/server lee el valor de la cookie establecido en visitas anteriores.

4. Verifica la preferencia almacenada en la ruta raíz

Utiliza la función redirect en el callback beforeLoad de una ruta para activar una redirección cuando se encuentra una preferencia almacenada.

import { createFileRoute, redirect } from "@tanstack/react-router";
import { getStoredLocale } from "./locale-preference";

const SUPPORTED_LOCALES = ["en", "es", "fr"];
const DEFAULT_LOCALE = "en";

export const Route = createFileRoute("/")({
  beforeLoad: async () => {
    const stored = await getStoredLocale();

    if (stored && SUPPORTED_LOCALES.includes(stored)) {
      throw redirect({ to: `/${stored}` });
    }

    throw redirect({ to: `/${DEFAULT_LOCALE}` });
  },
});

Esto verifica primero la preferencia almacenada y redirige a ese idioma si es válido, de lo contrario, recurre al predeterminado.

5. Validar el idioma almacenado contra los idiomas soportados

Añade validación para asegurar que el valor almacenado es un idioma reconocido antes de redirigir.

import { createFileRoute, redirect } from "@tanstack/react-router";
import { getStoredLocale } from "./locale-preference";

const SUPPORTED_LOCALES = ["en", "es", "fr", "de", "ja"] as const;

function isValidLocale(value: string | null): value is string {
  return value !== null && SUPPORTED_LOCALES.includes(value as any);
}

export const Route = createFileRoute("/")({
  beforeLoad: async () => {
    const stored = await getStoredLocale();
    const locale = isValidLocale(stored) ? stored : "en";
    throw redirect({ to: `/${locale}` });
  },
});

Esto previene redirecciones a idiomas inválidos o no soportados, protegiendo contra manipulación de cookies o valores obsoletos.