# General Translation Knowledge Base: ¿Cómo agrego i18n a una aplicación de Next.js con Pages Router?
URL: https://generaltranslation.com/es/kb/add-i18n-to-nextjs-pages-router.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Agregue un bloque i18n con locales y defaultLocale a next.config.js, y Next.js servirá /es y /fr, redirigirá a los visitantes según el idioma del navegador y pasará la configuración regional a getStaticProps y getServerSideProps. Una biblioteca renderiza los mensajes; gt-next de General Translation, además, genera las traducciones a partir de textos escritos inline en JSX.
Category: Internacionalización
Last updated: 2026-10-28
Authors: General Translation Team
Published: 2026-10-28

Pages Router incluye enrutamiento internacionalizado integrado desde Next.js 10: indique sus locales y una configuración regional predeterminada en el bloque `i18n` de `next.config.js`, y Next.js servirá cada idioma en su propia URL, redirigirá a quienes visitan el sitio por primera vez según el idioma del navegador y pasará la configuración regional activa a sus funciones de obtención de datos. Lo que no hace es cargar, renderizar ni traducir texto: Next.js diseñó el enrutamiento para funcionar junto con una biblioteca de i18n, así que todavía tendrá que elegir una biblioteca para los mensajes y una forma de generar las traducciones ([internacionalización en Next.js Pages Router](https://nextjs.org/docs/pages/guides/internationalization)).

## Qué hace el enrutamiento i18n integrado

Toda la funcionalidad se reduce a un único bloque de configuración:

```js title="next.config.js"
/** @type {import('next').NextConfig} */
module.exports = {
  i18n: {
    // Todas las configuraciones regionales que sirve el sitio, incluida la predeterminada
    locales: ['en', 'es', 'fr'],
    // Se sirve sin prefijo: /about; las demás, con prefijo: /es/about, /fr/about
    defaultLocale: 'en',
  },
};
```

Con eso configurado, Next.js se encarga de cuatro tareas:

* **URLs.** El enrutamiento por subruta mantiene la configuración regional predeterminada en `/about` y añade un prefijo al resto (`/fr/about`). Si prefieres servir los locales desde dominios independientes, como `example.fr`, añade una lista `domains` con un `domain` y un `defaultLocale` por entrada.
* **Detección.** Cuando alguien visita `/`, Next.js lee la cabecera `Accept-Language` y redirige al prefijo o dominio correspondiente. La cookie `NEXT_LOCALE`, que establece tu selector de idioma, tiene prioridad sobre la cabecera. Establece `localeDetection: false` para desactivar la redirección.
* **La configuración regional en tu código.** `useRouter()` devuelve `locale`, `locales` y `defaultLocale`. `getStaticProps` y `getServerSideProps` reciben `locale` en su contexto, y `getStaticPaths` recibe `locales`.
* **`<html lang>`.** Next.js asigna al atributo la configuración regional activa, salvo que tu `_document` defina su propio valor.

Con esto basta para implementar la i18n a mano. Esta página carga un archivo JSON por configuración regional en tiempo de compilación:

```tsx title="pages/index.tsx"
import type { GetStaticProps, InferGetStaticPropsType } from 'next';
import Link from 'next/link';
import { useRouter } from 'next/router';

export const getStaticProps = (async ({ locale }) => {
  // Next.js lo invoca una vez por cada configuración regional definida, en tiempo de compilación.
  const messages = (await import(`../messages/${locale}.json`)).default;
  return { props: { messages } };
}) satisfies GetStaticProps;

export default function Home({ messages }: InferGetStaticPropsType<typeof getStaticProps>) {
  const { locales } = useRouter(); // ['en', 'es', 'fr']

  return (
    <main>
      <h1>{messages.title}</h1>
      <nav>
        {locales?.map((code) => (
          // La misma página en cada idioma: /, /es, /fr
          <Link key={code} href="/" locale={code} lang={code}>
            {new Intl.DisplayNames([code], { type: 'language' }).of(code)}
          </Link>
        ))}
      </nav>
    </main>
  );
}
```

Una compilación de producción sirve `/es` como `<html lang="es">` con el encabezado en español, y una solicitud a `/` con `Accept-Language: fr-CA` recibe una redirección 307 a `/fr`. Los enlaces muestran el nombre de cada idioma en ese mismo idioma (English, español, français), como corresponde a un [selector de idioma](/kb/language-switcher).

### Lo que queda en tus manos

El enrutamiento llega hasta la URL y nada más. Los plurales, el formato de números y fechas y la interpolación de cadenas son tarea de una biblioteca, al igual que mantener los archivos de mensajes sincronizados a medida que cambian los componentes. Next.js tampoco agrega enlaces `hreflang` entre las versiones de cada idioma; tienes que agregarlos tú con `next/head`. (Consulta [¿Qué es hreflang?](/kb/what-is-hreflang)). Y nada de esto genera una traducción.

Al planificar, hay tres límites que debes tener en cuenta:

* **Sin exportación estática.** El enrutamiento internacionalizado no funciona con `output: 'export'`, porque depende de la capa de enrutamiento de Next.js.
* **El tiempo de compilación crece con cada configuración regional.** Cada página no dinámica con `getStaticProps` se compila una vez por configuración regional, así que 50 locales y 10 páginas suponen 500 llamadas. Las rutas dinámicas deben devolver cada configuración regional desde `getStaticPaths`; de lo contrario, Next.js solo compila la predeterminada.
* **Límites máximos.** `locales` y `domains` admiten un máximo de 100 entradas cada uno.

### No se aplica al App Router

La configuración `i18n` es una funcionalidad del Pages Router. En el App Router, `useRouter` de `next/navigation` ya no incluye `locale`, `locales` ni `defaultLocale`, y Next.js indica que sus funcionalidades de i18n integradas no son necesarias en el directorio `app` ([guía de migración](https://nextjs.org/docs/app/guides/migrating/app-router-migration#step-5-migrating-routing-hooks)). En su lugar, las aplicaciones con App Router colocan la configuración regional en un segmento `[locale]` o la resuelven en el middleware. (Consulta [¿Cómo agrego i18n a una aplicación de Next.js con App Router?](/kb/add-i18n-to-nextjs)).

## Bibliotecas que renderizan los mensajes

| Biblioteca                                                                 | Configuración inicial en Pages Router                                                                                                                     | Cómo se escribe el texto                                                                                                                 | De dónde provienen las traducciones                                                                           |
| -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| [next-i18next](https://github.com/i18next/next-i18next#pages-router-setup) | `appWithTranslation` envuelve `_app`; `serverSideTranslations(locale, ['common'])` en `getStaticProps` o `getServerSideProps`, desde `next-i18next/pages` | Claves en espacios de nombres JSON, renderizadas con `t('title')`                                                                        | Tú, traductores o un sistema de gestión de traducciones (TMS) como Locize                                     |
| [next-intl](https://next-intl.dev/docs/getting-started/pages-router)       | `NextIntlClientProvider` en `_app`, con `messages` devueltos desde `getStaticProps`                                                                       | Claves en un archivo JSON por configuración regional, renderizadas con [`useTranslations`](/docs/react/reference/hooks/use-translations) | Tú o tus traductores                                                                                          |
| [react-intl](https://formatjs.github.io/docs/react-intl)                   | `IntlProvider` en `_app`, que recibe la configuración regional activa y sus mensajes                                                                      | Mensajes ICU inline como `defaultMessage`, extraídos con `formatjs extract`                                                              | Tú, traductores o un TMS                                                                                      |
| General Translation (`gt-next`)                                            | `withGTServerSideProps` o `withGTStaticProps` en cada página; [`GTProvider`](/docs/react/reference/components/gt-provider) en `_app`                      | JSX envuelto en [`<T>`](/docs/react/reference/components/t), cadenas con [`useGT`](/docs/react/reference/hooks/use-gt)                   | Generadas con [`npx gt translate`](/docs/cli/reference/commands/translate) y revisadas en el panel de control |

next-i18next 16 es compatible con ambos routers y conserva su conocida API de Pages Router en `next-i18next/pages`. La documentación de next-intl recomienda el App Router, aunque sigue siendo totalmente compatible con el Pages Router. En el Pages Router, cada una se combina con el bloque `i18n` anterior para gestionar las URL y la detección.

Usa next-i18next si ya tienes espacios de nombres de i18next o quieres aprovechar su ecosistema de plugins. Usa next-intl si tienes pensado migrar al App Router y quieres usar la misma API antes y después de la migración. Usa react-intl si tus mensajes son cadenas ICU con las que tus traductores ya trabajan. Usa General Translation si prefieres mantener el texto inline en tus componentes y que las traducciones se generen, se revisen y se actualicen a medida que cambia el código. (Consulta [next-intl vs. gt-next](/kb/next-intl-vs-gt-next) para ver una comparación detallada).

Si sigues usando next-i18next o next-intl, la CLI de General Translation puede traducir igualmente sus archivos JSON, incluidas las cadenas ICU, sin necesidad de migrar ([traducción de archivos JSON](/docs/cli/reference/formats/json-files)).

## Añadir General Translation a una aplicación con Pages Router

Esta configuración inicial añade español y francés a una aplicación con Pages Router, y cada idioma tiene su propia URL. Se probó con una aplicación creada con `create-next-app` 16.4.3 (`--no-app`), Next.js 16.4.3, `gt-next@11.4.16` y `gt@2.26.11`. `gt-next` es compatible con Next.js 13.0.0 y versiones posteriores, salvo la 15.2.1 y la 15.2.2. Su punto de entrada `gt-next/server` solo funciona con App Router.

### 1. Instala la biblioteca y la CLI

```bash
npm install gt-next@11.4.16
npm install --save-dev gt@2.26.11
```

### 2. Configura tus idiomas

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["en", "es", "fr"],
  "files": {
    "gt": {
      "output": "public/_gt/[locale].json"
    }
  }
}
```

Mantén `en` en `locales`: esa misma lista se usa en el bloque `i18n` de Next.js, que requiere la configuración regional predeterminada.

### 3. Activa el enrutamiento i18n de Next.js

```ts title="next.config.ts"
import type { NextConfig } from 'next';
import { withGTConfig } from 'gt-next/config';
import gtConfig from './gt.config.json';

const nextConfig: NextConfig = {
  i18n: {
    locales: gtConfig.locales,
    defaultLocale: gtConfig.defaultLocale,
  },
};

export default withGTConfig(nextConfig);
```

Next.js se encarga del enrutamiento y la detección descritos anteriormente. No necesitas el middleware de `gt-next` ni una carpeta `pages/[locale]`.

`create-next-app` escribe `<Html lang="en">` en `pages/_document.tsx`, lo que reemplaza la configuración regional: en la aplicación de prueba, `/es` devolvía `lang="en"` con el texto en español. Elimina esa prop para que Next.js la establezca:

```tsx title="pages/_document.tsx"
import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}
```

### 4. Cargar traducciones desde archivos locales

```ts title="loadTranslations.ts"
export default async function loadTranslations(locale: string) {
  try {
    const translations = await import(`./public/_gt/${locale}.json`);
    return translations.default;
  } catch {
    // Mientras no existan los archivos, se renderiza el texto de origen
    return {};
  }
}
```

`withGTConfig` detecta `loadTranslations.ts` en la raíz del proyecto o en `src/`. Las traducciones se incluyen en tu compilación, así que la aplicación no hace ninguna llamada a General Translation en tiempo de ejecución. (Consulta [almacenamiento de traducciones](/docs/react/guides/storing-translations)).

### 5. Pasa la configuración regional y las traducciones a cada página

Envuelve la función de datos de cada página. El wrapper lee `context.locale` de Next.js y añade `locale` y `translations` a las props de la página:

```tsx title="pages/about.tsx"
import { T, withGTStaticProps } from 'gt-next';

// Next.js compila esta página una vez por cada configuración regional.
export const getStaticProps = withGTStaticProps();

export default function About() {
  return (
    <T>
      <h1>About us</h1>
    </T>
  );
}
```

Usa `withGTServerSideProps()` de la misma manera en las páginas server-rendered. Ambas funciones reciben como argumento tu propia función de datos, por ejemplo `withGTStaticProps(async (context) => ({ props: { posts } }))`, y dejan pasar sin modificar cualquier resultado `redirect` o `notFound`. Envuelve cada página que renderice contenido traducido.

Después, pasa esas props a [`GTProvider`](/docs/react/reference/components/gt-provider) en `_app`:

```tsx title="pages/_app.tsx"
import type { AppProps } from 'next/app';
import Router from 'next/router';
import { GTProvider, type WithGTServerSideProps } from 'gt-next';

export default function App({ Component, pageProps }: AppProps<WithGTServerSideProps>) {
  const { locale, translations } = pageProps;

  return (
    <GTProvider
      locale={locale}
      translations={translations}
      // Cambia de idioma mediante la navegación de Next.js: /es, /fr y de vuelta a /
      _reload={({ locale: nextLocale }) => {
        void Router.push(Router.pathname, Router.asPath, { locale: nextLocale });
      }}
    >
      <Component {...pageProps} />
    </GTProvider>
  );
}
```

### 6. Marca el contenido para traducir

```tsx title="pages/index.tsx"
import { LocaleSelector, T, useGT, withGTServerSideProps } from 'gt-next';

export const getServerSideProps = withGTServerSideProps();

export default function Home() {
  const gt = useGT();

  return (
    <main>
      <LocaleSelector />
      <T>
        <h1>Find your next project</h1>
        <p>Explore projects from teams around the world.</p>
      </T>
      <input type="search" placeholder={gt('Search projects')} aria-label={gt('Search projects')} />
    </main>
  );
}
```

[`<T>`](/docs/react/reference/components/t) traduce el encabezado y el párrafo en conjunto, usando su marcado como contexto. [`useGT`](/docs/react/reference/hooks/use-gt) se encarga de las cadenas de los atributos. [`<LocaleSelector>`](/docs/react/reference/components/locale-selector) muestra tus locales con su nombre en su propio idioma. Al elegir Español, se guarda `NEXT_LOCALE=es`, que Next.js lee en la siguiente visita a `/`, y el callback `_reload` redirige la página a `/es`.

### 7. Generar traducciones y comprobar la compilación

Inicia sesión con [`npx gt login`](/docs/cli/reference/commands/login), define `GT_PROJECT_ID` y ejecuta [`npx gt translate`](/docs/cli/reference/commands/translate) para generar `public/_gt/es.json` y `fr.json`. Si quieres probar la configuración inicial sin una cuenta, [`npx gt generate`](/docs/cli/reference/commands/generate) genera los mismos archivos con el texto de origen en inglés para que los traduzcas a mano.

En la aplicación de prueba, con el archivo en español ya completado, `next build` se ejecutó correctamente y `next start` sirvió:

* `/` como `<html lang="en">` con el encabezado en inglés
* `/es` como `<html lang="es">` con el encabezado y el marcador de posición en español
* `/es/about`, compilada con `withGTStaticProps`, en español
* `/` con `Accept-Language: es` como una redirección 307 a `/es`

## Publica y mantén las traducciones al día

Traduce antes de cada compilación para que el texto nuevo se publique en todos los idiomas:

```json title="package.json"
{
  "scripts": {
    "build": "gt validate && gt translate && next build"
  }
}
```

En tu proveedor de hosting, define `GT_PROJECT_ID` y una Clave de API del proyecto como `GT_API_KEY` con **Archivos &gt; Escritura** y **Cola de traducción &gt; Habilitada**. Mantén la clave en el server-side y nunca le agregues el prefijo `NEXT_PUBLIC_`. Si la compilación regenera `public/_gt/` cada vez, agrégalo a `.gitignore`. [`gt validate`](/docs/cli/reference/commands/validate) detiene la compilación si detecta contenido que rompería la traducción, antes de hacer cualquier llamada a la API, y en las ejecuciones posteriores solo se traduce el contenido de origen nuevo o modificado.

Los revisores pueden modificar cualquier traducción en el [Editor de Traducciones](/docs/platform/dashboard/guides/reviewing-translations) de General Translation, y un [grupo de contexto](/docs/platform/dashboard/guides/defining-context-for-translations) mantiene la coherencia de los términos del glosario y del tono con tus demás proyectos. Para que las versiones en cada idioma sean indexables, agrega `hreflang`, URL canónicas y títulos traducidos; en [SEO multilingüe para Next.js](/kb/multilingual-nextjs-seo) se explica cada uno.

## Preguntas frecuentes

### ¿Funciona la opción i18n de next.config.js en el App Router?

No. Es una funcionalidad del Pages Router; las aplicaciones con App Router usan un segmento de ruta `[locale]` o un middleware, y `gt-next` documenta una configuración inicial específica para el App Router.

### ¿Puedo usar getStaticProps con gt-next?

Sí. Envuélvelo con `withGTStaticProps` y Next.js generará una versión de la página para cada configuración regional. Las rutas dinámicas deben seguir devolviendo desde `getStaticPaths` una ruta por cada configuración regional.

### ¿Necesito middleware para la i18n con Pages Router?

No. Next.js resuelve la configuración regional a partir de la URL, la cookie `NEXT_LOCALE` y el encabezado `Accept-Language` antes de que se ejecuten tus funciones de obtención de datos.

## Puntos clave

* El bloque `i18n` de `next.config.js` proporciona al Pages Router URLs por configuración regional, redirecciones basadas en `Accept-Language` en `/`, la cookie `NEXT_LOCALE` y `locale` en `useRouter()` y en las funciones de obtención de datos.
* No renderiza ni traduce mensajes, no añade `hreflang`, no funciona con `output: 'export'` ni se aplica al App Router.
* Elimina el `lang="en"` fijo de `pages/_document.tsx`; de lo contrario, el HTML de todas las configuraciones regionales declarará el inglés como idioma.
* next-i18next, next-intl y react-intl renderizan las traducciones que tú proporcionas; `gt-next` de General Translation, además, las genera, usando `withGTStaticProps` o `withGTServerSideProps` en cada página y [`GTProvider`](/docs/react/reference/components/gt-provider) en `_app`.
* Añade [`gt validate && gt translate`](/docs/cli/reference/commands/validate) antes de `next build` para que cada lanzamiento salga en todos los idiomas.

## Related questions

- [¿Cómo agrego i18n a una aplicación de Next.js con App Router?](https://generaltranslation.com/es/kb/add-i18n-to-nextjs.mdx): Empieza con gt init para configurar General Translation en un proyecto compatible con App Router; luego marca el contenido de origen, genera las traducciones y verifica el cambio de idioma. gt-next mantiene el texto en JSX junto con el contexto de traducción; la CLI, el editor del panel de control y Locadex se encargan de la generación, la revisión y las actualizaciones continuas. Esta guía también muestra la configuración inicial explícita con archivos locales.
- [Alternativas a next-intl: gt-next vs. next-intl](https://generaltranslation.com/es/kb/next-intl-vs-gt-next.mdx): next-intl renderiza las traducciones que proporcionas en un catálogo de mensajes para cada idioma. gt-next también renderiza traducciones, pero además General Translation las genera a partir del texto escrito inline en tu JSX. Ambas tienen licencia MIT y son compatibles con App Router y los Componentes de servidor. Si tus catálogos de next-intl ya funcionan, puedes conservarlos y usar General Translation para traducirlos sin necesidad de migrar.
- [¿Cómo configuro el SEO de una aplicación de Next.js multilingüe?](https://generaltranslation.com/es/kb/multilingual-nextjs-seo.mdx): Asigna a cada idioma su propia URL con prefijo, como /en/about y /es/about, y luego publica html lang, una URL canónica autorreferente, versiones alternativas hreflang con x-default, un título y una descripción traducidos, y una entrada en el mapa del sitio para cada idioma publicado. Marca con noindex las versiones no publicadas. gt-next de General Translation dirige cada idioma a su propia URL y traduce los títulos con getGT.
- [Buenas prácticas para el selector de idioma: UX, SEO y accesibilidad](https://generaltranslation.com/es/kb/language-switcher.mdx): Escribe el nombre de cada idioma en ese mismo idioma, como Deutsch o 日本語, y no uses banderas, que representan países. Enlaza cada opción a la misma página en ese idioma mediante un enlace rastreable, guarda la elección en una cookie y nunca redirijas automáticamente una URL localizada.
- [Alternativas a i18next: General Translation vs. i18next](https://generaltranslation.com/es/kb/general-translation-vs-i18next.mdx): Elige General Translation para mantener los textos inline en los componentes de React y generar traducciones a partir de su estructura JSX y del contexto del producto. También puedes seguir usando i18next y recurrir a General Translation para traducir los catálogos existentes. i18next se encarga de renderizar los mensajes y seleccionar los plurales, pero las traducciones las genera un servicio aparte.

## Previous and next questions

- Previous question: [¿Cómo agrego i18n a TanStack Start?](https://generaltranslation.com/es/kb/add-i18n-to-tanstack-start.mdx)
- Next question: [¿Cómo creo un mapa del sitio para un sitio web multilingüe?](https://generaltranslation.com/es/kb/multilingual-sitemap.mdx)

## Sitemap

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