前端国际化解决方案(代码+教程)

676 阅读2分钟

语言: Vue

插件: Vue-i18n

环境: VSCode

本教程主要有以下内容:

  1. 通用的vue项目国际化解决方案
  2. 如何组织管理翻译文件
  3. uniapp国际化的特殊解决方案

1. 通用解决方案

国际化主要有三个步骤:

  • 安装并引入插件
  • 编写翻译文件
  • 使用对象属性代替普通文本

1. 安装并引入

首先安装vue-i18n 这个插件:

npm i vue-i18n

新建一个local 文件夹,里头再建一个index 文件,初始化一个i18n对象:

// src/local/index.js
import Vue from 'vue';

import VueI18n from 'vue-i18n'

import en from './en/index';  //待会会讲到引入翻译文件。这里先暂时不管

import zh from './zh/index';

Vue.use(VueI18n)

// 默认语言

const loadLanguage = 'zh'

const messages = {

  "en": en,

  "zh": zh,

}


function getLanguage() {

  localStorage.getItem('lang') ? null : localStorage.setItem('lang', loadLanguage)

  let locale = localStorage.getItem('lang')

  if (!(locale in messages)) locale = loadLanguage

  return locale

}

const i18n = new VueI18n({

  locale: getLanguage(),

  messages,

})

Vue.prototype._i18n = i18n

export default i18n

main.js 中引入

/* main.js */
import Vue from 'vue'
import App from './App.vue'
import i18n from './i18n'

new Vue({
  render: h => h(App),
  i18n
}).$mount('#app')

2. 编写翻译文件

这里就要稍微讲讲了,因为网上大部分都没提及这个问题。

现在我们就来思考一下这个配置文件怎么搞才好.

一种语言只写一个翻译文件,在多人开发时容易造成冲突,而且也不好起名字和维护。 我们一个页面单独配置一个翻译文件固然清晰明了, 但是对于那些经常重复的文字(确定,取消, 是否删除, 正在加载...)要写很多次, 确实比较烦,而且很冗余。

所以我们采用1+多 的形式, 我们可以把常用翻译的抽离成一个公共的文件,这样就会解决冗余的问题, 然后一些页面有许多特有的字段其他页面用不到,那么就给这个页面单独列一个翻译文件,这样就解决了如何命名对象属性,以及对象往哪放的问题, 以及和别人合作开发以防git冲突。

最后把所有的翻译文件都集中到index.js 中,就还是一种语言对应一个文件了。

so, 最终的文件目录是长这样的:

- local
	- index.js
	- zh //中文翻译
		- index.js  // 抽离公共的翻译, 并引入所有翻译文件
		- page1.js
		- page2.js
		- something.js
		- ......
	- en  // 英文翻译
		- index.js    // 抽离公共的翻译,并引入所有翻译文件
		- page1.js
		- page2.js
		- something.js
		- ......

所有翻译文件引入到index.js中,然后公共的部分可以直接写在index.js文件中,下面是示例:

// local/zh/index.js
import page1 from "./page1";
import page2 from "./page2";

export default {
	page1,
	page2,
	....,
	
	dialog: {
		// 确认
	    confirm: "确认",
	    submit: "提交",
	    // 取消
	    cancel: "取消",
	    // 删除
	    delete: "删除",
	    // 编辑
	    edit: "编辑",
	    // 新增
	    add: "新增",
	    // 是否继续删除?
	    confirmDelete: "确认删除?",
	    // 设为默认
	    setDefault: "设为默认",
	    // 添加成功
	    addSuccess: "添加成功",
	    // 修改成功
	    editSuccess: "修改成功",
	},

	//其他
	。。。。
}

好了,其他国家的语言,就把中文的翻译值改成(英语,日语,俄语啥的)就行,你可以用ai帮你写。

3. 页面中使用

在页面中,我们使用$t() 来替代需要翻译的文案。括号里头接收一个字符串,即对象属性名。 举个栗子;

<!-- 在template中 -->
<el-button>{{ $t('dialog.submit') }}</el-button>  // 代替“提交”这个需要翻译的字段。

<script>
	methods: {
		handleDeleteAddress(id){

        let superThis = this;

        uni.showModal({

            title: this.$t('dialog.delete'),

            content: this.$t('dialog.confirmDelete'), // 使用this.$t('xxx')替代文案

          confirmText: this.$t('dialog.confirm'),

          cancelText: this.$t('dialog.cancel'),
          ......
      },
	}
</script>

好的,普通的vue项目国际化解决方案应该就到这了。 接下来我们说说uni-appp 中的国际化。

uni-app 国际化解决方案

对于uniapp我们还是用上述的vue国际化方案,但是还需要改两个地方:一个是底部的导航栏tabBar, 第二个是页面标题navigationBarTitleText

修改页面标题

uniapp 他使用json字符串的格式,可能是为了配合pages.json 文件, 因为pages.json 识别不了我们.js 对象的写法,只能识别字符串的写法,也就是官网的写法, 所以更改页面标题,我们得另寻出路。

解决方法: 首先,我们在pages.json文件中,页面标题写翻译文件中对象的key:

"navigationBarTitleText": "pagesTitle.history",  //写对象的属性名

在进入页面的时候,我们调用钩子函数,获取当前页面的标题, 然后再调用api,用$t('页面标题') 的形式将页面标题进行转译。

每个页面都要调用钩子函数,emmm, 不会要给每个页面都写一个钩子吧,,,当然不会!! 我们可以使用Mxin 来注册一个全局的钩子就好了。

可以在根目录下创建一个globalMixin.js 的文件,然后附上下面的代码:

// globalMixin.js
export default {

  onLoad() {
    this.getPageTitle();
  },

  methods: {
    getPageTitle() {
      const pages = getCurrentPages();
      if (pages.length == 0) return;
      const page = pages[pages.length - 1];
	  // 获取页面标题
      const pageTitle = page.$holder.navigationBarTitleText;
      uni.setNavigationBarTitle({
        // 修改页面标题
        title: this.$t(pageTitle),
      })
    }
  }
}

然后main.js中全局混入:

// main.js
import globalMixin from "@/globalMixin.js"

Vue.mixin(globalMixin);

pages.json文件中,我们的页面标题就得写对象的key了:

{
	"path": "pages/user/readHistory",

     "style": {

       "enablePullDownRefresh": true,

       "navigationBarTitleText": "pagesTitle.history",  //写对象的属性名
       }
}

翻译文件中就可以这样写:

// local/zh/index.js
exports default {
	.....,
	pagesTitle: {
		home: '首页'cart: '购物车',
		history: '浏览记录',
		.....
	}
}

设置tabBar导航栏

// APP.vue
//调用一次性钩子
onLaunch() {

// 动态设置导航栏和标题
  uni.setTabBarItem({
	index: 0,
	text: this.$t("tabBar.home")
  });
  uni.setTabBarItem(
	index: 1,
	text: this.$t("tabBar.category")
  });
  uni.setTabBarItem({
	index: 2,
	text: this.$t("tabBar.cart")
  });
  uni.setTabBarItem({
	index: 3,
	text: this.$t("tabBar.me")
  });
}

ok, 大功告成! 希望对你有所帮助或者启发, 如果有更好的解决方案,请多多指点和分享!!

参考文献

Vue+Element 国际化(i18n)页面全覆盖(路由、表单检验、弹出框等)