
为了增加我的博客的访问量,我考虑尝试设置多语言。
找到了多种方法,首先的一步是为语言设置不同的路由。
决定使用 next-intl 来实现。
1. 安装
yarn add next-intl2. 应用
应用稍显复杂。
大致按以下步骤进行。
将 app 内部的所有路由文件放到 [locale] 文件夹中。
创建 i18n 文件夹,并在其中设置 config.ts、request.ts、ko.json、en.json 文件
在 middleware.ts 和 next.config.ts 中进行设置
在布局中通过 params 和 provider 包装子组件
在组件中加载消息
3. 运行
1) [locale] 文件夹

我的 app 内部文件结构如上图所示。
我打算将 app 下所有除 api 和 uploads 外的文件夹都放在 [locale] 中。
由于 .next 存在时移动文件夹会出现权限错误,因此需通过 sudo rm -r .next 删除后再移动文件夹。
需注意,因文件结构改变,若存在使用相对路径的调用需修改。

2) 创建 i18n 文件夹
如有 src 文件夹的用户,在 src 下创建即可;仅使用 app 的用户可直接在根目录创建。
我在 i18n 文件夹内创建了 config.ts 和 request.ts,并在 message 文件夹内创建了 ko.json 和 en.json。

config.ts 文件设置如下。
我将空路径 "/" 设置为韩语。
export const locales = ['ko', 'en'] as const;
export type Locale = (typeof locales)[number];
export const defaultLocale: Locale = 'ko'; // 将默认路径设置为韩语
export const pathnames = {
'/': '/',
'/about': {
ko: '/about',
en: '/about',
},
'/post/[slug]': {
ko: '/post/[slug]',
en: '/post/[slug]',
},
} as const;request.ts 文件的设置如下。
调用 locale 信息并返回给服务器。
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) 设置 middleware.ts 和 next.config.ts
首先,middleware.ts 设置如下。
简单来说就是在上方用 export 添加 createMiddleware。
import createMiddleware from 'next-intl/middleware';
import { locales, defaultLocale } from './i18n/config';
export createMiddleware({
locales,
defaultLocale,
localePrefix: 'as-needed', // 默认(ko)路径无前缀
});
//...现有设置...//
export default withAuth(
function middleware(req) {
//...现有设置...//
});然后在 next.config.ts 中创建 createNextIntlPlugin,并将现有设置包裹起来。
import type { NextConfig } from "next";
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin()
const withNextIntlConfig: NextConfig = withNextIntl({
现有 next.config 设置...
});
export default withNextIntlConfig;4) 包装布局
在布局中,通过 getMessage 获取 locale 并用 provider 包裹,以便于下级组件使用。
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) 试用消息
服务器渲染和客户端渲染时函数名不同。
import {useTranslations, useLocale, useFormatter} from 'next-intl'; // 在 'use client' 组件中调用
import {getTranslations, getLocale, getFormatter} from 'next-intl/server'; // 在服务器组件中调用分类 | 客户端组件 | 服务器组件 / 服务器函数 | 说明 |
|---|---|---|---|
Translations |
|
| 获取 |
Locale |
|
| 返回当前激活的语言( |
Formatter |
|
| 格式化日期、时间、数字以适应语言环境 |
Messages | — |
| 获取当前请求的完整翻译消息对象(通常用于布局中的 Provider) |
Request Locale 设置 | — |
| 在 SSG·SSR 缓存时用于保证语言一致性时在布局中使用 |
我决定先尝试修改 /about。
当前我的 /about 组件如下面硬编码状态一样,因此易于修改。
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: "大入统计分析",
...
},
...
],
};
return (
<div className="min-h-screen bg-gray-900 ">
<main className="rounded-lg container relative mx-auto scroll-my-12 overflow-auto">
{/* Language Selector */}
<HeroSection {...heroData} />
<JourneySection {...journeyData} />
<ProjectsSection {...projectsData} />
</main>
</div>
);
}
现在设置 ko.json 和 en.json 后,可以通过 getTranslations 将文本插入组件。

然而,用 getTranslations 调用的信息仅为字符串结构。
试图像下方这样进行更改时出了错误。
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")));
...
}于是十分麻烦,寻求了光标(cursor)导航的帮助。

这样逐个将参数传递给下级组件。
之后用 en 进行访问,确认是否生效。

可以看到应用得很好。
4. 结论
直到现在我还以为需要手动翻译所有英语博客,但如今有了 AI 和许多自动化工具,这将变得更为简单。
剩下的工作是将博客中的所有文章翻译,并存入数据库。
然后在数据库中添加 locale,通过 locale 搜索返回 post。
我打算不久后试一下。
댓글을 불러오는 중...