Nuxt.js 国际化支持

国际化(Internationalization,简称 i18n)是现代前端应用的重要功能之一,它允许应用支持多种语言和地区设置,为全球用户提供更好的用户体验。Nuxt.js 提供了完善的国际化支持,使开发者能够轻松构建多语言应用。本章节将详细介绍 Nuxt.js 的国际化功能,包括配置、使用方法和最佳实践。

1. 国际化的重要性

1.1 什么是国际化

国际化是指设计和开发应用时,使其能够适应不同语言和地区的需求,而不需要对代码进行重大修改。国际化的目标是让应用能够无缝地支持多种语言和地区设置。

1.2 国际化的重要性

  • 全球用户:支持多种语言可以吸引全球用户,扩大应用的受众范围
  • 用户体验:使用用户的母语可以提供更好的用户体验,增加用户满意度
  • 市场竞争力:国际化的应用在全球市场中更具竞争力
  • 合规要求:某些地区可能要求应用提供本地语言支持

1.3 国际化与本地化的区别

  • 国际化(i18n):设计和开发应用时,使其能够适应不同语言和地区的需求
  • 本地化(l10n):将国际化的应用适配到特定语言和地区的过程,包括翻译文本、调整日期格式、货币单位等

2. Nuxt.js 国际化模块

Nuxt.js 官方推荐使用 @nuxtjs/i18n 模块来实现国际化功能。这个模块基于 Vue I18n 库,提供了完善的国际化支持。

2.1 安装国际化模块

npm install @nuxtjs/i18n

2.2 基本配置

nuxt.config.js 文件中配置 @nuxtjs/i18n 模块:

export default {
  modules: [
    '@nuxtjs/i18n'
  ],
  i18n: {
    // 配置选项
    locales: [
      { code: 'en', iso: 'en-US', name: 'English' },
      { code: 'zh', iso: 'zh-CN', name: '中文' }
    ],
    defaultLocale: 'zh',
    vueI18n: {
      fallbackLocale: 'zh',
      messages: {
        en: {
          welcome: 'Welcome to Nuxt.js!',
          about: 'About Us',
          contact: 'Contact Us'
        },
        zh: {
          welcome: '欢迎使用 Nuxt.js!',
          about: '关于我们',
          contact: '联系我们'
        }
      }
    }
  }
}

2.3 配置选项详解

2.3.1 基本配置

  • locales:语言列表,每个语言包含 code(语言代码)、iso(ISO 语言代码)和 name(语言名称)
  • defaultLocale:默认语言
  • vueI18n:Vue I18n 配置,包含 fallbackLocale(回退语言)和 messages(语言消息)

2.3.2 高级配置

export default {
  i18n: {
    // 语言列表
    locales: [
      { code: 'en', iso: 'en-US', name: 'English', file: 'en.js' },
      { code: 'zh', iso: 'zh-CN', name: '中文', file: 'zh.js' }
    ],
    // 默认语言
    defaultLocale: 'zh',
    // 语言文件目录
    langDir: 'lang/',
    // 回退语言
    fallbackLocale: 'zh',
    // 路由国际化
    strategy: 'prefix_except_default',
    // 检测浏览器语言
    detectBrowserLanguage: {
      useCookie: true,
      cookieKey: 'i18n_redirected',
      onlyOnRoot: true
    },
    //  seo 优化
    vueI18n: {
      fallbackLocale: 'zh',
      messages: {
        en: {
          welcome: 'Welcome to Nuxt.js!'
        },
        zh: {
          welcome: '欢迎使用 Nuxt.js!'
        }
      }
    }
  }
}

3. 语言文件管理

3.1 语言文件结构

对于大型应用,建议将语言消息存储在单独的文件中,而不是直接在配置文件中定义。

3.1.1 目录结构

lang/
├── en.js
└── zh.js

3.1.2 语言文件内容

// lang/en.js
export default {
  welcome: 'Welcome to Nuxt.js!',
  about: 'About Us',
  contact: 'Contact Us',
  navigation: {
    home: 'Home',
    blog: 'Blog',
    products: 'Products'
  },
  buttons: {
    submit: 'Submit',
    cancel: 'Cancel',
    save: 'Save'
  }
}

// lang/zh.js
export default {
  welcome: '欢迎使用 Nuxt.js!',
  about: '关于我们',
  contact: '联系我们',
  navigation: {
    home: '首页',
    blog: '博客',
    products: '产品'
  },
  buttons: {
    submit: '提交',
    cancel: '取消',
    save: '保存'
  }
}

3.2 语言文件配置

nuxt.config.js 文件中配置语言文件目录:

export default {
  i18n: {
    locales: [
      { code: 'en', iso: 'en-US', name: 'English', file: 'en.js' },
      { code: 'zh', iso: 'zh-CN', name: '中文', file: 'zh.js' }
    ],
    langDir: 'lang/',
    defaultLocale: 'zh'
  }
}

4. 在应用中使用国际化

4.1 在模板中使用

在 Vue 模板中,可以使用 $t 方法来翻译文本:

<template>
  <div>
    <h1>{{ $t('welcome') }}</h1>
    <nav>
      <ul>
        <li><nuxt-link to="/" {{ $t('navigation.home') }}</nuxt-link></li>
        <li><nuxt-link to="/blog" {{ $t('navigation.blog') }}</nuxt-link></li>
        <li><nuxt-link to="/products" {{ $t('navigation.products') }}</nuxt-link></li>
      </ul>
    </nav>
    <button>{{ $t('buttons.submit') }}</button>
  </div>
</template>

4.2 在脚本中使用

在 Vue 脚本中,可以使用 this.$t 方法来翻译文本:

<script>
export default {
  data() {
    return {
      message: this.$t('welcome')
    }
  },
  methods: {
    showMessage() {
      alert(this.$t('welcome'))
    }
  }
}
</script>

4.3 在组件中使用

在组件中使用国际化:

<template>
  <div>
    <h2>{{ $t('about') }}</h2>
    <p>{{ $t('aboutDescription') }}</p>
  </div>
</template>

<script>
export default {
  mounted() {
    console.log(this.$t('about'))
  }
}
</script>

4.4 在页面中使用

在页面组件中使用国际化:

<template>
  <div>
    <h1>{{ $t('welcome') }}</h1>
    <p>{{ $t('description') }}</p>
  </div>
</template>

<script>
export default {
  async asyncData({ app }) {
    // 在 asyncData 中使用国际化
    const title = app.i18n.t('welcome')
    return { title }
  }
}
</script>

4.5 在插件中使用

在插件中使用国际化:

export default function({ app }) {
  // 在插件中使用国际化
  console.log(app.i18n.t('welcome'))
}

4.6 在中间件中使用

在中间件中使用国际化:

export default function({ app }) {
  // 在中间件中使用国际化
  console.log(app.i18n.t('welcome'))
}

5. 动态语言切换

5.1 语言切换方法

Nuxt.js 的国际化模块提供了 $i18n 对象,通过它可以切换语言:

<template>
  <div>
    <div class="language-switcher">
      <button @click="switchLanguage('zh')" :class="{ active: $i18n.locale === 'zh' }">中文</button>
      <button @click="switchLanguage('en')" :class="{ active: $i18n.locale === 'en' }">English</button>
    </div>
    <h1>{{ $t('welcome') }}</h1>
  </div>
</template>

<script>
export default {
  methods: {
    switchLanguage(lang) {
      this.$i18n.locale = lang
    }
  }
}
</script>

<style scoped>
.language-switcher {
  margin-bottom: 20px;
}

.language-switcher button {
  padding: 8px 16px;
  margin-right: 10px;
  border: 1px solid #ddd;
  background-color: #f0f0f0;
  cursor: pointer;
}

.language-switcher button.active {
  background-color: #007bff;
  color: white;
  border-color: #007bff;
}
</style>

5.2 语言切换的高级用法

5.2.1 带参数的语言切换

<template>
  <div>
    <div class="language-switcher">
      <button 
        v-for="locale in $i18n.locales" 
        :key="locale.code"
        @click="switchLanguage(locale.code)"
        :class="{ active: $i18n.locale === locale.code }"
      >
        {{ locale.name }}
      </button>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    switchLanguage(lang) {
      this.$i18n.locale = lang
    }
  }
}
</script>

5.2.2 语言切换时的路由处理

当切换语言时,Nuxt.js 的国际化模块会自动处理路由:

  • prefix_except_default 策略:默认语言没有前缀,其他语言有前缀
  • prefix 策略:所有语言都有前缀
  • no_prefix 策略:所有语言都没有前缀,通过其他方式区分

6. 国际化的高级特性

6.1 翻译参数

可以在翻译文本中使用参数:

// lang/en.js
export default {
  welcome: 'Welcome, {name}!',
  items: 'You have {count} items'
}

// lang/zh.js
export default {
  welcome: '欢迎,{name}!',
  items: '你有 {count} 个项目'
}

在模板中使用参数:

<template>
  <div>
    <h1>{{ $t('welcome', { name: 'John' }) }}</h1>
    <p>{{ $t('items', { count: 5 }) }}</p>
  </div>
</template>

6.2 复数形式

可以处理复数形式的翻译:

// lang/en.js
export default {
  item: 'item | items'
}

// lang/zh.js
export default {
  item: '项目'
}

在模板中使用复数形式:

<template>
  <div>
    <p>{{ $tc('item', 1) }}</p> <!-- 输出:item -->
    <p>{{ $tc('item', 5) }}</p> <!-- 输出:items -->
  </div>
</template>

6.3 日期和时间格式化

可以格式化日期和时间:

// lang/en.js
export default {
  date: {
    format: 'MM/DD/YYYY'
  }
}

// lang/zh.js
export default {
  date: {
    format: 'YYYY年MM月DD日'
  }
}

在模板中使用日期格式化:

<template>
  <div>
    <p>{{ $d(new Date(), 'date.format') }}</p>
  </div>
</template>

6.4 数字格式化

可以格式化数字:

// lang/en.js
export default {
  number: {
    currency: 'USD'
  }
}

// lang/zh.js
export default {
  number: {
    currency: 'CNY'
  }
}

在模板中使用数字格式化:

<template>
  <div>
    <p>{{ $n(1234.56, 'currency') }}</p>
  </div>
</template>

6.5 区域设置

可以设置区域特定的格式:

export default {
  i18n: {
    locales: [
      { code: 'en', iso: 'en-US', name: 'English', file: 'en.js' },
      { code: 'zh', iso: 'zh-CN', name: '中文', file: 'zh.js' }
    ],
    defaultLocale: 'zh',
    langDir: 'lang/',
    vueI18n: {
      fallbackLocale: 'zh',
      locale: 'zh',
      messages: {
        en: {
          // 英文翻译
        },
        zh: {
          // 中文翻译
        }
      },
      numberFormats: {
        en: {
          currency: {
            style: 'currency',
            currency: 'USD'
          }
        },
        zh: {
          currency: {
            style: 'currency',
            currency: 'CNY'
          }
        }
      },
      dateTimeFormats: {
        en: {
          short: {
            year: 'numeric',
            month: 'short',
            day: 'numeric'
          }
        },
        zh: {
          short: {
            year: 'numeric',
            month: 'short',
            day: 'numeric'
          }
        }
      }
    }
  }
}

7. 路由国际化

7.1 路由国际化策略

Nuxt.js 的国际化模块支持多种路由国际化策略:

  • prefix_except_default:默认语言没有前缀,其他语言有前缀(推荐)
  • prefix:所有语言都有前缀
  • no_prefix:所有语言都没有前缀,通过其他方式区分

7.2 配置路由国际化

export default {
  i18n: {
    strategy: 'prefix_except_default',
    locales: [
      { code: 'en', iso: 'en-US', name: 'English' },
      { code: 'zh', iso: 'zh-CN', name: '中文' }
    ],
    defaultLocale: 'zh'
  }
}

7.3 生成国际化路由

Nuxt.js 的国际化模块会自动为每个语言生成对应的路由:

  • 默认语言(中文)://about/contact
  • 其他语言(英文):/en//en/about/en/contact

7.4 路由参数国际化

可以为路由参数提供国际化支持:

<template>
  <div>
    <h1>{{ $t('productTitle', { id: $route.params.id }) }}</h1>
  </div>
</template>

<script>
export default {
  async asyncData({ params, app }) {
    const product = await fetchProduct(params.id)
    return { product }
  }
}
</script>

8. SEO 优化

8.1 国际化与 SEO

国际化的应用需要考虑 SEO 优化,确保不同语言版本的页面都能被搜索引擎正确索引。

8.2 配置 SEO 优化

export default {
  i18n: {
    seo: true,
    locales: [
      { code: 'en', iso: 'en-US', name: 'English' },
      { code: 'zh', iso: 'zh-CN', name: '中文' }
    ],
    defaultLocale: 'zh'
  }
}

8.3 hreflang 标签

Nuxt.js 的国际化模块会自动生成 hreflang 标签,帮助搜索引擎理解页面的语言和地区:

<link rel="alternate" hreflang="zh" href="https://example.com/" />
<link rel="alternate" hreflang="en" href="https://example.com/en/" />

8.4 页面标题和描述国际化

可以为不同语言设置不同的页面标题和描述:

<template>
  <div>
    <h1>{{ $t('welcome') }}</h1>
  </div>
</template>

<script>
export default {
  head() {
    return {
      title: this.$t('pageTitle'),
      meta: [
        {
          hid: 'description',
          name: 'description',
          content: this.$t('pageDescription')
        }
      ]
    }
  }
}
</script>

9. 国际化的最佳实践

9.1 组织翻译文件

  • 按功能模块组织:将翻译文件按功能模块组织,便于管理
  • 使用命名空间:使用命名空间来组织翻译文本,避免命名冲突
  • 保持一致性:保持翻译文本的一致性,使用相同的术语
  • 使用工具管理:使用专业的翻译管理工具来管理翻译文本

9.2 性能优化

  • 懒加载语言文件:只加载当前语言的文件,减少初始加载时间
  • 缓存翻译:缓存翻译结果,减少重复计算
  • 按需加载:按需加载翻译文件,避免一次性加载所有语言文件

9.3 开发流程

  • 翻译键命名规范:使用一致的命名规范,如 module.feature.action
  • 占位符使用:使用占位符而不是硬编码文本
  • 注释:为复杂的翻译文本添加注释,便于翻译人员理解
  • 测试:测试不同语言版本的应用,确保所有文本都能正确显示

9.4 常见问题

  • 文本长度:不同语言的文本长度可能不同,需要考虑布局适配
  • 日期和时间格式:不同地区的日期和时间格式可能不同
  • 货币单位:不同地区的货币单位可能不同
  • 方向:某些语言(如阿拉伯语)是从右到左书写的,需要考虑布局适配

10. 实际项目示例

10.1 完整的国际化配置

// nuxt.config.js
export default {
  modules: [
    '@nuxtjs/i18n'
  ],
  i18n: {
    locales: [
      { code: 'en', iso: 'en-US', name: 'English', file: 'en.js' },
      { code: 'zh', iso: 'zh-CN', name: '中文', file: 'zh.js' }
    ],
    defaultLocale: 'zh',
    langDir: 'lang/',
    strategy: 'prefix_except_default',
    detectBrowserLanguage: {
      useCookie: true,
      cookieKey: 'i18n_redirected',
      onlyOnRoot: true
    },
    vueI18n: {
      fallbackLocale: 'zh'
    }
  }
}

10.2 语言文件示例

// lang/en.js
export default {
  common: {
    welcome: 'Welcome to Nuxt.js!',
    about: 'About Us',
    contact: 'Contact Us'
  },
  navigation: {
    home: 'Home',
    blog: 'Blog',
    products: 'Products',
    services: 'Services'
  },
  buttons: {
    submit: 'Submit',
    cancel: 'Cancel',
    save: 'Save',
    delete: 'Delete'
  },
  errors: {
    required: '{field} is required',
    minLength: '{field} must be at least {min} characters',
    maxLength: '{field} must be at most {max} characters'
  }
}

// lang/zh.js
export default {
  common: {
    welcome: '欢迎使用 Nuxt.js!',
    about: '关于我们',
    contact: '联系我们'
  },
  navigation: {
    home: '首页',
    blog: '博客',
    products: '产品',
    services: '服务'
  },
  buttons: {
    submit: '提交',
    cancel: '取消',
    save: '保存',
    delete: '删除'
  },
  errors: {
    required: '{field} 是必填项',
    minLength: '{field} 至少需要 {min} 个字符',
    maxLength: '{field} 最多只能有 {max} 个字符'
  }
}

10.3 组件示例

<template>
  <div>
    <div class="language-switcher">
      <button 
        v-for="locale in $i18n.locales" 
        :key="locale.code"
        @click="switchLanguage(locale.code)"
        :class="{ active: $i18n.locale === locale.code }"
      >
        {{ locale.name }}
      </button>
    </div>
    
    <nav>
      <ul>
        <li><nuxt-link to="/" {{ $t('navigation.home') }}</nuxt-link></li>
        <li><nuxt-link to="/about" {{ $t('navigation.about') }}</nuxt-link></li>
        <li><nuxt-link to="/products" {{ $t('navigation.products') }}</nuxt-link></li>
        <li><nuxt-link to="/services" {{ $t('navigation.services') }}</nuxt-link></li>
      </ul>
    </nav>
    
    <h1>{{ $t('common.welcome') }}</h1>
    
    <form>
      <div>
        <label for="name">{{ $t('form.name') }}</label>
        <input type="text" id="name" v-model="name">
        <p v-if="!name" class="error">{{ $t('errors.required', { field: $t('form.name') }) }}</p>
      </div>
      <div>
        <button type="button" @click="submitForm">{{ $t('buttons.submit') }}</button>
        <button type="button" @click="cancelForm">{{ $t('buttons.cancel') }}</button>
      </div>
    </form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: ''
    }
  },
  methods: {
    switchLanguage(lang) {
      this.$i18n.locale = lang
    },
    submitForm() {
      // 提交表单
    },
    cancelForm() {
      // 取消表单
    }
  }
}
</script>

<style scoped>
.language-switcher {
  margin-bottom: 20px;
}

.language-switcher button {
  padding: 8px 16px;
  margin-right: 10px;
  border: 1px solid #ddd;
  background-color: #f0f0f0;
  cursor: pointer;
}

.language-switcher button.active {
  background-color: #007bff;
  color: white;
  border-color: #007bff;
}

nav ul {
  list-style: none;
  padding: 0;
  display: flex;
  gap: 20px;
  margin-bottom: 30px;
}

nav a {
  text-decoration: none;
  color: #333;
}

form {
  max-width: 500px;
}

form div {
  margin-bottom: 15px;
}

label {
  display: block;
  margin-bottom: 5px;
}

input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.error {
  color: #dc3545;
  font-size: 0.8em;
  margin-top: 5px;
}

button {
  padding: 8px 16px;
  margin-right: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  background-color: #f8f9fa;
  cursor: pointer;
}

button:hover {
  background-color: #e9ecef;
}
</style>

11. 总结

本章节介绍了 Nuxt.js 的国际化支持,包括:

  1. 国际化的重要性:全球用户、用户体验、市场竞争力、合规要求

  2. Nuxt.js 国际化模块

    • 安装和配置
    • 配置选项详解
  3. 语言文件管理

    • 语言文件结构
    • 语言文件配置
  4. 在应用中使用国际化

    • 在模板中使用
    • 在脚本中使用
    • 在组件中使用
    • 在页面中使用
    • 在插件中使用
    • 在中间件中使用
  5. 动态语言切换

    • 语言切换方法
    • 语言切换时的路由处理
  6. 国际化的高级特性

    • 翻译参数
    • 复数形式
    • 日期和时间格式化
    • 数字格式化
    • 区域设置
  7. 路由国际化

    • 路由国际化策略
    • 生成国际化路由
    • 路由参数国际化
  8. SEO 优化

    • 国际化与 SEO
    • 配置 SEO 优化
    • hreflang 标签
    • 页面标题和描述国际化
  9. 国际化的最佳实践

    • 组织翻译文件
    • 性能优化
    • 开发流程
    • 常见问题
  10. 实际项目示例

    • 完整的国际化配置
    • 语言文件示例
    • 组件示例

通过本章节的学习,你应该能够在 Nuxt.js 项目中实现完善的国际化功能,为全球用户提供更好的用户体验。国际化是一个持续的过程,需要不断完善和优化,以适应不同语言和地区的需求。

« 上一篇 Nuxt.js 与 TypeScript 集成 下一篇 » Nuxt.js 渐进式 Web 应用 (PWA) 支持