Getting Started internationalizing (i18n) with Intlayer and Next.js 14 with App Router
What is Intlayer?
Intlayer es una innovadora biblioteca de internacionalización (i18n) de código abierto diseñada para simplificar el soporte multilingüe en aplicaciones web modernas. Intlayer se integra sin problemas con el último marco de Next.js 14, incluyendo su poderoso App Router. Está optimizado para trabajar con Server Components para una renderización eficiente y es totalmente compatible con Turbopack (de Next.js >= 15).
Con Intlayer, puedes:
- Gestionar fácilmente las traducciones utilizando 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.
- Asegurar soporte de TypeScript con tipos autogenerados, mejorando la autocompletación y la detección de errores.
- Beneficiarte de características avanzadas, como la detección y el cambio dinámico de locales.
Intlayer es compatible con Next.js 12, 13, 14 y 15. Si estás utilizando Next.js Page Router, puedes consultar esta guía. Para Next.js 15 con o sin turbopack, consulta esta guía.
Step-by-Step Guide to Set Up Intlayer in a Next.js Application
Step 1: Install Dependencies
Instala los paquetes necesarios usando npm:
npm install intlayer next-intlayer
intlayer
El paquete central que proporciona herramientas de internacionalización para 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 de Next.js. Además, incluye el plugin de Next.js para integrar Intlayer con Webpack o Turbopack, así como middleware para detectar el locale preferido del usuario, gestionar cookies y manejar la redirección de URLs.
Step 2: Configure Your Project
Crea un archivo de configuración para configurar los idiomas de tu aplicación:
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 de 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 parámetros disponibles, consulta la documentación de configuración.
Step 3: Integrate Intlayer in Your Next.js Configuration
Configura tu configuración de Next.js para usar Intlayer:
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. Asegura la construcción de archivos de declaración de contenido y los monitorea en modo de desarrollo. Define variables de entorno de Intlayer dentro de los entornos de Webpack o Turbopack. Además, proporciona aliases para optimizar el rendimiento y asegurar la compatibilidad con componentes del servidor.
Step 4: Configure Middleware for Locale Detection
Configura middleware para detectar el locale preferido del usuario:
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 el locale preferido del usuario y redirigirlo a la URL apropiada como se especifica en la configuración. Además, permite guardar el locale preferido del usuario en una cookie.
Adapta el parámetro matcher para que coincida con las rutas de tu aplicación. Para más detalles, consulta la documentación de Next.js sobre la configuración del matcher.
Step 5: Define Dynamic Locale Routes
Elimina todo de RootLayout y reemplázalo con el siguiente código:
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 enrutamiento dinámico, proporciona la ruta para el locale añadiendo un nuevo layout en tu directorio [locale]:
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 el locale. Ejemplo: /en-US/about se referirá a en-US y /fr/about a fr.
Luego, implementa la función generateStaticParams en el Layout de tu aplicación.
export { generateStaticParams } from "next-intlayer"; // Línea a insertarconst LocaleLayout: Next14LayoutIntlayer = ({ children, params: { locale },}) => { /*... Resto del código*/};export default LocaleLayout;
generateStaticParams asegura que tu aplicación pre-construya las páginas necesarias para todos los locales, reduciendo la computación en tiempo de ejecución y mejorando la experiencia del usuario. Para más detalles, consulta la documentación de Next.js sobre generateStaticParams.
Step 6: Declare Your Content
Crea y gestiona tus declaraciones de contenido para almacenar traducciones:
import { t, type DeclarationContent } 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 DeclarationContent;export default pageContent;
Tus declaraciones de contenido pueden definirse en cualquier lugar 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.{ts,tsx,js,jsx,mjs,cjs}). Para más detalles, consulta la documentación de declaración de contenido.
Step 7: Utilize Content in Your Code
Accede a tus diccionarios de contenido a lo largo de tu aplicación:
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 el locale a los componentes del lado del cliente. Se puede colocar en cualquier componente padre, incluyendo el layout. Sin embargo, se recomienda colocarlo en un layout porque el código del layout se comparte entre páginas en Next.js, lo que lo hace más eficiente. Al usar IntlayerClientProvider en el layout, evitas reinitializarlo para cada página, mejorando el rendimiento y manteniendo un contexto de localización consistente a lo largo de tu aplicación.
IntlayerServerProvider se utiliza para proporcionar el locale a los 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 del servidor se basa en un almacenamiento de datos por solicitud (a través del cache de React). Esto causa que cada "contexto" se recree para diferentes segmentos de la aplicación. Colocar el proveedor en un layout compartido rompería esta aislamiento, impidiendo la correcta propagación de los valores de contexto del servidor a tus componentes del servidor.
"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 relacionada return ( <div> <h2>{content.title} </h2> <p>{content.content}</p> </div> );};
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 relacionada return ( <div> <h2>{content.title} </h2> <p>{content.content}</p> </div> );};
Si deseas usar tu contenido en un atributo 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.
(Optional) Step 8: Internationalization of your metadata
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 la función, utiliza la función getTranslationContent para traducir tus metadatos.
import { type IConfigLocales, getTranslationContent, 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>) => getTranslationContent(content, locale); /** * Genera un objeto que contiene todas las urls para cada locale. * * Ejemplo: * ```ts * getMultilingualUrls('/about'); * * // Retorna * // { * // en: '/about', * // fr: '/fr/about', * // es: '/es/about', * // } * ``` */ const multilingualUrls = getMultilingualUrls("/"); 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", }), alternates: { canonical: "/", languages: { ...multilingualUrls, "x-default": "/" }, }, openGraph: { url: multilingualUrls[locale], }, };};// ... Resto del código
Aprende más sobre la optimización de metadatos en la documentación oficial de Next.js.
(Optional) Step 9: Internationalization of your sitemap.xml and 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.
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;
import type { MetadataRoute } from "next";import { getMultilingualUrls } from "intlayer";const getAllMultilingualUrls = (urls: string[]) => urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);const robots = (): MetadataRoute.Robots => ({ rules: { userAgent: "*", allow: ["/"], disallow: getAllMultilingualUrls(["/login", "/register"]), }, host: "https://example.com", sitemap: `https://example.com/sitemap.xml`,});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 de robots.txt en la documentación oficial de Next.js.
(Optional) Step 10: Change the language of your content
Para cambiar el idioma de tu contenido, puedes usar la función setLocale proporcionada por el hook useLocale. Esta función te permite establecer el locale de la aplicación y actualizar el contenido en consecuencia.
"use client";import { Locales, getHTMLTextDir, getLocaleName, getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import { type FC } from "react";const LocaleSwitcher: FC = () => { const { locale, pathWithoutLocale, availableLocales, setLocale } = useLocale(); return ( <ol> {availableLocales.map((localeItem) => ( <li key={localeItem}> <a href={getLocalizedUrl(pathWithoutLocale, localeItem)} hrefLang={localeItem} aria-current={locale === localeItem ? "page" : undefined} onClick={(e) => { e.preventDefault(); setLocale(localeItem); }} > <span> {/* Idioma en su propio locale - e.g. Français */} {getLocaleName(localeItem, locale)} </span> <span dir={getHTMLTextDir(localeItem)} lang={localeItem}> {/* Idioma en el locale actual - e.g. Francés con el locale actual configurado en Locales.SPANISH */} {getLocaleName(localeItem)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* Idioma en inglés - e.g. French */} {getLocaleName(localeItem, Locales.ENGLISH)} </span> <span> {/* Idioma en su propio locale - e.g. FR */} {localeItem} </span> </a> </li> ))} </ol> );};
Referencias de documentación:
Configure TypeScript
Intlayer utiliza la ampliación de módulos para beneficiarse de TypeScript y fortalecer tu base de código.
Asegúrate de que tu configuración de TypeScript incluya los tipos autogenerados.
{ // ... Tus configuraciones existentes de TypeScript "include": [ // ... Tus configuraciones existentes de TypeScript "types", // Incluir los tipos auto-generados ],}
Git Configuration
Se recomienda ignorar los archivos generados por Intlayer. Esto te permite evitar comprometerlos a tu repositorio de Git.
Para hacer esto, puedes agregar las siguientes instrucciones a tu archivo .gitignore:
# Ignorar los archivos generados por Intlayer.intlayer
Si tienes una idea para mejorar esta documentación, no dudes en contribuir enviando una pull request en GitHub.
Enlace de GitHub a la documentación