登入

Nextjs+next-intl多語言國際化最佳實踐(APP路由器)

作者:neo yang 時間:2024/02/19 讀: 12441
Nextjs offers two routers: APP and Page, with Page being phased out. The author previously used Page router internationalization, but has since implemented internationalization based on the APP router. They catated several sooalration several that narl​st the sutrarst andmerc –mering the nex-cmermer面 n怎麼樣枚慢慢圖有所片面 - n見過面 n - n面 n - n面 n面 n面面 n面 n面面. . The post outlines the directory structure, routing, middleware setup, how to load translation files, and how to implement translations, emphasizing that regardless of the internationalization solution chosen, solting, file structure, and translfile遠.

Nextjs有兩種路由器:APP路由器和Page路由器。

前段時間,在Page路由器下,對nextjs做了國際化,並做了總結:

但Page路由器將會是Nextjs逐漸淘汰的路由器。所以,最近,基於APP路由器,對Nextjs做了國際化。

一、Nextjs國際化解決方案的選擇

1、i18next + react-i18next + i18next-resources-to-backend + next-i18n-router

似乎大多數都在用這個,我試了一下,挺複雜,還沒成功,所以我放棄了。

2、next-i18n-router react-intl

看著也挺複雜,由於有1的陰影,放棄了。

3、next-intl

next-intl 是一個完整的nextjs的國際化方案,無須其它軟體包。而且配置相對簡單。更重要的是,我配置成功了,沒遇到莫名其妙的問題。

所以,就是它了。

二、目錄結構

|app ..[locale] ...layout.js ...page.js |components ..LangSwitcher.js |public ..locales ...en ....common.json ...es .... common.json |i18n.js |navigation.js |middleware.js |next.config.js

三、國際化路由

1、novigation.js

這是個配置文件,這個文件中配置的項目會在其它一些文件中調用。

import { createSharedPathnamesNavigation } 從 'next-intl/navigation'; export const locales = ['en', 'de', 'es', 'ja','ko','it','pt']; export const localePrefix = 'as-needed'; export const defaultLocale= "en"; export const localeItems= [ { name: "English",code: "en", iso: "en-US", dir: "ltr" }, { name : "español",code: "es", iso: "es-ES", dir: "ltr" }, { name: "中文",code: "zh_cn", iso: "zh-CN", dir: " ltr" }, { name: "Deutsch",code: "de", iso: "de-DE", dir: "ltr" }, { name: "Italiano",code: "it", iso: "it- IT", dir: "ltr" }, { name: "日本語",code: "ja", iso: "ja-JP", dir: "ltr" }, { name: "한국인",code: "ko ", iso: "ko-KR", dir: "ltr" }, { name: "Português",code: "pt", iso: "pt-PT", dir: "ltr" }, ] export const { Link , redirect, usePathname, useRouter } = createSharedPathnamesNavigation({ locales, localePrefix });

2、[locale]目錄

app目錄中的頁面檔案全部放到[locale]目錄中。

3、中間件:middleware.js

說明:

實現以下樣式的URL

預設語言的URL:

首頁為:www.xxx.com

內頁為:www.xxx.com/about

其它語言的URL:(以西班牙語為例)

首頁為:www.xxx.com/es

內頁為:www.xxx.com/es/about

另外,如果URL中輸入了預設語言,例如預設語言為英語,使用者輸入URL:www.xxx.com/en

那麼,將自動前往www.xxx.com

代碼:

。 / Skip all paths that should not be internationalized. // This skips the folders "api", "_next" and all files // with an extension (eg favicon.ico) matcher: ["/(((!api|_next| .*\\..*).*)"], };

四、載入翻譯文件

1、翻譯文件

說明

我的翻譯檔案放在了「public」目錄中,但,其實,翻譯檔案也可以放在其它目錄中,只要在i18n.js檔案中配置好想應的路徑即可。

翻譯檔案是一個json文件,json檔案可以是嵌套格式,也可以不嵌套。這兩種,最終,在引用時會稍有不同。

程式碼(不嵌套)

{ "aaa": "hi", }

程式碼(嵌套)

{ "bbb":{ "aaa":"hi", } }

2、i18n.js文件

說明:

這個文件,是導入翻譯文件的,關鍵是配置翻譯文件的路徑,要和你的翻譯文件所在的路徑保持一致。

路徑中的${locale}表示語言。

程式碼

import { getRequestConfig } from "next-intl/server"; // Create this configuration once per request and // make it available to all Server Components. export default getRequestConfig(async ({ locale }) => ({ // Load translations for the active locale. messages: (await import(`./public/locales/${locale}/common.json`)).default, }));

3、next.config.js的配置

/** @type {import('next').NextConfig} */ const nextConfig = {} const withNextIntl = require("next-intl/plugin")("./i18n.js"); module.exports =withNextIntl ( nextConfig)

五、實現翻譯

layout.js中的程式碼:

import "./globals.css"; import { NextIntlClientProvider, useMessages } from 'next-intl'; import { locales } from '@/navigation'; import Header from '@/components/Header' import Footernavigation'; import Header from '@/components/Header' import Footernavigation'; import Header from '@/components/Header' import Footer from '@/components /Footer' export default function RootLayout({ children, params: { locale } }) { if (!locales.includes(locale)) { notFound(); } const messages = useMessages(); return (
    <html lang="{locale}">
      <nextintlclientprovider locale="{locale}" messages="{messages}">
      <body><header />{孩子}<footer /></body>
      </nextintlclientprovider>
    </html>
  );
}

page.js中的程式碼:

參數locale表示當前的語言。

如果翻譯檔案是不嵌套的方式,則const t = useTranslations();

如果翻譯檔案是嵌套的方式,則根據檔案結構和實際需要,用類似:const t = useTranslations(“bbb“);

import { useTranslations } from &#039;next-intl&#039;; import { Link } from &#039;@/navigation&#039;; export default function Home({ params: { locale } }) { const t = useTranslations(); return (<>   
<link href="{"/"}"><h1>{t(&quot;aaa&quot;)}</h1></Link>
</>)

六、語言切換器

1、效果

下拉選擇語言,目前頁面切換到所選的語言的頁面。

2、代碼

"use client";
import { useLocale } from "next-intl";
import { localeItems, useRouter, usePathname, defaultLocale } from '@/navigation';
export default function LangSwitcher() {
  const locale = useLocale();
  const router = useRouter();
  const pathname = usePathname();
  console.log(locale)

  const handleChange = (e) => {
    router.push(pathname, { locale: e.target.value });
  };
 
  return (
    <div>
      <select
      value={locale}
        onChange={handleChange}
        className="h-8 m-2 p-1 rounded border-current"
      >
        <option value={locale} > {GetLangData(locale).name}</option>

        {localeItems.map((item) => {

          if (item.code === locale) return null
          return (<option key={item.code} value={item.code}>
            {item.name}
          </option>)
        })}
      </select>
    </div>
  );
}
export function GetLangData(defaultLocale) {
  var res = {}
  {
    localeItems.map(locale => {
      if (locale.code === defaultLocale) {
        console.log(locale)
        res = locale
      }
    })
  }
  return res

}

七、SEO和搜尋引擎友好

1、Meta data

nextjs的APP路由器,產生頁面的title和Meta data,我嘗試了三種方式:

第一種方式:在layout.js中直接使用:expert const metadata={}

第二種方式:在page.js中使用動態產生Meta data

可參考:Optimizing: Metadata | Next.js (nextjs.org)

第這兩種方式,對於多語言的title和Meta data,我都失敗了。最後用了第三種方式,也是最簡單、直白的方式。

第三種方式:直接在page.js寫title標籤和Meta標籤。

所以,page.js的程式碼改成了這樣:

import { useTranslations } from &#039;next-intl&#039;; import { Link } from &#039;@/navigation&#039;; export default function Home({ params: { locale } }) { const t = useTranslations(); return (<>  
          <title>{t(&quot;site-name&quot;)}</title>
        <meta name="keyword" content="{t("site-name")}"></meta>
        <meta name="description" content="{t(&quot;site-description&quot;)}"></meta>
        <meta property="og:type" content="website"></meta>
        <meta property="og:title" content="{t(&quot;site-name&quot;)}"></meta>
        <meta property="og:description" content="{t(&quot;site-description&quot;)}"></meta>
        <meta property="og:site_name" content="{t(&quot;site-name&quot;)}"></meta>
        <meta property="og:image" content="/images/xxx.png"></meta>
        <meta property="og:image:width" content="512"></meta>
        <meta property="og:image:height" content="512"></meta>
        <meta property="og:image:alt" content=""></meta>
 
<link href="{"/"}"><h1>{t(&quot;aaa&quot;)}</h1></Link>
</>)

2.多語言導航:讓搜尋引擎更容易發現多語言URL

說明

語言切換器是前端渲染的,所以,我在頁面的底部,也就是元件Footer.js中增加了後端渲染的多語言導航。點選對應的語言就會進入此語言的網站首頁。

Footer.js程式碼如下:

import Link from 'next/link'
import { localeItems,defaultLocale } from '@/navigation';


export default function Footer(){


  return (<>
    <div className="divider"></div>
    <footer className="footer footer-center p-10 bg-base-200 text-base-content rounded">
      <nav className="flex flex-wrap gap-4">

     {localeItems.map(locale => {
          if (locale.code === defaultLocale) return(<Link className="link link-hover" href="/"  key={locale.code}>{locale.name}</Link>)
          const thehref="/"+locale.code
          return (<Link className="link link-hover" href={thehref} key={locale.code}> {locale.name}</Link>)
        })} 
  </nav> 
      <aside className='p-6 text-center'>
        <p>Copyright © 2024 - All right reserved by xxx.com</p>
      </aside>
     
    </footer>
  </>
    
  )
}

八、總結

國際化路由、翻譯文件的結構與引進、翻譯的實作。無論哪種國際化方案,都會涉及這三個面向。雖然都不叫麻煩,但總的來說,next-intl相對還是簡單一些。

九、參考

A Deep Dive into Next.js App Router Localization with next-intl

A complete guide for setting up next-intl with the App Router

標籤:


copyright © www.lyustu.com all rights reserve.
Theme: TheMoon V3.0. Author:neo yang