Cómo cargar traducciones desde archivos en Next.js (Pages Router) v16

Separar el contenido traducible del código

Problema

Codificar directamente las cadenas de texto destinadas al usuario en los componentes crea un acoplamiento estrecho entre el contenido y el código. Cada vez que cambia el texto, los desarrolladores deben localizar y modificar los archivos de implementación. Añadir soporte para un segundo idioma requiere encontrar cada cadena codificada y envolverla en lógica condicional. Un tercer idioma extiende aún más esa lógica. Este enfoque hace que los flujos de trabajo de traducción dependan de los despliegues de código e impide que los miembros no técnicos del equipo actualicen el contenido de forma independiente.

A medida que la aplicación crece, gestionar las traducciones se vuelve cada vez más difícil. Las cadenas dispersas en docenas de componentes son difíciles de auditar, duplicar o actualizar de manera consistente. Los traductores no pueden trabajar en paralelo con los desarrolladores porque necesitan acceso al código base en sí.

Solución

Almacenar todo el texto destinado al usuario en archivos de recursos externos, organizados por idioma, con un archivo JSON por localización. Cada mensaje se identifica mediante una clave única en lugar de su texto literal. Los componentes hacen referencia a estas claves en lugar de a cadenas codificadas.

Cargar el archivo de traducción apropiado basado en la configuración regional recibida de Next.js y pasar los mensajes al proveedor de react-intl. La aplicación puede entonces cambiar de idioma cargando un archivo diferente sin cambiar ningún código de componente. Esto desacopla el contenido de la implementación, permitiendo a los traductores trabajar en archivos JSON estándar mientras los desarrolladores hacen referencia a claves de mensaje estables.

Pasos

1. Crear archivos de traducción organizados por localización

Coloca los mensajes de traducción en archivos JSON separados por localización. Cada archivo contiene pares clave-valor donde las claves son identificadores estables y los valores son las cadenas traducidas para ese idioma.

{
"welcome": "Bienvenido de nuevo",
"greeting": "Hola, {name}",
"itemCount": "Tienes {count, plural, one {# elemento} other {# elementos}}"
}

Crea un archivo por cada localización soportada (por ejemplo, messages/en.json, messages/es.json, messages/fr.json) en un directorio messages en la raíz de tu proyecto. Utiliza las mismas claves en todos los archivos para que react-intl pueda buscar la traducción correcta para la localización activa.

2. Cargar mensajes en getStaticProps

Lee el archivo de traducción basado en la configuración regional recibida de Next.js en getStaticProps. Esto asegura que los mensajes estén disponibles del lado del servidor y se pasen a la página como props.

import { GetStaticProps } from "next";

export const getStaticProps: GetStaticProps = async (context) => {
  const locale = context.locale || "en";
  const messages = (await import(`../messages/${locale}.json`)).default;

  return {
    props: {
      messages,
    },
  };
};

La importación dinámica carga solo el archivo para la configuración regional actual. Next.js proporciona el valor locale automáticamente basado en la URL o las preferencias del usuario.

3. Pasar mensajes a IntlProvider en _app

Envuelve tu componente raíz con IntlProvider y configúralo con la configuración regional actual del usuario y los mensajes traducidos correspondientes. Accede a los mensajes desde pageProps para que cada página pueda proporcionar sus propias traducciones.

import { AppProps } from "next/app";
import { IntlProvider } from "react-intl";
import { useRouter } from "next/router";

export default function App({ Component, pageProps }: AppProps) {
  const { locale, defaultLocale } = useRouter();

  return (
    <IntlProvider
      locale={locale || "en"}
      defaultLocale={defaultLocale || "en"}
      messages={pageProps.messages}
    >
      <Component {...pageProps} />
    </IntlProvider>
  );
}

El proveedor hace que los mensajes estén disponibles para todos los componentes en el árbol. Cada página carga su propio archivo de mensajes a través de getStaticProps, y _app recibe esos mensajes a través de pageProps.

4. Referenciar mensajes por clave en los componentes

Utiliza el componente FormattedMessage o el hook useIntl de react-intl para mostrar texto traducido. Referencia los mensajes por su clave en lugar de codificar cadenas de texto directamente.

import { FormattedMessage, useIntl } from "react-intl";

export default function HomePage() {
  const intl = useIntl();
  const userName = "Alice";

  return (
    <div>
      <h1>
        <FormattedMessage id="welcome" />
      </h1>
      <p>
        <FormattedMessage id="greeting" values={{ name: userName }} />
      </p>
      <input placeholder={intl.formatMessage({ id: "searchPlaceholder" })} />
    </div>
  );
}

React-intl busca y formatea el mensaje traducido en el id dado. Si falta una traducción, utiliza el defaultMessage si se proporciona. Las variables pasadas en la prop values se interpolan en la cadena del mensaje.