日期: 2020-06-22 17:51:16
随着小程序应用越来越广泛,国际化支持逐渐成了刚需。
官方文档给出了一个 国际化方案 ,但觉得配置起来稍微有点复杂,对项目结构还有一定的要求。如果是旧项目改动成本太大,遂决定自己实现一个小程序国际化方案。
源码地址:https://github.com/cachecats/miniprogram-i18n
一、项目结构
整体目录结构如下图:
二、工具类封装及语言包准备
2.1 语言包准备
i18n
目录下的各语言包结构要一致,即对象的 key
保持一致, value
是对应的语言文本。
建议每个小模块分为一个对象,单个对象的内容不宜过多。
zh-CN.js
export default { common: { language: '语言', chinese: '中文', english: '英语', }, tabBarTitles: ['主页', '论坛', '我的'], navTitle: { home: '主页', forum: '论坛', mine: '我的', setting: '设置' }, home: { motto: '我们宁愿拥有一个不完美的变革,也不愿看到一个没有希望的未来', respect: '致勇者', getUserInfo: '获取头像昵称' }, forum: { forumModule: '我是论坛模块', tip: '下面是一个组件,用来展示组件的国际化配置' }, comment: { title: '评论组件', msg: '网络一线牵,珍惜这段缘' }, mine: { title: '这是我的页面', toNewPage: '跳转到新页面' }, setting: { title: '我是设置页面' } }
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
封装了国际化所需的所有方法,包括获取当前语言、设置语言、获取当前语言的资源文件、设置 TabBar
、设置 NavigationBar
等方法。
实现思路是把当前设置的语言存在小程序提供的 storage 中,每次项目初始化时从 storage
中读取语言,如果没有读到则默认设置为中文。
然后在每个页面或组件的 data
中将页面需要用到的文本资源引入进来, wxml
中使用 data
中绑定的变量展示文字。同时在生命周期的 onShow
方法中重新读取当前语言并设置 data
,使得每次改变语言都能正确的加载语言包。
先看 LangUtils
的代码:
import zh from '../i18n/zh-CN.js' import en from '../i18n/en-US.js' import Constants from '../constants/Constants'; export default{ //初始化语言设置。在 app.js 里调用这个方法。 initLang(){ //先获取是不是已存在语言的设置 let lang = wx.getStorageSync('lang') if(!lang){ //如果不存在,设置默认语言为中文 this.setLang(Constants.langCN) } }, //设置语言 setLang(lang){ try{ wx.setStorageSync('lang', lang) }catch(e){ console.log('设置语言失败', e) } }, //获取语言设置 getLang(){ try{ let lang = wx.getStorageSync('lang') return lang; }catch(e){ console.log('获取语言设置失败', e) } }, //获取当前语言下的资源文件 getLangSrc(){ let lang = this.getLang(); if(lang === Constants.langCN){ return zh; } else if(lang === Constants.langEN){ return en; }else{ return zh; } }, //设置 NavigationBarTitle setNavigationBarTitle(title){ wx.setNavigationBarTitle({ title: title }) }, /** * 设置 tabBar。因为 tabBar 是在 app.json 里写死的,需要使用 wx.setTabBarItem * 循环设置 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) } }); }); }, }
先引入中文和英文的语言包,以便根据当前语言设置返回对应的资源包。
Constants
是对常量的封装,这里保存的是中英文编码标识。
Constants.js /** * 保存项目中的常量 */ export default{ //中文编码 langCN: 'zh-CN', //英文编码 langEN: 'en-US', }
需要注意的是 tabBar
的处理,因为 tabBar
是写死在 app.json
中的,不能动态的改变文本,所以每次语言改变只能用小程序暴露出来的 wx.setTabBarItem
方法循环的设置 tabBar
。
至此前期的准备工作已经做完啦,接下来对具体的页面和组件做处理。
三、项目使用
需要改动三个地方
app.js
初始化语言xxx.js
的 data
添加语言属性,并在 onShow
生命周期方法中调用 setData
重新设置语言xxx.wxml
中的文本替换为 data
里绑定的变量3.1 app.js 初始化语言
在项目入口文件 app.js
中做初始化。
//初始化国际化语言设置 import LangUtils from './utils/LangUtils' App({ onLaunch: function () { // 国际化的初始化 LangUtils.initLang(); LangUtils.setTabBarLang(); } })
3.2 Page 页面的国际化 js 中使用
js 中的使用分三步:
首先引入 LangUtils.js
然后在 data
中定义变量 lang
,通过 ...
对象的解构赋值,把语言文件中对应模块定义的变量都赋值给 lang
,方便调用。如果是 settings 模块,可以这样写: lang: {...LangUtils.getLangSrc().settings}
。也可以只写个空对象: lang: {}
,然后在 onShow()
方法里对 lang
赋值。
onShow()
生命周期方法里,更新 lang
的值,以防语言被改变。如果需要设置小程序标题,则再调用 LangUtils.setNavigationBarTitle()
方法。
// pages/setting/setting.js import LangUtils from '../../utils/LangUtils' let langSrc = LangUtils.getLangSrc() Page({ /** * 页面的初始数据 */ data: { lang: { ...langSrc.setting } }, /** * 生命周期函数--监听页面显示 */ onShow: function () { this.setLanguage(); }, /** * 重新设置语言 */ setLanguage() { langSrc = LangUtils.getLangSrc(); this.setData({ lang: { ...langSrc.setting } }) // 设置 NavigationBarTitle LangUtils.setNavigationBarTitle(langSrc.navTitle.setting); } })
wxml 中使用
wxml 里比较简单,跟普通的变量使用方法一样。
<view class="setting-container"> <text class="title">{{lang.title}}</text> </view>
3.2 Component 组件的国际化
Component
跟 Page
国际化基本上相同,但因为生命周期方法不同,稍微有点区别。
Coponents
的 this.setLanguage()
在生命周期的 pageLifetimes
的 show
方法中调用。
// pages/forum/components/comment.js import LangUtils from '../../../../utils/LangUtils' let langSrc = LangUtils.getLangSrc(); Component({ data: { lang: { ...langSrc.comment } }, pageLifetimes: { // 组件所在页面的生命周期函数 show: function () { console.log('page show---') this.setLanguage(); }, }, /** * 组件的方法列表 */ methods: { /** * 重新设置语言 */ setLanguage() { langSrc = LangUtils.getLangSrc(); this.setData({ lang: { ...langSrc.comment } }) } } })
3.3 切换语言
切换语言放在 demo 的 home
页面中。用户更改语言后要调用 LangUtils.setLang
更改语言值,还要调用 LangUtils.setTabBarLang
重新设置 tabBar
的文本。
切换后的效果
//index.js //获取应用实例 const app = getApp() import Constants from '../../constants/Constants' // 获取对应语言的资源文件 import LangUtils from '../../utils/LangUtils' let langSrc = LangUtils.getLangSrc(); // 语言选项 const LANGUAGE_OPTIONS = [{ key: Constants.langCN, value: '中文' }, { key: Constants.langEN, value: 'English' } ] Page({ data: { // 通过解构赋值将 common 和 home 下的变量赋值给 lang。最好每个模块建一个对象 // 对象里的属性不宜过多,否则在 data 里放入太多内容会影响性能,用到什么放什么。 lang: { ...langSrc.common, ...langSrc.home }, langOptions: LANGUAGE_OPTIONS, index: 0 }, onLoad: function () { // 根据当前语言设置 picker 默认选中的值 let lang = LangUtils.getLang(); this.setData({ index: lang === Constants.langCN ? 0 : 1 }) }, onShow: function () { //每次 onShow 重新设置语言,以防语言更新 this.setLanguage(); }, getUserInfo: function (e) { console.log(e) app.globalData.userInfo = e.detail.userInfo this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) }, /** * 选择语言变化回调函数 */ onLanguageChange(e) { const index = e.detail.value console.log(e) this.setData({ index: index }) // 更改语言 LangUtils.setLang(this.data.langOptions[index].key); // 重新设置 tabBar 的语言 LangUtils.setTabBarLang(); this.setLanguage(); }, /** * 重新设置语言 */ setLanguage() { langSrc = LangUtils.getLangSrc(); this.setData({ lang: { ...langSrc.common, ...langSrc.home } }) // 设置 NavigationBarTitle LangUtils.setNavigationBarTitle(langSrc.navTitle.home); } })
四、总结
代码乍一看还挺多的,但优点是不用引入第三方模块,也不用按要求改项目结构。其实把前期的准备工作做完后,后期维护起来还是很方便的。
当然这个方案还有可优化的地方,比如每个页面的 onShow
方法里都要执行相似的逻辑,以后有时间会做优化。
项目地址:https://github.com/cachecats/miniprogram-i18n
到此这篇关于微信小程序国际化探索实现(附源码地址)的文章就介绍到这了,更多相关小程序国际化内容请搜索奥多码以前的文章或继续浏览下面的相关文章希望大家以后多多支持奥多码!