i18n
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesei18n (Internationalization)
国际化(i18n)
This project uses a custom, library-free i18n implementation. There is no , , or similar dependency.
next-intli18nextDEPENDENCY NOTICE: If you are bootstrapping a new project using this architecture, read i18n Utilities Reference immediately to copy the exact implementation for , , and so your components compile correctly.
LocaleProviderdetermineLocalesetLocaleAction本项目采用无依赖库的自定义国际化实现,未使用、或类似依赖。
next-intli18next依赖注意事项:如果您正基于该架构启动新项目,请立即阅读i18n工具参考文档,复制、和的完整实现,以确保组件正确编译。
LocaleProviderdetermineLocalesetLocaleAction1. Core Primitives
1. 核心基础代码
typescript
export const LOCALES = ["en", "es"] as const;
export const DEFAULT_LOCALE = "en";
export type LOCALE = (typeof LOCALES)[number];
export type Translations<T extends object> = Record<LOCALE, T>;typescript
export const LOCALES = ["en", "es"] as const;
export const DEFAULT_LOCALE = "en";
export type LOCALE = (typeof LOCALES)[number];
export type Translations<T extends object> = Record<LOCALE, T>;2. Translation Co-location Rule
2. 翻译代码内聚规则
Translations MUST NOT be stored in separate JSON/YAML files. They MUST be defined in the same file (or a sibling) as the component or page that uses them, as a typed .
const翻译内容不得存储在独立的JSON/YAML文件中,必须作为类型化定义在使用该翻译的组件或页面的**同一文件(或同级文件)**中。
constFlat structure (few keys)
扁平结构(少量翻译键)
typescript
const translations: Translations<{
title: string;
description: string;
}> = {
en: { title: "Create", description: "Fill details." },
es: { title: "Crear", description: "Complete detalles." },
};typescript
const translations: Translations<{
title: string;
description: string;
}> = {
en: { title: "Create", description: "Fill details." },
es: { title: "Crear", description: "Complete detalles." },
};Extracting to a sibling file (large components)
提取至同级文件(大型组件)
When the object grows large enough to distract from the component logic, you MUST move it to a sibling file named , co-located next to the component.
translations<component>.i18n.ts当对象过大,影响组件逻辑阅读时,必须将其移至组件的同级文件中,文件命名为****。
translations<component>.i18n.ts3. Accessing the Locale
3. 访问区域设置
CRITICAL: You MUST NOT read the locale from theURL segment (page[locale]). You MUST always useparamsin Server Components ordetermineLocale()in Client Components. The source of truth is the cookie/header injected by middleware.useLocale()
重要提示:禁止从URL路径段(页面[locale])读取区域设置。在服务端组件(Server Components)中必须使用params,在客户端组件(Client Components)中必须使用determineLocale()。真实数据源是中间件注入的Cookie/请求头。useLocale()
In Server Components (RSC)
在服务端组件(RSC)中
You MUST use . It is memoized per-request via React .
determineLocale()cachetypescript
import { determineLocale } from "@/shared/infrastructure/i18n/utils";
export default async function MyPage() {
const locale = await determineLocale();
const t = translations[locale];
return <h1>{t.title}</h1>;
}必须使用,该方法通过React 实现了按请求缓存。
determineLocale()cachetypescript
import { determineLocale } from "@/shared/infrastructure/i18n/utils";
export default async function MyPage() {
const locale = await determineLocale();
const t = translations[locale];
return <h1>{t.title}</h1>;
}In Client Components
在客户端组件中
You MUST use the hook. The Client Component MUST be rendered inside a parent .
useLocale()<LocaleProvider locale={locale}>typescript
"use client";
import { useLocale } from "@/shared/presentation/components/LocaleProvider";
export function MyClientComponent() {
const locale = useLocale();
const t = translations[locale];
return <p>{t.description}</p>;
}必须使用钩子。客户端组件必须在父组件内部渲染。
useLocale()<LocaleProvider locale={locale}>typescript
"use client";
import { useLocale } from "@/shared/presentation/components/LocaleProvider";
export function MyClientComponent() {
const locale = useLocale();
const t = translations[locale];
return <p>{t.description}</p>;
}4. Changing Locale (Server Action)
4. 切换区域设置(服务端操作)
Locale switching MUST be handled globally through cookies via a Server Action.
typescript
"use client";
import { setLocaleAction } from "@/shared/infrastructure/i18n/actions";
import { useRouter } from "next/navigation";
export function Switcher() {
const router = useRouter();
const handleSwitch = async (newLocale: string) => {
// MUST call the server action to update the cookie
await setLocaleAction(newLocale);
// MUST trigger a router.refresh() to update all server components
router.refresh();
}
// ...
}区域设置切换必须通过服务端操作(Server Action)全局处理,基于Cookie实现。
typescript
"use client";
import { setLocaleAction } from "@/shared/infrastructure/i18n/actions";
import { useRouter } from "next/navigation";
export function Switcher() {
const router = useRouter();
const handleSwitch = async (newLocale: string) => {
// MUST call the server action to update the cookie
await setLocaleAction(newLocale);
// MUST trigger a router.refresh() to update all server components
router.refresh();
}
// ...
}
```",