
Para aumentar el tráfico a mi blog, decidí probar la configuración multilingüe.
Investigué varias maneras y el primer paso es enrutar por idioma.
Decidí usar next-intl.
1. Instalación
yarn add next-intl2. Aplicación
La aplicación es algo complicada.
Aproximadamente se sigue el siguiente orden:
Colocar toda la estructura de carpetas internas de la app dentro de la carpeta [locale].
Crear una carpeta i18n y generar config.ts, request.ts, ko.json, en.json en su interior.
Configurar en middleware.ts y next.config.ts.
Envolver niños con params y provider en el layout.
Cargar mensajes en los componentes.
3. Probar
1) Carpeta [locale]

Esta es la estructura de carpetas interna de mi app.
Voy a envolver todas las carpetas excepto api y uploads dentro de [locale].
Al mover carpetas con .next presente, se produce un error de permisos, así que elimínelo con sudo rm -r .next y luego mueva las carpetas.
Es importante adaptar las llamadas de rutas relativas ya que la estructura de carpetas ha cambiado.

2) Crear carpeta i18n
Si tiene una carpeta src, puede crearla dentro de src; de lo contrario, simplemente en la raíz si solo usa la carpeta app.
Cree config.ts, request.ts en la carpeta i18n y ko.json, en.json en la carpeta message.

Configura config.ts como sigue:
Configuré la ruta base "/" al coreano.
export const locales = ['ko', 'en'] as const;
export type Locale = (typeof locales)[number];
export const defaultLocale: Locale = 'ko'; // Establece la ruta base en coreano
export const pathnames = {
'/': '/',
'/about': {
ko: '/about',
en: '/about',
},
'/post/[slug]': {
ko: '/post/[slug]',
en: '/post/[slug]',
},
} as const;Configura request.ts de la siguiente manera:
Se llama a la información del locale y se devuelve al servidor.
import { getRequestConfig } from 'next-intl/server';
import { defaultLocale } from './config';
export default getRequestConfig(async ({ requestLocale }: { requestLocale: Promise<string | undefined> }) => {
const locale = await requestLocale || defaultLocale;
return {
locale,
messages: (await import(`./message/${locale}.json`)).default,
};
});3) Configuración middleware.ts, next.config.ts
Primero, configura middleware.ts de la siguiente manera:
Es fácil pensar que se añade createMiddleware al principio como export.
import createMiddleware from 'next-intl/middleware';
import { locales, defaultLocale } from './i18n/config';
export createMiddleware({
locales,
defaultLocale,
localePrefix: 'as-needed', // El coreano (ko) no tiene prefijo en la ruta
});
//...configuraciones existentes...//
export default withAuth(
function middleware(req) {
//...configuraciones existentes...//
});Luego en next.config.ts, crea createNextIntlPlugin y envuelve las configuraciones existentes:
import type { NextConfig } from "next";
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin()
const withNextIntlConfig: NextConfig = withNextIntl({
configuraciones de next.config existentes...
});
export default withNextIntlConfig;4) Envolviendo el Layout
Ahora, obtén el locale con getMessage en el layout, envuelve con provider para que los componentes secundarios lo usen.
import { NextIntlClientProvider } from "next-intl";
import { getMessages, getLocale } from "next-intl/server";
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const messages = await getMessages();
const locale = await getLocale();
return (
<html
lang={locale}
>
<NextIntlClientProvider locale={locale} messages={messages}>
<body>
{children}
</body>
</NextIntlClientProvider>
</html>
);
}5) Usar mensajes
Los nombres de las funciones son diferentes cuando se renderiza en el lado servidor y el lado cliente.
import {useTranslations, useLocale, useFormatter} from 'next-intl'; // se llama desde el componente 'use client'
import {getTranslations, getLocale, getFormatter} from 'next-intl/server'; // se llama desde el componente del servidorCategoría | Componente Cliente | Componente Servidor / Función Servidor | Descripción |
|---|---|---|---|
Traducciones |
|
| Trae mensajes de traducción como |
Locale |
|
| Devuelve el locale activo como cadena ( |
Formatter |
|
| Formatea fecha, hora, números según el locale |
Mensajes | — |
| Objeto de mensajes de traducción completa de la solicitud actual (usualmente para layout como Provider) |
Establecer Locale de Solicitud | — |
| Se usa en layout para asegurar consistencia de locale en caching SSG·SSR |
Decidí cambiar /about.
El componente /about estaba codificado así que era bueno para cambios.
import {
HeroSection,
JourneySection,
ProjectsSection,
} from "@/components/about";
const baseUrl = process.env.NEXT_PUBLIC_URL||"";
export default function AboutPage() {
...
const heroData = {
...
};
const journeyData = {
title: "My Journey",
items: [
.....
]
};
const projectsData = {
title: "Featured Projects",
projects: [
{
title: "Análisis Estadístico de Admisiones",
...
},
...
],
};
return (
<div className="min-h-screen bg-gray-900 ">
<main className="rounded-lg container relative mx-auto scroll-my-12 overflow-auto">
{/* Selector de Idioma */}
<HeroSection {...heroData} />
<JourneySection {...journeyData} />
<ProjectsSection {...projectsData} />
</main>
</div>
);
}
Configura ko.json y en.json y utiliza getTranslations para insertar texto en el componente.

El problema es que lo obtenido con getTranslations es solo texto.
Intenté cambiarlo así y resultó en un error.
export default async function AboutPage() {
...
const t = await getTranslations("about");
const heroData = JSON.parse(JSON.stringify(t("hero")));
const journeyData = JSON.parse(JSON.stringify(t("journey")));
const projectsData = JSON.parse(JSON.stringify(t("projects")));
...
}Fue una molestia, así que pedí ayuda a Cursor.

De esta forma, se pasó a todos los componentes secundarios a través de props.
Luego verifiqué con en.

Puedo ver que se ha aplicado correctamente.
4. Conclusión
Hasta ahora pensaba que debía hacer todo el trabajo del blog en inglés manualmente, pero ahora con AI y herramientas automatizadas, será más fácil.
Lo que queda es traducir todas las entradas del blog e incorporarlas en la base de datos.
Luego agregaré el locale a la base de datos y recuperaré las publicaciones mediante búsquedas por locale.
Lo intentaré pronto.
댓글을 불러오는 중...