前端开发

Next.js 14 中的增强国际化 (i18n)

在本文中,我们将深入探讨为什么国际化 (i18n)对于 Web 开发至关重要,探索Next.js 14 的新功能,并学习如何轻松构建多语言 Web 体验。

想象一下,您登陆一个网站,需要提取一条重要信息,但突然遇到了语言障碍。令人沮丧,对吧?这就是国际化 (i18n) 发挥作用的地方,它使世界各地的人们都可以访问网站。

Next.js 14 通过语言路由和动态消息加载等工具简化了多语言 Web 开发。它旨在帮助开发人员轻松创建动态的多语言 Web 应用程序。

在本文结束时,我们将对 Next.js 14 中的国际化(从建立新项目到添加语言切换)有实际的了解。

设置 Next.js 14 项目

让我们首先使用内置 i18n 设置我们的项目。

步骤 1.通过运行以下命令创建一个新的 Next.js 项目。为了本文的目的,我们将其命名为i18n-next-app

npx create-next-app i18n-next-app

步骤 2.导航到项目文件夹并安装 Next.js(版本 14)和软件包next-intl

cd i18n-next-app
npm install next@latest next-intl

上面的命令会安装 Next.js 及其最新功能,例如 i18n,并包含next-intl. 使用的原因next-intl是它通过动态段与 App Router 无缝集成[locale]。这种集成使我们能够以多种语言提供内容。

步骤 3.通过在您的项目中添加以下配置,在项目的 Next.js 14 中启用 i18n 支持next.config.js

const withNextIntl = require('next-intl/plugin')();

module.exports = withNextIntl({
  //include other configs here
});

上面的代码使用next-intl插件配置 Next.js 以增强国际化功能。它导入插件并将其应用到 Next.js 配置中,使开发人员可以轻松地将国际化功能合并到他们的项目中。这样做的同时留出空间来保留其他项目配置。

步骤 4:content在项目根目录创建一个文件夹。en.json在里面,为每个区域设置( 、es.json、 )创建 JSON 文件de.json,其中包含翻译后的字符串。这种方法弥补了 Next.js 当前在自动翻译方面的限制。

为了这个项目,我们将使用英语、西班牙语和德语,但您可以根据您的项目要求随意添加更多区域设置:

//content/de.json
{
  "Home": {
    "navigation": {
      "home": "Heim",
      "about": "Über uns",
      "contact": "Kontakt"
    },
    "title": "Internationalisierung (i18n) in Next.js 14",
    "description": "Next.js 14 führt erweiterte Internationalisierungs (i18n)-Funktionen ein, die Entwicklern ermöglichen, Übersetzungen, lokalisierungsbasiertes Routing und Inhaltslokalisierung für weltweit zugängliche Webanwendungen mühelos zu verwalten. <br /> <br />Darüber hinaus bietet es integrierte Unterstützung für mehrere Sprachvarianten, dynamisches Inhaltsladen und robuste Fallback-Behandlung."
  }
}
//content/es.json
{
  "Home": {
    "navigation": {
      "home": "Inicio",
      "about": "Acerca de",
      "contact": "Contacto"
    },
    "title": "Internacionalización (i18n) en Next.js 14",
    "description": "Next.js 14 introduce características avanzadas de internacionalización (i18n), capacitando a los desarrolladores para gestionar fácilmente traducciones, enrutamiento basado en localización y localización de contenido para aplicaciones web globalmente accesibles. <br /> <br />Esto también aprovecha el soporte incorporado para múltiples locales, carga dinámica de contenido y manejo de respaldo robusto."
  }
}

//content/en.json
{
  "Home": {
    "navigation": {
      "home": "Home",
      "about": "About",
      "contact": "Contact Us"
    },
    "title": "Internationalization(i18n) in Next.js 14",
    "description": "Next.js 14 introduces enhanced internationalization (i18n) features, empowering developers to effortlessly manage translations, locale-based routing, and content localization for globally accessible web applications. <br /> <br />This also piggy-backs built-in support for multiple locales, dynamic content loading, and robust fallback handling."
  }
}

上面的内容代表了我们为迎合三种不同语言而定制的项目的登陆页面内容。

语言路由和 Slug

在多语言 Web 应用程序中,语言路由可确保用户根据其语言偏好定向到适当的网站版本。此外,slugs 允许动态生成路由,对于博客或产品列表等内容丰富的页面特别有用。

完成配置后,让我们实现特定于语言的路由。我们还可以在不依赖额外库的情况下设置语言块。

步骤 1.在该src/目录中,创建一个新文件并将其命名为i18n.ts. 将其配置为根据区域设置动态加载消息:

//i18n.ts
import { notFound } from "next/navigation";
import { getRequestConfig } from 'next-intl/server';

const locales: string[] = ['en', 'de', 'es'];

export default getRequestConfig(async ({ locale }) => {
  if (!locales.includes(locale as any)) notFound();

  return {
    messages: (await import(`../content/${locale}.json`)).default
  };
});

在此步骤中,我们将根据所选区域设置动态消息加载。该getRequestConfig函数从文件夹中动态导入与区域设置相对应的 JSON 文件content。这确保了应用程序可以轻松地调整其内容以适应不同的语言偏好。

步骤 2.在内部创建一个middleware.ts文件src/以匹配区域设置并允许根据区域设置重定向用户:

//middleware.ts
import createMiddleware from 'next-intl/middleware';

const middleware = createMiddleware({
  // Add locales you want in the app
  locales: ['en', 'de', 'es'],

  // Default locale if no match
  defaultLocale: 'en'
});

export default middleware;

export const config = {
  // Match only internationalized pathnames
  matcher: ['/', '/(de|es|en)/:page*']
};

在此步骤中,我们将定义一个匹配区域设置并根据用户的首选语言重定向用户的中间件。我们指定支持的区域设置,并在不匹配的情况下设置默认区域设置。

步骤3.接下来,我们配置应用程序语言并修改布局和页面组件。在其中建立一个[locale]目录app/并在其中layout.tsx移动page.tsx

//layout.tsx
interface RootLayoutProps {
  children: React.ReactNode;
  locale: never;
}

export default function RootLayout({ children, locale }: RootLayoutProps) {
  return (
    <html lang={locale}>
      <body className={inter.className}>{children}</body>
    </html>
  );
}
//page.tsx
import Header from "@/components/Header";
import { useTranslations } from "next-intl";
import Image from "next/image";
import heroImage from "../../assets/img/intl_icon.png";

export default function Home() {
  const t = useTranslations("Home");

  // Extract the navigation object keys from the translations
  const navigationKeys = Object.keys(t.raw("navigation"));

  return (
    <>
      <Header />
      <nav>
        <ul>
          {navigationKeys.map((key) => (
            <li key={key}>
              <a href={`#/${key}`}>{t(`navigation.${key}`)}</a>
            </li>
          ))}
        </ul>
      </nav>
      <main>
        <div>
          <aside>
            <h2>{t("title")}</h2>
            <p dangerouslySetInnerHTML={{ __html: t("description") }}></p>
          </aside>
          <aside>
            <Image src={heroImage} width={"600"} height={"600"} alt="" />
          </aside>
        </div>
      </main>
    </>
  );
}

从上面的代码中,为了清楚起见,我们删除了样式(可以在此处useTranslations找到样式版本),我们使用了钩子 fromnext-intl来检索翻译content,从而提供了一种更好的方法来管理多语言内容。

这个钩子允许我们从 JSON 消息文件中检索特定键的翻译,例如title或。description完成这些实现后,我们的 Next.js 14 应用程序现在配备了语言路由和 slugs。

步骤 4.当我们运行应用程序并访问localhost:port/enlocalhost:port/es、等 URL 时localhost:port/de,我们会看到不同语言的输出。

通过这些步骤,我们已在 Next.js 14 应用程序中成功实现了语言路由和 slugs,为用户提供了无缝的多语言体验。

实现语言切换

这里我们创建一个语言切换器组件LangSwitch.tsx。该组件将作为用户选择所需语言的网关:

//LangSwitcher.tsx

import React, { useState } from "react";
import Image from "next/image";
import { StaticImageData } from "next/image";
import { useRouter } from "next/navigation";
import { usePathname } from "next/navigation";
import gbFlag from "../assets/img/bg_flag.png";
import geFlag from "../assets/img/german_flag.png";
import esFlag from "../assets/img/spain_flag.png";

const LangSwitcher: React.FC = () => {
 interface Option {
   country: string;
   code: string;
   flag: StaticImageData;
}

const router = useRouter();
const pathname = usePathname();

const [isOptionsExpanded, setIsOptionsExpanded] = useState(false);

const options: Option[] = [
   { country: "English", code: "en", flag: gbFlag },
   { country: "Deutsch", code: "de", flag: geFlag },
   { country: "Spanish", code: "es", flag: esFlag },
 ];

 const setOption = (option: Option) => {
   setIsOptionsExpanded(false);
   router.push(`/${option.code}`);
 };

 return (
   <div className="flex items-center justify-center bg-gray-100">
     <div className="relative text-lg w-48">
       <button
         className=" justify-between w-full border border-gray-500 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
         onClick={() => setIsOptionsExpanded(!isOptionsExpanded)}
         onBlur={() => setIsOptionsExpanded(false)}
       >
         Select Language
         <svg
           fill="none"
           viewBox="0 0 24 24"
           stroke="currentColor"
           className={`h-4 w-4 transform transition-transform duration-200 ease-in-out ${
             isOptionsExpanded ? "rotate-180" : "rotate-0"
           }`}
         >
           <path
             strokeLinecap="round"
             strokeLinejoin="round"
             strokeWidth={2}
             d="M19 9l-7 7-7-7"
           />
         </svg>
       </button>
       <div
         className={`transition-transform duration-500 ease-custom ${
           !isOptionsExpanded
             ? "-translate-y-1/2 scale-y-0 opacity-0"
             : "translate-y-0 scale-y-100 opacity-100"
         }`}
       >
         <ul className="absolute left-0 right-0 mb-4 bg-white divide-y rounded-lg shadow-lg overflow-hidden">
           {options.map((option, index) => (
             <li
               key={index}
               className="px-3 py-2 transition-colors duration-300 hover:bg-gray-200 flex items-center cursor-pointer"
               onMouseDown={(e) => {
                 e.preventDefault();
                 setOption(option);
               }}
               onClick={() => setIsOptionsExpanded(false)}
             >
               <Image
                 src={option.flag}
                 width={"20"}
                 height={"20"}
                 alt="logo"
               />
               &nbsp;&nbsp;{option.country}
               {pathname === `/${option.code}` && (
                 <svg
                   xmlns="http://www.w3.org/2000/svg"
                   fill="none"
                   viewBox="0 0 24 24"
                   stroke="currentColor"
                   className="w-7 h-7 text-green-500 ml-auto"
                 >
                   <path
                     strokeLinecap="round"
                     strokeLinejoin="round"
                     strokeWidth={3}
                     d="M5 13l4 4L19 7"
                   />
                 </svg>
               )}
             </li>
           ))}
         </ul>
       </div>
     </div>
   </div>
 );
};

export default LangSwitcher;

上面的组件LangSwitcher使用 Next.jsrouterusePathname钩子来处理路由并跟踪当前的pathname. 使用挂钩来管理状态useState以切换语言选项下拉列表的可见性。一个名为 的数组options存储语言选项,每个对象代表一种语言并包含其各自的属性。

该函数setOption被定义为处理语言选择。单击语言选项时,它会URL使用所选的语言代码更新。如果语言选项与当前选择的语言匹配,则其旁边会显示一个复选标记图标。

该组件采用 Tailwind CSS 样式,LangSwitcher通过在多语言 Next.js 14 应用程序中提供直观的语言选择界面来增强用户体验。

现在我们已经准备好了语言切换器组件,我们将其集成到header.tsx布局中的文件中,以便可以在应用程序的所有页面上访问它。现在我们就知道了:无论用户在哪个页面,都可以轻松切换语言。

结论

总而言之,国际化在通过以用户首选语言提供内容来吸引全球受众和改善用户体验方面发挥着至关重要的作用。借助 Next.js 14,开发人员可以使用强大的工具来高效创建动态多语言网站。

从最初的设置next-intl到制作特定于语言的路由和动态 slugs,Next.js 14 组织了多语言 Web 开发的复杂性。此外,我们还探索了创建动态语言切换器以提升用户体验。

terry

这个人很懒,什么都没有留下~

Recent Posts

vue:页面注入js修改input值

一般会直接这样写: let z…

3 小时 ago

聊聊vue3中的defineProps

在Vue 3中,defineP…

1 周 ago

在 Chrome 中删除、允许和管理 Cookie

您可以选择删除现有 Cooki…

2 周 ago

自定义指令:聊聊vue中的自定义指令应用法则

今天我们来聊聊vue中的自定义…

3 周 ago

聊聊Vue中@click.stop和@click.prevent

一起来学下聊聊Vue中@cli…

4 周 ago

Nginx 基本操作:启动、停止、重启命令。

我们来学习Nginx基础操作:…

1 月 ago