翻譯 Next.js 應用程式的最簡單方法(帶頁面設定) 。
如果您在生產中使用 next-i18next (頁面目錄)並且想要釋放一些超能力,您可以看看這篇部落格文章。
如果您將 Next.js 13/14 與 app 目錄一起使用,則不需要 next-i18next,您可以直接使用 i18next 和 react-i18next,如本部落格文章所述。
儘管 Next.js 直接提供國際化路由,但它不處理翻譯內容的任何管理,也不處理實際的翻譯功能本身。 Next.js 所做的只是保持區域設定和 URL 同步。
為了補充這一點, next-i18next
提供了剩餘的功能——翻譯內容的管理,以及用於翻譯 React 元件的元件/掛鉤——同時完全支援 SSG/SSR、多個命名空間、程式碼分割等。
雖然next-i18next
在底層使用 i18next 和 react-i18next,但next-i18next
的使用者只需將其翻譯內容作為 JSON 檔案包含進來,而不必擔心其他問題。
此處提供現場演示。這個演示應用程式是一個簡單的例子 - 僅此而已。
易於設置,易於使用:設置只需幾個步驟,配置也很簡單。
沒有其他要求: next-i18next
簡化了 Next.js 應用程式的國際化,無需額外的依賴項。
生產就緒: next-i18next
支援將翻譯和設定選項作為具有 SSG/SSR 支援的 props 傳遞到頁面中。
您的next-i18next.config.js
檔案將為next-i18next
提供設定。配置完成後, appWithTranslation
允許我們透過鉤子在元件中使用t
(翻譯)函數。
然後我們將serverSideTranslation
新增到頁面層級元件中的 getStaticProps 或 getServerSideProps (取決於您的情況)。
現在我們的 Next.js 應用程式是完全可翻譯的!
yarn add next-i18next react-i18next i18next
您還需要安裝react
和next
。
預設情況下, next-i18next
希望您的翻譯如下組織:
.
└── public
└── locales
├── en
| └── common.json
└── de
└── common.json
這個結構也可以在簡單的例子中看到。
如果您想以自訂方式建立翻譯/命名空間,則需要將修改後的localePath
和localeStructure
值傳遞到初始化配置中。
首先,在專案的根目錄中建立一個next-i18next.config.js
檔案。嵌套i18n
物件的語法直接來自 Next.js。
這告訴next-i18next
你的defaultLocale
和其他語言環境是什麼,以便它可以在伺服器上預先載入翻譯:
next-i18next.config.js
/** @type {import('next-i18next').UserConfig} */
module . exports = {
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'de' ] ,
} ,
}
現在,透過將i18n
物件傳遞到next.config.js
檔案中來建立或修改next.config.js
文件,以啟用本地化 URL 路由:
next.config.js
const { i18n } = require ( './next-i18next.config' )
module . exports = {
i18n ,
}
next-i18next
匯出三個函數,您需要使用它們來翻譯您的專案:
這是一個 HOC,它包裝了你的_app
:
import { appWithTranslation } from 'next-i18next'
const MyApp = ( { Component , pageProps } ) => (
< Component { ... pageProps } / >
)
export default appWithTranslation ( MyApp )
appWithTranslation
HOC 主要負責新增I18nextProvider
。
這是一個非同步函數,您需要透過getStaticProps
或getServerSideProps
(取決於您的用例)將其包含在頁面層級元件中:
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
export async function getStaticProps ( { locale } ) {
return {
props : {
... ( await serverSideTranslations ( locale , [
'common' ,
'footer' ,
] ) ) ,
// Will be passed to the page component as props
} ,
}
}
請注意, serverSideTranslations
必須從next-i18next/serverSideTranslations
導入-這是一個包含 NodeJs 特定程式碼的單獨模組。
另請注意, serverSideTranslations
與getInitialProps
不相容,因為它只能在伺服器環境中執行,而getInitialProps
在頁面之間導航時在客戶端呼叫。
serverSideTranslations
HOC 主要負責將翻譯和設定選項作為 props 傳遞到頁面中 - 您需要將其新增至任何具有翻譯的頁面。
這是您實際用來進行翻譯的鉤子。 useTranslation
鉤子來自react-i18next
,但需要直接從next-i18next
匯入。
不要使用react-i18next
的useTranslation
匯出,而只能使用next-i18next
中的匯出!
import { useTranslation } from 'next-i18next'
export const Footer = ( ) => {
const { t } = useTranslation ( 'footer' )
return (
< footer >
< p > { t ( 'description' ) } < / p >
< / footer >
)
}
預設情況下, next-i18next
會在每次初始請求時將所有命名空間傳送到客戶端。對於內容較少的小型應用程式來說,這可能是一種合適的方法,但許多應用程式將受益於根據路由分割命名空間。
為此,您可以將每個頁面所需的命名空間陣列傳遞到serverSideTranslations
中。您可以在 example/simple/pages/index.tsx 中看到這種方法。傳入所需命名空間的空數組將不會發送任何命名空間。
注意: useTranslation
為您在其中使用它的元件serverSideTranslations
命名空間。兩者都是必需的。
預設情況下, next-i18next
在每次請求時僅將活動區域設定傳送至客戶端。這有助於減少發送到客戶端的初始有效負載的大小。然而,在某些情況下,人們可能在運行時也需要其他語言的翻譯。例如,當使用useTranslation
掛鉤的 getFixedT 時。
要變更行為並載入額外的語言環境,只需將語言環境陣列作為最後一個參數傳遞給serverSideTranslations
。
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
export async function getStaticProps({ locale }) {
return {
props: {
- ...(await serverSideTranslations(locale, ['common', 'footer'])),
+ ...(await serverSideTranslations(locale, ['common', 'footer'], null, ['en', 'no'])),
},
};
}
因此,無論當前語言如何,都將始終載入no
和en
語言環境的翻譯。
注意:所有使用
getFixedT
函數的頁面都應該要增加額外的參數。
預設情況下, next-i18next
將新增defaultLocale
作為後備。若要變更此設置,您可以設定fallbackLng
。 next-i18next
也支援i18next
支援的所有值( string
、 array
、 object
和function
)。
此外, nonExplicitSupportedLngs
可以設定為true
以支援語言的所有變體,而無需為每種語言提供 JSON 檔案。請注意,所有變體仍然必須包含在locales
中才能在next.js
中啟用路由。
注意:
fallbackLng
和nonExplicitSupportedLngs
可以同時使用。只有一個例外:當nonExplicitSupportedLngs
為true
時,您不能使用fallbackLng
函數,
module . exports = {
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'fr' , 'de-AT' , 'de-DE' , 'de-CH' ] ,
} ,
fallbackLng : {
default : [ 'en' ] ,
'de-CH' : [ 'fr' ] ,
} ,
nonExplicitSupportedLngs : true ,
// de, fr and en will be loaded as fallback languages for de-CH
}
請注意,使用fallbackLng
和nonExplicitSupportedLngs
可以輕鬆增加頁面的初始大小。
僅供參考:將fallbackLng
設定為false
不會序列化您的後備語言(通常是defaultLocale
)。這將減少初始頁面載入的大小。
如果需要修改更進階的設定選項,可以透過next-i18next.config.js
傳遞它們。例如:
module . exports = {
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'de' ] ,
} ,
localePath :
typeof window === 'undefined'
? require ( 'path' ) . resolve ( './my-custom/path' )
: '/public/my-custom/path' ,
ns : [ 'common' ] ,
}
有些i18next
插件(您可以將其傳遞到config.use
)是不可序列化的,因為它們包含函數和其他 JavaScript 原語。
如果您的用例更高級,您可能會遇到這種情況。您將看到 Next.js 拋出以下錯誤:
Error: Error serializing `._nextI18Next.userConfig.use[0].process` returned from `getStaticProps` in "/my-page".
Reason: `function` cannot be serialized as JSON. Please only return JSON serializable data types.
要解決此問題,您需要將config.serializeConfig
設定為false
,並手動將配置傳遞到appWithTranslation
中:
import { appWithTranslation } from 'next-i18next'
import nextI18NextConfig from '../next-i18next.config.js'
const MyApp = ( { Component , pageProps } ) => (
< Component { ... pageProps } / >
)
export default appWithTranslation ( MyApp , nextI18NextConfig )
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import nextI18NextConfig from '../next-i18next.config.js'
export const getStaticProps = async ( { locale } ) => ( {
props : {
... ( await serverSideTranslations (
locale ,
[ 'common' , 'footer' ] ,
nextI18NextConfig
) ) ,
} ,
} )
當在伺服器端產生的頁面上使用getStaticPaths
和fallback: true
或fallback: 'blocking'
時,上面指出的預設設定將導致應用程式在每次載入時卸載並重新安裝,從而導致各種不良後果,例如調用每個useEffect(() => {...}, [])
掛鉤兩次,性能略有下降。
這是因為,對於這些頁面,Next.js 使用空的serverSideProps
進行第一次渲染,然後使用包含next-i18next
翻譯的serverSideProps
進行第二次渲染。使用預設設置,當serverSideProps
為empty
時, i18n
實例最初是undefined
,從而導致卸載重新安裝。
若要緩解此問題,您可以執行以下操作:
import { UserConfig } from 'next-i18next' ;
import nextI18NextConfig from '../next-i18next.config.js'
const emptyInitialI18NextConfig : UserConfig = {
i18n : {
defaultLocale : nextI18NextConfig . i18n . defaultLocale ,
locales : nextI18NextConfig . i18n . locales ,
} ,
} ;
const MyApp = ( { Component , pageProps } ) => (
< Component { ... pageProps } / >
)
export default appWithTranslation ( MyApp , emptyInitialI18NextConfig ) // Makes sure the initial i18n instance is not undefined
只要您確保在後備頁面狀態下,您的客戶端程式碼不會嘗試顯示任何翻譯,這就會起作用,否則您將從 Next.js 收到“伺服器-客戶端不匹配”錯誤(由於事實上,伺服器在其html 中具有實際翻譯,而客戶端html 在同一位置具有翻譯金鑰)。
這是正常且正常的:無論如何您都不應該向使用者顯示翻譯金鑰!
從 v11.0.0 開始,next-i18next 也提供對客戶端載入翻譯的支援。
在某些用例中,您可能希望動態載入翻譯文件,而不必使用serverSideTranslations
。這對於您不希望減慢頁面速度的延遲載入元件特別有用。
有關這方面的更多資訊可以在這裡找到。
由於資源在伺服器啟動時加載一次,因此在開發過程中對翻譯 JSON 檔案所做的任何更改都不會加載,直到伺服器重新啟動。
在生產中,這通常不會成為問題,但在開發中,您可能想要查看翻譯 JSON 檔案的更新,而不必每次都重新啟動開發伺服器。為此,請將reloadOnPrerender
設定選項設為true
。
每當呼叫serverSideTranslations
(在getStaticProps
或getServerSideProps
中)時,此選項將重新載入您的翻譯。如果您在getServerSideProps
中使用serverSideTranslations
,建議在生產環境中停用reloadOnPrerender
,以避免在每次伺服器呼叫時重新載入資源。
鑰匙 | 預設值 | 筆記 |
---|---|---|
defaultNS | 'common' | |
localePath | './public/locales' | 可以是一個函數,請參閱下面的註釋。 (如果直接透過設定傳遞資源選項,也可以為 null,如下所示) |
localeExtension | 'json' | 如果localePath 是函數,則忽略。 |
localeStructure | '{{lng}}/{{ns}}' | 如果localePath 是函數,則忽略。 |
reloadOnPrerender | false | |
serializeConfig | true | |
use (用於插件) | [] | |
onPreInitI18next | undefined | 即(i18n) => i18n.on('failedLoading', handleFailedLoading) |
localePath
作為函數的形式為(locale: string, namespace: string, missing: boolean) => string
傳回包含檔案名稱和副檔名的整個路徑。當missing
為 true 時,傳回i18next-fs-backend
的addPath
選項的路徑,當 false 時,傳回loadPath
選項的路徑。更多資訊請參閱i18next-fs-backend
儲存庫。
如果 localePath 是一個函數,請確保您也定義了 ns 選項,因為在伺服器端我們無法預先載入名稱空間。
所有其他 i18next 選項和react-i18next 選項也可以傳入。
您也可以直接傳入resources
並結合將localePath
設為null
。
預設情況下,i18next 使用{{
作為前綴, }}
作為後綴進行插值。如果您想要/需要覆寫這些插值設置,您還必須指定與您的自訂前綴和後綴相符的備用localeStructure
設定。
例如,如果您想使用{
和}
配置將如下所示:
{
i18n : {
defaultLocale : 'en' ,
locales : [ 'en' , 'nl' ] ,
} ,
interpolation : {
prefix : '{' ,
suffix : '}' ,
} ,
localeStructure : '{lng}/{ns}' ,
}
next-i18next.config.js
路徑如果要變更預設配置路徑,可以設定環境變數I18NEXT_DEFAULT_CONFIG_PATH
。
例如,在.env
檔中,您可以設定靜態路徑:
I18NEXT_DEFAULT_CONFIG_PATH=/path/to/project/apps/my-app/next-i18next.config.js
或者您可以使用動態路徑技巧並在next.config.js
中設定以下內容:
process . env . I18NEXT_DEFAULT_CONFIG_PATH = ` ${ __dirname } /next-i18next.config.js` ;
// ... Some other imports
const { i18n } = require ( './next-i18next.config' ) ;
// ... Some other code
module . exports = {
i18n ,
...
} ;
這意味著 i18n 設定檔將與next.config.js
位於同一目錄中,而目前工作目錄在哪裡並不重要。例如,當您擁有 monorepo 並從專案根目錄啟動應用程式但應用程式位於apps/{appName}
時,這對nx
很有幫助。
注意如果您的設定next-i18next.config.js
與next.config.js
不在同一目錄中,必須手動複製它(或透過自訂腳本)。
如果您打算逐步將 next-i18next 加入到專案中,我們建議您將next-i18next.config
傳遞給appWithTranslation
以避免任何問題。
IE
import nextI18nextConfig from '../../next-i18next.config' ;
//...
export default appWithTranslation ( MyApp , nextI18nextConfig ) ;
有關詳細信息,請參閱問題 #2259。
某些無伺服器 PaaS 可能無法找到翻譯的路徑,並且需要額外的配置。如果您在使用serverSideTranslations
時遇到檔案系統問題,請將config.localePath
設定為使用path.resolve
。可以在這裡找到一個例子。
對於 Docker 部署,請注意,如果您使用 Next.js 文件中的Dockerfile
,請不要忘記將next.config.js
和next-i18next.config.js
複製到 Docker 映像中。
COPY --from=builder /app/next.config.js ./next.config.js
COPY --from=builder /app/next-i18next.config.js ./next-i18next.config.js
如果您選擇使用與內建 i18next-fs-backend 不同的 i18next 後端,則需要確保在呼叫t
函數之前載入翻譯資源。由於 SSR 尚不支援 React Suspense,因此可以透過兩種不同的方式解決這個問題:
1)預載命名空間:
設定ns
選項,如本例所示。這樣做將確保在初始化時載入所有翻譯資源。
2)檢查就緒標誌:
如果您不能或不想提供ns
數組,則呼叫t
函數將導致命名空間動態載入。這表示您需要透過檢查ready === true
或props.tReady === true
來處理「未就緒」狀態。不這樣做將導致在加載之前渲染您的翻譯,這將導致儘管翻譯實際存在(尚未加載),但仍會調用“保存缺失”。這可以透過 useTranslation 掛鉤或 withTranslation HOC 來完成。
您是否嘗試透過執行next export
一個匯出來產生靜態 HTML 匯出並收到此錯誤?
錯誤:i18n 支援與下一次導出不相容。有關部署的更多信息,請參閱此處:https://nextjs.org/docs/deployment
但有一種方法可以在下一種語言檢測器的幫助下解決這個問題。查看這篇文章和這個範例項目。
您可以透過多種方式在子元件中使用 t 函數:
t
函數傳遞給子級useTranslation
函數,如本例所示:next-i18next/examples/simple/components/Footer.tsx
e6b5085 中的第 6 行
withTranslation
函數一般來說,您始終需要確保 serverSideTranslations 包含樹中所需的所有命名空間。
感謝這些優秀的人(表情符號鍵):
羅布·卡佩里尼 | 亞歷山大·卡奇卡耶夫 ? ? | 馬蒂亞斯·沃貝 ? | 盧卡斯·費里西亞諾 ? ? | 梁瑞恩 | 內森·弗里梅爾 ? | 艾薩克·辛曼 ️️️️♿️? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? |
阿德里亞諾·拉伊亞諾 ️️️️♿️? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? | 菲利克斯·莫舍夫 ? | 塞巴斯蒂安·範韋爾特姆 ? ? |
該項目遵循所有貢獻者規範。歡迎任何形式的貢獻!
在地化即服務 -locize.com
需要翻譯管理嗎?想要使用 InContext Editor 編輯您的翻譯嗎?使用 i18next 維護者提供給您的原始版本!
使用 locize,您可以直接支援 i18next 和 next-i18next 的未來。