在一个 Vue 应用中,如何设计一个可扩展的国际化(i18n)解决方案,支持多语言、动态加载和日期格式化?

各位靓仔靓女们,晚上好!我是老码农,今天给大家伙唠唠 Vue 项目里如何搞一个靠谱又灵活的国际化(i18n)方案。这玩意儿听起来高大上,其实只要掌握了方法,就能让你写的代码瞬间拥有走向世界的潜力!

咱们今天这堂课,主要围绕以下几个方面展开:

  1. 选择 i18n 库: 咱们先看看市面上都有哪些好用的库,以及为啥我推荐vue-i18n
  2. 项目初始化配置: 怎么在 Vue 项目里把vue-i18n安排得明明白白。
  3. 多语言支持: 如何组织和管理你的语言文件,让新增语言变得so easy。
  4. 动态加载: 别一口气加载所有语言包,按需加载才是王道。
  5. 日期格式化: 不同国家地区,日期格式千差万别,咱得优雅地处理。
  6. 组件内使用: 在 Vue 组件里怎么用 i18n,让你的 UI 界面语言切换自如。
  7. 高级用法: 比如复数形式、参数化等等,让你的 i18n 更强大。

话不多说,咱们这就开始!

1. 选择 i18n 库:vue-i18n,你的不二之选

市面上 Vue 的 i18n 库不少,但vue-i18n绝对是主流选择。为啥?

  • 文档完善: 遇到问题,找文档是程序员的本能。vue-i18n的文档那是相当的全面,各种场景都有示例。
  • 社区活跃: 遇到坑,不怕!活跃的社区能帮你快速找到解决方案。
  • 功能强大: 支持多语言、动态加载、复数形式、日期格式化等等,你想到的它都有。
  • 易于使用: API 简单易懂,上手快。

所以,别犹豫了,vue-i18n就是你的好伙伴!

2. 项目初始化配置:让 vue-i18n 安家落户

首先,你需要安装 vue-i18n

npm install vue-i18n@9
# 或者
yarn add vue-i18n@9

注意这里我们指定了@9,因为vue-i18n的v9版本是和vue3兼容的。如果你用的vue2,请安装vue-i18n@8

安装完之后,咱们创建一个 i18n.js 文件,用来配置 i18n 实例:

// i18n.js
import { createI18n } from 'vue-i18n'

function loadLocaleMessages() {
  const locales = require.context('./locales', true, /[A-Za-z0-9-_,s]+.json$/i)
  const messages = {}
  locales.keys().forEach(key => {
    const matched = key.match(/([A-Za-z0-9-_]+)./i)
    if (matched && matched.length > 1) {
      const locale = matched[1]
      messages[locale] = locales(key).default
    }
  })
  return messages
}

const i18n = createI18n({
  locale: process.env.VUE_APP_I18N_LOCALE || 'zh-CN',
  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en-US',
  messages: loadLocaleMessages()
})

export default i18n

这段代码做了以下几件事:

  • 引入 createI18n 这是 Vue 3 提供的创建 i18n 实例的方法。
  • loadLocaleMessages 函数: 这个函数负责加载 locales 目录下的所有语言文件。它使用 require.context 来动态导入 locales 目录下的所有 .json 文件,并将它们合并成一个 messages 对象。
  • 创建 i18n 实例: 使用 createI18n 创建 i18n 实例,并配置 locale(当前语言)、fallbackLocale(备用语言)和 messages(语言包)。
  • 导出 i18n 实例: 方便在其他地方使用。

接下来,在你的 main.js 文件中,引入并使用 i18n 实例:

// main.js
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 项目里了!

3. 多语言支持:构建你的语言帝国

接下来,咱们得创建语言文件。按照上面的配置,我们需要在项目根目录下创建一个 locales 目录,并在里面创建不同的语言文件,例如 zh-CN.jsonen-US.jsonja-JP.json 等等。

/src
  /locales
    /zh-CN.json
    /en-US.json
    /ja-JP.json
  /components
  /App.vue
  /main.js
  /i18n.js

每个语言文件都是一个 JSON 对象,包含了该语言对应的所有文本信息。例如:

zh-CN.json:

{
  "message": {
    "hello": "你好,世界!",
    "welcome": "欢迎来到我的网站!",
    "productName": "产品名称"
  },
  "date": {
    "formats": {
      "short": {
        "year": "numeric",
        "month": "short",
        "day": "numeric"
      },
      "long": {
        "year": "numeric",
        "month": "long",
        "day": "numeric",
        "weekday": "long"
      }
    }
  }
}

en-US.json:

{
  "message": {
    "hello": "Hello, world!",
    "welcome": "Welcome to my website!",
    "productName": "Product Name"
  },
  "date": {
    "formats": {
      "short": {
        "year": "numeric",
        "month": "short",
        "day": "numeric"
      },
      "long": {
        "year": "numeric",
        "month": "long",
        "day": "numeric",
        "weekday": "long"
      }
    }
  }
}

ja-JP.json:

{
  "message": {
    "hello": "こんにちは、世界!",
    "welcome": "私のウェブサイトへようこそ!",
    "productName": "製品名"
  },
  "date": {
    "formats": {
      "short": {
        "year": "numeric",
        "month": "short",
        "day": "numeric"
      },
      "long": {
        "year": "numeric",
        "month": "long",
        "day": "numeric",
        "weekday": "long"
      }
    }
  }
}

注意:JSON 文件的格式一定要正确,否则会加载失败。

4. 动态加载:按需加载,告别臃肿

如果你的应用支持的语言很多,一次性加载所有语言包会影响性能。这时候,动态加载就派上用场了。

修改 i18n.js 文件,添加一个 loadLocaleMessagesAsync 函数:

// i18n.js
import { createI18n } from 'vue-i18n'

function loadLocaleMessages() {
    const locales = require.context('./locales', true, /[A-Za-z0-9-_,s]+.json$/i)
    const messages = {}
    locales.keys().forEach(key => {
      const matched = key.match(/([A-Za-z0-9-_]+)./i)
      if (matched && matched.length > 1) {
        const locale = matched[1]
        messages[locale] = locales(key).default
      }
    })
    return messages
  }

const i18n = createI18n({
  locale: process.env.VUE_APP_I18N_LOCALE || 'zh-CN',
  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en-US',
  messages: loadLocaleMessages()
})

export async function loadLocaleMessagesAsync(locale) {
  // 如果已经加载过了,就不再加载
  if (i18n.global.availableLocales.includes(locale)) {
    return Promise.resolve()
  }

  try {
    const messages = await import(
      /* webpackChunkName: "locale-[request]" */ `./locales/${locale}.json`
    )

    i18n.global.setLocaleMessage(locale, messages.default)
    i18n.global.locale.value = locale

    return Promise.resolve()
  } catch (e) {
    console.error(e)
    return Promise.reject(e)
  }
}

export default i18n

这个 loadLocaleMessagesAsync 函数会异步加载指定的语言文件,并将其添加到 i18n 实例中。

在你的组件中,你可以这样使用它:

// MyComponent.vue
<template>
  <div>
    <button @click="changeLocale('en-US')">English</button>
    <button @click="changeLocale('ja-JP')">Japanese</button>
    <p>{{ $t('message.hello') }}</p>
  </div>
</template>

<script>
import { loadLocaleMessagesAsync } from '../i18n'

export default {
  methods: {
    async changeLocale(locale) {
      try {
        await loadLocaleMessagesAsync(locale)
      } catch (e) {
        console.error(e)
      }
    }
  }
}
</script>

这样,只有当你点击按钮切换到对应的语言时,才会加载该语言的语言包。

5. 日期格式化:让日期更懂你

不同国家地区的日期格式千差万别,vue-i18n 提供了强大的日期格式化功能。

在你的语言文件中,定义不同的日期格式:

zh-CN.json:

{
  "message": {
    "hello": "你好,世界!",
    "welcome": "欢迎来到我的网站!",
    "productName": "产品名称"
  },
  "date": {
    "formats": {
      "short": {
        "year": "numeric",
        "month": "short",
        "day": "numeric"
      },
      "long": {
        "year": "numeric",
        "month": "long",
        "day": "numeric",
        "weekday": "long"
      }
    }
  }
}

en-US.json:

{
  "message": {
    "hello": "Hello, world!",
    "welcome": "Welcome to my website!",
    "productName": "Product Name"
  },
  "date": {
    "formats": {
      "short": {
        "year": "numeric",
        "month": "short",
        "day": "numeric"
      },
      "long": {
        "year": "numeric",
        "month": "long",
        "day": "numeric",
        "weekday": "long"
      }
    }
  }
}

然后在你的组件中,使用 $d 来格式化日期:

// MyComponent.vue
<template>
  <div>
    <p>Short Date: {{ $d(date, 'short') }}</p>
    <p>Long Date: {{ $d(date, 'long') }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      date: new Date()
    }
  }
}
</script>

$d 函数接收两个参数:

  • date: 要格式化的日期对象。
  • format: 日期格式的名称,对应于语言文件中定义的 date.formats 对象中的键。

6. 组件内使用:让 UI 界面语言切换自如

在 Vue 组件中使用 i18n 非常简单,只需要使用 $t 函数即可。

// MyComponent.vue
<template>
  <div>
    <h1>{{ $t('message.welcome') }}</h1>
    <p>{{ $t('message.hello') }}</p>
  </div>
</template>

$t 函数接收一个参数:

  • key: 语言文件中对应的键。

如果你的语言文件是嵌套的,可以使用点号来访问深层级的键。例如,message.hello

7. 高级用法:让你的 i18n 更强大

vue-i18n 还提供了很多高级用法,例如:

  • 复数形式: 根据数量显示不同的文本。
  • 参数化: 在文本中使用变量。
  • 自定义格式: 定义自己的日期、数字格式。

咱们一个一个来看。

复数形式:

在你的语言文件中,使用 plural 属性来定义复数形式:

en-US.json:

{
  "message": {
    "apples": "I have {count} apple | I have {count} apples"
  }
}

然后在你的组件中,使用 $t 函数的 choice 选项来选择正确的复数形式:

// MyComponent.vue
<template>
  <div>
    <p>{{ $t('message.apples', { count: appleCount }, appleCount) }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      appleCount: 1
    }
  }
}
</script>

$t 函数的第三个参数 appleCount 会传递给 choice 选项,vue-i18n 会根据 appleCount 的值来选择正确的复数形式。

参数化:

在你的语言文件中,使用花括号 {} 来定义变量:

en-US.json:

{
  "message": {
    "greeting": "Hello, {name}!"
  }
}

然后在你的组件中,使用 $t 函数的第二个参数来传递变量:

// MyComponent.vue
<template>
  <div>
    <p>{{ $t('message.greeting', { name: 'John' }) }}</p>
  </div>
</template>

自定义格式:

vue-i18n 允许你定义自己的日期、数字格式。具体方法可以参考 vue-i18n 的官方文档。

总结

今天咱们一起学习了如何在 Vue 项目中设计一个可扩展的国际化解决方案。从选择 i18n 库、项目初始化配置、多语言支持、动态加载、日期格式化、组件内使用,到高级用法,都做了详细的讲解。

希望大家能够掌握这些知识,让你的 Vue 项目拥有走向世界的潜力!

速查表:常用 API

API 描述 示例
$t(key) 获取指定 key 对应的翻译文本 $t('message.hello')
$d(date, format) 格式化日期 $d(new Date(), 'short')
$n(number, format) 格式化数字(需要安装 @intlify/vue-i18n 的 NumberFormat 相关功能) $n(1234567.89, 'currency') 需要先定义 currency 格式在语言文件中。
i18n.global.locale.value 获取或设置当前语言 i18n.global.locale.value = 'en-US'
loadLocaleMessagesAsync(locale) 异步加载指定语言包 loadLocaleMessagesAsync('ja-JP')

记住,实践才是检验真理的唯一标准。多写代码,多踩坑,才能真正掌握这些知识。 祝大家编码愉快!

发表回复

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