} */
const metadataContent = {
key: "metadata",
content: {
title: t({
zh: "我的项目标题",
en: "My Project Title",
fr: "Le Titre de mon Projet",
es: "El Título de mi Proyecto",
}),
description: t({
zh: "了解我们的创新平台,旨在简化您的工作流程并提升生产力。",
en: "Discover our innovative platform designed to streamline your workflow and boost productivity.",
fr: "Découvrez notre plateforme innovante conçue pour simplifier votre flux de travail et booster votre productivité.",
es: "Descubra nuestra plataforma innovadora diseñada para simplificar su flujo de trabajo y aumentar su productividad.",
}),
keywords: t({
zh: ["创新", "生产力", "工作流", "SaaS"],
en: ["innovation", "productivity", "workflow", "SaaS"],
fr: ["innovation", "productivité", "flux de travail", "SaaS"],
es: ["innovación", "productividad", "flujo de trabajo", "SaaS"],
}),
},
};
module.exports = metadataContent;
```
```json fileName="src/app/metadata.content.json" contentDeclarationFormat="json"
{
"key": "metadata",
"content": {
"title": {
"nodeType": "translation",
"translation": {
"zh": "我的项目标题",
"en": "My Project Title",
"fr": "Le Titre de mon Projet",
"es": "El Título de mi Proyecto"
}
},
"description": {
"nodeType": "translation",
"translation": {
"zh": "探索我们创新的平台,旨在简化您的工作流程并提升生产力。",
"en": "Discover our innovative platform designed to streamline your workflow and boost productivity.",
"zh": "探索我们的创新平台,旨在简化您的工作流程并提升您的生产力。",
"fr": "Découvrez notre plateforme innovante conçue pour simplifier votre flux de travail et booster votre productivité.",
"es": "Descubra nuestra plataforma innovadora diseñada para simplificar su flujo de trabajo y aumentar su productividad."
}
},
"keywords": {
"nodeType": "translation",
"translation": {
"zh": ["创新", "生产力", "工作流程", "SaaS"],
"en": ["innovation", "productivity", "workflow", "SaaS"],
"fr": ["innovation", "productivité", "flux de travail", "SaaS"],
"es": ["innovación", "productividad", "flujo de trabajo", "SaaS"]
}
}
}
}
```
```tsx fileName="src/app/page.content.ts" contentDeclarationFormat="typescript"
import { t, type Dictionary } from "intlayer";
const pageContent = {
key: "page",
content: {
getStarted: {
main: t({
zh: "通过编辑开始",
en: "Get started by editing",
fr: "Commencez par éditer",
es: "Comience por editar",
}),
pageLink: "src/app/page.tsx",
},
},
} satisfies Dictionary;
export default pageContent;
```
```javascript fileName="src/app/page.content.mjs" contentDeclarationFormat="esm"
import { t } from "intlayer";
/** @type {import('intlayer').Dictionary} */
const pageContent = {
key: "page",
content: {
getStarted: {
main: t({
zh: "通过编辑开始",
en: "Get started by editing",
fr: "Commencez par éditer",
es: "Comience por editar",
}),
pageLink: "src/app/page.tsx",
},
},
};
export default pageContent;
```
```javascript fileName="src/app/page.content.cjs" contentDeclarationFormat="commonjs"
const { t } = require("intlayer");
/** @type {import('intlayer').Dictionary} */
const pageContent = {
key: "page",
content: {
getStarted: {
main: t({
zh: "通过编辑开始",
en: "Get started by editing",
fr: "Commencez par éditer",
es: "Comience por editar",
}),
pageLink: "src/app/page.tsx",
},
},
};
module.exports = pageContent;
```
```json fileName="src/app/page.content.json" contentDeclarationFormat="json"
{
"$schema": "https://intlayer.org/schema.json",
"key": "page",
"content": {
"getStarted": {
"nodeType": "translation",
"translation": {
"zh": "通过编辑开始",
"en": "Get started by editing",
"fr": "Commencez par éditer",
"es": "Comience por editar"
}
},
"pageLink": "src/app/page.tsx"
}
}
```
> 你的内容声明可以在应用的任何位置定义,只要它们被包含到 `contentDir` 目录(默认 `./src`)中。并且与内容声明文件扩展名匹配(默认 `.content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}`)。
> 有关详细信息,请参阅 [内容声明文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/content_file.md)。
### 步骤 6:在代码中使用内容
在应用程序中随处访问你的内容字典:
```tsx fileName="src/app/page.tsx" codeFormat="typescript"
import type { FC } from "react";
import { ClientComponentExample } from "@components/clientComponentExample/ClientComponentExample";
import { ServerComponentExample } from "@components/serverComponentExample/ServerComponentExample";
import {
IntlayerServerProvider,
useIntlayer,
getLocale,
} from "next-intlayer/server";
import { NextPage } from "next";
import { headers, cookies } from "next/headers";
const PageContent: FC = () => {
const content = useIntlayer("page");
return (
<>
{content.getStarted.main}
{content.getStarted.pageLink}
>
);
};
const Page: NextPage = async () => {
// 在 Next.js 15+ 中等待 headers 和 cookies
const headerList = await headers();
const cookieList = await cookies();
const locale = await getLocale({
// 首先检查 intlayer cookie(默认: 'INTLAYER_LOCALE')
getCookie: (name) => cookieList.get(name)?.value,
// 然后检查 intlayer header(默认:'x-intlayer-locale')
// 最后检查 accept-language header('accept-language')
getHeader: (name) => headerList.get(name),
});
return (
);
};
export default Page;
```
```jsx fileName="src/app/page.mjx" codeFormat="esm"
import { ClientComponentExample } from "@components/clientComponentExample/ClientComponentExample";
import { ServerComponentExample } from "@components/serverComponentExample/ServerComponentExample";
import { IntlayerServerProvider, useIntlayer, getLocale } from "next-intlayer/server";
import { headers, cookies } from "next/headers";
import { NextPage } from "next";
const Page: NextPage = async () => {
const content = useIntlayer("page");
return (
<>
{content.getStarted.main}
{content.getStarted.pageLink}
>
);
};
const Page = async () => {
// 在 Next.js 15+ 中等待 headers 和 cookies
const headerList = await headers();
const cookieList = await cookies();
const locale = await getLocale({
// 首先检查 intlayer cookie(默认:'INTLAYER_LOCALE')
getCookie: (name) => cookieList.get(name)?.value,
// 然后检查 intlayer header(默认:'x-intlayer-locale')
// 最后检查 accept-language 头('accept-language')
getHeader: (name) => headerList.get(name),
});
return (
);
};
export default Page;
```
```jsx fileName="src/app/page.csx" codeFormat="commonjs"
import { ClientComponentExample } from "@components/clientComponentExample/ClientComponentExample";
import { ServerComponentExample } from "@components/serverComponentExample/ServerComponentExample";
import { IntlayerServerProvider, useIntlayer, getLocale } from "next-intlayer/server";
import { NextPage } from "next";
import { headers, cookies } from "next/headers";
const Page: NextPage = async () => {
const content = useIntlayer("page");
return (
<>
{content.getStarted.main}
{content.getStarted.pageLink}
>
);
};
const Page: NextPage = async () => {
// 在 Next.js 15+ 中等待 headers 和 cookies
const headerList = await headers();
const cookieList = await cookies();
const locale = await getLocale({
// 首先检查 intlayer cookie(默认: 'INTLAYER_LOCALE')
getCookie: (name) => cookieList.get(name)?.value,
// 然后检查 intlayer header(默认: 'x-intlayer-locale')
// 最后检查 accept-language header('accept-language')
getHeader: (name) => headerList.get(name),
});
return (
);
};
```
- **`IntlayerClientProvider`** 用于将 locale 提供给客户端组件。它可以放在任何父组件中,包括 layout。然而,建议将其放在 layout 中,因为 Next.js 在页面之间会共享 layout 代码,这样更高效。将 `IntlayerClientProvider` 放在 layout 中可以避免为每个页面重新初始化,从而提高性能并在整个应用中保持一致的本地化上下文。
- **`IntlayerServerProvider`** 用于将 locale 提供给服务端子组件。它不能设置在 layout 中。
> Layout 和 page 不能共享同一个 server context,因为 server context 系统基于每次请求的数据存储(通过 [React's cache](https://react.dev/reference/react/cache) 机制),导致每个 "context" 会为应用的不同部分被重新创建。将 provider 放在共享 layout 中会破坏此隔离,阻止 server context 值正确传播到你的 server components。
```tsx {4,7} fileName="src/components/clientComponentExample/ClientComponentExample.tsx" codeFormat="typescript"
"use client";
import type { FC } from "react";
import { useIntlayer } from "next-intlayer";
export const ClientComponentExample: FC = () => {
const content = useIntlayer("client-component-example"); // 创建相关内容声明
return (
{content.title}
{content.content}
);
};
```
```jsx {3,6} fileName="src/components/clientComponentExample/ClientComponentExample.mjx" codeFormat="esm"
"use client";
import { useIntlayer } from "next-intlayer";
const ClientComponentExample = () => {
const content = useIntlayer("client-component-example"); // 创建相关内容声明
return (
{content.title}
{content.content}
);
};
```
```jsx {3,6} fileName="src/components/clientComponentExample/ClientComponentExample.csx" codeFormat="commonjs"
"use client";
const { useIntlayer } = require("next-intlayer");
const ClientComponentExample = () => {
const content = useIntlayer("client-component-example"); // 创建相关内容声明
return (
{content.title}
{content.content}
);
};
```
```tsx {2} fileName="src/components/serverComponentExample/ServerComponentExample.tsx" codeFormat="typescript"
import type { FC } from "react";
import { useIntlayer } from "next-intlayer/server";
export const ServerComponentExample: FC = () => {
const content = useIntlayer("server-component-example"); // 创建相关内容声明
return (
{content.title}
{content.content}
);
};
```
```jsx {1} fileName="src/components/serverComponentExample/ServerComponentExample.mjx" codeFormat="esm"
import { useIntlayer } from "next-intlayer/server";
const ServerComponentExample = () => {
const content = useIntlayer("server-component-example"); // 创建相关内容声明
return (
{content.title}
{content.content}
);
};
```
```jsx {1} fileName="src/components/serverComponentExample/ServerComponentExample.csx" codeFormat="commonjs"
const { useIntlayer } = require("next-intlayer/server");
const ServerComponentExample = () => {
const content = useIntlayer("server-component-example"); // 创建相关内容声明
return (
{content.title}
{content.content}
);
};
```
> 如果您想在 `string` 属性(例如 `alt`、`title`、`href`、`aria-label` 等)中使用内容,必须调用函数的值,例如:
> ```jsx
>
> ```
> 若要了解有关 `useIntlayer` hook 的更多信息,请参阅 [文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/packages/next-intlayer/useIntlayer.md)。
### (可选)步骤 7:配置 Proxy 以进行 locale 检测
设置 Proxy 以检测用户的首选 locale:
```typescript fileName="src/proxy.ts" codeFormat="typescript"
export { intlayerProxy as proxy } from "next-intlayer/proxy";
export const config = {
matcher:
"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
};
```
```javascript fileName="src/proxy.mjs" codeFormat="esm"
export { intlayerProxy as proxy } from "next-intlayer/proxy";
export const config = {
matcher:
"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
};
```
```javascript fileName="src/proxy.cjs" codeFormat="commonjs"
const { intlayerProxy } = require("next-intlayer/proxy");
const config = {
matcher:
"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
};
module.exports = { proxy: intlayerProxy, config };
```
> `intlayerProxy` 用于检测用户偏好的 locale,并根据 [配置](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/configuration.md) 将用户重定向到相应的 URL。除此之外,它还可以将用户偏好的 locale 保存在 cookie 中。
> 如果需要将多个代理串联在一起(例如将 `intlayerProxy` 与身份验证或自定义代理一起使用),Intlayer 现在提供了一个名为 `multipleProxies` 的辅助函数。
```ts
import { multipleProxies, intlayerProxy } from "next-intlayer/proxy";
import { customProxy } from "@utils/customProxy";
export const proxy = multipleProxies([intlayerProxy, customProxy]);
```
### (可选)步骤 8:更改您内容的语言
要在 Next.js 中更改内容的语言,推荐的方法是使用 `Link` 组件将用户重定向到相应的本地化页面。`Link` 组件支持页面预取,这有助于避免整页重新加载。
```tsx fileName="src/components/localeSwitcher/LocaleSwitcher.tsx" codeFormat="typescript"
"use client";
import type { FC } from "react";
import { Locales, getHTMLTextDir, getLocaleName } from "intlayer";
import { useLocale } from "next-intlayer";
export const LocaleSwitcher: FC = () => {
const { locale, availableLocales, setLocale } = useLocale({
onChange: () => window.location.reload(),
});
return (
{availableLocales.map((localeItem) => (
))}
);
};
```
```jsx fileName="src/components/localeSwitcher/LocaleSwitcher.msx" codeFormat="esm"
"use client";
import { Locales, getHTMLTextDir, getLocaleName } from "intlayer";
import { useLocale } from "next-intlayer";
export const LocaleSwitcher = () => {
const { locale, availableLocales, setLocale } = useLocale({
onChange: () => window.location.reload(),
});
return (
{availableLocales.map((localeItem) => (
))}
);
};
```
```jsx fileName="src/components/localeSwitcher/LocaleSwitcher.csx" codeFormat="commonjs"
"use client";
const { Locales, getHTMLTextDir, getLocaleName } = require("intlayer");
const { useLocale } = require("next-intlayer");
export const LocaleSwitcher = () => {
const path
const { locale availableLocales, setLocale } = useLocale({
onChange: ()=> window.location.reload(),
});
return (
{availableLocales.map((localeItem) => (
))}
);
};
```
> 另一种方法是使用 `useLocale` hook 提供的 `setLocale` 函数。此函数不会允许预获取页面。有关更多详细信息,请参阅 [`useLocale` hook 文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/packages/next-intlayer/useLocale.md)。
> 文档参考:
>
> - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/packages/next-intlayer/useLocale.md)
> - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/packages/intlayer/getLocaleName.md)
> - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/packages/intlayer/getLocalizedUrl.md)
> - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/packages/intlayer/getHTMLTextDir.md)
> - [`hrefLang` attribute](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr)
> - [`lang` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang)
> - [`dir` attribute`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir)
> - [`aria-current` attribute`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current)
###(可选)步骤 9:在 Server Actions 中获取当前 locale
如果你需要在 Server Action 中使用活动 locale(例如,用于本地化电子邮件或运行与 locale 相关的逻辑),请从 `next-intlayer/server` 调用 `getLocale`:
```tsx fileName="src/app/actions/getLocale.ts" codeFormat="typescript"
"use server";
import { getLocale } from "next-intlayer/server";
export const myServerAction = async () => {
const locale = await getLocale();
// 使用该 locale 执行一些操作
};
```
> `getLocale` 函数采用级联策略来确定用户的语言环境:
>
> 1. 首先,它会检查请求头中是否存在可能由代理设置的 locale 值
> 2. 如果在请求头中未找到 locale,则查找存储在 cookies 中的 locale
> 3. 如果未找到 cookie,它会尝试从用户的浏览器设置中检测首选语言
> 4. 最后,它会回退到应用程序配置的默认 locale
>
> 这可确保基于可用上下文选择最合适的 locale。
### (可选)步骤 10:优化你的 bundle 大小
在使用 `next-intlayer` 时,字典默认会被包含到每个页面的 bundle 中。为了优化 bundle 大小,Intlayer 提供了一个可选的 SWC 插件,它使用宏智能替换 `useIntlayer` 调用。这样只有实际使用这些字典的页面的 bundle 才会包含相应字典。
要启用此优化,请安装 `@intlayer/swc` 包。安装后,`next-intlayer` 会自动检测并使用该插件:
```bash packageManager="npm"
npm install @intlayer/swc --save-dev
npx intlayer init
```
```bash packageManager="pnpm"
pnpm add @intlayer/swc --save-dev
pnpm intlayer init
```
```bash packageManager="yarn"
yarn add @intlayer/swc --save-dev
yarn intlayer init
```
```bash packageManager="bun"
bun add @intlayer/swc --dev
bunx intlayer init
```
> 注意:此优化仅适用于 Next.js 13 及更高版本。
> 注意:该包默认不安装,因为 SWC 插件在 Next.js 中仍然是实验性的。将来可能会发生变化。
> 注意:如果你将选项设置为 `importMode: 'dynamic'` 或 `importMode: 'live'`,它将依赖 Suspense,因此你必须在一个 `Suspense` 边界中包裹你的 `useIntlayer` 调用。这意味着你不能在页面 / 布局组件的顶层直接使用 `useIntlayer`。
### 在 Turbopack 上监视字典更改
当使用 Turbopack 作为通过 `next dev` 命令运行的开发服务器时,字典更改默认不会被自动检测。
这个限制是因为 Turbopack 无法并行运行 webpack 插件来监视内容文件的更改。为了解决这个问题,你需要使用 `intlayer watch` 命令同时运行开发服务器和 Intlayer 构建监视器。
```json5 fileName="package.json"
{
// ... 你现有的 package.json 配置
"scripts": {
// ... 你现有的 scripts 配置
"dev": "intlayer watch --with 'next dev'",
},
}
```
> 如果你使用的是 next-intlayer@<=6.x.x,你需要保留 `--turbopack` 标志以使 Next.js 16 应用程序能与 Turbopack 正常工作。我们建议使用 next-intlayer@>=7.x.x 来避免此限制。
### 配置 TypeScript
Intlayer 使用模块扩展(module augmentation)来利用 TypeScript 的优势并增强你的 codebase 的类型安全性。


确保你的 TypeScript 配置包含自动生成的类型。
```json5 fileName="tsconfig.json"
{
// ... 你现有的 TypeScript 配置
"include": [
// ... 你现有的 TypeScript 配置
".intlayer/**/*.ts", // 包含自动生成的类型
],
}
```
### Git 配置
建议将 Intlayer 生成的文件忽略(ignore)。这样可以避免将这些文件提交到你的 Git 仓库。
为此,你可以将以下内容添加到你的 `.gitignore` 文件中:
```plaintext fileName=".gitignore"
# 忽略 Intlayer 生成的文件
.intlayer
```
### VS Code Extension
为了提升在 Intlayer 的开发体验,你可以安装官方的 **Intlayer VS Code Extension**。
[从 VS Code Marketplace 安装](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
此扩展提供:
- **Autocompletion**:翻译键自动补全。
- **Real-time error detection**:实时检测缺失的翻译。
- **内联预览** 翻译后的内容。
- **快速操作** 以便轻松创建和更新翻译。
有关如何使用该扩展的更多详细信息,请参阅 [Intlayer VS Code 扩展文档](https://intlayer.org/doc/vs-code-extension)。
### 更进一步
要深入了解,您可以实现 [可视化编辑器](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/intlayer_visual_editor.md) 或使用 [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/intlayer_CMS.md) 将内容外部化。