网上搜很多vue多语言的,一般都是介绍vue-i18n怎么使用,当然这是不错的,但是我们如果只是讲这个的话,只是解决了静态文字的多语言化。
这一部分我们也简单讲一下
npm install vue-i18n --save安装

// main.js
import VueI18n from 'vue-i18n';
import messages from './i18n';

Vue.use(VueI18n);
const locale = (localStorage.getItem("language") || navigator.language || navigator.browserLanguage).toLowerCase();
为了避免被坑都转成小写。
// 通过选项创建 VueI18n 实例
const i18n = new VueI18n({
  locale, // 设置地区
  messages, // 设置地区信息
});
new Vue({
  router,
  store,
  i18n,
  render: (h) => h(App),
}).$mount('#app');

里面的messages就是我们的多语言数据

//i18n/index.js
export default {
    ['zh-cn']: {
        hello: '你好',
    },
    ['en-us']: {
        hello: 'Hello',
    }
}

这里的zh-cn是和上面的zh-cn对应的.

在.vue文件里面使用时就是这样

<tempalate>
    <div> 
        {{$t('hello')}}
    </div>
</tempalate>

到这里vue-i18n说完了

很多时候我们在处理接口返回、录入的数据也需要支持多语言的。比如电商运营人员是需要提前分别输入商品的中文名和英文名的。
否则会出现这样的(这是一个录入电商运营人员录入品牌信息的页面)
file
是不是多少有点怪啊。
我们是不是需要这种
录入英文
file
录入中文
file

前端怎么实现的?
在没有多语言的情况下,表单绑定的数据是这样的

dataForm = {
    brandName: '',
    sort: 0,
    isDisplay: 1,
}

显然这里的品牌名brandName是需要支持的多语言的,其它的都是数字也不涉及到什么多语言。
我们需要改造下dataForm

<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({
          google_ad_client: "ca-pub-3013839362871866",
          enable_page_level_ads: true
     });
</script>
dataForm = {
    brandName: {
        ['en-US']: '',
        ['zh-CN']: ''
    },
    sort: 0,
    isDisplay: 1,
}

此时dataForm.brandName不再是字符串了,而是对象了,这样我们就根据key的变化显示对应的值,这样brandName能使用多语言了。
实际使用过程中跟上面的例子还是略有不同的

  1. 某个用户支持哪些语言,提前是不知道的,需要有一个单独提供支持语言的接口返回的,所以我们无法简单的像brandName: {['en-US']: '',['zh-CN']: ''},这样写死的。
  2. 历史数据怎么处理?历史数据都是不支持多语言的啊,总不能自行判断,然后有的brandName是字符串,有的是对象吧,想想都不好处理。如果所有的数据都是统一格式不就好了?这时很自然的想到了数据的归一化。可以参考我昨天写的《从mapState、mapMutations的源码看数据归一化normalize》

首先我们要支持一点,既然开始支持多语言了,那就需要用户指定一个默认语言,历史数据就是那个默认语言的数据。
以上面的例子的后端返回数据为例继续讲。
后端肯定不会再原始表里面加字段,比如en-US-brandName之类的。他们会建立一个多语言的表,专门存储多语言信息,在原始表里面还是存储默认语言信息。

这样如果数据已经存在多语言的会返回这样,默认语言为中文zh-CN

    data: {
        brandName: '品牌XX',
        sort:2,
        isDisplay: 1,
        langMap: {
            'zh-CN': {
                brandName:  '品牌XX',
            },
            'en-US: {
                brandName:  'brandXX',
            }
        }
    }

外层的brandName的值就是该用户的默认语言的值,这样也是为了兼容性考虑的。
历史数据(也就是前端没有提交过多语言信息的)

    data: {
        brandName: '品牌XX',
        sort:2,
        isDisplay: 1,
    }

其实你是多么希望就算原来没有多语言,后端也会这样返回

    data: {
        brandName: '品牌XX',
        sort:2,
        isDisplay: 1,
        langMap: {
            'zh-CN': {
                brandName:  '品牌XX',
            },
        }
    }

哈哈,每一个强大的前端都是被产品、后端、设计师、测试逼出来的
前端就要这么强。
我们可以根据接口拿到数据后,自己判断是否有langMap,如果没有,我们就直接将数据归一化变成含有langMap的。
然后我们需要根据langMap再次处理数据,最终变成

data(){
    return {
        dataForm = {
            brandName: {
                ['en-US']: 'brandXX',
                ['zh-CN']: '品牌XX'
            },
            sort: 0,
            isDisplay: 1,
        },
        languageList:[{
            languageCode: 'zh-CN',
            language: '简体中文'
        },{
            languageCode: 'en-US',
            language: 'Englist'
        }]
    };
},
<template>
    <section>
        <el-radio-group
                class="lang-select"
                :value="currentLang"
                size="small"
              >
                <el-radio-button
                  v-for="(item, index) in languageList"
                  :key="'lang' + index"
                  :class="currentLang === item.languageCode ? 'active' : ''"
                  :label="item.languageCode"
                  @click.native="currentLang = item.languageCode"
                >
                  {{ item.language }}
                </el-radio-button>
        </el-radio-group>

        <el-form :model="dataForm">
            <el-form-item :label="$t('brand_name')" prop="brandName">
                <el-input
                v-model.trim="(dataForm.brandName || {})[currentLang]"
                maxlength="50"
                ></el-input>
            </el-form-item>
            <el-form-item :label="$t('sort')" prop="sort">
                <el-input
                v-model.trim="dataForm.sort"
                ></el-input>
            </el-form-item>
            <el-form-item
                    :label="$t('display_is_or_no')"
                    prop="isDisplay"
                  >
                    <el-radio-group v-model="dataForm.isDisplay">
                      <el-radio :label="1">{{ $t("yes") }}</el-radio>
                      <el-radio :label="0">{{ $t(no") }}</el-radio>
                    </el-radio-group>
                  </el-form-item>
        </el-form>
    </section>
</template>

这里的上半部分就是多语言选择器那一部分了,通过点击切换当前语言currentLang,下面的v-model.trim="(dataForm.brandName || {})[currentLang]"这里的品牌名的值也就会切换对应的key显示对应的文字了。


发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据