首页
开发技巧正文内容

使用 Next.js App Router 进行本地化

2024年04月22日
阅读时长 2 分钟
阅读量 3
使用 Next.js App Router 进行本地化

使用新的 App Router 为 Next.js 应用程序进行本地化和国际化

使用以下命令从头开始安装一个新的 Next.js 应用程序:

npx create-next-app@latest

安装过程将引导您选择应用程序的名称和其他选项,如下所示。

使用 App Router 创建新的 Next.js 应用程序

如果您想按照本教程进行操作,请确保选择以下选项。

✔ 是否要使用 src/ 目录?... No ✔ 是否要使用 App Router?(推荐)... Yes

现在,您可以导航到应用程序的根文件夹(例如,在我的情况下是 test-i18n),并使用 npm run dev 运行应用程序。

App Router

如果您熟悉 App Router,则可以跳过此部分。

文档中了解到以下信息:

  • App Router 在名为 app 的目录中工作。

  • 您可以与 Pages Router 一起使用 App Router,此时前者优先。

  • 默认情况下,app 目录中的组件是 React Server Components

  • Next.js 使用基于文件系统的路由器,因此 app 目录中的每个文件夹都表示一个路由。

  • 要在定义的路由上创建一些 UI,只需在路由文件夹中添加一个名为 page.js 的文件(扩展名可以是 .jsx 或 .tsx)。Page 是用于创建路由的 UI 并使路由公开访问的特殊文件。同一文件夹中的其他文件将无法公开访问。

在下面的图片中,您可以在 settings 文件夹中添加一个 page.tsx 文件,以创建一个在 acme.com/dashboard/settings 上可用的 UI。

Next.js 文件系统路由器

简而言之,每个文件夹表示一个路由段,它映射到一个 URL 段。一个特殊的 page 文件创建了路由的 UI。

动态路由

在深入研究国际化之前,您需要了解的最后一个概念是动态路由。

根据文档,"当您事先不知道确切的段名并且想要根据动态数据创建路由时,可以使用在请求时填充或在构建时预渲染的动态段。"

可以通过将文件夹的名称放在方括号中来创建动态段:[folderName]。例如,[language][id]

这很快就会被使用。

Next.js App Router 国际化 - i18n

让我们创建一个支持国际化的文件夹结构。

app 文件夹内,创建一个动态文件夹路由,并将其命名为 [lang]

[lang] 内部,我添加了几个更多的文件夹,它们将成为 URL 路由段。在每个文件夹内,我添加了一个 page.tsx 文件来创建 UI。

文件夹结构如下所示:

app/
  [lang]
    about/page.tsx
    cart/page.tsx
    products/page.tsx
    page.tsx

每个 page.tsx 文件都是一个简单的 React 函数组件,如下所示:

// app/[lang]/page.tsx

export default function Home() {
  return <div>Home</div>;
}

如果您导航到以下位置,将会发生以下情况:

Next.js 应用程序与 App Router - 用于国际化的文件夹结构

组件中的语言

现在,我们在 URL 中有了语言,但我们可能希望在组件内部使用它来本地化语言。

这是一个 JavaScript 组件的示例:


export default function Home({ params: { lang } }) {
  console.log(lang);

  return <div>Home - Language: {lang}</div>;
}

这是它的 TypeScript 对应组件:

type Props = {
  params: { [lang: string]: string };
};

export default function Home({ params: { lang } }: Props) {
  console.log(lang);

  return <div>Home - Language: {lang}</div>;
}

请注意,由于默认情况下,app 目录中的组件是 React Server Components,因此 console.log 将在终端中输出。

现在我们知道了语言,我们可以继续本地化 UI。

Next.js App Router 本地化 - l10n

本地化意味着根据用户的首选语言或区域设置更改 "显示的内容"。

根据文档的指导,我们应该在应用程序的 [lang] 文件夹内创建一个名为 dictionaries 的文件夹。

然后,我们需要为每种语言创建一个类似 en.json 的文件,其中 en 将根据语言而变化。根据提供的示例,我得到了以下结果:

Next.js App Router 本地化

然后,我们在 [lang] 文件夹中创建一个 dictionaries.js 文件。

// app/[lang]/dictionaries.js

import "server-only";

const dictionaries = {
  en: () => import("./dictionaries/en.json").then((module) => module.default),
  nl: () => import("./dictionaries/nl.json").then((module) => module.default),
};

export const getDictionary = async (locale) => dictionaries[locale]();

最后,我们可以使用 getDictionary 函数来访问正确的字典,从而本地化应用程序的内容,如下所示:

import { getDictionary } from "./dictionaries";

...

export default async function Home({ params: { lang } }: Props) {
  console.log(lang);
  const dict = await getDictionary(lang);

  return <div>Home in {lang}: {dict.home}</div>;
}

请注意,在组件中:

  • 导入 getDictionary 函数

  • 将函数声明为 async,以便我们可以使用 await 关键字

  • 一旦获取到正确的字典,我们将其保存在 dict 中,并像使用对象一样访问所需的内容。

因此,如果您导航到以下位置:

为了解决这个错误,我们可以添加一个条件来检查语言,并在使用不受支持的语言时返回默认语言。

这个条件应该在每个组件中使用,所以我们可能会将其提取出来,并在某个 utils 中声明它。但是然后我们需要导入它并在每个组件中调用它。

对于这种情况,我们可以利用中间件。

用于本地化的中间件

您可以将中间件视为位于服务器和应用程序之间的中间层,松散地位于 CDN 级别,例如在服务器和应用程序之间。

在这个层中,我们可以设置一个中间件来转换一些请求以适应我们的需求。

例如,我们希望中间件层将所有不受支持的语言转换为 en

要使用中间件,我们首先在根目录中创建一个 middleware.ts 文件,与 app 文件夹处于同一级别。

// middleware.ts

let locales = ["en", "nl"];

export function middleware(request) {
  // 检查路径名中是否有任何受支持的语言环境
  const { pathname } = request.nextUrl;
  const pathnameHasLocale = locales.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
  );

  if (pathnameHasLocale) return;

  // 如果没有语言环境,则重定向
  const locale = "en";
  request.nextUrl.pathname = `/${locale}${pathname}`;
  // 例如,如果传入的请求是 /products
  // 新的 URL 将是 /en/products
  return Response.redirect(request.nextUrl);
}

export const config = {
  matcher: [
    // 跳过所有内部路径(_next)
    "/((?!_next).*)",
    // 仅在根(/)URL 上运行
    "/",
  ],
};

该中间件是根据文档进行调整的,原因如下:

  • 文档依赖于两个不同的库来完成工作,而我不想安装更多的库。

  • 他们有一个通用的解决方案,可以轻松扩展以考虑更多的用例,并最终使用 cookie 来设置语言。

对于这个示例,我对一个简单的解决方案感到满意,它的工作原理如下:

  1. 如果没有选择语言,则默认为英语,例如 http://localhost:3000/en

  2. 如果选择了语言,则使用该语言

  3. 如果 URL 不包含语言,则添加 en 并保留其他段。例如,如果传入的请求(到中间件)是 http://localhost:3000/about,则默认为 http://localhost:3000/en/about请注意,如果在中间件中添加 console.log,每次路由更改时都会看到多个日志。这是因为中间件在项目中的每个路由上都会被调用。因此,如果您想定义中间件应该运行的特定路径,请阅读匹配路径

上面示例中的配置仅在 / 上运行中间件。

您可以在https://erichowey.dev/找到使用 Cookies 的更全面的解决方案。

通过设置中间件,我们可以创建一种改变语言的方式。

切换按钮以更改语言环境

一种常见的改变语言的方式是创建一个语言切换组件,其中包含一些按钮或其他元素来切换语言。

// app/components/LangSwitcher.tsx

import Link from "next/link";

export default function LangSwitcher() {
  return (
    <>
      <Link href="/en"> EN </Link>
      <Link href="/nl"> NL </Link>
    </>
  );
}

在这一点上,无论您在何处需要,都可以导入该组件,用户将能够点击首选语言。

这将相应地更改 URL 和内容。

在接下来的内容中,我将添加使用 cookies 来获取和保存用户的本地化偏好的可能性。

免责声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

相关文章

使用 Next.js App Router 进行本地化
2024年04月22日23:11

使用 Next.js App Router 进行本地化

使用新的 App Router 为 Next.js 应用程序进行本地化和国际化。App Router 在名为 app 的目录中工作,可以与 Pages Router 一起使用。使用动态路由来创建根据动态数据创建的路由。使用中间件来实现本地化和语言切换。
如何像专业人士一样编写异步 JavaScript 的 11 个最佳实践
2024年04月21日04:04

如何像专业人士一样编写异步 JavaScript 的 11 个最佳实践

当处理不会立即发生的任务时,使用 JavaScript 编写异步代码可能会很棘手。本文分享了11个可以帮助你更好地编写异步 JavaScript 代码的最佳实践,包括避免在循环中使用await、不在Promise构造函数中返回值等。这些实践可以提高代码的性能和可读性,让你的JavaScript代码更加专业。
UI 设计师需要了解 Flexbox 和 CSS Grid
2024年04月08日08:11

UI 设计师需要了解 Flexbox 和 CSS Grid

大多数设计师都熟悉响应式设计,但现代 CSS 布局可以提供更灵活和动态的设计。本文介绍了响应式基于列的设计与现代 CSS 布局、作为设计师理解 CSS Flexbox 和 CSS Grid、以及断点的使用。CSS Grid 是一种强大的布局工具,可以创建复杂的布局结构,而 Flexbox 则适用于组件级别的布局。设计师可以根据具体情况选择使用 Flexbox、CSS Grid 或两者结合。
10款提升Web开发速度的强大工具
2024年04月07日02:13

10款提升Web开发速度的强大工具

10款提升Web开发速度的强大工具,覆盖了页面动效,前端框架,颜色选择,背景移除,Icon等各个方面。
Android Compose实战:开发动态银行卡UI
2024年03月19日21:19

Android Compose实战:开发动态银行卡UI

本教程介绍了如何使用Jetpack Compose构建一个漂亮的数字银行卡UI。通过使用Canvas和组合函数,您可以创建一个灵活且可自定义的银行卡UI,包括卡号、持卡人信息和卡类型。这个教程还介绍了如何使用Modifier参数和外部文件来增加灵活性和可重用性。
完美的Next.js点赞按钮
2024年03月17日10:22

完美的Next.js点赞按钮

在Next.js中实现一个完美的点赞按钮并不容易。但是通过结合tRPC内置的乐观更新功能和lodash的防抖能力,我解决了这些问题,打造了完美的Next.js点赞按钮,今天我将向您展示如何做到这一点。本文介绍了认证、tRPC、后端和前端的实现步骤,并提供了相关代码示例。通过这篇文章,您可以学习如何在Next.js应用程序中实现一个功能强大的点赞按钮。