i18n

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

i18n (Internationalization)

国际化(i18n)

This project uses a custom, library-free i18n implementation. There is no
next-intl
,
i18next
, or similar dependency.
DEPENDENCY NOTICE: If you are bootstrapping a new project using this architecture, read i18n Utilities Reference immediately to copy the exact implementation for
LocaleProvider
,
determineLocale
, and
setLocaleAction
so your components compile correctly.
本项目采用无依赖库的自定义国际化实现,未使用
next-intl
i18next
或类似依赖。
依赖注意事项:如果您正基于该架构启动新项目,请立即阅读i18n工具参考文档,复制
LocaleProvider
determineLocale
setLocaleAction
的完整实现,以确保组件正确编译。

1. 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文件中,必须作为类型化
const
定义在使用该翻译的组件或页面的**同一文件(或同级文件)**中。

Flat 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
translations
object grows large enough to distract from the component logic, you MUST move it to a sibling file named
<component>.i18n.ts
, co-located next to the component.
translations
对象过大,影响组件逻辑阅读时,必须将其移至组件的同级文件中,文件命名为**
<component>.i18n.ts
**。

3. Accessing the Locale

3. 访问区域设置

CRITICAL: You MUST NOT read the locale from the
[locale]
URL segment (page
params
). You MUST always use
determineLocale()
in Server Components or
useLocale()
in Client Components. The source of truth is the cookie/header injected by middleware.
重要提示禁止
[locale]
URL路径段(页面
params
)读取区域设置。在服务端组件(Server Components)中必须使用
determineLocale()
,在客户端组件(Client Components)中必须使用
useLocale()
。真实数据源是中间件注入的Cookie/请求头。

In Server Components (RSC)

在服务端组件(RSC)中

You MUST use
determineLocale()
. It is memoized per-request via React
cache
.
typescript
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>;
}
必须使用
determineLocale()
,该方法通过React
cache
实现了按请求缓存。
typescript
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
useLocale()
hook. The Client Component MUST be rendered inside a parent
<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(); 
    }
    
    // ...
}
```",