Communitygithub.com

mwasobaddy/skills

Arquitectura e implementación de internacionalización para aplicaciones Next.js App Router: estructura de carpetas, enrutamiento con prefijo de locale, archivos de mensajes tipados, plurales ICU y SEO localizado con hreflang. Úselo al agregar o corregir múltiples idiomas o traducciones en un sitio o aplicación Next.js, eligiendo entre next-intl, Lingui y next-i18next, conectando un segmento [locale] con proxy o middleware, o migrando una aplicación solo en inglés a URLs localizadas. Se activa con i18n, localización, multi-idioma, traducciones, enrutamiento por locale, atributo lang, hreflang, next-intl.

¿Qué es skills?

Esta habilidad proporciona una guía estructural completa para implementar internacionalización (i18n) en aplicaciones Next.js que utilizan App Router. Cubre la selección de la biblioteca adecuada (recomendando next-intl como opción predeterminada), la arquitectura canónica de carpetas, la configuración desde cero, la migración de aplicaciones existentes y la resolución de problemas comunes. La habilidad es útil para desarrolladores que necesitan agregar soporte multilingüe, corregir problemas de localización o migrar aplicaciones solo en inglés a URLs localizadas. Funciona con Next.js App Router y plataformas como Claude Code, Cursor y Codex. Se basa en documentación detallada (SKILL.md) que incluye comparaciones de bibliotecas, configuraciones paso a paso, estrategias de SEO y scripts de evaluación para garantizar que la descripción de la habilidad active los prompts correctos.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mwasobaddy/skills/tree/HEAD/nextjs-i18n

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

i18n en Next.js

Guía estructural para poner una aplicación Next.js en varios idiomas: cómo debe ser el diseño de carpetas, qué falla cuando está mal y qué evitar.

Elija la biblioteca primero

Por defecto, use next-intl para cualquier proyecto nuevo con App Router. No necesita complemento de compilación, ni paso de macros, ni gestión de instancias por locale; los mensajes son JSON simple tipados a partir de su locale de origen.

BibliotecaÚsela cuandoCosto
next-intl (predeterminada)Nuevo trabajo con App Router, cualquier tamaño de equipoNinguno: JSON simple, sin generación de código
@lingui/reactQuiere extracción en tiempo de compilación y un runtime pequeño, o una capa de i18n común para React/Vue/AstroComplemento de macro SWC o Babel, versionado exacto
next-i18nextEl equipo ya conoce i18next, o migra código de Pages RouterInstancia por solicitud, división getT/useT
i18n integrado de Next.jsSolo Pages Router. Nunca App RouterNo aplicable

La configuración i18n: { locales, defaultLocale } de Next.js es solo para Pages Router. En App Router no hace nada: el enrutamiento por locale allí implica un segmento [locale] más un proxy. No permita que el agente "active" el i18n integrado para un proyecto de App Router.

Comparación completa, incluido el costo de bundle y las compensaciones por biblioteca: references/library-comparison.md.

Arquitectura canónica

Mantenga los diccionarios estáticos fuera de src/ para que el empaquetado y las rutas de importación sean obvias, y mantenga toda la maquinaria de locale en una carpeta.

messages/                      # diccionarios estáticos puros — mantener fuera de /src
├── en.json                     # fuente de verdad; cada otro locale lo refleja
├── de.json
└── ja.json
src/
├── i18n/
│   ├── routing.ts              # defineRouting: locales + defaultLocale
│   ├── request.ts              # getRequestConfig: resolver locale, cargar mensajes
│   └── navigation.ts           # createNavigation: Link/redirect consciente del locale
├── proxy.ts                    # detección de locale + redirección (Next 16; antes era middleware.ts)
└── app/
    ├── [locale]/               # envuelve toda la aplicación localizada
    │   ├── layout.tsx          # validar locale, <html lang>, generateStaticParams
    │   └── page.tsx
    └── not-found.tsx           # 404 global vive FUERA de [locale]

Reglas que hacen que esta estructura funcione:

  • [locale] es un segmento dinámico raíz. Todo lo localizado vive debajo de él. Las rutas raíz (not-found.tsx, error.tsx, api/) permanecen fuera y no deben llamar a hooks de i18n de forma incondicional, o fallarán en tiempo de ejecución.
  • Un locale de origen. messages/en.json es el maestro. Cada otro archivo debe reflejar exactamente su estructura.
  • Todo el conocimiento de locale en src/i18n/. Los componentes importan Link desde @/i18n/navigation, nunca desde next/link. Un solo lugar para agregar un idioma.

Configuración (proyecto nuevo)

Ejecute en este orden. El orden importa: proxy.ts depende de routing.ts, y el layout depende de request.ts.

  1. Instale next-intl, envuelva next.config.ts con createNextIntlPlugin().
  2. Cree src/i18n/routing.ts con defineRouting.
  3. Cree src/proxy.ts exportando createMiddleware(routing) más el matcher predeterminado.
  4. Cree src/i18n/request.ts con getRequestConfig resolviendo el locale.
  5. Mueva app/** bajo app/[locale]/**; agregue generateStaticParams y valide el parámetro.
  6. Cree src/i18n/navigation.ts con createNavigation(routing).
  7. Cree messages/en.json y reemplace las cadenas fijas con useTranslations.
  8. Establezca <html lang> y agregue metadatos localizados + hreflang.

Contenido exacto de los archivos para cada paso: references/next-intl-setup.md.

Problemas comunes

Lea esta sección antes de escribir cualquier código de i18n. Estos son los fallos que cuestan horas.

  • setRequestLocale es legado. En Next.js 16.3+, lea el locale con next/root-params dentro de getRequestConfig. La mayoría de las guías, tutoriales y datos de entrenamiento de LLM aún enseñan setRequestLocale(params.locale). Todavía funciona y está documentado como retrocompatible, pero es la API antigua. Úselo solo en Next < 16.3. generateStaticParams sigue siendo necesario de cualquier manera.
  • params es una Promesa en Next 15+. const {locale} = await params. Trate params.locale como un error de tipo, no de ejecución.
  • Valide el locale o los valores desconocidos se renderizan. Use hasLocale(routing.locales, locale) y notFound(). Sin esto, /xx/about renderiza su página en inglés en una URL falsa.
  • proxy.ts, no middleware.ts, en Next 16. middleware.ts está obsoleto. El proxy se ejecuta solo en Node.js: el runtime Edge no es compatible. Lingui y next-i18next promocionan proxies compatibles con Edge; si necesita Edge, tiene una compensación real, no una victoria gratuita.
  • Nunca concatene cadenas traducidas. "Tienes " + count + " elementos" es agramatical en japonés y árabe. Use ICU: "{count, plural, =1 {Un elemento} other {# elementos}}".
  • Nunca interpole con + o plantillas literales dentro de un mensaje. Use marcadores de posición con nombre — {name} — para que el orden de las palabras pueda cambiar.
  • Las fechas y números causan discrepancias de hidratación. new Date() en el servidor y en el navegador difieren por zona horaria y reloj. Establezca timeZone en getRequestConfig, o renderice solo en el cliente para tiempos relativos. Síntoma: "El contenido del texto no coincide con el HTML renderizado por el servidor".
  • El formato depende del locale. toLocaleString() sin un locale explícito formatea según el locale del runtime, no el locale solicitado. Use useFormatter() / getFormatter().
  • getRequestConfig se ejecuta por solicitud y es almacenado en caché por React. No coloque estado variable por solicitud (carrito, preferencias de usuario) allí. Solo configuración variable por locale.
  • Las Server Actions y Route Handlers no tienen parámetros raíz. await locale() funciona solo en Server Components. Pase el locale explícitamente como argumento en acciones y handlers.

Modernización de una aplicación existente

Trate esto como una migración con impacto en las URL, no como un cambio de configuración. Cada URL existente cambia de forma cuando agrega un prefijo [locale].

Planifique en este orden:

  1. Inventario de cadenas — ejecute scripts/find-untranslated.sh para encontrar texto JSX fijo.
  2. Elija la estrategia de enrutamiento antes de codificar. Prefijo de locale siempre (/en/about, /de/about) es el predeterminado; es inequívoco y limpio para hreflang. localePrefix: 'as-needed' sirve el locale predeterminado en la ruta simple — mejores URL, señal SEO más débil. Decida ahora; cambiar después es una migración completa.
  3. Configure el enrutamiento antes de tocar cualquier componente. Haga que proxy.ts + [locale] funcionen solo con mensajes en inglés.
  4. Mueva las rutas bajo [locale]/ — esto es un gran git mv mecánico. Hágalo en un solo commit para que git log --follow siga siendo útil.
  5. Reemplace cadenas por espacio de nombres, no por archivo. Traduzca un espacio de nombres de principio a fin para que la forma de la clave esté probada antes de que se multiplique.
  6. Agregue redirecciones para cada URL que cambió. /about → /en/about (o 307 al locale detectado). Sin esto, pierde todos los rankings existentes. No negociable.
  7. Agregue hreflang + metadatos localizados solo después de que cada locale tenga la ruta, o emitirá alternativas que apuntan a 404.

Secuencia completa de migración con notas sobre redirecciones y reversión: references/migration.md.

Qué evitar

  • No ponga messages/ dentro de src/. Los diccionarios solo del servidor en el árbol fuente desdibujan lo que se envía al cliente.
  • No importe Link desde next/link en rutas localizadas. Elimina el prefijo de locale y enlaza silenciosamente al idioma incorrecto.
  • No escriba manualmente prefijos de locale en los hrefs (href={/${locale}/about}). Use Link desde @/i18n/navigation, que maneja enrutamiento con prefijo, según necesidad y por dominio.
  • No use un espacio de nombres de claves plano. Agrupe por funcionalidad/página. Las claves planas chocan y no se pueden buscar.
  • No traduzca automáticamente en tiempo de compilación como fuente de verdad. La salida de la máquina es un borrador; comprometerla sin revisión hace que los errores sean permanentes y no rastreables.
  • No agregue un locale a routing.locales y lo dé por terminado. Sin un messages/xx.json traducido, cada página renderiza claves o retrocede silenciosamente.
  • No mezcle estrategias de enrutamiento. as-needed más un hreflang que apunta a URLs con prefijo es un error SEO autoinfligido.

Referencias

Léalas bajo demanda, no por adelantado:

  • references/library-comparison.md — elegir entre next-intl, Lingui, next-i18next; costo de bundle, desencadenantes de migración, forma de configuración por biblioteca.
  • references/next-intl-setup.md — cada archivo en la configuración canónica, listo para copiar y pegar.
  • references/messages-and-keys.md — estructura de espacios de nombres, nomenclatura de claves, sintaxis ICU, formato de fecha/número/lista, mensajes tipados.
  • references/seo.md — hreflang, <html lang>, generateMetadata localizado, canónico, alternativas de sitemap, reglas SEO para selector de locale.
  • references/migration.md — modernización de una aplicación existente, redirecciones, reversión.

Scripts

  • scripts/find-untranslated.sh — marca cadenas probablemente fijas dirigidas al usuario en un proyecto para que pueda dimensionar el trabajo antes de comenzar. Ejecútelo como paso 1 de una modernización.
  • scripts/run-trigger-eval.sh — mide si la description de esta habilidad se activa con los prompts correctos. Úselo al cambiar la descripción.

Prueba de la descripción

La description es lo único que el agente ve antes de decidir cargar esta habilidad. Si no se activa, nada de lo siguiente importa.

bash scripts/run-trigger-eval.sh --dry-run          # mostrar el plan, sin llamadas a la API
bash scripts/run-trigger-eval.sh --split train     # 12 consultas x 3 ejecuciones
bash scripts/run-trigger-eval.sh --split validation --out report.json

Conjunto de consultas: evals/trigger-queries.json — 12 deben activarse, 8 no deben activarse, divididas 60/40 en un conjunto fijo de entrenamiento y validación.

Al editar la descripción:

  • Corrija fallos usando solo el conjunto de entrenamiento. Toque el conjunto de validación una vez al final para verificar que el cambio se generaliza: si el entrenamiento mejora y la validación empeora, se sobreajustó.
  • Los fallos de "debe activarse" significan que la descripción es demasiado estrecha: agregue el concepto que representa la consulta, nunca las palabras clave de la consulta.
  • Los fallos de "no debe activarse" significan que es demasiado amplia: diga lo que la habilidad no cubre.
  • Vuelva a ejecutar antes de editar. La activación es no determinista, y una ejecución no prueba nada.

No agregue palabras clave de una consulta fallida: así es como las descripciones terminan pareciendo una lista de palabras clave y dejan de coincidir con prompts reales.

Skills relacionados