如何利用`Vue I18n`实现Vue应用的国际化(Internationalization)?

好的,让我们开始深入探讨如何利用 Vue I18n 实现 Vue 应用的国际化。

讲座:Vue I18n 国际化实战

大家好!今天我们来聊聊 Vue 应用的国际化(Internationalization),也就是我们常说的 i18n。为什么要做国际化?很简单,为了让你的应用能够服务于全球用户,支持不同语言和文化习惯。Vue I18n 是 Vue.js 官方推荐的国际化解决方案,它功能强大、易于使用,是构建多语言 Vue 应用的理想选择。

一、国际化的基本概念

在深入 Vue I18n 之前,我们先简单了解几个国际化的基本概念:

  • Locale (语言环境): Locale 指定了用户使用的语言、国家/地区以及其他文化偏好。例如,en-US 代表美国英语,zh-CN 代表中国大陆简体中文。
  • Message Catalog (消息目录): 消息目录是一个存储所有需要翻译的文本(消息)的地方。它通常是一个 JSON 文件,每个 Locale 对应一个消息目录。
  • Translation Key (翻译键): 翻译键是一个唯一的标识符,用于在代码中引用需要翻译的文本。
  • Fallback Locale (备用语言环境): 当找不到当前 Locale 的翻译时,会使用备用语言环境的翻译。

二、Vue I18n 的安装和配置

  1. 安装 Vue I18n

    使用 npm 或 yarn 安装 Vue I18n

    npm install vue-i18n
    # 或
    yarn add vue-i18n
  2. 创建 i18n 实例:

    创建一个 i18n.js 文件,用于初始化 Vue I18n 实例:

    import { createI18n } from 'vue-i18n'
    
    const messages = {
      'en-US': {
        message: {
          hello: 'hello world'
        }
      },
      'zh-CN': {
        message: {
          hello: '你好,世界'
        }
      }
    }
    
    const i18n = createI18n({
      locale: 'en-US', // 设置默认语言
      fallbackLocale: 'en-US', // 设置备用语言
      messages, // 设置语言包
      globalInjection: true //全局注入
    })
    
    export default i18n
    • locale: 指定当前使用的 Locale。
    • fallbackLocale: 指定备用 Locale。
    • messages: 包含所有 Locale 的消息目录。这是一个对象,键是 Locale,值是对应的消息对象。
    • globalInjection: 是否全局注入 $t 等方法。设置为 true 后,可以在任何组件中直接使用 $t 进行翻译。
  3. 在 Vue 应用中注册 Vue I18n

    main.jsapp.js 中,将 i18n 实例注册到 Vue 应用中:

    import { createApp } from 'vue'
    import App from './App.vue'
    import i18n from './i18n'
    
    const app = createApp(App)
    app.use(i18n)
    app.mount('#app')

三、使用 Vue I18n 进行翻译

Vue I18n 提供了多种方式来进行翻译:

  1. 在模板中使用 $t 方法:

    这是最常用的方法。 $t 方法接收一个翻译键作为参数,并返回对应 Locale 的翻译文本。

    <template>
      <h1>{{ $t('message.hello') }}</h1>
    </template>

    在这个例子中,$t('message.hello') 会根据当前的 Locale,返回 messages 对象中对应 message.hello 的值。

  2. 在组件中使用 t 函数:

    如果 globalInjection 设置为 false,或者需要在组件内部使用 i18n 实例的更多功能,可以使用 useI18n hook:

    <script>
    import { useI18n } from 'vue-i18n'
    
    export default {
      setup() {
        const { t } = useI18n()
        return { t }
      }
    }
    </script>
    
    <template>
      <h1>{{ t('message.hello') }}</h1>
    </template>
  3. 在 JavaScript 代码中使用 i18n.global.t

    在非组件的 JavaScript 代码中,可以通过 i18n.global.t 方法进行翻译:

    import i18n from './i18n'
    
    function greet() {
      console.log(i18n.global.t('message.hello'))
    }
    
    greet()

四、消息格式化和参数传递

Vue I18n 支持消息格式化,允许在翻译文本中使用变量。

  1. 命名参数:

    const messages = {
      'en-US': {
        message: {
          greeting: 'Hello, {name}!'
        }
      },
      'zh-CN': {
        message: {
          greeting: '你好,{name}!'
        }
      }
    }
    <template>
      <p>{{ $t('message.greeting', { name: 'Alice' }) }}</p>
    </template>

    在这个例子中,{name} 会被替换为 Alice

  2. 列表参数:

    const messages = {
      'en-US': {
        message: {
          list: 'I have {0} apple(s) and {1} banana(s).'
        }
      },
      'zh-CN': {
        message: {
          list: '我有 {0} 个苹果和 {1} 根香蕉。'
        }
      }
    }
    <template>
      <p>{{ $t('message.list', [3, 5]) }}</p>
    </template>

    在这个例子中,{0} 会被替换为 3{1} 会被替换为 5

  3. 复数化:

    Vue I18n 支持根据数量自动选择合适的复数形式。这需要使用特殊的格式:

    const messages = {
      'en-US': {
        message: {
          apple: 'no apples | one apple | {count} apples'
        }
      },
      'zh-CN': {
        message: {
          apple: '没有苹果 | 一个苹果 | {count} 个苹果'
        }
      }
    }
    <template>
      <p>{{ $t('message.apple', { count: appleCount }) }}</p>
    </template>
    
    <script>
    export default {
      data() {
        return {
          appleCount: 2
        }
      }
    }
    </script>

    在这个例子中,Vue I18n 会根据 appleCount 的值选择合适的复数形式。需要注意的是,复数形式的规则取决于 Locale。 英文使用 no apples | one apple | {count} apples这种格式,中文使用 没有苹果 | 一个苹果 | {count} 个苹果 这种格式。

五、切换 Locale

动态切换 Locale 是国际化应用的关键。可以使用 i18n.global.locale 属性来切换 Locale:

<template>
  <select v-model="currentLocale">
    <option value="en-US">English</option>
    <option value="zh-CN">简体中文</option>
  </select>
  <h1>{{ $t('message.hello') }}</h1>
</template>

<script>
import { ref, watch } from 'vue'
import i18n from './i18n'

export default {
  setup() {
    const currentLocale = ref(i18n.global.locale)

    watch(currentLocale, (newLocale) => {
      i18n.global.locale = newLocale
    })

    return {
      currentLocale
    }
  }
}
</script>

在这个例子中,当用户选择不同的 Locale 时,i18n.global.locale 会被更新,$t 方法会自动返回对应 Locale 的翻译文本。

六、组织消息目录

随着应用的增长,消息目录可能会变得非常庞大。为了更好地组织消息目录,可以将其拆分成多个文件,并使用 import 语句将其导入到 i18n 实例中。

例如,可以创建以下文件结构:

locales/
├── en-US.json
└── zh-CN.json

en-US.json

{
  "message": {
    "hello": "hello world",
    "greeting": "Hello, {name}!"
  },
  "components": {
    "button": "Click me"
  }
}

zh-CN.json

{
  "message": {
    "hello": "你好,世界",
    "greeting": "你好,{name}!"
  },
  "components": {
    "button": "点击我"
  }
}

然后在 i18n.js 中导入这些文件:

import { createI18n } from 'vue-i18n'
import en from './locales/en-US.json'
import zh from './locales/zh-CN.json'

const messages = {
  'en-US': en,
  'zh-CN': zh
}

const i18n = createI18n({
  locale: 'en-US',
  fallbackLocale: 'en-US',
  messages,
  globalInjection: true
})

export default i18n

七、使用 Composition API 进行更高级的国际化

Vue I18n 提供了 useI18n hook,可以与 Vue 3 的 Composition API 完美结合,实现更灵活和可维护的国际化方案。

  1. 自定义格式化:

    可以使用 useI18n hook 提供的 numberFormatsdatetimeFormats 选项来自定义数字和日期时间的格式化规则。

    import { createI18n, useI18n } from 'vue-i18n'
    
    const numberFormats = {
      'en-US': {
        currency: {
          style: 'currency',
          currency: 'USD'
        }
      },
      'zh-CN': {
        currency: {
          style: 'currency',
          currency: 'CNY'
        }
      }
    }
    
    const i18n = createI18n({
      locale: 'en-US',
      fallbackLocale: 'en-US',
      messages: {
        'en-US': {
          price: 'Price: {price, number, currency}'
        },
        'zh-CN': {
          price: '价格:{price, number, currency}'
        }
      },
      numberFormats,
      globalInjection: true
    })
    
    export default i18n
    <template>
      <p>{{ $t('price', { price: 1234.56 }) }}</p>
    </template>

    在这个例子中,{price, number, currency} 会根据当前的 Locale 和 numberFormats 中定义的格式化规则进行格式化。

  2. 自定义组件:

    可以创建自定义组件来封装国际化逻辑,提高代码的可重用性。

    // I18nButton.vue
    <template>
      <button>{{ $t(messageKey) }}</button>
    </template>
    
    <script>
    export default {
      props: {
        messageKey: {
          type: String,
          required: true
        }
      }
    }
    </script>
    <template>
      <I18nButton messageKey="components.button" />
    </template>
    
    <script>
    import I18nButton from './I18nButton.vue'
    
    export default {
      components: {
        I18nButton
      }
    }
    </script>

    在这个例子中,I18nButton 组件接收一个 messageKey 作为属性,并使用 $t 方法进行翻译。

八、SSR(服务端渲染)中的国际化

在 SSR 应用中,需要在服务器端初始化 Vue I18n 实例,并将当前的 Locale 传递给客户端。

  1. 在服务器端初始化 Vue I18n

    // server.js
    import { createSSRApp } from 'vue'
    import App from './App.vue'
    import i18n from './i18n'
    
    export function createApp(context) {
      const app = createSSRApp(App)
      app.use(i18n)
    
      // 设置服务器端的 Locale
      i18n.global.locale = context.locale || 'en-US'
    
      return app
    }
  2. 将 Locale 传递给客户端:

    在 HTML 模板中,将当前的 Locale 作为 JavaScript 变量传递给客户端:

    <!-- index.html -->
    <!DOCTYPE html>
    <html>
    <head>
      <title>Vue SSR</title>
    </head>
    <body>
      <div id="app"><!--ssr-outlet--></div>
      <script>
        window.__LOCALE__ = "{{ locale }}";
      </script>
      <script src="/js/app.js"></script>
    </body>
    </html>
  3. 在客户端初始化 Vue I18n

    在客户端的 main.js 中,从 window.__LOCALE__ 中获取 Locale,并将其设置为 Vue I18n 的初始 Locale:

    // client.js
    import { createApp } from 'vue'
    import App from './App.vue'
    import i18n from './i18n'
    
    // 从 window.__LOCALE__ 中获取 Locale
    const locale = window.__LOCALE__ || 'en-US'
    i18n.global.locale = locale
    
    const app = createApp(App)
    app.use(i18n)
    app.mount('#app')

九、一些最佳实践

  • 使用一致的翻译键: 为每个需要翻译的文本定义一个唯一的翻译键,并在整个应用中使用该翻译键。这有助于保持代码的一致性和可维护性。
  • 将消息目录组织成模块: 将消息目录拆分成多个文件,并按照模块或功能进行组织。这可以提高代码的可读性和可维护性。
  • 使用翻译工具: 可以使用翻译工具来管理和维护消息目录。一些流行的翻译工具包括 Lokalise、Phrase 和 Crowdin。
  • 测试国际化: 确保测试你的应用在不同的 Locale 下都能正常工作。

十、常见问题与解决方案

问题 解决方案
$t 方法返回未翻译的文本 1. 检查 i18n 实例是否正确配置,包括 localefallbackLocalemessages。 2. 确保翻译键存在于消息目录中,并且拼写正确。 3. 检查组件是否正确注册了 Vue I18n
切换 Locale 后,界面没有更新 1. 确保使用了响应式的 locale 属性,例如使用 refreactive。 2. 检查是否正确地更新了 i18n.global.locale 属性。 3. 在某些情况下,可能需要强制 Vue 重新渲染组件。
复数化规则不正确 1. 检查消息目录中的复数形式是否符合当前 Locale 的规则。 2. 确保传递给 $t 方法的 count 参数是数字类型。 3. 某些语言的复数形式非常复杂,可能需要使用更高级的复数化解决方案。
在 SSR 中,客户端显示的语言不正确 1. 确保在服务器端正确初始化了 Vue I18n 实例,并将当前的 Locale 传递给客户端。 2. 检查客户端是否正确地从 window.__LOCALE__ 中获取 Locale,并将其设置为 Vue I18n 的初始 Locale。 3. 确保客户端和服务器端使用的消息目录版本一致。
如何处理动态加载的语言包 1. 可以使用 i18n.global.setLocaleMessage 方法来动态添加语言包。 2. 可以使用 import() 动态导入语言包文件。 3. 在加载语言包之前,可以显示一个加载指示器。

总结陈述:

通过以上讲解,我们了解了 Vue I18n 的基本概念、安装配置、使用方法、消息格式化、Locale 切换、消息目录组织以及在 SSR 中的应用。掌握这些知识,你就可以轻松地为你的 Vue 应用添加国际化支持,让你的应用走向世界。 Vue I18n 是一个强大而灵活的工具,希望今天的讲解能够帮助你更好地利用它。 熟练运用 Vue I18n 可以构建出更具包容性和更易于使用的 Web 应用。

持续学习,不断进步!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注