Nuxt.js 国际化支持
学习目标
通过本章节的学习,你将能够:
- 掌握 Nuxt.js 中国际化插件的集成方法
- 理解如何配置和管理语言文件
- 学会实现动态语言切换功能
- 了解如何配置路由国际化
- 掌握日期、数字等格式化的方法
- 了解国际化的最佳实践
核心知识点讲解
什么是国际化?
国际化(Internationalization,简称 i18n)是指设计和开发应用程序时,使其能够适应不同语言和地区的需求,而无需进行工程上的改变。国际化的目标是让应用程序能够轻松地支持多语言和多地区。
Nuxt.js 中的国际化方案
Nuxt.js 提供了多种国际化方案,其中最常用的是使用 @nuxtjs/i18n 模块。这个模块基于 Vue I18n 库,提供了完整的国际化功能。
安装和配置 @nuxtjs/i18n 模块
步骤:
- 安装
@nuxtjs/i18n模块 - 在
nuxt.config.js中配置国际化选项 - 创建语言文件
示例:安装模块
# 使用 npm
npm install @nuxtjs/i18n
# 使用 yarn
yarn add @nuxtjs/i18n
# 使用 pnpm
pnpm add @nuxtjs/i18n示例:在 nuxt.config.js 中配置
export default {
modules: [
'@nuxtjs/i18n'
],
i18n: {
// 支持的语言
locales: [
{
code: 'zh',
iso: 'zh-CN',
name: '中文',
file: 'zh-CN.js'
},
{
code: 'en',
iso: 'en-US',
name: 'English',
file: 'en-US.js'
}
],
// 语言文件的目录
langDir: 'locales/',
// 默认语言
defaultLocale: 'zh',
// 路由国际化配置
strategy: 'prefix_and_default',
// 检测浏览器语言
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
alwaysRedirect: true,
fallbackLocale: 'zh'
},
// 自定义路径
pages: {
about: {
zh: '/about',
en: '/about-us'
}
}
}
}创建语言文件
在 locales 目录下创建语言文件:
示例:locales/zh-CN.js
export default {
welcome: '欢迎来到我的网站',
about: '关于我们',
contact: '联系我们',
home: '首页',
blog: '博客',
products: '产品',
services: '服务',
login: '登录',
register: '注册',
logout: '退出登录',
search: '搜索',
submit: '提交',
cancel: '取消',
save: '保存',
delete: '删除',
edit: '编辑',
create: '创建',
update: '更新',
name: '姓名',
email: '邮箱',
password: '密码',
confirmPassword: '确认密码',
phone: '电话',
address: '地址',
message: '留言',
send: '发送',
thanks: '谢谢',
success: '成功',
error: '错误',
warning: '警告',
info: '信息',
loading: '加载中...',
noData: '暂无数据',
pageNotFound: '页面不存在',
serverError: '服务器错误',
backToHome: '返回首页',
retry: '重试',
continue: '继续',
finish: '完成',
next: '下一步',
previous: '上一步',
// 日期相关
date: {
format: 'YYYY-MM-DD',
today: '今天',
yesterday: '昨天',
tomorrow: '明天',
monday: '周一',
tuesday: '周二',
wednesday: '周三',
thursday: '周四',
friday: '周五',
saturday: '周六',
sunday: '周日',
january: '一月',
february: '二月',
march: '三月',
april: '四月',
may: '五月',
june: '六月',
july: '七月',
august: '八月',
september: '九月',
october: '十月',
november: '十一月',
december: '十二月'
},
// 数字相关
number: {
currency: '¥{{ value }}',
percentage: '{{ value }}%',
decimal: '{{ value }}'
}
}示例:locales/en-US.js
export default {
welcome: 'Welcome to my website',
about: 'About Us',
contact: 'Contact Us',
home: 'Home',
blog: 'Blog',
products: 'Products',
services: 'Services',
login: 'Login',
register: 'Register',
logout: 'Logout',
search: 'Search',
submit: 'Submit',
cancel: 'Cancel',
save: 'Save',
delete: 'Delete',
edit: 'Edit',
create: 'Create',
update: 'Update',
name: 'Name',
email: 'Email',
password: 'Password',
confirmPassword: 'Confirm Password',
phone: 'Phone',
address: 'Address',
message: 'Message',
send: 'Send',
thanks: 'Thank you',
success: 'Success',
error: 'Error',
warning: 'Warning',
info: 'Info',
loading: 'Loading...',
noData: 'No data',
pageNotFound: 'Page not found',
serverError: 'Server error',
backToHome: 'Back to home',
retry: 'Retry',
continue: 'Continue',
finish: 'Finish',
next: 'Next',
previous: 'Previous',
// Date related
date: {
format: 'MM/DD/YYYY',
today: 'Today',
yesterday: 'Yesterday',
tomorrow: 'Tomorrow',
monday: 'Monday',
tuesday: 'Tuesday',
wednesday: 'Wednesday',
thursday: 'Thursday',
friday: 'Friday',
saturday: 'Saturday',
sunday: 'Sunday',
january: 'January',
february: 'February',
march: 'March',
april: 'April',
may: 'May',
june: 'June',
july: 'July',
august: 'August',
september: 'September',
october: 'October',
november: 'November',
december: 'December'
},
// Number related
number: {
currency: '${{ value }}',
percentage: '{{ value }}%',
decimal: '{{ value }}'
}
}在组件中使用国际化
在组件中,你可以使用 $t 方法来翻译文本:
<template>
<div>
<h1>{{ $t('welcome') }}</h1>
<nav>
<nuxt-link to="/" class="nav-link">{{ $t('home') }}</nuxt-link>
<nuxt-link to="/about" class="nav-link">{{ $t('about') }}</nuxt-link>
<nuxt-link to="/contact" class="nav-link">{{ $t('contact') }}</nuxt-link>
</nav>
</div>
</template>
<script>
export default {
name: 'HomePage'
}
</script>
<style scoped>
.nav-link {
margin-right: 20px;
text-decoration: none;
color: #333;
}
.nav-link:hover {
color: #1890ff;
}
</style>动态语言切换
你可以使用 $i18n 对象来实现动态语言切换:
<template>
<div class="language-switcher">
<button
v-for="locale in $i18n.locales"
:key="locale.code"
:class="{ active: $i18n.locale === locale.code }"
@click="switchLanguage(locale.code)"
>
{{ locale.name }}
</button>
</div>
</template>
<script>
export default {
name: 'LanguageSwitcher',
methods: {
switchLanguage(locale) {
this.$i18n.locale = locale
}
}
}
</script>
<style scoped>
.language-switcher {
display: flex;
gap: 10px;
}
button {
padding: 5px 10px;
border: 1px solid #ddd;
background-color: #f0f0f0;
border-radius: 4px;
cursor: pointer;
}
button.active {
background-color: #1890ff;
color: white;
border-color: #1890ff;
}
button:hover {
background-color: #e0e0e0;
}
button.active:hover {
background-color: #40a9ff;
}
</style>路由国际化
@nuxtjs/i18n 模块提供了路由国际化功能,支持多种路由策略:
- prefix:为所有路由添加语言前缀
- prefix_except_default:只为非默认语言添加前缀
- prefix_and_default:为所有路由添加前缀,包括默认语言
- no_prefix:不添加语言前缀
示例:在 nuxt.config.js 中配置路由国际化
export default {
i18n: {
// 路由策略
strategy: 'prefix_and_default',
// 自定义路由
pages: {
about: {
zh: '/about',
en: '/about-us'
},
contact: {
zh: '/contact',
en: '/contact-us'
}
}
}
}日期、数字等格式化
Vue I18n 提供了日期、数字等格式化功能,你可以在组件中使用这些功能:
示例:日期格式化
<template>
<div>
<p>{{ $d(new Date(), 'short') }}</p>
<p>{{ $d(new Date(), 'long') }}</p>
<p>{{ $d(new Date(), 'custom') }}</p>
</div>
</template>
<script>
export default {
name: 'DateFormatExample'
}
</script>示例:数字格式化
<template>
<div>
<p>{{ $n(123456.78) }}</p>
<p>{{ $n(123456.78, 'currency') }}</p>
<p>{{ $n(0.75, 'percentage') }}</p>
</div>
</template>
<script>
export default {
name: 'NumberFormatExample'
}
</script>示例:在语言文件中配置格式化选项
// locales/zh-CN.js
export default {
// 其他翻译...
datetimeFormats: {
short: {
year: 'numeric',
month: 'short',
day: 'numeric'
},
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
hour: 'numeric',
minute: 'numeric'
},
custom: {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}
},
numberFormats: {
currency: {
style: 'currency',
currency: 'CNY',
minimumFractionDigits: 2
},
percentage: {
style: 'percent',
minimumFractionDigits: 1
},
decimal: {
style: 'decimal',
minimumFractionDigits: 2,
maximumFractionDigits: 2
}
}
}实用案例分析
案例一:多语言博客网站
场景描述:创建一个支持多语言的博客网站,用户可以在不同语言之间切换,并且博客内容也会根据选择的语言显示。
实现方案:
<template>
<div class="blog-page">
<!-- 语言切换器 -->
<div class="language-switcher">
<button
v-for="locale in $i18n.locales"
:key="locale.code"
:class="{ active: $i18n.locale === locale.code }"
@click="switchLanguage(locale.code)"
>
{{ locale.name }}
</button>
</div>
<!-- 博客文章列表 -->
<div class="blog-list">
<div v-for="post in posts" :key="post.id" class="blog-post">
<h2>{{ post.title }}</h2>
<p class="post-meta">
{{ $d(new Date(post.createdAt), 'long') }}
</p>
<p class="post-excerpt">{{ post.excerpt }}</p>
<nuxt-link :to="`/blog/${post.slug}`">{{ $t('readMore') }}</nuxt-link>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'BlogPage',
data() {
return {
posts: []
}
},
async fetch() {
// 根据当前语言获取博客文章
const locale = this.$i18n.locale
this.posts = await this.$axios.$get(`/api/blog/posts?locale=${locale}`)
},
methods: {
switchLanguage(locale) {
this.$i18n.locale = locale
// 切换语言后重新获取数据
this.fetch()
}
}
}
</script>
<style scoped>
.blog-page {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.language-switcher {
display: flex;
gap: 10px;
margin-bottom: 30px;
}
button {
padding: 5px 10px;
border: 1px solid #ddd;
background-color: #f0f0f0;
border-radius: 4px;
cursor: pointer;
}
button.active {
background-color: #1890ff;
color: white;
border-color: #1890ff;
}
.blog-list {
display: flex;
flex-direction: column;
gap: 30px;
}
.blog-post {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
background-color: #f9f9f9;
}
.post-meta {
color: #666;
font-size: 14px;
margin-bottom: 10px;
}
.post-excerpt {
line-height: 1.6;
margin-bottom: 20px;
}
a {
color: #1890ff;
text-decoration: none;
}
a:hover {
color: #40a9ff;
text-decoration: underline;
}
</style>案例二:多语言电商网站
场景描述:创建一个支持多语言的电商网站,用户可以在不同语言之间切换,并且产品信息、价格等也会根据选择的语言显示。
实现方案:
<template>
<div class="product-page">
<!-- 语言切换器 -->
<div class="language-switcher">
<button
v-for="locale in $i18n.locales"
:key="locale.code"
:class="{ active: $i18n.locale === locale.code }"
@click="switchLanguage(locale.code)"
>
{{ locale.name }}
</button>
</div>
<!-- 产品信息 -->
<div class="product-info">
<h1>{{ product.name }}</h1>
<div class="price">{{ $n(product.price, 'currency') }}</div>
<p class="description">{{ product.description }}</p>
<button class="add-to-cart">{{ $t('addToCart') }}</button>
</div>
</div>
</template>
<script>
export default {
name: 'ProductPage',
data() {
return {
product: {}
}
},
async fetch() {
// 根据当前语言获取产品信息
const locale = this.$i18n.locale
const productId = this.$route.params.id
this.product = await this.$axios.$get(`/api/products/${productId}?locale=${locale}`)
},
methods: {
switchLanguage(locale) {
this.$i18n.locale = locale
// 切换语言后重新获取数据
this.fetch()
}
}
}
</script>
<style scoped>
.product-page {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.language-switcher {
display: flex;
gap: 10px;
margin-bottom: 30px;
}
button {
padding: 5px 10px;
border: 1px solid #ddd;
background-color: #f0f0f0;
border-radius: 4px;
cursor: pointer;
}
button.active {
background-color: #1890ff;
color: white;
border-color: #1890ff;
}
.product-info {
display: flex;
gap: 40px;
}
.price {
font-size: 24px;
font-weight: bold;
color: #ff4d4f;
margin: 20px 0;
}
.description {
line-height: 1.6;
margin-bottom: 30px;
}
.add-to-cart {
background-color: #1890ff;
color: white;
border: none;
padding: 12px 24px;
font-size: 16px;
border-radius: 4px;
cursor: pointer;
}
.add-to-cart:hover {
background-color: #40a9ff;
}
</style>国际化最佳实践
1. 语言文件管理
- 模块化语言文件:将语言文件按照功能模块进行拆分
- 使用命名空间:使用命名空间来组织翻译键
- 保持语言文件同步:确保所有语言文件包含相同的翻译键
- 使用工具管理翻译:考虑使用专业的翻译管理工具
2. 性能优化
- 延迟加载语言文件:只加载当前语言的文件
- 使用缓存:缓存翻译结果
- 避免频繁切换语言:减少语言切换的次数
3. 用户体验
- 保存用户语言偏好:使用 cookie 或 localStorage 保存用户的语言选择
- 提供明确的语言切换方式:在页面顶部或导航栏提供语言切换器
- 保持 UI 一致性:确保不同语言版本的 UI 布局一致
- 考虑文本长度:不同语言的文本长度可能不同,需要考虑 UI 布局的适应性
4. 内容管理
- 支持多语言内容:确保后端 API 支持多语言内容
- 提供翻译工具:为内容管理员提供翻译工具
- 考虑 RTL 语言:如果支持阿拉伯语等 RTL(从右到左)语言,需要特别处理
5. 测试
- 测试所有语言版本:确保所有语言版本都能正常工作
- 检查翻译质量:确保翻译准确、自然
- 测试边界情况:测试文本长度、日期格式等边界情况
总结
国际化是现代 Web 应用的重要功能之一,它可以帮助你的应用触达全球用户。通过本章节的学习,你已经掌握了:
- 在 Nuxt.js 中集成和配置
@nuxtjs/i18n模块 - 创建和管理语言文件
- 实现动态语言切换功能
- 配置路由国际化
- 使用日期、数字等格式化功能
- 国际化的最佳实践
在实际开发中,你应该根据应用的具体需求,选择合适的国际化方案,并不断优化和完善国际化功能。良好的国际化设计可以提升用户体验,扩大应用的受众范围,为你的应用带来更多的用户。