美文网首页让前端飞程序员
vue搭配i18n国际化语言插件开发多语言网站

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

作者: ziclee | 来源:发表于2018-01-17 01:03 被阅读0次

    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 =================================

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

    相关文章

      网友评论

        本文标题:vue搭配i18n国际化语言插件开发多语言网站

        本文链接:https://www.haomeiwen.com/subject/rkcyoxtx.html