Recibe notificaciones sobre los próximos lanzamientos de Intlayer
    Creación:2024-12-06Última actualización:2025-06-29

    Comenzando con la internacionalización (i18n) usando Intlayer y Next.js 14 con App Router

    Consulta la Plantilla de Aplicación en GitHub.

    ¿Qué es Intlayer?

    Intlayer es una biblioteca innovadora y de código abierto para la internacionalización (i18n) diseñada para simplificar el soporte multilingüe en aplicaciones web modernas. Intlayer se integra perfectamente con el último framework Next.js 14, incluyendo su potente App Router. Está optimizada para trabajar con Componentes del Servidor para un renderizado eficiente y es totalmente compatible con Turbopack (a partir de Next.js >= 15).

    Con Intlayer, puedes:

    • Gestionar fácilmente las traducciones usando diccionarios declarativos a nivel de componente.
    • Localizar dinámicamente metadatos, rutas y contenido.
    • Acceder a las traducciones tanto en componentes del lado del cliente como del servidor.
    • Garantizar soporte para TypeScript con tipos autogenerados, mejorando la autocompletación y la detección de errores.
    • Beneficiarse de funciones avanzadas, como la detección y el cambio dinámico de idioma.

    Intlayer es compatible con Next.js 12, 13, 14 y 15. Si utilizas Next.js Page Router, puedes consultar esta guía. Para Next.js 15 con o sin turbopack, consulta esta guía.


    Guía paso a paso para configurar Intlayer en una aplicación Next.js

    Paso 1: Instalar dependencias

    Instala los paquetes necesarios usando npm:

    bash
    npm install intlayer next-intlayer
    • intlayer

      El paquete principal que proporciona herramientas de internacionalización para la gestión de configuración, traducción, declaración de contenido, transpilación y comandos CLI.

    • next-intlayer

    El paquete que integra Intlayer con Next.js. Proporciona proveedores de contexto y hooks para la internacionalización en Next.js. Además, incluye el plugin de Next.js para integrar Intlayer con Webpack o Turbopack, así como middleware para detectar el idioma preferido del usuario, gestionar cookies y manejar la redirección de URLs.

    Paso 2: Configura tu proyecto

    Crea un archivo de configuración para configurar los idiomas de tu aplicación:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // Tus otros locales    ],    defaultLocale: Locales.ENGLISH,  },};export default config;

    A través de este archivo de configuración, puedes configurar URLs localizadas, redirección en middleware, nombres de cookies, la ubicación y extensión de tus declaraciones de contenido, desactivar los registros de Intlayer en la consola, y más. Para una lista completa de los parámetros disponibles, consulta la documentación de configuración.

    Paso 3: Integra Intlayer en tu configuración de Next.js

    Configura tu entorno de Next.js para usar Intlayer:

    next.config.mjs
    import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {};export default withIntlayer(nextConfig);

    El plugin withIntlayer() de Next.js se utiliza para integrar Intlayer con Next.js. Garantiza la construcción de archivos de declaración de contenido y los supervisa en modo desarrollo. Define variables de entorno de Intlayer dentro de los entornos de Webpack o Turbopack. Además, proporciona alias para optimizar el rendimiento y asegura la compatibilidad con componentes del servidor.

    Paso 4: Configurar Middleware para la Detección de Idioma

    Configura el middleware para detectar el idioma preferido del usuario:

    src/middleware.ts
    export { intlayerMiddleware as middleware } from "next-intlayer/middleware";export const config = {  matcher:    "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",};

    El intlayerMiddleware se utiliza para detectar la configuración regional preferida del usuario y redirigirlo a la URL apropiada según lo especificado en la configuración. Además, permite guardar la configuración regional preferida del usuario en una cookie.

    Adapte el parámetro matcher para que coincida con las rutas de su aplicación. Para más detalles, consulte la documentación de Next.js sobre la configuración del matcher.

    Paso 5: Definir rutas dinámicas por configuración regional

    Elimine todo de RootLayout y reemplácelo con el siguiente código:

    src/app/layout.tsx
    import type { PropsWithChildren, FC } from "react";import "./globals.css";const RootLayout: FC<PropsWithChildren> = ({ children }) => children;export default RootLayout;

    Mantener el componente RootLayout vacío permite establecer los atributos lang y dir en la etiqueta <html>.

    Para implementar el enrutamiento dinámico, proporcione la ruta para la configuración regional agregando un nuevo layout en su directorio [locale]:

    src/app/[locale]/layout.tsx
    import type { Next14LayoutIntlayer } from "next-intlayer";import { Inter } from "next/font/google";import { getHTMLTextDir } from "intlayer";const inter = Inter({ subsets: ["latin"] });const LocaleLayout: Next14LayoutIntlayer = ({  children,  params: { locale },}) => (  <html lang={locale} dir={getHTMLTextDir(locale)}>    <body className={inter.className}>{children}</body>  </html>);export default LocaleLayout;

    El segmento de ruta [locale] se utiliza para definir la configuración regional. Ejemplo: /en-US/about se referirá a en-US y /fr/about a fr.

    En esta etapa, encontrará el error: Error: Missing <html> and <body> tags in the root layout.. Esto es esperado porque el archivo /app/page.tsx ya no se usa y puede eliminarse. En su lugar, el segmento de ruta [locale] activará la página /app/[locale]/page.tsx. En consecuencia, las páginas serán accesibles a través de rutas como /en, /fr, /es en su navegador. Para establecer la configuración regional predeterminada como la página raíz, consulte la configuración del middleware en el paso 4.

    Luego, implemente la función generateStaticParams en el Layout de su aplicación.

    src/app/[locale]/layout.tsx
    export { generateStaticParams } from "next-intlayer"; // Línea para insertarconst LocaleLayout: Next14LayoutIntlayer = ({  children,  params: { locale },}) => {  /*... Resto del código*/};export default LocaleLayout;

    generateStaticParams asegura que su aplicación precompile las páginas necesarias para todos los locales, reduciendo el cálculo en tiempo de ejecución y mejorando la experiencia del usuario. Para más detalles, consulte la documentación de Next.js sobre generateStaticParams.

    Paso 6: Declare su Contenido

    Cree y gestione sus declaraciones de contenido para almacenar traducciones:

    src/app/[locale]/page.content.ts
    import { t, type Dictionary } from "intlayer";const pageContent = {  key: "page",  content: {    getStarted: {      main: t({        en: "Get started by editing",        fr: "Commencez par éditer",        es: "Comience por editar",      }),      pageLink: "src/app/page.tsx",    },  },} satisfies Dictionary;export default pageContent;

    Tus declaraciones de contenido pueden definirse en cualquier parte de tu aplicación tan pronto como se incluyan en el directorio contentDir (por defecto, ./src). Y coincidan con la extensión del archivo de declaración de contenido (por defecto, .content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}).

    Para más detalles, consulta la documentación de declaración de contenido.

    Paso 7: Utiliza el contenido en tu código

    Accede a tus diccionarios de contenido a lo largo de tu aplicación:

    src/app/[locale]/page.tsx
    import { ClientComponentExample } from "@components/ClientComponentExample";import { ServerComponentExample } from "@components/ServerComponentExample";import { type Next14PageIntlayer, IntlayerClientProvider } from "next-intlayer";import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";const Page: Next14PageIntlayer = ({ params: { locale } }) => {  const content = useIntlayer("page", locale);  return (    <>      <p>        {content.getStarted.main}        <code>{content.getStarted.pageLink}</code>      </p>      <IntlayerServerProvider locale={locale}>        <IntlayerClientProvider locale={locale}>          <ServerComponentExample />          <ClientComponentExample />        </IntlayerClientProvider>      </IntlayerServerProvider>    </>  );};export default Page;
    • IntlayerClientProvider se utiliza para proporcionar la configuración regional a los componentes del lado del cliente. Puede colocarse en cualquier componente padre, incluido el layout. Sin embargo, se recomienda colocarlo en un layout porque Next.js comparte el código del layout entre páginas, lo que lo hace más eficiente. Al usar IntlayerClientProvider en el layout, se evita reinicializarlo en cada página, mejorando el rendimiento y manteniendo un contexto de localización consistente en toda la aplicación.
    • IntlayerServerProvider se utiliza para proporcionar la configuración regional a los hijos del servidor. No puede establecerse en el layout.

    • IntlayerClientProvider se utiliza para proporcionar la configuración regional a los componentes del lado del cliente. Puede colocarse en cualquier componente padre, incluido el layout. Sin embargo, se recomienda colocarlo en un layout porque Next.js comparte el código del layout entre páginas, lo que lo hace más eficiente. Al usar IntlayerClientProvider en el layout, se evita reinicializarlo en cada página, mejorando el rendimiento y manteniendo un contexto de localización consistente en toda su aplicación.

    • IntlayerServerProvider se utiliza para proporcionar la configuración regional a los componentes hijos del servidor. No puede establecerse en el layout.

    El layout y la página no pueden compartir un contexto de servidor común porque el sistema de contexto de servidor se basa en un almacén de datos por solicitud (a través del mecanismo de caché de React), lo que provoca que cada “contexto” se recree para diferentes segmentos de la aplicación. Colocar el proveedor en un layout compartido rompería este aislamiento, impidiendo la correcta propagación de los valores del contexto del servidor a tus componentes de servidor.

    src/components/ClientComponentExample.tsx
    "use client";import type { FC } from "react";import { useIntlayer } from "next-intlayer";const ClientComponentExample: FC = () => {  const content = useIntlayer("client-component-example"); // Crear declaración de contenido relacionado  return (    <div>      <h2>{content.title}</h2>      <p>{content.content}</p>    </div>  );};
    src/components/ServerComponentExample.tsx
    import type { FC } from "react";import { useIntlayer } from "next-intlayer/server";const ServerComponentExample: FC = () => {  const content = useIntlayer("server-component-example"); // Crear declaración de contenido relacionado  return (    <div>      <h2>{content.title}</h2>      <p>{content.content}</p>    </div>  );};

    Si deseas usar tu contenido en un atributo de tipo string, como alt, title, href, aria-label, etc., debes llamar al valor de la función, así:

    jsx
    <img src={content.image.src.value} alt={content.image.value} />

    Para aprender más sobre el hook useIntlayer, consulta la documentación.

    (Opcional) Paso 8: Internacionalización de tus metadatos

    En caso de que desees internacionalizar tus metadatos, como el título de tu página, puedes usar la función generateMetadata proporcionada por Next.js. Dentro de esta función, puedes obtener el contenido desde la función getIntlayer para traducir tus metadatos.

    src/app/[locale]/metadata.content.ts
    import { type Dictionary, t } from "intlayer";import { Metadata } from "next";const metadataContent = {  key: "page-metadata",  content: {    title: t({      en: "Create Next App",      fr: "Créer une application Next.js",      es: "Crear una aplicación Next.js",    }),    description: t({      en: "Generated by create next app",      fr: "Généré par create next app",      es: "Generado por create next app",    }),  },} satisfies Dictionary<Metadata>;export default metadataContent;
    src/app/[locale]/layout.tsx or src/app/[locale]/page.tsx
    import { getIntlayer, getMultilingualUrls } from "intlayer";import type { Metadata } from "next";import type { LocalParams } from "next-intlayer";export const generateMetadata = ({  params: { locale },}: LocalParams): Metadata => {  const metadata = getIntlayer("page-metadata", locale);  /**   * Genera un objeto que contiene todas las URL para cada idioma.   *   * Ejemplo:   * ```ts   *  getMultilingualUrls('/about');   *   *  // Devuelve   *  // {   *  //   en: '/about',   *  //   fr: '/fr/about',   *  //   es: '/es/about',   *  // }   * ```   */  const multilingualUrls = getMultilingualUrls("/");  return {    ...metadata,    alternates: {      canonical: multilingualUrls[locale as keyof typeof multilingualUrls],      languages: { ...multilingualUrls, "x-default": "/" },    },    openGraph: {      url: multilingualUrls[locale],    },  };};javascript fileName="src/app/[locale]/layout.mjs or src/app/[locale]/page.mjs" codeFormat="esm"import { getIntlayer, getMultilingualUrls } from "intlayer";export const generateMetadata = ({ params: { locale } }) => {  const metadata = getIntlayer("page-metadata", locale);  /**   * Genera un objeto que contiene todas las URLs para cada localización.   *   * Ejemplo:   * ```ts   *  getMultilingualUrls('/about');   *   *  // Retorna   *  // {   *  //   en: '/about',   *  //   fr: '/fr/about',   *  //   es: '/es/about'   *  // }   * ```   */  const multilingualUrls = getMultilingualUrls("/");  return {    ...metadata,    alternates: {      canonical: multilingualUrls[locale],      languages: { ...multilingualUrls, "x-default": "/" },    },    openGraph: {      url: multilingualUrls[locale],    },  };};// ... Resto del código

    Tenga en cuenta que la función getIntlayer importada desde next-intlayer devuelve su contenido envuelto en un IntlayerNode, lo que permite la integración con el editor visual. En contraste, la función getIntlayer importada desde intlayer devuelve su contenido directamente sin propiedades adicionales.

    Alternativamente, puede usar la función getTranslation para declarar sus metadatos. Sin embargo, se recomienda usar archivos de declaración de contenido para automatizar la traducción de sus metadatos y externalizar el contenido en algún momento.

    src/app/[locale]/layout.tsx or src/app/[locale]/page.tsx
    import {  type IConfigLocales,  getTranslation,  getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalParams } from "next-intlayer";export const generateMetadata = ({  params: { locale },}: LocalParams): Metadata => {  const t = <T>(content: IConfigLocales<T>) => getTranslation(content, locale);  return {    title: t<string>({      en: "My title",      fr: "Mon titre",      es: "Mi título",    }),    description: t({      en: "My description",      fr: "Ma description",      es: "Mi descripción",    }),  };};// ... Resto del código

    Aprende más sobre la optimización de metadatos en la documentación oficial de Next.js.

    (Opcional) Paso 9: Internacionalización de tu sitemap.xml y robots.txt

    Para internacionalizar tu sitemap.xml y robots.txt, puedes usar la función getMultilingualUrls proporcionada por Intlayer. Esta función te permite generar URLs multilingües para tu sitemap.

    src/app/sitemap.ts
    import { getMultilingualUrls } from "intlayer";import type { MetadataRoute } from "next";const sitemap = (): MetadataRoute.Sitemap => [  {    url: "https://example.com",    alternates: {      languages: getMultilingualUrls("https://example.com"),    },  },  {    url: "https://example.com/login",    alternates: {      languages: getMultilingualUrls("https://example.com/login"),    },  },  {    url: "https://example.com/register",    alternates: {      languages: getMultilingualUrls("https://example.com/register"),    },  },];export default sitemap;
    src/app/robots.ts
    import type { MetadataRoute } from "next";import { getMultilingualUrls } from "intlayer";// Obtiene todas las URLs multilingües a partir de una lista de URLs baseconst getAllMultilingualUrls = (urls: string[]) =>  urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);// Define las reglas para el archivo robots.txtconst robots = (): MetadataRoute.Robots => ({  rules: {    userAgent: "*",    allow: ["/"],    disallow: getAllMultilingualUrls(["/login", "/register"]),  },  host: "https://example.com",  sitemap: `https://example.com/sitemap.xml`,});export default robots;export default robots;

    Aprende más sobre la optimización del sitemap en la documentación oficial de Next.js. Aprende más sobre la optimización del archivo robots.txt en la documentación oficial de Next.js.

    (Opcional) Paso 10: Cambia el idioma de tu contenido

    Para cambiar el idioma de tu contenido en Next.js, la forma recomendada es usar el componente Link para redirigir a los usuarios a la página localizada correspondiente. El componente Link permite la precarga de la página, lo que ayuda a evitar una recarga completa.

    src/components/LocaleSwitcher.tsx
    "use client";import {  Locales,  getHTMLTextDir,  getLocaleName,  getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import { type FC } from "react";import Link from "next/link";const LocaleSwitcher: FC = () => {  const { locale, pathWithoutLocale, availableLocales } = useLocale();  const { setLocaleCookie } = useLocaleCookie();  return (    <div>      <button popoverTarget="localePopover">{getLocaleName(locale)}</button>      <div id="localePopover" popover="auto">        {availableLocales.map((localeItem) => (          <Link            href={getLocalizedUrl(pathWithoutLocale, localeItem)}            hrefLang={localeItem}            key={localeItem}            aria-current={locale === localeItem ? "page" : undefined}            onClick={() => setLocaleCookie(localeItem)}          >            <span>              {/* Localización - p.ej. FR */}              {localeItem}            </span>            <span>              {/* Idioma en su propia localización - p.ej. Français */}              {getLocaleName(localeItem, locale)}            </span>            <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>              {/* Idioma en la configuración regional actual - por ejemplo, Francés con la configuración regional establecida en Locales.SPANISH */}              {getLocaleName(localeItem)}            </span>            <span dir="ltr" lang={Locales.ENGLISH}>              {/* Idioma en inglés - por ejemplo, French */}              {getLocaleName(localeItem, Locales.ENGLISH)}            </span>          </Link>        ))}      </div>    </div>  );};

    Una forma alternativa es usar la función setLocale proporcionada por el hook useLocale. Esta función no permitirá la precarga de la página y recargará la página.

    En este caso, sin redirección usando router.push, solo el código del lado del servidor cambiará el idioma del contenido.

    src/components/LocaleSwitcher.tsx
    "use client";import { useRouter } from "next/navigation";import { useLocale } from "next-intlayer";import { getLocalizedUrl } from "intlayer";// ... Resto del códigoconst router = useRouter();const { setLocale } = useLocale({  onLocaleChange: (locale) => {    router.push(getLocalizedUrl(pathWithoutLocale, locale));  },});return (  <button onClick={() => setLocale(Locales.FRENCH)}>Cambiar a francés</button>);

    Referencias de la documentación:

    (Opcional) Paso 11: Crear un Componente de Enlace Localizado

    Para asegurar que la navegación de tu aplicación respete la configuración regional actual, puedes crear un componente personalizado Link. Este componente antepone automáticamente a las URLs internas el idioma actual. Por ejemplo, cuando un usuario francófono hace clic en un enlace a la página "Acerca de", es redirigido a /fr/about en lugar de /about.

    Este comportamiento es útil por varias razones:

    • SEO y Experiencia de Usuario: Las URLs localizadas ayudan a los motores de búsqueda a indexar correctamente las páginas específicas por idioma y proporcionan a los usuarios contenido en su idioma preferido.
    • Consistencia: Al usar un enlace localizado en toda su aplicación, garantiza que la navegación se mantenga dentro del idioma actual, evitando cambios inesperados de idioma.
    • Mantenibilidad: Centralizar la lógica de localización en un solo componente simplifica la gestión de URLs, haciendo que su base de código sea más fácil de mantener y ampliar a medida que su aplicación crece.

    A continuación se muestra la implementación de un componente Link localizado en TypeScript:

    src/components/Link.tsx
    "use client";import { getLocalizedUrl } from "intlayer";import NextLink, { type LinkProps as NextLinkProps } from "next/link";import { useLocale } from "next-intlayer";import { forwardRef, PropsWithChildren, type ForwardedRef } from "react";/**/** * Función utilitaria para verificar si una URL dada es externa. * Si la URL comienza con http:// o https://, se considera externa. */export const checkIsExternalLink = (href?: string): boolean =>  /^https?:\/\//.test(href ?? "");/** * Un componente Link personalizado que adapta el atributo href según la configuración regional actual. * Para enlaces internos, utiliza `getLocalizedUrl` para anteponer la configuración regional a la URL (por ejemplo, /fr/about). * Esto asegura que la navegación se mantenga dentro del mismo contexto de configuración regional. */export const Link = forwardRef<  HTMLAnchorElement,  PropsWithChildren<NextLinkProps>>(({ href, children, ...props }, ref: ForwardedRef<HTMLAnchorElement>) => {  const { locale } = useLocale();  const isExternalLink = checkIsExternalLink(href.toString());  // Si el enlace es interno y se proporciona un href válido, obtener la URL localizada.  const hrefI18n: NextLinkProps["href"] =    href && !isExternalLink ? getLocalizedUrl(href.toString(), locale) : href;  return (    <NextLink href={hrefI18n} ref={ref} {...props}>      {children}    </NextLink>  );});Link.displayName = "Link";

    Cómo Funciona

    • Detección de Enlaces Externos:
      La función auxiliar checkIsExternalLink determina si una URL es externa. Los enlaces externos se dejan sin cambios porque no necesitan localización.

    • Obtención del Locale Actual:
      El hook useLocale proporciona el locale actual (por ejemplo, fr para francés).

    • Localización de la URL:
      Para enlaces internos (es decir, no externos), se utiliza getLocalizedUrl para anteponer automáticamente la URL con la configuración regional actual. Esto significa que si tu usuario está en francés, pasar /about como href se transformará en /fr/about.

    • Devolviendo el enlace:
      El componente devuelve un elemento <a> con la URL localizada, asegurando que la navegación sea coherente con la configuración regional.

    Al integrar este componente Link en toda tu aplicación, mantienes una experiencia de usuario coherente y consciente del idioma, además de beneficiarte de una mejor SEO y usabilidad.

    (Opcional) Paso 12: Optimiza el tamaño de tu paquete

    Al usar next-intlayer, los diccionarios se incluyen en el paquete para cada página por defecto. Para optimizar el tamaño del paquete, Intlayer proporciona un plugin SWC opcional que reemplaza inteligentemente las llamadas a useIntlayer usando macros. Esto asegura que los diccionarios solo se incluyan en los paquetes de las páginas que realmente los usan.

    Para habilitar esta optimización, instala el paquete @intlayer/swc. Una vez instalado, next-intlayer detectará y usará automáticamente el plugin:

    bash
    npm install @intlayer/swc --save-dev

    Nota: Esta optimización solo está disponible para Next.js 13 y versiones superiores.

    Nota: Este paquete no se instala por defecto porque los plugins SWC aún son experimentales en Next.js. Esto podría cambiar en el futuro.

    Configurar TypeScript

    Intlayer utiliza la ampliación de módulos para aprovechar las ventajas de TypeScript y fortalecer tu base de código.

    alt text

    alt text

    Asegúrate de que tu configuración de TypeScript incluya los tipos generados automáticamente.

    tsconfig.json
    {  // ... Tus configuraciones existentes de TypeScript  "include": [    // ... Tus configuraciones existentes de TypeScript    ".intlayer/**/*.ts", // Incluir los tipos generados automáticamente  ],}

    Configuración de Git

    Se recomienda ignorar los archivos generados por Intlayer. Esto te permite evitar comprometerlos en tu repositorio Git.

    Para hacer esto, puedes agregar las siguientes instrucciones a tu archivo .gitignore:

    .gitignore
    # Ignorar los archivos generados por Intlayer.intlayer

    Extensión para VS Code

    Para mejorar tu experiencia de desarrollo con Intlayer, puedes instalar la Extensión oficial de Intlayer para VS Code.

    Instalar desde el Marketplace de VS Code

    Esta extensión proporciona:

    • Autocompletado para las claves de traducción.
    • Detección de errores en tiempo real para traducciones faltantes.
    • Vistas previas en línea del contenido traducido.
    • Acciones rápidas para crear y actualizar traducciones fácilmente.

    Para más detalles sobre cómo usar la extensión, consulta la documentación de la extensión Intlayer para VS Code.

    Ir Más Allá

    Para ir más allá, puedes implementar el editor visual o externalizar tu contenido usando el CMS.

    Historial del Documento

    • 5.5.10 - 2025-06-29: Historial inicial
    Recibe notificaciones sobre los próximos lanzamientos de Intlayer