Next.js + next-intl: Aprende Internacionalización en 10 Minutos

¿Alguna vez pateaste el i18n para “después” y terminó quedando para nunca? A mí me pasó mil veces. Por eso armé este video corto donde, en 10 minutos, dejo lista una app de Next.js con internacionalización usando next-intl. Es simple, escalable y no tenés que pelearte con rutas raras ni mil providers.


Lo clave del video

¿Por qué next-intl?

  • Funciona perfecto con el App Router de Next.js.
  • Soporta server y client components.
  • Te da helpers para fechas, números y pluralización sin que tengas que reinventar la rueda.
  • Middleware listo para redirigir al locale correcto.

Estructura mínima que uso

  • Rutas con prefijo de idioma: /[locale]/...
  • Un middleware para detectar/forzar locale.
  • Un NextIntlClientProvider en el layout.
  • Archivos de mensajes por idioma.

1) Middleware para locales

Define qué idiomas soportás y el default. Listo, next-intl se encarga del resto.

// middleware.ts
import createMiddleware from 'next-intl/middleware';

export default createMiddleware({
  locales: ['es', 'en'],
  defaultLocale: 'es'
});

export const config = {
  // Evita interferir con assets internos y archivos estáticos
  matcher: ['/((?!_next|.*\\..*).*)']
};

2) Provider en el layout de cada locale

Cargamos los mensajes y envolvemos la app para que todo tenga acceso a las traducciones.

// app/[locale]/layout.tsx
import {NextIntlClientProvider} from 'next-intl';
import {notFound} from 'next/navigation';

export function generateStaticParams() {
  return [{locale: 'es'}, {locale: 'en'}];
}

export default async function LocaleLayout({
  children,
  params: {locale}
}: {
  children: React.ReactNode;
  params: {locale: 'es' | 'en'};
}) {
  let messages;
  try {
    messages = (await import(`../../messages/${locale}.json`)).default;
  } catch (error) {
    notFound();
  }

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider locale={locale} messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}

3) Mensajes por idioma

Definí tus textos por namespace. Ejemplo:

// messages/es.json
{
  "Home": {
    "title": "Bienvenido",
    "cta": "Ver vuelos"
  }
}
// messages/en.json
{
  "Home": {
    "title": "Welcome",
    "cta": "Browse flights"
  }
}

4) Usar traducciones en Server o Client

  • Server (recomendado cuando podés): getTranslations.
  • Client: useTranslations.
// app/[locale]/page.tsx (Server Component)
import {getTranslations} from 'next-intl/server';

export default async function Page({params: {locale}}: {params: {locale: 'es' | 'en'}}) {
  const t = await getTranslations({locale, namespace: 'Home'});
  return (
    <>
      <h1>{t('title')}</h1>
      <p>{t('cta')}</p>
    </>
  );
}
// components/CTA.tsx (Client Component)
'use client';

import {useTranslations} from 'next-intl';

export default function CTA() {
  const t = useTranslations('Home');
  return <button>{t('cta')}</button>;
}

5) Cambiador de idioma (sin romper la URL actual)

Usando el Link de next-intl y el pathname del App Router.

// components/LocaleSwitcher.tsx
'use client';

import {useLocale} from 'next-intl';
import {usePathname} from 'next/navigation';
import Link from 'next-intl/link';

export default function LocaleSwitcher() {
  const locale = useLocale();
  const pathname = usePathname();

  return (
    <nav>
      <Link href={pathname} locale="es" aria-current={locale === 'es' ? 'page' : undefined}>
        ES
      </Link>
      {' · '}
      <Link href={pathname} locale="en" aria-current={locale === 'en' ? 'page' : undefined}>
        EN
      </Link>
    </nav>
  );
}

Bonus: formateo de fechas y números

Queda muy pro y respeta el locale activo.

// components/Price.tsx
'use client';

import {useFormatter} from 'next-intl';

export default function Price({value}: {value: number}) {
  const f = useFormatter();
  return <span>{f.number(value, {style: 'currency', currency: 'USD'})}</span>;
}

Mirá el video completo


Recursos y repo

VER:  5 Apps que instalo SIEMPRE en todas mis macs

Cierre

Si venías esquivando el i18n, con next-intl ya no hay excusas. Queda prolijo, mantenible y te permite escalar a varios idiomas sin dolor. Cualquier duda me la dejás en comentarios, y si te sirvió, compartilo con ese/a amigo/a que siempre dice “lo hago después”. Nos vemos en el próximo, con más código y mate.

Loading

Esta entrada fue publicada el youtube. Agregá a favoritos el enlace permalink.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *