Cómo traducir metadatos de página en React Router v7
Traducir metadatos para búsqueda y redes sociales
Problema
Los metadatos de la página —títulos y descripciones— aparecen fuera de la página misma, en pestañas del navegador, marcadores, resultados de búsqueda y vistas previas en redes sociales. Cuando estos metadatos no coinciden con el idioma de la página, se crea una inconsistencia discordante. Una página en español con un título en inglés confunde a los usuarios antes incluso de que vean el contenido. Los motores de búsqueda interpretan esta discrepancia como una señal de que la página está mal localizada o es de baja calidad, potencialmente reduciendo su clasificación en los resultados específicos del idioma. Los usuarios pueden abandonar la página antes de que se cargue, asumiendo que no está en su idioma.
Solución
Traduce los metadatos de la página para que coincidan con el idioma actual exportando una función meta desde tu módulo de ruta. Utiliza la API formatMessage de react-intl con Message Descriptors para traducir las cadenas de título y descripción, asegurando que los metadatos utilicen los mismos recursos de traducción que el contenido de la página. Esto mantiene todo consistente entre lo que se muestra en las pestañas del navegador, los resultados de búsqueda y la página misma.
Pasos
1. Crear un helper para acceder a intl fuera de los componentes
El objeto intl proporciona formatMessage y puede accederse a través del hook useIntl en componentes o crearse directamente con createIntl en entornos que no son de React. Como la función meta se ejecuta fuera del árbol de componentes de React, crea un helper que construya una instancia de intl a partir de tus mensajes.
import { createIntl, createIntlCache } from "react-intl";
const cache = createIntlCache();
export function createIntlForLocale(
locale: string,
messages: Record<string, string>,
) {
return createIntl(
{
locale,
messages,
},
cache,
);
}
Este helper crea una instancia de intl que puede formatear mensajes en cualquier función, no solo en componentes de React.
2. Cargar mensajes en un loader de ruta padre
Los cargadores de ruta devuelven datos a los que los componentes acceden a través de las propiedades loaderData. Carga tus mensajes de traducción en una ruta padre para que estén disponibles para las rutas hijas.
import type { Route } from "./+types/root";
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const locale = url.pathname.split("/")[1] || "en";
const messages = await import(`../translations/${locale}.json`);
return {
locale,
messages: messages.default,
};
}
La función meta recibe un parámetro matches que contiene datos del cargador de todas las rutas coincidentes, haciendo que los datos del cargador padre sean accesibles para las funciones meta de las rutas hijas.
3. Exporta una función meta que traduce los metadatos
Exporta una función meta desde tu módulo de ruta que devuelva un array de objetos descriptores meta. Accede a los datos del cargador padre desde matches y usa tu helper intl para traducir cadenas.
import type { Route } from "./+types/product";
import { createIntlForLocale } from "~/utils/intl";
export function meta({ matches }: Route.MetaArgs) {
const rootMatch = matches.find((match) => match.id === "root");
const { locale, messages } = rootMatch?.data || {
locale: "en",
messages: {},
};
const intl = createIntlForLocale(locale, messages);
return [
{
title: intl.formatMessage({
id: "product.meta.title",
defaultMessage: "Product Details",
}),
},
{
name: "description",
content: intl.formatMessage({
id: "product.meta.description",
defaultMessage: "View detailed information about this product",
}),
},
];
}
La función formatMessage acepta un Message Descriptor con un id y defaultMessage, devolviendo la cadena traducida para el locale actual.
4. Añade cadenas de metadatos traducidas a tus archivos de mensajes
Añade las claves de traducción de metadatos a cada archivo de mensajes del locale para que formatMessage pueda encontrarlas.
{
"product.meta.title": "Détails du produit",
"product.meta.description": "Voir les informations détaillées sur ce produit"
}
Cuando los usuarios navegan a esta ruta, el componente Meta en tu layout raíz renderiza todas las etiquetas meta creadas por las exportaciones meta de la ruta, mostrando títulos y descripciones traducidos que coinciden con el idioma de la página.