前端不使用i18n該如何優(yōu)雅的實現(xiàn)多語言
前言:
關于ERP管理系統(tǒng)的多語言,或者其他應用的多語言一直是我們比較麻煩的問題,大部分是使用 i18n 在代碼里進行配置,如果想要修改語言就要自己去改代碼!
今天我們分享一下如何不使用 i18n 去實現(xiàn)多語言,用到以下的技術棧:
ERP管理系統(tǒng):Vue + 若依 + Element-ui
微信小程序 :uniapp + uView
一、業(yè)務需求
1. 確定業(yè)務
最近要實現(xiàn)多語言的 ERP,以及對應的H5、小程序;但是因為語言可能不確定,需求是客戶自己去添加、修改自己想要的語言,所以就需要在 ERP 上實現(xiàn) 一個叫 language(可以定義語言) 的功能,可以去給客戶提供一個可以添加默認語言、添加新的語言、修改、刪除當前語言的平臺,如果當前語言沒有加過翻譯則用 [ key ] 這種方式去提醒客戶,該 key 未加多語言!然后我們的ERP、H5、小程序就可以使用當前的全局多語言...
2. 實現(xiàn)思路
思路其實比較簡單,但是復雜的需求往往離不開后端大佬支持!下面我們一起來捋一捋我們的實現(xiàn)思路(假設我們現(xiàn)在的需求是三個地區(qū)的語言:簡體中文、繁體中文、英文)!
① 既然我們再 ERP 上需要有一個 language 的功能供客戶去操作語言,考慮到客戶還可能設置默認語言,添加多種不同地區(qū)的語言,所以我們的 UI 可以像下圖設計的那樣;

② 新增完地區(qū)語言以后我們該如何讓去修改、新增的不同地區(qū)的語言呢?我們這個時候就需要 一個子頁面,負責新增當前 key 的多語言,查詢當前 key 的多語言去做修改,看完下圖你就會明白啦?。?!

③經(jīng)過以上兩個步驟我們已經(jīng)成功的讓客戶實現(xiàn)了想要的效果,但是我們要怎么把后端大哥保存好的東西拿過來用呢
1. 保存時的數(shù)據(jù)結構:
{
key: "Status"
texts:[
{
"languageName": "en-GB",
"text": "Status"
},
{
"languageName": "zh-CN",
"text": "狀態(tài)"
},
{
"languageName": "zh-HK",
"text": "狀態(tài)"
}
]
}關于ERP 查詢時的數(shù)據(jù)結構這里就不一一列舉了,和上面類似!
2. ERP | H5 | 微信小程序 用時查詢的數(shù)據(jù)結構:
// ERP | H5 | 微信小程序 用時的查詢
// language_texts 是我們再 SQL Table 中存儲的所有多語言集合
language_texts : {
key : 當前語言的value, // 如何知道當前語言,我們稍后再說
key : value,
key : value,
... : ...
... : ...
}3. 前端如何使用已經(jīng)保存好的數(shù)據(jù)結構呢?
其實有了上面查詢我們就可以用到 language_texts[ key ] 的方式去取出來我們想要的語言數(shù)據(jù);使用的話也比較簡單,js html 中的不同使用方法下面給大家一 一講解 ;
值得我們思考的問題是 我們該何時把 當前語言集全部查詢出來?
我這里采用的方案是在 new Vue 之前去調用我們當前的 VFrame方法,這樣我們可以確保 我們的多語言所有的 [ key ] [ value ] 可以成功加載,具體步驟請看下方!
二、實現(xiàn)步驟
1. 新建 VFrame.js 文件
我這里的 VFrame.js 是直接建在Src 目錄下的
import axiso from 'axios'
import { getAll } from '@/api/uxretail/application.js'
const format = require('string-format')
export default class VFrame {
static host;
static wsUrl;
/**
* 在vue實例化之前調用異步start方法
*/
static start() {
return new Promise((resolve, reject) => {
axiso.request({
url: "/static/appconfig.json",
method: "get",
}).then(result => {
VFrame.host = (result.host || window.location.host);
VFrame.wsUrl = "ws://" + VFrame.host + ":" + result.wsPort + "/ws/notify/";
VFrame.getAll(resolve);
}).catch(error => {
reject(error);
});
});
}
static getAll(resolve) {
getAll().then(res => {
VFrame.applicationResource = res
resolve()
});
}
static l(key, ...args) {
if (localStorage.getItem("ux_debug_language")) {
return `[${key}]`
}
if (!VFrame.applicationResource) {
return key
}
if (VFrame.applicationResource.language_texts) {
let res = VFrame.applicationResource.language_texts[key];
if (res) {
return format(res, args);
} else {
return `[${key}]`
}
}
return key;
}
}2. main.js 中 使用我們新建的 VFrame.js
上面我們說到 VFrame 的執(zhí)行時機,我們可以看下面代碼!
import Vue from "vue";
import App from "./App";
import store from "./store";
import router from "./router";
import VFrame from "./framework/VFrame";
Vue.prototype.l = VFrame.l;
// 這個為了方便用 VFrame ,并沒有其他用途
Vue.prototype.$ux = {
v: VFrame
}
// 重要的就是這一步,VFrame 的執(zhí)行時機
VFrame.start().then(() => {
//set layout to store
store.commit("dragLayout/initLayout")
new Vue({
el: "#app",
router,
store,
render: h => h(App)
});
});3. html js 中使用我們配置好的多語言
Html 中使用: 【 l("Key") 】
<div> {{ l('ManyLanguage') }} </div>
<el-form :model="item" :rules="tableRules">
<el-form-item :label="l("ManyLanguage")" prop="language">
<el-input v-model="item.language"></el-input>
</el-form-item>
</el-form>js 中使用: 【 this.l("Key") 】
export default{
data(){
return {
language:this.l("ManyLanguage")
}
},
created(){
console.log(this.l("MyLanguage"))
},
}經(jīng)過上面一番操作我們已經(jīng)可以在管理系統(tǒng)中成功的調用當前多語言了;
那么我們 VFrame 中的 getAll() API 調用時 如何返回我們剛好我們想要的語言呢?
我們就要處理 【 request.js 】中的封裝,在請求攔截中去攜帶我們自定義的請求頭信息,后端大佬去對應的處理即可!
import Cookies from "js-cookie";
import axios from "axios";
axios.defaults.headers["Content-Type"] = "application/json;charset=utf-8";
// 創(chuàng)建axios實例
const service = axios.create({
// axios中請求配置有baseURL選項,表示請求URL公共部分
baseURL: process.env.VUE_APP_BASE_API,
// 超時
timeout: 120000
});
service.interceptors.request.use(
config => {
var cultureName = Cookies.get(CONSTANT.UX_LANGUAGE);
if (cultureName) {
config.headers[CONSTANT.UX_LANGUAGE] = cultureName; // 讓每個請求攜帶自定義token 請根據(jù)實際情況自行修改
}
})三、微信小程序中使用
實現(xiàn)步驟就像上面寫的步驟一樣,那么注意點是什么呢( 本文用的是uniapp去開發(fā)的微信小程序,也是基于 vue 的語法 )?
在 uniapp 里面我們不能寫的像我們上面那樣,因為 uniapp 是不支持的,那么這個時候我們如何去確保頁面加載完成時,多語言可以全部返回呢?
答:做一個預加載頁,當我們多語言成功返回以后跳轉至業(yè)務頁面
1. 完成上方基礎 VFrame 創(chuàng)建,main.js 中掛載,但是不要在用 new vue 勿動(不然會報錯)!
因為小程序有 Tabbar 所以我們的 VFrame.js 需要多一個方法;
import {
request
} from "util/request.js";
export default class VFrame {
static applicationResource;
/**
* 在vue實例化之前調用異步start方法
*/
static start() {
return new Promise((resolve, reject) => {
request({
url: '/application/getAppAll', //activityType=0 查詢全部
method: 'GET',
hideLoading: true,
data: {
orgId: uni.getStorageSync('companyOrgId')
}
}).then(res => {
VFrame.applicationResource = res.data.result
resolve(res)
});
});
}
static l(key, args) {
if (VFrame.applicationResource && VFrame.applicationResource.language_texts) {
let res = VFrame.applicationResource.language_texts[key];
if (res) {
return res;
} else {
return `[${key}]`
}
}
return key;
}
static tabbarLanguage(tabbarList) {
let language = uni.getStorageSync('language') || 'zh-CN'
if (language) {
switch (language) {
case 'en-GB':
tabbarList[0].text = "Coupons"
tabbarList[1].text = "Stamp"
tabbarList[2].text = "Account"
tabbarList[3].text = "Discount"
tabbarList[4].text = "Favourite"
break
case 'zh-CN':
tabbarList[0].text = "電子優(yōu)惠券"
tabbarList[1].text = "電子印花"
tabbarList[2].text = "我的賬戶"
tabbarList[3].text = "優(yōu)惠獎賞"
tabbarList[4].text = "我的最愛"
break
case 'zh-HK':
tabbarList[0].text = "電子優(yōu)惠券"
tabbarList[1].text = "電子印花"
tabbarList[2].text = "我的賬戶"
tabbarList[3].text = "優(yōu)惠獎賞"
tabbarList[4].text = "我的最愛"
break
}
}
return tabbarList
}
}2. 預加載頁面的制作
新建 preload.vue
<template>
<view class="preload">fashion-cue</view>
</template>
<script>
import { mapMutations } from 'vuex';
import VFrame from '@/util/VFrame';
export default {
name: 'Preload', // 預加載動畫頁面
data() {
return {};
},
methods: {
...mapMutations(['setAppAll'])
},
onLoad(e) {
console.log('onLoad', e);
VFrame.start().then(res => {
if (res && res.data.result.brandList && res.data.result.categoryList) {
this.setAppAll(res.data.result);
}
getApp().globalData.isLoaded = true;
uni.switchTab({
url: e.redirect ? '/' + e.redirect : '/platforms/mp-weixin/discount/discount'
});
});
}
};
</script>
<style>
.preload {
width: 100%;
font-weight: bold;
font-family: 'Arial', 'Microsoft YaHei', '黑體', '宋體', sans-serif;
font-size: 2.5rem;
text-align: center;
background-image: -webkit-linear-gradient(left, black, transparent 25%, black 50%, transparent 75%, black);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-background-size: 200% 100%;
-webkit-animation: masked-animation 2s infinite linear;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -140%);
}
@-webkit-keyframes masked-animation {
0% {
background-position: 0 0;
}
100% {
background-position: -100% 0;
}
}
</style>3. 切換語言
切換語言是再次調用我們的 VFrame.js 中的 start() 方法即可;
但是小程序切換要注意幾個點:
① 自定義請求頭的特殊處理
② 切換完成以后需要刷新當前頁面
③ Tabbar 頁面需要再 onShow 時處理



結語:
其實實現(xiàn)步驟略微有些繁瑣,但是并不難,主要還是后端大佬的配合!
到此這篇關于前端不使用i18n該如何優(yōu)雅的實現(xiàn)多語言的文章就介紹到這了,更多相關前端實現(xiàn)多語言內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
javascript面向對象創(chuàng)建對象的方式小結
這篇文章主要介紹了javascript面向對象創(chuàng)建對象的方式,結合實例形式總結分析了javascript常見的7種創(chuàng)建對象的方式,需要的朋友可以參考下2019-07-07
JavaScript對象數(shù)組排序函數(shù)及六個用法
本文給大家分享一個用于數(shù)組或者對象的排序的函數(shù)。該函數(shù)可以以任意深度的數(shù)組或者對象的值作為排序基數(shù)對數(shù)組或的元素進行排序2015-12-12

