让前端飞程序员

vue搭配i18n国际化语言插件开发多语言网站

2018-01-17  本文已影响0人  ziclee

vue搭配i18n国际化语言插件开发多语言网站

安装过程直接略过,安装步骤链接:

vue命令行工具 (CLI)
vue-i18n插件
vue-i18n基本使用

使用vue开发,使用最多的是单文件组件,所以碰到的坑都是在这一部分;

开发使用版本:

    "vue": "^2.5.2",
    "vue-router": "^3.0.1"
    ====================================
     "vue-i18n": "^7.4.0",
    "@kazupon/vue-i18n-loader": "^0.2.1",

问题一、vue-i18n-loader如何添加在vue的配置文件

为了使用单文件组件时配合i18n存储map数据,需要先安装vue-i18n-loader,然后使用<i18n></i18n>标签定义map数据。
原谅小白,以前使用vue时,都没好好研究vue的配置文件,直到这次碰到问题,才稍微认真看了一会(还没全部弄明白);

根据i18n给的添加方法

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            // you need to specify `i18n` loaders key with `vue-i18n-loader` (https://github.com/kazupon/vue-i18n-loader)
            i18n: '@kazupon/vue-i18n-loader'
          }
        }
      },
      // ...
    ]
  },
  // ...
}

但是,vue的配置文件都是封装好的一系列方法,中间尝试过各种办法,这里就不一一列举出来(PS:主要是时间有点久,记不住了😢)。

最后,尝试在webpack.base.conf.js文件console vueLoaderConfig变量(编译时能看到输出结果)

npm run dev

vueLoaderConfig的输出结果:


{ loaders:
   { css: [ 'vue-style-loader', [Object] ],
     postcss: [ 'vue-style-loader', [Object] ],
     less: [ 'vue-style-loader', [Object], [Object] ],
     sass: [ 'vue-style-loader', [Object], [Object] ],
     scss: [ 'vue-style-loader', [Object], [Object] ],
     stylus: [ 'vue-style-loader', [Object], [Object] ],
     styl: [ 'vue-style-loader', [Object], [Object] ]
  cssSourceMap: true,
  cacheBusting: true,
  transformToRequire:
   { video: [ 'src', 'poster' ],
     source: 'src',
     img: 'src',
     image: 'xlink:href' } }

看到这里,客官就该明白,要如何添加了~

没错,直接给vueLoaderConfig对象添加一条属性值即可;

vueLoaderConfig.loaders.i18n = '@kazupon/vue-i18n-loader';

重新编译,结果如下:

{ loaders:
   { css: [ 'vue-style-loader', [Object] ],
     postcss: [ 'vue-style-loader', [Object] ],
     less: [ 'vue-style-loader', [Object], [Object] ],
     sass: [ 'vue-style-loader', [Object], [Object] ],
     scss: [ 'vue-style-loader', [Object], [Object] ],
     stylus: [ 'vue-style-loader', [Object], [Object] ],
     styl: [ 'vue-style-loader', [Object], [Object] ],
     i18n: '@kazupon/vue-i18n-loader' },
  cssSourceMap: true,
  cacheBusting: true,
  transformToRequire:
   { video: [ 'src', 'poster' ],
     source: 'src',
     img: 'src',
     image: 'xlink:href' } }
     

到此,vue-i18n-loader我们就正确添加到vue配置文件里啦。

问题二、 如何全局修改i18n的语言切换,使各个组件能够同步切换语言

根据i18n文档,全局修改i18n的语言配置,可以这么用:

  const i18n = new VueI18n({
    locale: 'en',
    // ...
  })
  const app = new Vue({ i18n }).$mount('#app')

  // change locale
  i18n.locale = 'ja'
  // or
  app.$i18n.locale = 'ja'

看到这个,瞬间觉得自己明白了,开心地继续往下码

根据使用文档,先引入i18n

//main.js

import router from './router';
import layOut from '@/components/layout';
import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)

const i18n = new VueI18n({
      locale: 'cn',
      messages: {
          cn: {

          },
          en: {

          }
      }
  })

new Vue({
  el: '#app',
  router,
  i18n,
  components: { layOut },
  template: '<layOut/>'
});
//layout.vue 片段(英文翻译为了测试随便写,因为公司翻译还没翻译完😂)

<i18n>
    {
        "en": {
            "navTitle": {
                "ivf": {
                    "name": "ivf",
                    "path": "ivf"
                },
                "juanLuan": {
                    "name": "Egg Donation",
                    "path": "egg_donation"
                },
                "surrogacy": {
                    "name": "Surrogacy",
                    "path": "surrogacy"
                },
                "law": {
                    "name": "Law",
                    "path": "law"
                },
                "recruit": {
                    "name": "Recruit",
                    "path": "recruit",
                    "detail": {
                        "juanLuan": {
                            "name": "As Egg Donation",
                            "path": "recruit/egg_donation"
                        },
                        "daiMa": {
                            "name": "As Baby Mama",
                            "path": "recruit/baby_mama"
                        }
                    }
                },
                "successCase": {
                    "name": "successCase",
                    "path": "successCase"
                },
                "aboutUs": {
                    "name": "aboutUs",
                    "path": "aboutUs"
                }
            }
        },
        "cn": {
            "navTitle": {
                "ivf": {
                    "name": "ivf",
                    "path": "ivf"
                },
                "juanLuan": {
                    "name": "捐卵",
                    "path": "egg_donation"
                },
                "surrogacy": {
                    "name": "代孕",
                    "path": "surrogacy"
                },
                "law": {
                    "name": "法律政策",
                    "path": "law"
                },
                "recruit": {
                    "name": "捐卵者/代码招募",
                    "path": "recruit",
                    "detail": {
                        "juanLuan": {
                            "name": "成为捐卵者",
                            "path": "recruit/egg_donation"
                        },
                        "daiMa": {
                            "name": "成为代妈",
                            "path": "recruit/baby_mama"
                        }
                    }
                },
                "successCase": {
                    "name": "成功案例",
                    "path": "successCase"
                },
                "aboutUs": {
                    "name": "关于我们",
                    "path": "aboutUs"
                }
            }
        }
    }
</i18n>

<template>
<div class="u-icon-block">
    <span class="u-icon u-icon--cn" @click="changeLang('cn')"></span>
    <span class="u-icon u-icon--en" @click="changeLang('en')"></span>
    <span class="u-icon u-icon--ua" @click="changeLang('ua')"></span>
</div>
 <keep-alive>
    <router-view></router-view>
</keep-alive>
<template>

<script>
    methods: {
        changeLang (lan) {
            this.$i18n.locale = lan
        }
    }
</script>

OK,到了这里,测试一下,导航的标题能够正常切换了,但是router组件却没变化,瞬间懵逼了(原谅小白的不懂)

怎么回事呢,为什么没有全部替换呢?

原因一、此时的this.$i18n所替换的作用域仅是在当前组件里面,router子组件没有收到来自父组件的通信,所以没有跟着一起变化;

原因二、没有使用i18n文档里面的全局替换方法(这个暂时还没想好怎么换,请大神指教,谢谢)

想明白了这点,那么为了能够全局跟踪i18nlocale的变化,我决定使用Vuex状态管理

撸起袖子,重新编写

//main.js

import Vue from 'vue';
import router from './router';
import layOut from '@/components/layout';
import store from './store/locale';

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
    el: '#app',
    router,
    i18n: store.i18n,
    store: store.store,
    components: { layOut },
    template: '<layOut/>'
});
//store.js
import Vue from 'vue';
import Vuex from 'vuex';
import VueI18n from 'vue-i18n';
Vue.use(Vuex);
Vue.use(VueI18n);

let status = {
    store: new Vuex.Store({
        state: {
            locale: 'cn'
        },
        getters: {
            locale (state) {
                console.log(state.locale);
                return state.locale;
            }
        },
        mutations: {
            changeLang (state, payload) {
                state.locale = payload;
                console.log(state);
                status.i18n.locale = payload;
            }
        }
    }),
    i18n: new VueI18n({
        locale: 'cn',
        messages: {
            cn: {

            },
            en: {

            }
        }
    })
};

export default status;
//layout.vue 片段
export default {
    methods: {
        changeLang (lang) {
            this.$store.commit('changeLang', lang);
        }
    }
};

OK,到了这里,我们就能实现全局变换i18n的locale了。但是,接下来,又碰到一个问题。

问题三、想要在组件里面使用v-for数据,及想往子组件里面传递props数据怎么办?

现在我们的mpa数据都是存储在<i18n></i18n>里面的,要怎么取出来呢?

这里就要用到i18n提供的一个method getLocaleMessage( locale )

//描述

getLocaleMessage( locale )
Arguments:

{Locale} locale
Return: LocaleMessageObject

Get the locale message of locale.

我们依然通过Vuex来获取变化的locale

//banner组件
<template>
    <div class="u-grid-fluid banner">
        <div class="u-grid u-title">
            <h3 class="u-title__item u-title__item--border--b">{{ bannerData.title1 }}</h3>
            <h3 class="u-title__item">{{ bannerData.title2 }}</h3>
            <p v-if="bannerData.desc" class="u-title__desc">{{ bannerData.desc }}</p>
        </div>
    </div>
</template>

<script>
export default {
    props: ['bannerData']
};
</script>
//index.vue(父组件)

<template>
    <div>
        <banner :banner-data="bannerData"></banner>
    <div>
</template>

//map数据
<i18n>
    {
        "en": {
            "banner": {
                "title1": "Freyja",
                "title2": "乌克兰捐卵,代孕服务专家",
                "desc": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo cursus magnavel scelerisque nisl consectetur et."
            },
            "sectionOne": {
                "title": "Freyja",
                "content": "芙蕾雅成立于2016年,致力于为有需要的用户提供专业的乌克兰捐卵,代孕服务。芙蕾雅团队由专业的生殖医疗专家,律师,生活服务人员组成。为用户的乌克兰捐卵,代孕之旅提供科学可信赖的保障。",
                "desc": "Freyja- healtch for you"
            },
            "sectionTwo": {
                "title": "Freyja",
                "content1": "乌克兰支持捐卵与代孕,您的权益将受到法律的保护"
            }
        },
        "cn": {
            "banner": {
                "title1": "芙蕾雅",
                "title2": "乌克兰捐卵,代孕服务专家",
                "desc": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo cursus magnavel scelerisque nisl consectetur et."
            },
            "sectionOne": {
                "title": "关于芙蕾雅",
                "content": "芙蕾雅成立于2016年,致力于为有需要的用户提供专业的乌克兰捐卵,代孕服务。芙蕾雅团队由专业的生殖医疗专家,律师,生活服务人员组成。为用户的乌克兰捐卵,代孕之旅提供科学可信赖的保障。",
                "desc": "Freyja- healtch for you"
            },
            "sectionTwo": {
                "title": "为什么选择芙蕾雅?",
                "content1": "乌克兰支持捐卵与代孕,您的权益将受到法律的保护"
            }
        }
    }
</i18n>

<script>
import banner from '../components/banner';
export default {
    data () {
        return {
            locale: this.$store.getters.locale
        };
    },
    computed: {
        bannerData () {
            let label = this.$store.getters.locale;
            return this.$i18n.getLocaleMessage(label).banner;
        }
    },
    components: {
        banner
    }
};
</script>

至此,我们就能顺利把<i18n></i18n>里面的数据顺利提取出来为我们所用了。

PS:<i18n>里面的json数据,最后的一条json对象里面不能有多余的逗号",",否则就会报错

//错误示例 sectionTwo的content1不小心加了一个逗号,结果就报错了
{
    "banner": {
        "title1": "Freyja",
        "title2": "乌克兰捐卵,代孕服务专家",
        "desc": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo cursus magnavel scelerisque nisl consectetur et."
    },
    "sectionOne": {
        "title": "Freyja",
        "content": "芙蕾雅成立于2016年,致力于为有需要的用户提供专业的乌克兰捐卵,代孕服务。芙蕾雅团队由专业的生殖医疗专家,律师,生活服务人员组成。为用户的乌克兰捐卵,代孕之旅提供科学可信赖的保障。",
        "desc": "Freyja- healtch for you"
    },
    "sectionTwo": {
        "title": "Freyja",
        "content1": "乌克兰支持捐卵与代孕,您的权益将受到法律的保护",
    }
}

//==================报错信息

error  in ./src/pages/index.vue

Syntax Error: Unexpected token } in JSON at position 707
    at JSON.parse (<anonymous>)


 @ ./src/pages/index.vue 31:18-136

这个错误,让我蒙圈了好一会儿,坑惨了😭

====================== The End =================================

流水式记录,不足之处,还请各位大神多多指教,谢谢!

上一篇下一篇

猜你喜欢

热点阅读