微信小程序國際化探索實(shí)現(xiàn)(附源碼地址)
隨著小程序應(yīng)用越來越廣泛,國際化支持逐漸成了剛需。
官方文檔給出了一個(gè) 國際化方案 ,但覺得配置起來稍微有點(diǎn)復(fù)雜,對項(xiàng)目結(jié)構(gòu)還有一定的要求。如果是舊項(xiàng)目改動(dòng)成本太大,遂決定自己實(shí)現(xiàn)一個(gè)小程序國際化方案。
源碼地址:https://github.com/cachecats/miniprogram-i18n
一、項(xiàng)目結(jié)構(gòu)
整體目錄結(jié)構(gòu)如下圖:

- assets 存放資源文件,如圖片
- constants 存放項(xiàng)目中用到的常量
- i18n 存放語言文件,中文是 zh-CN.js 英文是 en-US.js ,如果還需要支持其他語言再建一個(gè) js 即可
- pages 存放業(yè)務(wù)邏輯代碼
- utils 存放工具類。LangUtils 是封裝的國際化工具類。
二、工具類封裝及語言包準(zhǔn)備
2.1 語言包準(zhǔn)備
i18n 目錄下的各語言包結(jié)構(gòu)要一致,即對象的 key 保持一致, value 是對應(yīng)的語言文本。
建議每個(gè)小模塊分為一個(gè)對象,單個(gè)對象的內(nèi)容不宜過多。
zh-CN.js
export default {
common: {
language: '語言',
chinese: '中文',
english: '英語',
},
tabBarTitles: ['主頁', '論壇', '我的'],
navTitle: {
home: '主頁',
forum: '論壇',
mine: '我的',
setting: '設(shè)置'
},
home: {
motto: '我們寧愿擁有一個(gè)不完美的變革,也不愿看到一個(gè)沒有希望的未來',
respect: '致勇者',
getUserInfo: '獲取頭像昵稱'
},
forum: {
forumModule: '我是論壇模塊',
tip: '下面是一個(gè)組件,用來展示組件的國際化配置'
},
comment: {
title: '評論組件',
msg: '網(wǎng)絡(luò)一線牽,珍惜這段緣'
},
mine: {
title: '這是我的頁面',
toNewPage: '跳轉(zhuǎn)到新頁面'
},
setting: {
title: '我是設(shè)置頁面'
}
}
en-US.js
export default {
common: {
language: 'Language',
chinese: 'Chinese',
english: 'English',
},
tabBarTitles: ['Home', 'Forum', 'Mine'],
navTitle: {
home: 'Home',
forum: 'Forum',
mine: 'Mine',
setting: 'setting'
},
home: {
motto: 'We would rather have an imperfect change than see a hopeless future',
respect: 'to warrior',
getUserInfo: 'Get avatar nickname'
},
forum: {
forumModule: 'I am forum module',
tip: 'The following is a component to show the international configuration of the component'
},
comment: {
title: 'Comment Components',
msg: 'The network leads, cherish this relationship'
},
mine: {
title: 'This is mine page',
toNewPage: 'Go to new page'
},
setting: {
title: 'I am setting page'
}
}
2.2 工具類 LangUtils 封裝
工具類 LangUtils 封裝了國際化所需的所有方法,包括獲取當(dāng)前語言、設(shè)置語言、獲取當(dāng)前語言的資源文件、設(shè)置 TabBar 、設(shè)置 NavigationBar 等方法。
實(shí)現(xiàn)思路是把當(dāng)前設(shè)置的語言存在小程序提供的 storage 中,每次項(xiàng)目初始化時(shí)從 storage 中讀取語言,如果沒有讀到則默認(rèn)設(shè)置為中文。
然后在每個(gè)頁面或組件的 data 中將頁面需要用到的文本資源引入進(jìn)來, wxml 中使用 data 中綁定的變量展示文字。同時(shí)在生命周期的 onShow 方法中重新讀取當(dāng)前語言并設(shè)置 data ,使得每次改變語言都能正確的加載語言包。
先看 LangUtils 的代碼:
import zh from '../i18n/zh-CN.js'
import en from '../i18n/en-US.js'
import Constants from '../constants/Constants';
export default{
//初始化語言設(shè)置。在 app.js 里調(diào)用這個(gè)方法。
initLang(){
//先獲取是不是已存在語言的設(shè)置
let lang = wx.getStorageSync('lang')
if(!lang){
//如果不存在,設(shè)置默認(rèn)語言為中文
this.setLang(Constants.langCN)
}
},
//設(shè)置語言
setLang(lang){
try{
wx.setStorageSync('lang', lang)
}catch(e){
console.log('設(shè)置語言失敗', e)
}
},
//獲取語言設(shè)置
getLang(){
try{
let lang = wx.getStorageSync('lang')
return lang;
}catch(e){
console.log('獲取語言設(shè)置失敗', e)
}
},
//獲取當(dāng)前語言下的資源文件
getLangSrc(){
let lang = this.getLang();
if(lang === Constants.langCN){
return zh;
} else if(lang === Constants.langEN){
return en;
}else{
return zh;
}
},
//設(shè)置 NavigationBarTitle
setNavigationBarTitle(title){
wx.setNavigationBarTitle({
title: title
})
},
/**
* 設(shè)置 tabBar。因?yàn)?tabBar 是在 app.json 里寫死的,需要使用 wx.setTabBarItem
* 循環(huán)設(shè)置 tabBar
*/
setTabBarLang(){
let tabBarTitles = this.getLangSrc().tabBarTitles;
console.log('tabBarTitles', tabBarTitles)
tabBarTitles.forEach((item, index) => {
console.log(item, index)
wx.setTabBarItem({
index: index,
text: item,
success: (res) => {
console.log('setTabBarItem success', res)
},
fail: (err) => {
console.log('setTabBarItem fail', err)
}
});
});
},
}
先引入中文和英文的語言包,以便根據(jù)當(dāng)前語言設(shè)置返回對應(yīng)的資源包。
Constants 是對常量的封裝,這里保存的是中英文編碼標(biāo)識。
Constants.js
/**
* 保存項(xiàng)目中的常量
*/
export default{
//中文編碼
langCN: 'zh-CN',
//英文編碼
langEN: 'en-US',
}
需要注意的是 tabBar 的處理,因?yàn)?tabBar 是寫死在 app.json 中的,不能動(dòng)態(tài)的改變文本,所以每次語言改變只能用小程序暴露出來的 wx.setTabBarItem 方法循環(huán)的設(shè)置 tabBar 。
至此前期的準(zhǔn)備工作已經(jīng)做完啦,接下來對具體的頁面和組件做處理。
三、項(xiàng)目使用
需要改動(dòng)三個(gè)地方
app.js初始化語言xxx.js的data添加語言屬性,并在onShow生命周期方法中調(diào)用setData重新設(shè)置語言xxx.wxml中的文本替換為data里綁定的變量
3.1 app.js 初始化語言
在項(xiàng)目入口文件 app.js 中做初始化。
//初始化國際化語言設(shè)置
import LangUtils from './utils/LangUtils'
App({
onLaunch: function () {
// 國際化的初始化
LangUtils.initLang();
LangUtils.setTabBarLang();
}
})
3.2 Page 頁面的國際化 js 中使用
js 中的使用分三步:
首先引入 LangUtils.js
然后在 data 中定義變量 lang ,通過 ... 對象的解構(gòu)賦值,把語言文件中對應(yīng)模塊定義的變量都賦值給 lang ,方便調(diào)用。如果是 settings 模塊,可以這樣寫: lang: {...LangUtils.getLangSrc().settings} 。也可以只寫個(gè)空對象: lang: {} ,然后在 onShow() 方法里對 lang 賦值。
onShow() 生命周期方法里,更新 lang 的值,以防語言被改變。如果需要設(shè)置小程序標(biāo)題,則再調(diào)用 LangUtils.setNavigationBarTitle() 方法。
// pages/setting/setting.js
import LangUtils from '../../utils/LangUtils'
let langSrc = LangUtils.getLangSrc()
Page({
/**
* 頁面的初始數(shù)據(jù)
*/
data: {
lang: {
...langSrc.setting
}
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面顯示
*/
onShow: function () {
this.setLanguage();
},
/**
* 重新設(shè)置語言
*/
setLanguage() {
langSrc = LangUtils.getLangSrc();
this.setData({
lang: {
...langSrc.setting
}
})
// 設(shè)置 NavigationBarTitle
LangUtils.setNavigationBarTitle(langSrc.navTitle.setting);
}
})
wxml 中使用
wxml 里比較簡單,跟普通的變量使用方法一樣。
<view class="setting-container">
<text class="title">{{lang.title}}</text>
</view>
3.2 Component 組件的國際化
Component 跟 Page 國際化基本上相同,但因?yàn)樯芷诜椒ú煌?,稍微有點(diǎn)區(qū)別。
Coponents 的 this.setLanguage() 在生命周期的 pageLifetimes 的 show 方法中調(diào)用。
// pages/forum/components/comment.js
import LangUtils from '../../../../utils/LangUtils'
let langSrc = LangUtils.getLangSrc();
Component({
data: {
lang: {
...langSrc.comment
}
},
pageLifetimes: {
// 組件所在頁面的生命周期函數(shù)
show: function () {
console.log('page show---')
this.setLanguage();
},
},
/**
* 組件的方法列表
*/
methods: {
/**
* 重新設(shè)置語言
*/
setLanguage() {
langSrc = LangUtils.getLangSrc();
this.setData({
lang: {
...langSrc.comment
}
})
}
}
})
3.3 切換語言
切換語言放在 demo 的 home 頁面中。用戶更改語言后要調(diào)用 LangUtils.setLang 更改語言值,還要調(diào)用 LangUtils.setTabBarLang 重新設(shè)置 tabBar 的文本。

切換后的效果

//index.js
//獲取應(yīng)用實(shí)例
const app = getApp()
import Constants from '../../constants/Constants'
// 獲取對應(yīng)語言的資源文件
import LangUtils from '../../utils/LangUtils'
let langSrc = LangUtils.getLangSrc();
// 語言選項(xiàng)
const LANGUAGE_OPTIONS = [{
key: Constants.langCN,
value: '中文'
},
{
key: Constants.langEN,
value: 'English'
}
]
Page({
data: {
// 通過解構(gòu)賦值將 common 和 home 下的變量賦值給 lang。最好每個(gè)模塊建一個(gè)對象
// 對象里的屬性不宜過多,否則在 data 里放入太多內(nèi)容會影響性能,用到什么放什么。
lang: {
...langSrc.common,
...langSrc.home
},
langOptions: LANGUAGE_OPTIONS,
index: 0
},
onLoad: function () {
// 根據(jù)當(dāng)前語言設(shè)置 picker 默認(rèn)選中的值
let lang = LangUtils.getLang();
this.setData({
index: lang === Constants.langCN ? 0 : 1
})
},
onShow: function () {
//每次 onShow 重新設(shè)置語言,以防語言更新
this.setLanguage();
},
getUserInfo: function (e) {
console.log(e)
app.globalData.userInfo = e.detail.userInfo
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
},
/**
* 選擇語言變化回調(diào)函數(shù)
*/
onLanguageChange(e) {
const index = e.detail.value
console.log(e)
this.setData({
index: index
})
// 更改語言
LangUtils.setLang(this.data.langOptions[index].key);
// 重新設(shè)置 tabBar 的語言
LangUtils.setTabBarLang();
this.setLanguage();
},
/**
* 重新設(shè)置語言
*/
setLanguage() {
langSrc = LangUtils.getLangSrc();
this.setData({
lang: {
...langSrc.common,
...langSrc.home
}
})
// 設(shè)置 NavigationBarTitle
LangUtils.setNavigationBarTitle(langSrc.navTitle.home);
}
})
四、總結(jié)
代碼乍一看還挺多的,但優(yōu)點(diǎn)是不用引入第三方模塊,也不用按要求改項(xiàng)目結(jié)構(gòu)。其實(shí)把前期的準(zhǔn)備工作做完后,后期維護(hù)起來還是很方便的。
當(dāng)然這個(gè)方案還有可優(yōu)化的地方,比如每個(gè)頁面的 onShow 方法里都要執(zhí)行相似的邏輯,以后有時(shí)間會做優(yōu)化。
項(xiàng)目地址:https://github.com/cachecats/miniprogram-i18n
到此這篇關(guān)于微信小程序國際化探索實(shí)現(xiàn)(附源碼地址)的文章就介紹到這了,更多相關(guān)小程序國際化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
countUp.js實(shí)現(xiàn)數(shù)字滾動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了countUp.js實(shí)現(xiàn)數(shù)字滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
js如何將多個(gè)json結(jié)構(gòu)組成的字符串轉(zhuǎn)換為數(shù)組?
接口返回的EventStream結(jié)構(gòu)的數(shù)據(jù),由于http流式傳輸時(shí),可能會分段,所以導(dǎo)致本該每次返回一段json數(shù)據(jù)結(jié)構(gòu)的字符串,變成了多個(gè)json數(shù)據(jù)結(jié)構(gòu)的字符串拼接在了一起,本文講述js如何將多個(gè)json結(jié)構(gòu)組成的字符串轉(zhuǎn)換為數(shù)組2024-08-08
JS前端面試必備——基本排序算法原理與實(shí)現(xiàn)方法詳解【插入/選擇/歸并/冒泡/快速排序】
這篇文章主要介紹了JS前端面試基本排序算法原理與實(shí)現(xiàn)方法,結(jié)合實(shí)例形式詳細(xì)分析了JS常見的基本排序算法相關(guān)原理、實(shí)現(xiàn)方法、時(shí)間復(fù)雜度及操作注意事項(xiàng),需要的朋友可以參考下2020-02-02
javascript數(shù)組去重方法終極總結(jié)
這篇文章主要介紹了javascript數(shù)組去重終極總結(jié),本文列舉了3種javascript數(shù)組去重方法,并分別分析了它們的優(yōu)缺點(diǎn),需要的朋友可以參考下2014-06-06
JS刪除數(shù)組中某個(gè)元素的四種方式總結(jié)
js刪除指定元素方法有很多,下面這篇文章主要給大家介紹了關(guān)于JS刪除數(shù)組中某個(gè)元素的四種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02

