# General Translation Knowledge Base: ¿Cómo configuro el SEO de una aplicación de Next.js multilingüe?
URL: https://generaltranslation.com/es/kb/multilingual-nextjs-seo.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Asigna a cada idioma su propia URL, define el atributo lang de html, haz que la URL canónica de cada página apunte a sí misma, añade versiones alternativas hreflang para cada idioma, traduce los títulos y las descripciones, e incluye todas las versiones de idioma en tu sitemap.
Category: SEO multilingüe
Last updated: 2026-02-17
Authors: General Translation Team
Published: 2026-02-17

## Video

The video is narrated in English, with English captions.

[How do I set up SEO for a multilingual Next.js app?](https://caxecubb9c64cezv.public.blob.vercel-storage.com/films/kb-multilingual-nextjs-seo.mp4) (50 s)

General Translation lets you give every language its own URL and tell search engines about them. Move your pages into `app/[locale]` with `gt-next`'s middleware, set the html `lang` attribute with `useLocale`, add canonical and hreflang links with a helper, translate the title with `getGT`, and list every page in every language in a sitemap.

## Por qué el SEO multilingüe requiere especial atención

La mayoría de los desarrolladores que añaden i18n a su aplicación de Next.js se limitan a traducir la UI y dan el trabajo por terminado.
Pero si los motores de búsqueda no pueden encontrar, indexar y asociar correctamente las distintas versiones de idioma de tu sitio,
todo ese trabajo de traducción queda invisible.

Un sitio multilingüe sin una configuración de SEO adecuada presenta varios problemas:

* Google puede indexar solo una versión de idioma e ignorar las demás
* Los usuarios que buscan en español reciben la página en inglés
* Penalizaciones por contenido duplicado, porque Google interpreta `/en/about` y `/fr/about` como la misma página
* Los fragmentos de los resultados de búsqueda muestran el idioma incorrecto

**La buena noticia:** configurar bien el SEO multilingüe en Next.js no es complicado.
Hay seis aspectos clave que debes resolver, y esta guía los cubre todos con [`gt-next`](/docs/react/nextjs-quickstart).

***

## 1. Enrutamiento de URL basado en la configuración regional

La base del SEO multilingüe consiste en tener una URL distinta para cada idioma.
Los motores de búsqueda necesitan URL independientes y rastreables para indexar cada versión de idioma por separado.

Esto significa **incluir la configuración regional en la URL**: ni cookies, ni parámetros de consulta, ni únicamente la detección mediante `Accept-Language`.

```text
✅ generaltranslation.com/en/about
✅ generaltranslation.com/fr/about
✅ generaltranslation.com/es/about

❌ generaltranslation.com/about?lang=fr
❌ generaltranslation.com/about (con la configuración regional en una cookie)
```

### Configurar el enrutamiento por configuración regional con gt-next

Primero, coloca tus páginas dentro de un segmento dinámico `[locale]`:

```text
app/
└── [locale]/
    ├── layout.tsx
    ├── page.tsx
    └── about/
        └── page.tsx
```

Luego, crea un middleware en la raíz del proyecto (`proxy.ts` para Next.js 16+ o `middleware.ts` para Next.js 15 y versiones anteriores):

```ts title="proxy.ts"
import { createNextMiddleware } from 'gt-next/middleware';

export default createNextMiddleware();

export const config = {
  matcher: ['/((?!api|static|.*\\..*|_next).*)'],
};
```

Así obtienes automáticamente URL con el prefijo de la configuración regional.
De forma predeterminada, la configuración regional predeterminada (p. ej., inglés) no lleva prefijo: `/about` se mantiene limpia,
mientras que los usuarios hispanohablantes ven `/es/about` y los francófonos, `/fr/about`.

***

## 2. Configurar el atributo `lang` de HTML

El atributo `lang` de tu etiqueta `<html>` indica a los navegadores y a los motores de búsqueda en qué idioma está la página.
Es una de las medidas más sencillas y eficaces que puedes aplicar para mejorar la accesibilidad y el SEO.

Sin él, los lectores de pantalla tienen que adivinar el idioma (y a menudo se equivocan), y los motores de búsqueda clasifican el idioma de la página con menos certeza.

{/* useLocale funciona tanto en componentes renderizados en el cliente como en el servidor, pero no en componentes asíncronos */}

gt-next proporciona el hook [`useLocale`](/docs/react/reference/hooks/use-locale), que hace que esto sea muy sencillo en tu layout raíz:

```tsx title="app/[locale]/layout.tsx"
import { useLocale, GTProvider } from 'gt-next';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  const locale = useLocale();

  return (
    <html lang={locale}>
      <body>
        <GTProvider>
          {children}
        </GTProvider>
      </body>
    </html>
  );
}
```

[`useLocale`](/docs/react/reference/hooks/use-locale) devuelve el código de configuración regional BCP 47 (p. ej., `en-US`, `ar`, `zh-Hans`).

***

## 3. URL canónicas

Las etiquetas canonical indican a los motores de búsqueda qué URL es la versión &quot;principal&quot; de una página.
En los sitios multilingües, cada versión de idioma debe apuntar a sí misma como URL canónica:

```html
<!-- En /fr/about -->
<link rel="canonical" href="https://example.com/fr/about" />
```

Esto evita que los motores de búsqueda consideren tu página en francés como un duplicado de tu página en inglés.

En Next.js, las URL canónicas se definen mediante la [API de metadatos](https://nextjs.org/docs/app/api-reference/functions/generate-metadata).
Combínala con [`getLocale`](/docs/react/nextjs/reference/functions/get-locale) de gt-next para generar la URL canónica correcta para cada configuración regional:

```tsx title="app/[locale]/about/page.tsx"
import { getLocale } from 'gt-next/server';

const BASE_URL = 'https://example.com';

export async function generateMetadata() {
  const locale = await getLocale();

  return {
    alternates: {
      canonical: `${BASE_URL}/${locale}/about`,
    },
  };
}

export default function AboutPage() {
  return <h1>About Us</h1>;
}
```

Si la configuración regional predeterminada no lleva prefijo, haz los ajustes correspondientes:

```tsx
import { getDefaultLocale } from 'gt-next';
import { getLocale } from 'gt-next/server';

export async function generateMetadata() {
  const locale = await getLocale();
  const defaultLocale = getDefaultLocale();
  const path = '/about';

  const prefix = locale === defaultLocale ? '' : `/${locale}`;

  return {
    alternates: {
      canonical: `${BASE_URL}${prefix}${path}`,
    },
  };
}
```

***

## 4. Etiquetas hreflang

Las etiquetas hreflang son la señal de SEO multilingüe más importante.
Les indican a los motores de búsqueda: &quot;esta página existe en estos otros idiomas y estas son sus URL&quot;.

Sin hreflang, Google tiene que adivinar qué versión de idioma mostrar en los resultados de búsqueda, y a menudo se equivoca.

```html
<link rel="alternate" hreflang="en" href="https://example.com/about" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/about" />
<link rel="alternate" hreflang="es" href="https://example.com/es/about" />
<link rel="alternate" hreflang="x-default" href="https://example.com/about" />
```

La etiqueta `x-default` indica a los motores de búsqueda qué URL deben mostrar cuando ninguno de los idiomas especificados coincide con el del usuario.

En Next.js, puedes añadir hreflang mediante la propiedad `alternates.languages` de la API de metadatos.
Aquí tienes una función auxiliar reutilizable que funciona con gt-next:

```tsx title="lib/i18n-metadata.ts"
import { getDefaultLocale } from 'gt-next';
import { getLocale } from 'gt-next/server';

const BASE_URL = 'https://example.com';
const SUPPORTED_LOCALES = ['en', 'fr', 'es'];

export async function getI18NMetadata(path: string) {
  const locale = await getLocale();
  const defaultLocale = getDefaultLocale();

  const getUrl = (loc: string) => {
    const prefix = loc === defaultLocale ? '' : `/${loc}`;
    return `${BASE_URL}${prefix}${path}`;
  };

  const languages: Record<string, string> = {};
  for (const loc of SUPPORTED_LOCALES) {
    languages[loc] = getUrl(loc);
  }
  languages['x-default'] = getUrl(defaultLocale);

  return {
    alternates: {
      canonical: getUrl(locale),
      languages,
    },
  };
}
```

Luego, úsalo en cualquier página:

```tsx title="app/[locale]/about/page.tsx"
import { getI18NMetadata } from '@/lib/i18n-metadata';

export async function generateMetadata() {
  return await getI18NMetadata('/about');
}
```

Esto genera tanto la URL canónica como todas las etiquetas hreflang en una sola llamada.

***

## 5. Metadatos traducidos

Los motores de búsqueda muestran el título y la descripción de tu página en los resultados.
Si aparecen en inglés en una página en francés, es menos probable que los usuarios hagan clic, y Google podría relegar el resultado.

Usa la función [`getGT`](/docs/react/nextjs/reference/functions/get-gt) de gt-next para traducir las cadenas de metadatos:

```tsx title="app/[locale]/about/page.tsx"
import { getGT } from 'gt-next/server';
import { getI18NMetadata } from '@/lib/i18n-metadata';

export async function generateMetadata() {
  const t = await getGT();
  const i18nMeta = await getI18NMetadata('/about');

  return {
    title: t('About Us'),
    description: t('Learn about our mission and team.'),
    ...i18nMeta,
  };
}
```

Así obtienes títulos y descripciones localizados en los resultados de búsqueda,
lo que mejora notablemente la tasa de clics en las búsquedas en idiomas distintos del inglés.

***

## 6. Sitemaps multilingües

Un sitemap ayuda a los motores de búsqueda a descubrir todas tus páginas, incluidas las versiones en cada idioma.
En los sitios multilingües, también conviene incluir anotaciones hreflang en el sitemap.

Next.js admite [sitemaps programáticos](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap) mediante un archivo `sitemap.ts`:

```ts title="app/sitemap.ts"
import { MetadataRoute } from 'next';

const BASE_URL = 'https://example.com';
const LOCALES = ['en', 'fr', 'es'];
const DEFAULT_LOCALE = 'en';
const PAGES = ['/', '/about', '/blog', '/contact'];

export default function sitemap(): MetadataRoute.Sitemap {
  return PAGES.flatMap((path) => {
    const getUrl = (locale: string) => {
      const prefix = locale === DEFAULT_LOCALE ? '' : `/${locale}`;
      return `${BASE_URL}${prefix}${path === '/' ? '' : path}`;
    };

    const languages: Record<string, string> = {};
    for (const locale of LOCALES) {
      languages[locale] = getUrl(locale);
    }

    return LOCALES.map((locale) => ({
      url: getUrl(locale),
      lastModified: new Date(),
      alternates: { languages },
    }));
  });
}
```

Esto genera un sitemap con una entrada por página y por configuración regional,
y cada entrada incluye anotaciones hreflang que apuntan a todas las versiones en otros idiomas.

***

## Lista de verificación

Aquí tienes un breve resumen de todo lo que hemos visto:

| Requisito de SEO                 | Implementación                                                                                                                |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Configuración regional en la URL | [`createNextMiddleware()`](/docs/react/nextjs/reference/functions/create-next-middleware) con el segmento dinámico `[locale]` |
| Atributo HTML `lang`             | [`useLocale()`](/docs/react/reference/hooks/use-locale) en el layout raíz                                                     |
| URL canónicas                    | [`getLocale()`](/docs/react/nextjs/reference/functions/get-locale) + `alternates.canonical` de la API de metadatos de Next.js |
| Etiquetas hreflang               | `alternates.languages` de la API de metadatos de Next.js con todas las configuraciones regionales compatibles                 |
| Metadatos traducidos             | [`getGT()`](/docs/react/nextjs/reference/functions/get-gt) para los títulos y descripciones de las páginas                    |
| Sitemap multilingüe              | `sitemap.ts` con entradas por configuración regional y versiones alternativas hreflang                                        |

***

Usa el [Inicio rápido de `gt-next`](/docs/react/nextjs-quickstart) para configurar la plataforma completa de internacionalización. Después, configura el enrutamiento con la [Guía de Middleware](/docs/react/nextjs/app-router-middleware), genera páginas multilingües mediante la [Generación de Sitios Estáticos](/docs/react/nextjs/app-router-static-site-generation) y añade [compatibilidad con idiomas right-to-left](/docs/react/guides/managing-locales).

## Related questions

- [¿Puedo hacer i18n sin archivos de traducción?](https://generaltranslation.com/es/kb/i18n-without-translation-files.mdx): Sí. Con gt-react o gt-next, el contenido se mantiene inline en tus componentes, dentro de un componente `<T>`, y las traducciones se generan en tiempo de compilación, por lo que no tienes que escribir claves ni archivos JSON por configuración regional ni mantenerlos sincronizados.
- [¿Cuál es el mejor software de localización para desarrolladores?](https://generaltranslation.com/es/kb/best-localization-software.mdx): Busca un único sistema que cubra todo el flujo, desde la biblioteca de i18n en tu código hasta la traducción y la entrega, en lugar de ir uniendo por separado una biblioteca, un sistema de gestión de traducciones y un proveedor de traducción.
- [General Translation vs. Weblate: ¿cuál deberías usar?](https://generaltranslation.com/es/kb/general-translation-vs-weblate.mdx): Weblate es una plataforma de localización autoalojable y basada en Git, pensada para traducir los archivos de un repositorio junto con una comunidad o un equipo. General Translation integra la generación de traducciones en el desarrollo y los lanzamientos mediante JSX marcado y contexto compartido del producto. Conserva tus archivos de gettext o adopta la redacción inline para eliminar también el mantenimiento del catálogo de origen.

## Previous and next questions

- Previous question: [¿Cómo traduzco texto condicional en JSX?](https://generaltranslation.com/es/kb/translate-conditional-jsx.mdx)
- Next question: [¿Cuál es el mejor software de localización para desarrolladores?](https://generaltranslation.com/es/kb/best-localization-software.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/es/kb/sitemap.md) for every article.
