翻译 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
为整个 React 树提供全部可用命名空间,并且属于页面级别。两者都是必需的。
默认情况下, 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 的未来。