微信小程序国际化探索实现(附源码地址)


Posted in Javascript onMay 20, 2020

随着小程序应用越来越广泛,国际化支持逐渐成了刚需。

官方文档给出了一个 国际化方案 ,但觉得配置起来稍微有点复杂,对项目结构还有一定的要求。如果是旧项目改动成本太大,遂决定自己实现一个小程序国际化方案。

源码地址:https://github.com/cachecats/miniprogram-i18n

一、项目结构

整体目录结构如下图:

微信小程序国际化探索实现(附源码地址)

  • assets 存放资源文件,如图片
  • constants 存放项目中用到的常量
  • i18n 存放语言文件,中文是 zh-CN.js 英文是 en-US.js ,如果还需要支持其他语言再建一个 js 即可
  • pages 存放业务逻辑代码
  • utils 存放工具类。LangUtils 是封装的国际化工具类。

二、工具类封装及语言包准备

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.jsdata 添加语言属性,并在 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 组件的国际化

ComponentPage 国际化基本上相同,但因为生命周期方法不同,稍微有点区别。

Coponentsthis.setLanguage() 在生命周期的 pageLifetimesshow 方法中调用。

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

到此这篇关于微信小程序国际化探索实现(附源码地址)的文章就介绍到这了,更多相关小程序国际化内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
用Javascript做flash做的事..才完成的一个类.Auntion Action var 0.1
Feb 23 Javascript
基于jQuery制作迷你背词汇工具
Jul 27 Javascript
关于锚点跳转及jQuery下相关操作与插件
Oct 01 Javascript
关于IE中getElementsByClassName不能用的问题解决方法
Aug 26 Javascript
调试代码导致IE出错的避免方法
Apr 04 Javascript
jQuery中clone()方法用法实例
Jan 16 Javascript
javascript判断元素存在和判断元素存在于实时的dom中的方法
Jan 17 Javascript
JS使用cookie实现只出现一次的广告代码效果
Apr 22 Javascript
jQuery制作input提示内容(兼容IE8以上)
Jul 05 jQuery
详解让sublime text3支持Vue语法高亮显示的示例
Sep 29 Javascript
vue实现条件判断动态绑定样式的方法
Sep 29 Javascript
通过Kettle自定义jar包供javascript使用
Jan 29 Javascript
jQuery HTML设置内容和属性操作实例分析
May 20 #jQuery
jquery html添加元素/删除元素操作实例详解
May 20 #jQuery
jQuery HTML css()方法与css类实例详解
May 20 #jQuery
15分钟上手vue3.0(小结)
May 20 #Javascript
jQuery 隐藏/显示效果函数用法实例分析
May 20 #jQuery
Vue的props父传子的示例代码
May 20 #Javascript
Vue项目移动端滚动穿透问题的实现
May 19 #Javascript
You might like
PHP 数组入门教程小结
2009/05/20 PHP
PHP防止表单重复提交的几种常用方法汇总
2014/08/19 PHP
PHP在线书签系统分享
2016/01/04 PHP
thinkPHP自定义类实现方法详解
2016/11/30 PHP
PHP程序员必须知道的两种日志实例分析
2020/05/14 PHP
用于判断用户注册时,密码强度的JS代码
2009/01/01 Javascript
JavaScript Event学习第七章 事件属性
2010/02/07 Javascript
Js 时间函数getYear()的使用问题探讨
2013/04/01 Javascript
jquery自定义右键菜单、全选、不连续选择
2016/03/01 Javascript
JS实现兼容火狐及IE iframe onload属性的遮罩层隐藏及显示效果
2016/08/23 Javascript
js捕捉键盘事件和按键键值的方法
2016/10/10 Javascript
jQuery ajaxForm()的应用
2016/10/14 Javascript
在vue-cli中组件通信的方法
2017/12/16 Javascript
vue cli使用融云实现聊天功能的实例代码
2019/04/19 Javascript
使用webpack搭建vue环境的教程详解
2019/12/31 Javascript
JS实现iframe中子父页面跨域通讯的方法分析
2020/03/10 Javascript
24个ES6方法解决JS实际开发问题(小结)
2020/05/31 Javascript
Vue页面手动刷新,实现导航栏激活项还原到初始状态
2020/08/06 Javascript
[01:10]DOTA2亚洲邀请赛 征战号角响彻全场
2015/01/06 DOTA
[01:13:46]iG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
解决Python 命令行执行脚本时,提示导入的包找不到的问题
2019/01/19 Python
Django实现发送邮件找回密码功能
2019/08/12 Python
Python数据分析模块pandas用法详解
2019/09/04 Python
pytorch读取图像数据转成opencv格式实例
2020/06/02 Python
基于Keras中Conv1D和Conv2D的区别说明
2020/06/19 Python
使用anaconda安装pytorch的实现步骤
2020/09/03 Python
scrapy在python爬虫中搭建出错的解决方法
2020/11/22 Python
Django集成MongoDB实现过程解析
2020/12/01 Python
西班牙鞋子和箱包在线销售网站:zapatos.es
2020/02/17 全球购物
毕业生个人的求职信范文
2013/12/03 职场文书
房产公证书范本
2014/04/10 职场文书
挂靠协议书范本
2014/04/22 职场文书
爱祖国演讲稿
2014/05/04 职场文书
大学学风建设方案
2014/05/04 职场文书
GoLang中生成UUID唯一标识的实现
2021/05/08 Golang
windows11选中自动复制怎么开启? Win11自动复制所选内容的方法
2022/07/23 数码科技