Cómo traducir metadatos de página en React Router v7
Traduce metadatos para búsqueda y redes sociales
Problema
Los metadatos de página (títulos y descripciones) aparecen fuera de la página en sí, en pestañas del navegador, marcadores, resultados de búsqueda y vistas previas de 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 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, lo que puede reducir su posicionamiento en resultados específicos del idioma. Los usuarios pueden abandonar la página antes de que cargue, asumiendo que no está en su idioma.
Solución
Traduce los metadatos de 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 usen 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 en sí.
Pasos
1. Crea un helper para acceder a intl fuera de componentes
El objeto intl proporciona formatMessage y se puede acceder a él mediante el hook useIntl en componentes o crearse directamente con createIntl en entornos no React. Dado que 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. Carga mensajes en un loader de ruta padre
Los loaders de ruta devuelven datos a los que los componentes acceden mediante props loaderData. Carga tus mensajes de traducción en una ruta padre para que estén disponibles en 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.