Nuxt+Element+I18n实现多语言国际化

2021-01-06 12:14:25  卢浮宫  版权声明:本文为站长原创文章,转载请写明出处


一、背景

    最近官网更新需要实现国际化,目前暂支持中文和英文。考虑到我们现在是使用的前后端分离,

所以需要使用前端来实现。在花费了一上午的时间之后,终于大致定下来了,这里简单记录下。


二、预期效果和实现情况

    2.1、支持中英文,同时可自由配置及拓展 -> OK

    2.2、国际化需要包括:网页元素、自定义组件、element-ui组件 -> OK

    2.3、配置式 -> 自定义组件原本是读取Json文件,但是有些问题所以暂时存在本地了


三、整体实现流程


    3.1、首先安装 Vue-i18n

        npm install vue-i18n --save


    3.2、配置Plugin

        ① 在plugins文件夹下创建i18n.js

        ② 其内容如下:

            import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)

export default ({ app, store }) => {
app.i18n = new VueI18n({
locale: store.state.locale,
fallbackLocale: 'zh-CN', // 我这里默认语言为中文
messages: {
'en-US': require('@/locales/en-US.json'),
'zh-CN': require('@/locales/zh-CN.json')
}
})

app.i18n.path = (link) => {
// 如果是默认语言,就省略
if (app.i18n.locale === app.i18n.fallbackLocale) {
return `/${link}`
}
return `/${link}?lang=/${app.i18n.locale}`
}
}


    3.3、在Store中保存当前的语言状态

        ① store文件夹下创建index.js

        ② 其代码如下:

            export const state = () => ({
locales: ['en-US', 'zh-CN'],
locale: 'zh-CN'
})

export const mutations = {
// 此处为设置locale
SET_LANG(state, locale) {
if (state.locales.indexOf(locale) !== -1) {
state.locale = locale
}
}
}


    3.4、在middleware文件夹下创建i18n.js来进行语言的控制        

        export default function ({
isHMR, app, store, route, redirect, query,req
}) {

// 从服务端请求头cookie中获取语种
let locale;
locale= 1
// cookie中没有的情况下,获取路由参数中的语种,再没有就默认为中文
if(!locale){
locale = query.lang || 'zh-CN';
}
// 设置语种
store.commit('SET_LANG', locale); // set store
app.i18n.locale = store.state.locale;

// 跳转该去的地方, isHMR我还没看是什么。
if (isHMR) {
return;
}
else if (!query.lang) {
return redirect(route.fullPath);
}
}


    3.5、配置Nuxt.config.js中的国际化 

        PS: 这里贴部分代码

        plugins: [
'@/plugins/element-ui',
'@/plugins/i18n.js',
],

// Auto import components (https://go.nuxtjs.dev/config-components)
components: true,

// Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
buildModules: [
],

router: {
middleware: 'i18n'
},


     3.6、配置多语言json配置文件

            ① 创建locales文件夹

            ② 创建en-US.json

            {
"menu": {
"home": "Home"
}
}

            ③ 创建zh-CN.json

            {
"menu": {
"home": "网站首页"
}
}


    3.7、element组件的国际化

        ① 修改plugin文件夹下的element的配置

            import Vue from 'vue'
import Element from 'element-ui/lib/element-ui.common'

import enLang from 'element-ui/lib/locale/lang/en'
import cnLang from 'element-ui/lib/locale/lang/zh-CN'
import locale from 'element-ui/lib/locale'

export default ({
app
}) => {
Vue.use(Element, {
i18n: (key, value) => {
// 设置语言
const lang = localStorage.getItem('lang');
if(lang == 'zh-CN'){
locale.use(cnLang)
}else{
locale.use(enLang)
}
app.i18n.t(key, value)
}
})
}


    3.8、页面相关配置

        ① 放入语言切换的按钮

            <button @click="changeLang('zh-CN')" v-if="$i18n.local!='zh-CN'">中文</button>

            <button @click="changeLang('en-US')" v-if="$i18n.local!='en-US'">英文</button>

                  <el-button type="text" @click="open">点击打开 Message Box</el-button>
            <el-date-picker
                v-model="value1"
                type="date"
                placeholder="选择日期">
            </el-date-picker>
            <!-- 这里是需要国际化的内容 -->
            <el-menu-item index="/">{{$t('menu.home')}}</el-menu-item>
        
        ② 自定义组件的数据存放 (这里后续优化成读取json)
            mounted(){
const enLangJson = {
"menu": {
"home": "Home231"
},
"confirmTitle": "Submit1"
};
const cnLangJson = {
"menu": {
"home": "网站首页123"
},
"confirmTitle": "提交"
};
localStorage.setItem('enLangCache', JSON.stringify(enLangJson))
localStorage.setItem('cnLangCache', JSON.stringify(cnLangJson))
},


        ③ 语言切换的方法

            changeLang(lang) {
this.$i18n.locale = lang;
// 此时语言就会显示为切换的语言
localStorage.setItem('lang',lang);
},

        ④ 监听实现自定义组件的国际化

            PS: 以element的弹出框为例 

            open() {
let confirmTitle = '确定';
const lang = localStorage.getItem('lang');
let langJson = {};
if(lang == 'zh-CN'){
const langStr = localStorage.getItem('cnLangCache');
langJson = JSON.parse(langStr);
}else if(lang == 'en-US'){
const langStr = localStorage.getItem('enLangCache');
langJson = JSON.parse(langStr);
}
confirmTitle = langJson.confirmTitle;
this.$alert('这是一段内容', '标题名称', {
confirmButtonText: confirmTitle,
callback: action => {
this.$message({
type: 'info',
message: `action: ${ action }`
});
}
});
},


四、效果预览


    4.1、菜单的中英文切换


        


        


    4.2、自定义组件 


                        


            


    4.3、element-ui组件 

            

      

        

        

五、后记


    5.1、存在问题

        页面抖动,在切换英文语言后进行页面刷新会先切换为中文再切换为英文。

    5.2、问题排查及尝试

        ① 首先我们是默认为中文语言的

        ② 在middleware下的i18n.js中,里面的语言选项是获取的store中的数据

        ③ 但是页面每次刷新时store里面存放的语言都会重置

        ④ 尝试写了一个store持久化的js,但是最终还是会出现页面抖动问题

    5.3、官方解决方案

        其实在官方是有一个国际化的示例项目的:Nuxt国际化官方示例项目

        在其中我们可以看到他是使用的nuxt-link的方式进行处理的

    5.4、当前解决方案

        ① 使用nuxtlink进行多语言页面的切换

        ② 每个页面都copy出一份,以index为例(有index.vue和indexEn.vue)

        ③ 默认页面时中文语言

        ④ XXXEn的页面指定为英文语言

        附相关处理代码:

       页面切换代码:
        <nuxt-link target="_blank" :to="$route.fullPath.replace(/^\/[^\/]+/, '')" >中文</nuxt-link>
<nuxt-link target="_blank" :to="`/newsEn` + $route.fullPath" >英文</nuxt-link>

        

        英文版本页面指定语言相关代码:
        mounted(){
this.$i18n.locale = 'en-US';
},

    

    5.5、写在最后

        这个是我这边目前的解决方案,整体来说需要额外copy一份页面并手动指定语言。

        虽然说还是有重复造轮子的情况,但是好在工作量不大(copy文件 -> 修改文件名 -> 指定语言)

        工作重心需要,暂时处理如上,后续有更好的解决方案后再进行补充完善。


    更多精彩请持续关注 guangmuhua.com



最新评论: