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

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容