vue-i18n — 前端国际化笔记

4,091 阅读3分钟

这里总结了自己静态站项目中遇到的问题和解决办法

安装

yarn add vue-i18n

//安装 js-cookie 通过 cookie 判断浏览器语言设置默认语言
yarn add js-cookie --save

main.js配置

import VueI18n from 'vue-i18n'
import Cookies from 'js-cookie'
import zh from '@/assets/lang/zh.js'
import en from '@/assets/lang/en.js'
import es from '@/assets/lang/es.js'

Vue.use(VueI18n)

const messages = {
  zh: {
    ...zh
  },
  en: {
    ...en
  },
  es: {
    ...es
  }
}

function getLanguage() {
  const chooseLanguage = Cookies.get('language')
  if (chooseLanguage) return chooseLanguage

  // if has not choose language
  const language = (navigator.language || navigator.browserLanguage).toLowerCase()
  const locales = Object.keys(messages)
  for (const locale of locales) {
    if (language.indexOf(locale) > -1) {
      return locale
    }
  }
  return 'en' //没有目标语言默认显示英文
}

const i18n = new VueI18n({
  // 调用 Cookie 设置语言函数
  locale: getLanguage(),
  // 引入语言包对象
  messages
})


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

js语言包文件

zh.js:

module.exports = {
    common: {
        home: "中文",
        title: "示例"
    },
    user: {
        name: "名字"
    }
}

en.js:

module.exports = {
    common: {
        home: "English",
        title: "demo"
    },
    user: {
        name: "Avery"
    }
}

组件调用方式

全局通过 $t('') 调用获取每个语言包内的对应的属性,

//html
$t('common.home')

//js
this.$t('common.home')

切换语言组件

通过 this.$i18n.locale = "zh" 修改当前语言

<template>
	<div class="box">
		<button class="btn">{{ $t('mainNav.lang') }}</button>
        <div class="select">
            <p @click="zh">中文简体</p>
            <p @click="en">English</p>
            <p @click="es">Español</p>
    	</div>
	</div>
</template>

<script>
export default {
	name: "langSelect",
	methods: {
		zh() {
			this.$i18n.locale = "zh";
		},
		en() {
			this.$i18n.locale = "en";
		},
		es() {
			this.$i18n.locale = "es";
		}
	}
};
</script>

获取当前语言

通过 $i18n.locale 获取当前语言,

console.log(this.$i18n.locale) //zh

语言包管理

[Excel语言包管理 - 百度云](pan.baidu.com/s/1MIwdsm4p… 提取码: vnx8)

当整个项目过大,分开管理各个语言包就显得非常繁琐,这时可以使用 excel 来集中管理语言包,通过宏来导出各个语言包

在最左侧表格 列表 的右侧输入要导出的文件夹名,和需要翻译的语言包,左侧不用填写,运行宏后会按顺序自动填写每个表格内的中英文变量名方便查看

image-20200707210104176

在右侧复制表格格式,填写变量名和各语言的值

image-20200707210815547

通过 视图 > 宏 > 查看宏 > MakeAll > 执行 来导出语言包,宏速度很快,点击执行后就已经完成了导出,在C盘的 DbSql 文件夹 Website 内找到语言包放入项目的语言包文件夹内使用

image-20200707211240878 image-20200707211310823

添加更多语言,或删除西班牙语,需要更改宏,点击宏对话框的编辑,在打开的宏里找到MakeAll,修改为对应数量

image-20200707211310823

修改上图目录为项目目录,表格 列表 内的文件夹名改成lang,直接生成语言包到项目目录的lang文件夹下

sBaseFolderName = "d:\\App\\src\\assets"

v-for 列表渲染

语言包为列表渲染的内容单独声明了数组或对象,直接 v-for = "item in $t( 'list' )" 就可以

data内可以 $t 获取语言包内的变量,但是对切换语言是无法做出响应的

所以当需要拼凑一个对象用于列表渲染,需要在计算属性内 return 这个拼凑的语言包对象,这个对象就可以通过计算属性来响应语言的切换

computed: {
    list() {
        return {
            listTitle: this.$t("list.mainTitle"),
            advantage: [
                {
                    title: this.$t("list.title1"),
                    text: this.$t("list.text1")
                },
                {
                    title: this.$t("list.title2"),
                    text: this.$t("list.text2")
                },
                {
                    title: this.$t("list.title3"),
                    text: this.$t("list.text3")
                }
            ]
        };
    }
}

组件复用情况

结合上方计算属性返回对象的操作,再通过 $route 获取路由,计算属性嵌套,来让组件显示固定的不同内容

computed: {
    content() {
        let content;
        let type = this.$route.matched[0].name;
        switch (type) {
            case "page1":
                content = this.list1;
                break;
            case "page2":
                content = this.list2;
                break;
            case "page3":
                content = this.list3;
                break;
        }
        return content;
    },
    list1() {
        return {
            listTitle: this.$t("list.mainTitle"),
            advantage: [
                {
                    title: this.$t("list.title1"),
                    text: this.$t("list.text1")
                },
                .....
            ]
        };
    },
    list2() {
        return {
            listTitle: this.$t("list.mainTitle"),
            advantage: [
                {
                    title: this.$t("list.title1"),
                    text: this.$t("list.text1")
                },
                .....
            ]
        };
    },
    list3() {
        return {
            listTitle: this.$t("list.mainTitle"),
            advantage: [
                {
                    title: this.$t("list.title1"),
                    text: this.$t("list.text1")
                },
                .....
            ]
        };
    }
}

不同语言CSS适配

绑定元素属性并选择元素

因为语言不同使用同一个 css 导致的标题或其他内容,宽度超出或其他意外情况,或者不同语言使用不同的背景图片

可以使用 :lang() 伪选择器,来对不同语言的个别内容进行单独调整适配

首先需要对元素动态绑定语言类型,通过:

<h3 :lang="$i18n.locale">{{content.title}}</h3>
h3 {
    color: #fff;
    text-align: center;
    white-space: nowrap;
    &:lang(zh) {
        font-size: 0.8rem;
    }
    &:lang(en) {
        font-size: 0.59rem;
    }
    &:lang(es) {
        font-size: 0.5rem;
    }
}

多个语言包同语种选择器

如果是适配 zh-cn、zh-hk、zh-tw,或者 en-uk、en-us....这种多语言包但是同语种长度相同的语言

改为使用 属性选择器 会更灵活,注意 lang 后的管道符 |

//选择属性 lang 值以 zh 或 zh- 开头的元素
h3[lang|='zh']{
    font-size: 0.8rem;
}
//绑定属性为zh_cn的话,可以使用以开始字符为特征选择
h3[lang^='zh']{
    font-size: 0.8rem;
}

标题过长超出部分省略

一些并不是很重要的标题,可以给的空间又非常有限,可以采用css的方法将超出部分省略

h3{
    overflow: hidden;
    white-space: nowrap;
    text-overflow:ellipsis;
}

深度作用选择器

因为vue组件在 css 设置 scoped 的情况下编译,会在标签内生成 data-v-xxxx ,css 通过属性选择器选择,来避免 css 污染全局

<div data-v-654a55d5 class="box"></div>
.box[data-v-654a55d5] {
    ...
}

当使用 v-html 导入的变量带有标签和类名,是无法通过当前组件的 css 来控制的

vue提供了 深度作用选择器 来完成这个操作

// css:
.box >>> .title{
    ...
}
// sass/less
.box {
    /deep/ .title{
        ...
    }
}

编译结果:

.box[data-v-654a55d5] .title {
    ...
}

这个方法同样适用于插件导入的内容

主副意思相同

当英文副标题和中文主标题意思相同时,语言包内英文副标题值为空,不会占用页面空间,空值也不会报错