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


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 相关文章推荐
js脚本学习 比较实用的基础
Sep 07 Javascript
DWZ刷新dialog解决方法
Mar 03 Javascript
深入理解JavaScript系列(46):代码复用模式(推荐篇)详解
Mar 04 Javascript
检测一个函数是否是JavaScript原生函数的小技巧
Mar 13 Javascript
javascript的理解及经典案例分析
May 20 Javascript
限制复选框最多选择项的实现代码
May 30 Javascript
早该知道的7个JavaScript技巧
Jun 21 Javascript
用jQuery实现可输入多选下拉组合框实例代码
Jan 18 Javascript
EasyUI修改DateBox和DateTimeBox的默认日期格式示例
Jan 18 Javascript
jQuery事件详解
Feb 23 Javascript
Node错误处理笔记之挖坑系列教程
Jun 05 Javascript
JQuery Ajax动态加载Table数据的实例讲解
Aug 09 jQuery
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获取文件名后缀常用方法小结
2015/02/24 PHP
PHP基于迭代实现文件夹复制、删除、查看大小等操作的方法
2017/08/11 PHP
解决在laravel中leftjoin带条件查询没有返回右表为NULL的问题
2019/10/15 PHP
ASP.NET中基于JQUERY的高性能的TreeView补充
2011/02/23 Javascript
JavaScript原型链示例分享
2014/01/26 Javascript
JS实现从网页顶部掉下弹出层效果的方法
2015/08/06 Javascript
AngularJS使用ngOption实现下拉列表的实例代码
2016/01/23 Javascript
javascript实现延时显示提示框特效代码
2016/04/27 Javascript
JS控制页面跳转时未请求要跳转的地址怎么回事
2016/10/14 Javascript
ES6新特性二:Iterator(遍历器)和for-of循环详解
2017/04/20 Javascript
BootStrap Table 后台数据绑定、特殊列处理、排序功能
2017/05/27 Javascript
深入浅析Nodejs的Http模块
2017/06/20 NodeJs
基于 Vue.js 2.0 酷炫自适应背景视频登录页面实现方式
2018/01/17 Javascript
使用Vue的slot插槽分发父组件内容实现高度复用、更加灵活的组件(推荐)
2018/05/01 Javascript
jquery实现动态添加附件功能
2018/10/23 jQuery
基于vue-cli3创建libs库的实现方法
2019/12/04 Javascript
element-ui如何防止重复提交的方法步骤
2019/12/09 Javascript
Vue3 实现双盒子定位Overlay的示例
2020/12/22 Vue.js
解决python selenium3启动不了firefox的问题
2018/10/13 Python
利用anaconda保证64位和32位的python共存
2021/03/09 Python
Python测试Kafka集群(pykafka)实例
2019/12/23 Python
TensorFlow——Checkpoint为模型添加检查点的实例
2020/01/21 Python
python+Selenium自动化测试——输入,点击操作
2020/03/06 Python
在tensorflow下利用plt画论文中loss,acc等曲线图实例
2020/06/15 Python
浅谈python处理json和redis hash的坑
2020/07/16 Python
Python连接mysql数据库及简单增删改查操作示例代码
2020/08/03 Python
Sarenza德国:法国最大的时尚鞋和包包网上商店
2019/06/08 全球购物
大学生毕业求职简历的自我评价
2013/10/24 职场文书
大学生就业策划书范文
2014/04/04 职场文书
应届毕业生自荐书
2014/06/18 职场文书
小学生国庆65周年演讲稿范文(2篇)
2014/09/21 职场文书
教师群众路线剖析材料
2014/09/29 职场文书
刑事申诉状范文
2015/05/20 职场文书
vue生命周期钩子函数以及触发时机
2022/04/26 Vue.js
vue使用watch监听属性变化
2022/04/30 Vue.js
Nginx代理Redis哨兵主从配置的实现
2022/07/15 Servers