# General Translation Knowledge Base: ¿Cómo migro de next-intl a gt-next?
URL: https://generaltranslation.com/es/kb/migrate-from-next-intl.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Sustituye el plugin, el middleware y el proveedor de next-intl por los de gt-next, replica su configuración de prefijo de configuración regional y carga messages/en.json como diccionario de gt-next para que los mensajes ICU y las traducciones existentes sigan funcionando. Mapea las rutas localizadas antes de eliminar el enrutamiento de next-intl y, después, mueve el texto inline a `<T>` ruta por ruta.
Category: Internacionalización
Last updated: 2026-11-11
Authors: Kevin Wu
Published: 2026-11-11

Tanto next-intl como gt-next localizan aplicaciones de Next.js con App Router mediante rutas con prefijo de configuración regional y Componentes de servidor, así que la estructura de la aplicación apenas cambia. Tus mensajes de next-intl ya usan el formato de mensajes ICU, el mismo que usan los diccionarios de gt-next. Gracias a esto, puedes conservar `messages/en.json` y tus catálogos traducidos mientras cambias de biblioteca y, después, mover el texto inline a [`<T>`](/docs/react/reference/components/t) a tu ritmo.

Si tus catálogos funcionan y lo único que te frena es lo lento que resulta producir las traducciones, puede que no necesites migrar. Si te quedas con next-intl, la CLI `gt` traduce sus catálogos en el mismo documento. (Consulta [next-intl vs. gt-next](/kb/next-intl-vs-gt-next)).

## ¿Cómo se corresponden las API de next-intl con gt-next?

| next-intl                                                                          | gt-next                                                                                                                                                                                                                                                                      |
| ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defineRouting({ locales, defaultLocale })`                                        | `defaultLocale` y `locales` en `gt.config.json`                                                                                                                                                                                                                              |
| `createNextIntlPlugin()` en `next.config.ts`                                       | [`withGTConfig`](/docs/react/nextjs/config) de `gt-next/config`                                                                                                                                                                                                              |
| `createMiddleware(routing)` en `proxy.ts`                                          | [`createNextMiddleware`](/docs/react/nextjs/reference/functions/create-next-middleware) de `gt-next/middleware`                                                                                                                                                              |
| `localePrefix: 'as-needed'` / `'always'`                                           | `prefixDefaultLocale: false` (valor predeterminado) / `true`                                                                                                                                                                                                                 |
| `getRequestConfig` en `i18n/request.ts`                                            | Un `getLocale.ts` en la raíz que lee `next/root-params`, junto con la opción `dictionary`                                                                                                                                                                                    |
| `NextIntlClientProvider`                                                           | [`GTProvider`](/docs/react/reference/components/gt-provider) en `app/[locale]/layout.tsx`                                                                                                                                                                                    |
| `useTranslations('ns')`                                                            | [`useTranslations`](/docs/react/reference/hooks/use-translations)`('ns')` de `gt-next`                                                                                                                                                                                       |
| `await getTranslations('ns')`                                                      | `await` [`getTranslations`](/docs/react/nextjs/reference/functions/get-translations)`('ns')` de `gt-next/server`                                                                                                                                                             |
| `t.rich` y `t.markup`                                                              | [`<T>`](/docs/react/reference/components/t) envolviendo directamente el JSX                                                                                                                                                                                                  |
| `useFormatter` / `getFormatter`                                                    | [`<Num>`](/docs/react/reference/components/num), [`<Currency>`](/docs/react/reference/components/currency), [`<DateTime>`](/docs/react/reference/components/datetime) y [`<RelativeTime>`](/docs/react/reference/components/relative-time), o argumentos ICU en los mensajes |
| [`useLocale` / `getLocale`](https://next-intl.dev/docs/usage/configuration#locale) | [`useLocale`](/docs/react/reference/hooks/use-locale) / [`getLocale`](/docs/react/nextjs/reference/functions/get-locale)                                                                                                                                                     |
| `setRequestLocale(locale)`                                                         | No es necesario en páginas y layouts con `getLocale.ts`; [`registerLocale`](/docs/react/nextjs/reference/functions/register-locale) para manejadores de ruta y rutas de imágenes                                                                                             |
| `Link` de `createNavigation`                                                       | [`Link`](/docs/react/nextjs/link) de `gt-next/link`                                                                                                                                                                                                                          |
| `useRouter` / `getPathname` / `redirect`                                           | Las API nativas de Next.js con [`useLocalizeHref`](/docs/react/nextjs/reference/hooks/use-localize-href) o [`getLocalizeHref`](/docs/react/nextjs/reference/functions/get-localize-href)                                                                                     |
| Cookie `NEXT_LOCALE`                                                               | `generaltranslation.locale`, que se puede renombrar con `headersAndCookies.localeCookieName`                                                                                                                                                                                 |

## Paso 1: Reemplaza el plugin y conserva tus mensajes

Instala `gt-next` y la CLI `gt`, y después enumera tus idiomas en `gt.config.json`. Haz que `withGTConfig` apunte a tu catálogo de origen existente y replica la estructura de URL de next-intl:

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

const nextConfig: NextConfig = {};

export default withGTConfig(nextConfig, {
  dictionary: './messages/en.json',
  prefixDefaultLocale: true, // valor predeterminado de next-intl, localePrefix: 'always'
  headersAndCookies: { localeCookieName: 'NEXT_LOCALE' }, // conserva el idioma de los visitantes que regresan
});
```

Omite `prefixDefaultLocale` si usabas `localePrefix: 'as-needed'`. Define las opciones de enrutamiento en `withGTConfig` y no solo en el middleware, porque el `<Link>` de gt-next las lee de ahí.

Este ejemplo abarca los prefijos de configuración regional estándar, como `/de/about`. Si tu llamada a `defineRouting` personaliza las rutas, traslada cada personalización antes de que el Paso 2 la elimine:

* **Rutas localizadas** (`pathnames`, como `/de/ueber-uns`): asigna cada una con la opción [`pathConfig`](/docs/react/nextjs/reference/functions/create-next-middleware#path-config) de gt-next, que sigue la misma estructura: una ruta compartida y una ruta localizada por cada configuración regional.
* **Prefijos personalizados, enrutamiento basado en dominios o `localePrefix: 'never'`:** gt-next no tiene un equivalente directo. Define las nuevas URL y agrega redirecciones permanentes desde las anteriores antes de eliminar el enrutamiento de next-intl.

Para seguir sirviendo tus traducciones revisadas, agrega un archivo `loadDictionary.ts` en la raíz del proyecto. gt-next lo detecta automáticamente:

```ts title="loadDictionary.ts"
export default async function loadDictionary(locale: string) {
  try {
    return (await import(`./messages/${locale}.json`)).default;
  } catch {
    return {}; // una configuración regional nueva sin catálogo recurre a las traducciones de General Translation
  }
}
```

Las entradas de estos archivos tienen prioridad. Para cualquier clave que falte en un catálogo, se renderiza la traducción de General Translation. Si `gt.config.json` ya incluye estos catálogos en `files`, elimina esa entrada: gt-next ahora los carga como diccionarios, y cada cadena debe tener un único responsable de su traducción.

## Paso 2: Sustituye el middleware, el layout y la configuración de solicitudes

Reemplaza el middleware de next-intl en `proxy.ts` (`middleware.ts` en 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).*)'],
};
```

Una vez asignadas sus rutas, elimina `i18n/request.ts` e `i18n/routing.ts`. En su lugar, añade un archivo `getLocale.ts` en la raíz para que las páginas y los layouts puedan renderizarse de forma estática sin `setRequestLocale`:

```ts title="getLocale.ts"
import { locale } from 'next/root-params';

export default async function getLocale() {
  return await locale();
}
```

`next/root-params` requiere Next.js 15.5 o posterior; para las versiones 15.2 a 15.4, consulta la [guía de middleware](/docs/react/nextjs/app-router-middleware#root-locale). A continuación, reemplaza el proveedor en el layout de tu configuración regional:

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

export function generateStaticParams() {
  return getLocales().map((locale) => ({ locale }));
}

export default async function LocaleLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang={await getLocale()}>
      <body>
        <GTProvider>{children}</GTProvider>
      </body>
    </html>
  );
}
```

De forma predeterminada, gt-next recurre a `defaultLocale` cuando el segmento de configuración regional no es compatible. Para devolver un 404, como hace la comprobación `hasLocale` de next-intl, valida el segmento con [`isLocaleSupported`](/docs/react/nextjs/reference/functions/is-locale-supported) y llama a `notFound()`.

## Paso 3: Cambia las importaciones

Con el catálogo cargado como diccionario, en la mayoría de los componentes solo cambia la línea de importación:

```tsx
// Antes
import { useTranslations } from 'next-intl';
import { getTranslations } from 'next-intl/server';
import { Link } from '@/i18n/navigation';

// Después
import { useTranslations } from 'gt-next';
import { getTranslations } from 'gt-next/server';
import Link from 'gt-next/link';
```

`t('heading')`, los espacios de nombres, los marcadores de posición `{name}` y los mensajes ICU `plural` y `select` funcionan sin cambios, incluso en `generateMetadata`. Hay tres patrones que requieren modificaciones:

* **`t.rich` y `t.markup`.** La función [`t()`](/docs/react/reference/hooks/use-translations) de gt-next devuelve una cadena. Mueve el texto enriquecido inline a [`<T>`](/docs/react/reference/components/t) con elementos reales.
* **`t.raw` con listas.** gt-next no tiene `t.raw` y solo interpreta una lista de un diccionario como un mensaje con sus opciones. Reestructura las listas como objetos anidados y léelas con [`t.obj()`](/docs/react/guides/translating-with-dictionaries#objects) o clave por clave.
* **Claves faltantes.** next-intl registra un error y renderiza un contenido alternativo; gt-next lanza una excepción, así que comprueba si una clave se usa antes de eliminarla del catálogo.

Después, ejecuta [`npx gt validate`](/docs/cli/reference/commands/validate) para detectar entradas que no sean ICU válido, y [`npx gt translate --dictionary ./messages/en.json`](/docs/cli/reference/commands/translate) para generar traducciones de las claves que faltan en tus catálogos y de cualquier configuración regional nueva. La CLI solo detecta un diccionario automáticamente si se llama `dictionary.json`, `.ts` o `.js` y está en la raíz del proyecto o en `src/`, así que pasa `--dictionary ./messages/en.json` a ambos comandos, tanto en local como en CI, mientras mantengas el catálogo:

```bash
npx gt validate --dictionary ./messages/en.json
npx gt translate --dictionary ./messages/en.json
```

## Paso 4: Mueve los textos inline, ruta por ruta

Las claves siguen funcionando, así que puedes detenerte aquí. Si quieres mantener los textos junto al JSX que los renderiza, muévelos a [`<T>`](/docs/react/reference/components/t) ruta por ruta, empezando por los mensajes de `t.rich`:

```tsx
// Antes: "terms": "By continuing you accept the <link>terms</link>."
t.rich('terms', { link: (chunks) => <a href="/terms">{chunks}</a> });

// Después
<T>
  By continuing you accept the <a href="/terms">terms</a>.
</T>
```

En los Componentes de servidor asíncronos, usa [`getGT`](/docs/react/nextjs/reference/functions/get-gt) para las cadenas simples. El mismo comando [`npx gt translate`](/docs/cli/reference/commands/translate) genera nuevas traducciones para el texto que pases a inline, usando el JSX que lo rodea como contexto. Los revisores pueden corregirlas en el [panel de control](/docs/platform/dashboard/guides/reviewing-translations), y el glosario de un [grupo de contexto](/docs/platform/dashboard/guides/defining-context-for-translations) mantiene la coherencia de tu terminología. Elimina cada clave de tus catálogos en cuanto ya no se lea en ningún sitio.

## Paso 5: Elimina next-intl

Cuando una búsqueda de `next-intl` ya no devuelva resultados, elimina la dependencia y `createNextIntlPlugin`, y prueba una compilación de producción en cada configuración regional. Después, añade [`npx gt translate`](/docs/cli/reference/commands/translate) a tu compilación o a tu [CI](/kb/translations-in-ci) para que los textos nuevos se publiquen ya traducidos, con `--dictionary ./messages/en.json` si conservaste el catálogo.

## Preguntas frecuentes

### ¿Cambiarán mis URL?

No en el caso de los prefijos de configuración regional estándar, siempre que repliques la configuración de next-intl: `localePrefix: 'as-needed'` corresponde al valor predeterminado de gt-next, y `'always'`, a `prefixDefaultLocale: true`. gt-next también usa un segmento `app/[locale]`. Las rutas localizadas requieren un mapeo explícito en `pathConfig`, y los prefijos personalizados y el enrutamiento basado en dominios no tienen un equivalente directo en gt-next, así que configura redirecciones para esas URL y prueba todas las rutas antes de eliminar el enrutamiento de next-intl.

### ¿Pierdo mis traducciones existentes?

No. Carga tus catálogos de next-intl con [`loadDictionary`](/docs/react/reference/functions/load-dictionary) y se seguirán renderizando como hasta ahora. General Translation solo traduce las claves que les falten, además de cualquier texto que más adelante muevas inline a [`<T>`](/docs/react/reference/components/t).

### ¿gt-next admite el renderizado estático?

Sí. Agrega un archivo `getLocale.ts` en la raíz del proyecto y `generateStaticParams`. (Consulta [Generación de Sitios Estáticos](/docs/react/nextjs/app-router-static-site-generation)).

### ¿Es gratis gt-next?

gt-next tiene licencia MIT y renderiza traducciones empaquetadas sin necesidad de una cuenta. La generación de traducciones con General Translation se factura [según el uso](https://generaltranslation.com/pricing).

## Puntos clave

* Reemplaza el plugin, el middleware, la configuración de solicitudes y el proveedor de next-intl por `withGTConfig`, [`createNextMiddleware`](/docs/react/nextjs/reference/functions/create-next-middleware), `getLocale.ts` y [`GTProvider`](/docs/react/reference/components/gt-provider).
* Conserva `messages/en.json` como diccionario de gt-next y carga tus catálogos traducidos mediante [`loadDictionary`](/docs/react/reference/functions/load-dictionary); los mensajes ICU funcionan sin cambios.
* Haz coincidir `localePrefix` con `prefixDefaultLocale` y conserva la cookie `NEXT_LOCALE` para que las URL estándar con configuración regional y las preferencias guardadas sigan funcionando; asigna las rutas localizadas con `pathConfig` antes de eliminar el enrutamiento de next-intl.
* Reescribe `t.rich` como [`<T>`](/docs/react/reference/components/t) y, después, traslada el resto del texto inline, ruta por ruta.

## Related questions

- [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 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.
- [¿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.
- [Redirecciones de idioma y SEO: ¿URL, cookie o Accept-Language?](https://generaltranslation.com/es/kb/locale-routing-seo.mdx): Deja que la URL determine el idioma de cada página que quieras indexar, porque Googlebot no envía la cabecera Accept-Language y rastrea sobre todo desde direcciones de EE. UU. Recurre a la preferencia guardada en una cookie y, en su defecto, a Accept-Language solo para decidir adónde redirige una raíz neutral como /, mediante una redirección temporal 302 o 307.
- [¿Cómo mantengo las traducciones actualizadas en cada despliegue?](https://generaltranslation.com/es/kb/translations-in-ci.mdx): Ejecuta la traducción como un paso del flujo antes de cada compilación de producción, para que el texto nuevo se publique ya traducido en el mismo despliegue que lo incorpora. La CLI gt de General Translation lo hace con npx gt translate, usando una clave de API del proyecto y el ID del proyecto almacenados como secretos de CI.

## Previous and next questions

- Previous question: [¿Qué herramientas de traducción cobran por uso en lugar de por puesto?](https://generaltranslation.com/es/kb/translation-pricing-without-seat-fees.mdx)
- Next question: [¿Cómo migro de react-i18next a gt-react?](https://generaltranslation.com/es/kb/migrate-from-react-i18next.mdx)

## Sitemap

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