5
头图
本篇文章开始,笔者准备开启一个小系列,称之为现代 Vue 工程 ,本篇为第一篇 国际化 i18n 开发

我们公司的开源工具产品 Bytebase, 目前只有英文版本。社区里也有一些小伙伴也提问到了有没有中文版本的计划,答案当然是有了。我们团队正计划于下次版本发布日 12 月 23 日发布国际化支持,顺利的话将全面支持中、英版本的切换。

如果做过前端国际化方案的小伙伴应该会有所了解,维护大量的文案翻译是很让人头疼的,徒手翻译更是个体力活。以笔者以往的经验来讲,无论是用文案提取工具一次性提取文案去翻译的方法,还是人工一条条去提取文案到文案资产。在复杂项目中遇到的一些问题往往不是翻译个单词或者语句这么简单。

所以笔者总结了一些在 Vue 工程中实现国际化 i18n 的开发方法,主要是针对 Vue 项目而言的,所谓现代Vue工程 即是借助一些好用的工具,可能是你以往没有接触过的,也可能是你正在使用的,它们是一些提升开发效率的方法、工具等。

本期主要介绍的工具是 VSCode 插件 i18n-ally

国际化 i18n 开发

满足的条件

  • VSCode
  • VSCode 插件 i18n-ally
  • Vue 工程集成 vue-i18n

接下来,我会通过 Vite 创建一个 Vue 3 演示工程来和大家实践以下在 Vue 工程中如何做国际化的

🌰 工程地址:

https://github.com/xiaoluoboding/vue-i18n-practice

TL;DR

  • 初始化 Vue 工程
  • 在 vite 中配置 vue-i18n
  • 持久化用户选择习惯
  • 使用 i18n-ally 插件加速翻译流程

初始化 Vue 工程

使用 Vite 创建一个 Vue 工程,我选择的 vue-ts 模版

yarn create vite

✔ Project name: … vue-i18n-practice
✔ Select a framework: › vue
✔ Select a variant: › vue-ts

🔗 可查看 commit: https://github.com/xiaoluobod...

在 vite 中配置 vue-i18n

需要安装三个库:

  • vue-i18n@next
  • @types/node
  • @intlify/vite-plugin-vue-i18n

PS. 在 Vue 3 项目中我们需要安装 vue-i18n 的 next 版本

yarn add vue-i18n@next -S && yarn add @types/node @intlify/vite-plugin-vue-i18n -D

配置 vite.config.ts

指定 locales 文件路径为 src/locales

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import VueI18n from '@intlify/vite-plugin-vue-i18n'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    // https://github.com/intlify/vite-plugin-vue-i18n
    VueI18n({
      // define the locales files directory
      include: [resolve(__dirname, 'src/locales/**')],
    }),
  ],
})

以 Vue 插件的形式使用 i18n:

// plugins/i18n.ts
import { App } from 'vue'
import { createI18n } from 'vue-i18n'

const localPathPrefix = '../locales/'

// import i18n resources
// https://vitejs.dev/guide/features.html#glob-import
const messages = Object.fromEntries(
  Object.entries(import.meta.globEager('../locales/*.y(a)?ml')).map(
    ([key, value]) => {
      const yaml = key.endsWith('.yaml')
      return [key.slice(localPathPrefix.length, yaml ? -5 : -4), value.default]
    }
  )
)

const install = (app: App) => {
  const i18n = createI18n({
    legacy: false,
    locale: 'en',
    globalInjection: true,
    messages,
  })

  app.use(i18n)
}

export default install

增加一个文案

<template>
    <h1>{{ $t('common.home') }}</h1>
</template>
// en.yml
common:
  home: Home

// zh_cn.yml
common:
  home: 主页

最后的展示效果如下:

vue-i18n works

🔗 可查看 commit:https://github.com/xiaoluobod...

持久化用户语言选择习惯

一般用户会在进入站点选择完语言版本后,希望再次进入站点还是看到我选择过的语言版本。所以我们需要保存用户的偏好设置。这里推荐使用 localStorage 来存储用户数据,我来介绍一个比较好用的库结合此场景,做一下用户行为持久化。

使用 @vueuse/core 库中的 useLocalStorage 实现一个相应式的配置项

设定初始值,下次进入应用时,优先读取 localStorage 中的值,代表用户选择过的语言版本

import { useLocalStorage } from '@vueuse/core'

const storage = useLocalStorage('site_locale', 'en')
const locale = storage.value

跟随按钮切换改变语言版本,设置到 localStorage

const setLang = (lang: string) => {
  const storage = useLocalStorage('site_locale', '')
  storage.value = lang
}

🔗 可查看 commit:https://github.com/xiaoluobod...

使用 i18n-ally 插件加速翻译流程

感谢 Anthony Fu 提供的 i18n-ally 插件,这是一款基于 VSCode 的通用的一站式翻译插件,不仅仅用于 Vue 工程中的翻译场景,可以阅读下官方文档。

传统翻译流程,可能大多数开发者也都遇到过,就是看到文案,复制粘贴到相应到 locales 文件中进行翻译,而现在我们借助 i18n-ally 插件,我们可以进一步的加速翻译的流程,可能就是点击几下的事儿,就搞定了文案的翻译。

安装 VScode i18n-ally 插件

VSCode 扩展中搜索 i18n-ally 安装即可

i18n-ally

启用 i18n-ally 插件

这里推荐使用项目中的 .vscode 配置项中配置

.vscode/settings.json

// .vscode/settings.json
{
  "i18n-ally.localesPaths": [
    "src/locales"
  ],
  "i18n-ally.enabledParsers": [
    "yaml"
  ],
  "i18n-ally.sourceLanguage": "en",
  "i18n-ally.displayLanguage": "zh-cn",
  "i18n-ally.keystyle": "nested"
}

再次打开 Vue 组件 HelloWorld.vue,可以看到文案发生了一些变化:

i18n ally works

这是插件的一个特性 Inline Annotations (行内注释),将我们之间写的形$t('common.home')这样的代码映射为英文的 “Home”,当然我们还可以映射为你喜好的语言,通过改变配置项中的 "i18n-ally.sourceLanguage"的值来设定。

翻译过程的术语

  • 语言文件 - /locale/en.yml | /locale/zh_CN.yml
  • 命名空间 - 在 i18n-ally 中称为路径,我称之为“命名空间“(namespace)

    比如语言文件中的树形层级关系:'common.save''field.name'

  • t 格式化方法 - t 方法为 vue-i18n 提供的文案格式化翻译方法,常用格式如下:

    • Vue 模版插值中 - {{ $t('common.save') }}
    • Vue 模版组件参数中 - $t('common.save')
    • Vue Script 中 - this.$t('common.save') / t('common.save')

提取文案到 YAML 语言文件

i18n-ally 支持将代码文件内的文案提取到语言文件中,支持 YAMLJSON 文件的读写操作。这个功能大大提高了我们翻译的速度,再也不用手动去复制粘贴文案了,整个翻译流程我们可以不用打开语言文件,插件会帮助把文案提取写入到相应的命名空间下最后一行。

我们所做的大部分工作都转化为了去命名一个命名空间与文案的对应关系,其他的都交给插件来处理。

大概的一个翻译流程:

  1. 选取文案
  2. 提取文案到语言文件,输入命名空间
  3. 替换文案为 t 方法
  4. 翻译其他语言版本

translate message

🔗 可查看 commit:https://github.com/xiaoluobod...

i18n Ally 特性

  • 快速提取文案
  • 自动预先翻译(可人工修正)
  • 组件内部行内注释
  • 审阅系统(暂未使用)

这些特性可以让我们快速上手翻译文案,做到边开发边翻译的状态。

翻译技巧

这里是这在使用 vue-i18n 时遇到的一些常用的翻译用法,简单介绍。

文案引用

假设我们已经积累一些单词表了,那么有些词语或者短语是可以通过单词拼接出来的。vue-i18n 中提供了 Linked messages ,提供了引用其他文案连接语法 @:xxx ,类似于引用变量,这个机制非常适合组合词语,比如翻译 App Name ,我们可以定义两个简单词 AppName,拼成一个短语 App Name

common:
  app: App
  name: Name
header:
  title: '@:common.app @:common.name'

为什么不直接去翻译 App Name 呢,写起来也并不难,其实这个还考虑到人工翻译笔误、错别字的问题,多写多错是可能存在的,使用 Linked Messages 是可以避免这个问题的,并且 vue-i18n 还提供了内置的类似修饰符一样的声明方法,比如:upperlowercapitalize 在翻译英文文案的时候很有帮助。

🔗可查看 commit:https://github.com/xiaoluobod...

传递插值

这种方式比较常见,类似传递一个变量,我直接拿官网的例子吧:

在模版中映射翻译的同时传递一个 msg

<p>{{ $t('common.hello', { msg: 'hello' }) }}</p>
common:
  hello: '{msg} world'

最终展现为 hello world

🔗可查看 commit:https://github.com/xiaoluobod...

vue-i18n 还有一些比较特殊的用法比如组件插值、单数复数等特殊的翻译方法,这里就不展开了。官方文档讲述的比较详细。


最后再说一句,我们团队所有人,对是所有人,无论前端后端,都在参与文案的翻译工作,如果你对 bytebase.com 感兴趣,或者对开源项目感兴趣,欢迎来参与 PR 哦。

Bytebase.com 是一款聚焦在团队协作场景下的数据库结构变更和版本管理(database schema change and version control for teams)开源工具,主要解决研发工程师和 DBA(数据库管理员) 在变更数据库结构时的协同问题

xiaoluoboding
2.1k 声望503 粉丝

I 💗 Web Dev, 💻 I'm a Senior Frontend Engineer