Traducción de metadatos de página
Configuración de etiquetas <title> y <description> localizadas
Problema
Un usuario visualiza una página en español y todo el contenido visible está correctamente traducido. Sin embargo, la pestaña del navegador y el fragmento del resultado del motor de búsqueda aún muestran el título y la descripción en inglés. Esta discrepancia en los metadatos crea una experiencia de usuario confusa y perjudica el SEO al presentar información irrelevante en la búsqueda.
Solución
Utiliza la función generateMetadata de Next.js dentro de tus páginas y layouts. Esta función del lado del servidor puede cargar las traducciones correctas basándose en el parámetro lang (utilizando la misma lógica de carga de diccionarios que tus componentes) y devolver un objeto metadata dinámico con el título y la descripción localizados.
Pasos
1. Crear una función para cargar diccionarios
Necesitas una forma de cargar tus archivos de traducción planos en el servidor. Crea una función auxiliar para esto.
// app/get-dictionary.ts
import 'server-only';
type Messages = Record<string, string>;
const dictionaries: { [key: string]: () => Promise<Messages> } = {
en: () => import('@/dictionaries/en.json').then((module) => module.default),
es: () => import('@/dictionaries/es.json').then((module) => module.default),
};
export const getDictionary = async (lang: string) => {
const load = dictionaries[lang];
if (load) {
return load();
}
return dictionaries.en();
};
2. Definir metadatos en una página
En tu archivo de página (por ejemplo, app/[lang]/about/page.tsx), exporta una función async llamada generateMetadata. Next.js la llamará automáticamente al renderizar la página.
// app/[lang]/about/page.tsx
import { getDictionary } from '@/app/get-dictionary';
import type { Metadata } from 'next';
type Props = {
params: { lang: string };
};
// This function generates metadata
export async function generateMetadata({ params }: Props): Promise<Metadata> {
// Load the dictionary for this page
const dict = await getDictionary(params.lang);
return {
title: dict['about.title'], // e.g., "About Us" or "Sobre Nosotros"
description: dict['about.description'],
};
}
// The rest of your page component
export default function AboutPage() {
return (
<div>
{/* Page content */}
<h1>...</h1>
</div>
);
}
3. Establecer una plantilla de título en el layout raíz
Para evitar repetir el nombre de tu sitio en cada título, puedes establecer una plantilla en tu layout raíz.
// app/[lang]/layout.tsx
import { getDictionary } from '@/app/get-dictionary';
import type { Metadata } from 'next';
type Props = {
params: { lang: string };
children: React.ReactNode;
};
// You can generate metadata in layouts too
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const dict = await getDictionary(params.lang);
return {
// This provides a base title and a template
title: {
default: dict['site.name'], // e.g., "My Awesome Site"
template: `%s | ${dict['site.name']}`, // e.g., "About Us | My Awesome Site"
},
description: dict['site.description'],
};
}
export default async function RootLayout({ children, params }: Props) {
// ... rest of your layout (loading providers, etc.)
return (
<html lang={params.lang}>
<body>{children}</body>
</html>
);
}