学习如何在您的 Next.js 应用中实现无缝的国际化 (i18n),以触达全球受众。内容涵盖路由、内容翻译和最佳实践。
Next.js 国际化:构建面向全球受众的多语言应用
在当今这个互联互通的世界里,构建能够满足全球受众需求的应用不再是奢侈品,而是一种必需。Next.js,一个强大的 React 框架,为实现国际化 (i18n) 提供了强大的功能,让您能够创建多语言应用,为全球用户提供本地化的体验。本综合指南将引导您了解构建国际化 Next.js 应用的基本概念、技术和最佳实践。
理解国际化与本地化
在深入探讨 Next.js i18n 的具体细节之前,让我们先明确几个关键术语:
- 国际化 (i18n):设计和开发应用程序的过程,使其能够轻松适应各种语言和地区,而无需进行工程上的更改。这涉及到对文本、格式和其他与区域设置相关的元素的抽象化处理。
- 本地化 (l10n):使应用程序适应特定语言和地区的过程。这包括翻译文本、调整日期和时间格式、货币符号等。
从本质上讲,i18n 是为您的应用程序进行本地化做准备。通过将依赖于语言的元素与核心代码分离,您可以更轻松地为不同市场对应用程序进行本地化。
为什么要在 Next.js 中实现国际化?
在您的 Next.js 应用中实现 i18n 会带来诸多好处:
- 扩大覆盖范围:通过提供用户偏好的语言内容,触及更广泛的受众。
- 改善用户体验:为不同地区的用户提供更个性化、更具吸引力的体验。
- 增强 SEO:通过提供针对特定地理区域的本地化内容,改善搜索引擎优化 (SEO)。
- 提高转化率:通过以用户的母语呈现信息来增加转化率,从而建立信任和理解。
- 建立全球品牌形象:通过展示对包容性的承诺和迎合多样化受众的需求,建立更强大的全球品牌形象。
Next.js 的 i18n 功能与配置
Next.js 通过其路由和内容管理功能为 i18n 提供了内置支持。以下是重要功能的分解说明:
1. 在 next.config.js 中配置 i18n
i18n 的核心配置位于 next.config.js
文件中。示例如下:
/** @type {import('next').NextConfig} */
const nextConfig = {
i18n: {
locales: ['en', 'es', 'fr'], // 支持的区域设置(语言代码)数组
defaultLocale: 'en', // 要使用的默认区域设置
localeDetection: true, // 启用/禁用基于浏览器设置的自动区域检测(可选)
// domains: [
// {
// domain: 'example.com',
// defaultLocale: 'en',
// },
// {
// domain: 'example.es',
// defaultLocale: 'es',
// },
// ],
},
}
module.exports = nextConfig;
说明:
locales
:一个包含您的应用所支持语言的语言代码(例如,'en'
代表英语,'es'
代表西班牙语,'fr'
代表法语)的数组。请务必遵循 ISO 639-1 语言代码以保持一致性。defaultLocale
:您的应用将使用的默认语言。这是在 URL 中未指定或未从用户浏览器设置中检测到其他语言时显示的语言。选择一种能代表您主要目标受众的语言。localeDetection
:一个布尔值,用于控制 Next.js 是否根据用户的浏览器设置自动检测其偏好语言。如果设置为true
,Next.js 将尝试将用户重定向到您网站的相应语言版本。domains
(可选):一个允许您将区域设置与特定域名关联的数组。如果您为不同语言使用不同的域名(例如,example.com
用于英语,example.es
用于西班牙语),这将非常有用。
2. 使用区域设置前缀进行路由
Next.js 会自动为路由添加区域设置前缀。例如,如果您有一个位于 /about
的页面,并且区域设置为 'es'(西班牙语),那么 URL 将变为 /es/about
。这使得页面的不同语言版本成为可能,并能让搜索引擎为每个区域设置索引内容。框架会为您处理重定向和路由。
3. 使用 useRouter
钩子
来自 next/router
的 useRouter
钩子提供了对当前区域设置和其他路由信息的访问。
import { useRouter } from 'next/router';
function MyComponent() {
const router = useRouter();
const { locale, locales, defaultLocale } = router;
return (
Current locale: {locale}
Available locales: {locales.join(', ')}
Default locale: {defaultLocale}
);
}
export default MyComponent;
router
对象提供了以下关键属性:
locale
: 当前选择的区域设置(例如 'en', 'es', 'fr')。locales
: 在next.config.js
中定义的所有受支持的区域设置数组。defaultLocale
: 在next.config.js
中设置的默认区域设置。asPath
: 浏览器中显示的路径,包括区域设置前缀(例如/es/about
)。pathname
: 不含区域设置前缀的路径(例如/about
)。
内容翻译策略
为 Next.js 应用配置好 i18n 后,您需要实施策略来翻译您的内容。以下是几种流行的方法:
1. 使用专门的翻译管理系统 (TMS)
对于拥有多种语言的大型项目,强烈建议使用 TMS。流行的选项包括:
- Phrase:一个基于云的 TMS,可与包括 Next.js 在内的各种平台集成。提供协作功能和自动化工作流程。
- Localize:另一个基于云的 TMS,支持多种文件格式并提供翻译管理功能。
- Crowdin:一个功能强大的 TMS,在开源社区中非常受欢迎,并与 Next.js 良好集成,使团队能够高效地翻译内容。
优点:
- 集中式翻译管理。
- 为译者提供协作功能。
- 翻译工作流程自动化。
- 与您的开发工作流程集成。
2. 创建 JSON 翻译文件
对于较小的项目,使用 JSON 文件存储翻译是一种简单有效的方法。
目录结构示例:
/src
├── locales
│ ├── en.json
│ └── es.json
├── components
│ └── MyComponent.js
└── pages
└── index.js
en.json
示例:
{
"greeting": "Hello, world!",
"welcomeMessage": "Welcome to our website."
}
es.json
示例:
{
"greeting": "¡Hola, mundo!",
"welcomeMessage": "Bienvenido a nuestro sitio web."
}
MyComponent.js
示例:
import { useRouter } from 'next/router';
import en from '../locales/en.json';
import es from '../locales/es.json';
function MyComponent() {
const { locale } = useRouter();
const t = locale === 'es' ? es : en;
return (
{t.greeting}
{t.welcomeMessage}
);
}
export default MyComponent;
这种方法提供了灵活性,并且对于小型项目而言简单明了。通常易于更新和维护。
3. 使用翻译库
有几个 JavaScript 库可以简化您 React 组件内的内容翻译。
next-i18next
:一个专为 Next.js 设计的流行库。它与框架集成良好,并提供服务器端渲染 (SSR) 和客户端翻译等功能。react-i18next
:一个通用的 React i18n 库。您可以在您的 Next.js 应用中使用它,但与next-i18next
相比,可能需要更多配置。
使用 next-i18next
的示例(安装:npm install next-i18next i18next react-i18next
):
创建一个 i18n 配置文件(例如,在您的根目录中的 i18n.js
):
// i18n.js
import { createServerSideHelpers } from 'next-i18next'
import { i18n } from './next-i18next.config'
export function initI18next(req, res, namespaces = ['common']) {
const helpers = createServerSideHelpers(
req,
res,
i18n,
namespaces
)
return helpers
}
export { appWithTranslation } from 'next-i18next'
export { i18n }
为 next-i18next 创建您的 Next.js 配置。
// next-i18next.config.js
const { i18n } = require('./next-i18next.config');
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
i18n: {
defaultLocale: 'en',
locales: ['en', 'es', 'fr'],
},
// 其他配置
}
module.exports = nextConfig
将配置和翻译导入添加到您的 _app.js
中:
import { appWithTranslation } from 'next-i18next';
import '../styles/globals.css';
function MyApp({ Component, pageProps }) {
return ;
}
export default appWithTranslation(MyApp);
创建一个文件夹并用您的翻译区域设置文件填充它。
/public
└── locales
├── en
│ └── common.json
├── es
│ └── common.json
└── fr
└── common.json
en/common.json 示例:
{
"greeting": "Hello, world!",
"welcomeMessage": "Welcome to our website."
}
在组件中使用翻译:
import { useTranslation } from 'next-i18next';
function MyComponent() {
const { t } = useTranslation('common');
return (
{t('greeting')}
{t('welcomeMessage')}
);
}
export default MyComponent;
此示例使用 useTranslation
钩子根据当前区域设置检索翻译。
处理动态路由和静态站点生成 (SSG)
在处理动态路由(例如,博客文章、产品页面)和静态站点生成 (SSG) 时,国际化会变得更加复杂。
1. 动态路由(例如 /blog/[slug])
对于动态路由,您需要在构建时使用 getStaticPaths
为每个区域设置生成正确的路径。此函数返回一个 Next.js 应该预渲染的路径数组。
export async function getStaticPaths() {
const paths = [];
const locales = ['en', 'es', 'fr'];
const posts = await fetchPosts(); // 获取博客文章数据
posts.forEach(post => {
locales.forEach(locale => {
paths.push({
params: {
slug: post.slug,
},
locale,
});
});
});
return {
paths,
fallback: false, // 或者 'blocking' 如果你想显示加载状态
};
}
export async function getStaticProps({ params, locale }) {
const post = await getPostBySlug(params.slug, locale);
return {
props: {
post,
},
};
}
说明:
getStaticPaths
:此函数遍历您的博客文章,并为每篇文章和每个区域设置生成一个路径。params
对象包含路由参数(例如,博客文章的 slug)。locale
:此参数提供当前区域设置,允许您获取特定区域设置的翻译内容。fallback
:决定 Next.js 如何处理未在getStaticPaths
中定义的路径。fallback: false
会为未定义的路径生成 404 页面。fallback: 'blocking'
会按需预渲染页面。
2. 使用 getStaticProps
进行静态站点生成 (SSG)
在 getStaticProps
中,您可以根据 locale
参数获取翻译内容。
export async function getStaticProps({ params, locale }) {
// 根据区域设置和参数获取内容
const { post } = await getPostBySlug(params.slug, locale);
return {
props: {
post,
},
};
}
getPostBySlug
函数应获取给定 slug 和区域设置的翻译内容,这些内容可以从您的翻译文件、数据库或 CMS 中检索。
3. 使用 getServerSideProps
进行服务器端渲染 (SSR)
对于需要在请求时获取的内容,请使用 getServerSideProps
。如果内容频繁更改或为每个用户个性化,这将非常有用。
export async function getServerSideProps({ params, locale, req, res }) {
// 根据区域设置和参数获取数据(例如,从数据库)
const data = await fetchData(params.slug, locale);
return {
props: {
data,
},
};
}
Next.js 国际化的最佳实践
遵循这些最佳实践将帮助您构建健壮、可维护且用户友好的多语言应用程序:
- 尽早规划:从项目一开始就考虑国际化。预先实施比事后改造要容易得多。
- 内容与代码分离:将所有可翻译的文本存储在单独的文件中(例如,JSON 文件或 TMS),并避免在组件中硬编码文本。
- 使用翻译管理系统 (TMS):对于较大的项目,TMS 可以简化翻译流程并改善协作。
- 彻底测试:在所有支持的语言中测试您的应用程序,以确保翻译准确、格式正确,并在不同浏览器和设备上正确呈现。在真实设备上测试,而不仅仅是模拟器。
- 考虑从右到左 (RTL) 的语言:如果您支持像阿拉伯语或希伯来语这样的语言,请确保您的设计和布局能够适应从右到左的文本方向。Next.js 不会自动处理此问题,因此需要 CSS 或其他解决方案。
- 处理日期和时间格式:使用库或内置函数根据用户的区域设置格式化日期和时间。Moment.js 和 date-fns 是两个有用的流行库。
- 管理数字和货币格式:根据用户的区域设置正确格式化数字和货币符号。
- 优化 SEO:使用特定于语言的元标签 (
hreflang
) 来帮助搜索引擎正确索引您的内容。在您的 URL 中包含语言代码。 - 优先考虑用户体验:为用户提供清晰直观的方式来切换语言。考虑根据浏览器设置提供自动语言检测。
- 保持更新:保持您的 Next.js 版本和 i18n 库为最新,以受益于最新的功能和安全补丁。
- 考虑可访问性 (a11y):确保您的翻译内容对残障用户是可访问的。为图像提供替代文本并使用适当的 ARIA 属性。使用屏幕阅读器进行测试。
国际化网站的 SEO 注意事项
为您的国际化网站优化搜索引擎对于从世界各地吸引自然流量至关重要。以下是一些关键的 SEO 最佳实践:
hreflang
标签:在您的 HTML 的<head>
中实施hreflang
标签,以告知搜索引擎您内容的语言和区域变体。这对 SEO 至关重要。例如:<link rel="alternate" hreflang="en" href="https://example.com/en/" />
和<link rel="alternate" hreflang="es" href="https://example.com/es/" />
- 特定于语言的 URL:在您的 URL 中使用语言代码(例如,
/en/about
,/es/acerca-de
)。这向用户和搜索引擎清楚地表明了内容的语言。 - 本地化内容:准确自然地翻译您的内容。机器翻译应由母语人士审阅。
- 本地化的元描述和标题:为每种语言编写独特且引人注目的元描述和标题,以提高搜索结果中的点击率。
- XML 站点地图:创建并提交包含您页面所有语言变体的 XML 站点地图。
- 内部链接:在您内容的语言版本之间使用适当的内部链接。
- 特定国家/地区的关键字研究:用每种语言进行关键字研究,以确定用户在每个地区搜索的术语。
示例:构建一个简单的多语言博客
让我们使用 Next.js 创建一个简化的多语言博客示例。这将更具体地说明如何应用上述概念。
1. 项目设置
创建一个新的 Next.js 项目:
npx create-next-app my-multi-lang-blog
cd my-multi-lang-blog
2. 配置 i18n (next.config.js
)
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
i18n: {
locales: ['en', 'es', 'fr'],
defaultLocale: 'en',
},
}
module.exports = nextConfig
3. 创建翻译文件
在根目录中创建一个 locales
文件夹,并添加以下 JSON 文件:
locales/en.json
:
{
"title": "Welcome to My Blog",
"postTitle": "My First Post",
"postContent": "This is the content of my first blog post."
}
locales/es.json
:
{
"title": "Bienvenido a mi Blog",
"postTitle": "Mi Primer Post",
"postContent": "Este es el contenido de mi primer publicación de blog."
}
locales/fr.json
:
{
"title": "Bienvenue sur Mon Blog",
"postTitle": "Mon Premier Article",
"postContent": "Ceci est le contenu de mon premier article de blog."
}
4. 创建博客文章组件 (例如 components/BlogPost.js
)
import { useRouter } from 'next/router';
import en from '../locales/en.json';
import es from '../locales/es.json';
import fr from '../locales/fr.json';
function BlogPost() {
const router = useRouter();
const { locale } = router;
let translations;
switch (locale) {
case 'es':
translations = es;
break;
case 'fr':
translations = fr;
break;
default:
translations = en;
}
return (
{translations.postTitle}
{translations.postContent}
);
}
export default BlogPost;
5. 创建索引页面 (pages/index.js
)
import { useRouter } from 'next/router';
import BlogPost from '../components/BlogPost';
import en from '../locales/en.json';
import es from '../locales/es.json';
import fr from '../locales/fr.json';
function HomePage() {
const router = useRouter();
const { locale, locales } = router;
let translations;
switch (locale) {
case 'es':
translations = es;
break;
case 'fr':
translations = fr;
break;
default:
translations = en;
}
return (
);
}
export default HomePage;
这个简化的示例展示了 Next.js 国际化的基本原则。您可以在此基本框架上进行扩展,以包含更复杂的功能,例如动态路由和与翻译管理系统的集成。可以考虑使用 Link
组件改进上面的链接,并添加适当的 locale
属性。
6. 运行应用程序
使用以下命令运行应用程序:
npm run dev
现在您可以在 http://localhost:3000
(英语)、http://localhost:3000/es
(西班牙语)和 http://localhost:3000/fr
(法语)访问您的博客。您应该能看到标题和博客文章内容根据所选区域设置进行了翻译。
结论
Next.js 提供了一套全面的功能,用于在您的 Web 应用程序中实现国际化。通过遵循本指南中概述的原则和技术,您可以创建能够为全球用户提供本地化体验的多语言应用程序。请记住尽早规划您的 i18n 策略,选择适合您需求的正确翻译方法,并优先考虑用户体验。通过精心的规划和执行,您可以构建能与全球受众产生共鸣的应用程序,并开启新的增长机会。持续学习、跟上最新版本和最佳实践将确保您有效地利用您的工具和技术。
随着技术的发展,预计会出现更多先进的 i18n 功能。能够触达不同文化和语言群体的用户,仍将是全球应用程序开发人员的首要任务。因此,掌握 i18n 的基础知识是一项宝贵的技能,它将提升您在当今全球化开发领域中的价值。