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


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 相关文章推荐
JQuery UI皮肤定制
Jul 27 Javascript
基于jQuery的弹出警告对话框美化插件(警告,确认和提示)
Jun 10 Javascript
javascript 控制input只允许输入的各种指定内容
Jun 19 Javascript
jQuery 动态云标签插件
Nov 11 Javascript
javascript实现类似超链接的效果
Dec 26 Javascript
JQuery.validate在ie8下不支持的快速解决方法
May 18 Javascript
详解在vue-cli中引用jQuery、bootstrap以及使用sass、less编写css
Nov 08 jQuery
最实用的JS数组函数整理
Dec 05 Javascript
禁止弹窗中蒙层底部页面跟随滚动的几种方法
Dec 07 Javascript
vue mounted 调用两次的完美解决办法
Oct 29 Javascript
node 标准输入流和输出流代码实例
Sep 19 Javascript
js实现简单的秒表
Jan 16 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加密解密类代码
2011/11/27 PHP
php 判断字符串中是否包含html标签
2014/02/17 PHP
最新版本PHP 7 vs HHVM 多角度比较
2016/02/14 PHP
CI框架源码解读之URI.php中_fetch_uri_string()函数用法分析
2016/05/18 PHP
Zend Framework入门教程之Zend_Config组件用法详解
2016/12/09 PHP
jquery-easyui关闭tab自动切换到前一个tab
2010/07/29 Javascript
jquery异步循环获取功能实现代码
2010/09/19 Javascript
深入理解JavaScript系列(8) S.O.L.I.D五大原则之里氏替换原则LSP
2012/01/15 Javascript
解析JavaScript中的标签语句
2013/06/19 Javascript
jQuery对于显示和隐藏等常用状态的判断方法
2014/12/13 Javascript
js实现图片点击左右轮播
2015/07/08 Javascript
深入探讨javascript函数式编程
2015/10/11 Javascript
JS使用eval()动态创建变量的方法
2016/06/03 Javascript
AngularJS基础 ng-mousemove 指令简单示例
2016/08/02 Javascript
前端框架Vue.js构建大型应用浅析
2016/09/12 Javascript
jQuery+正则+文本框只能输入数字的实现方法
2016/10/07 Javascript
利用vue实现模态框组件
2016/12/19 Javascript
javascript将list转换成树状结构的实例
2017/09/08 Javascript
详解js跨域请求的两种方式,支持post请求
2018/05/05 Javascript
基于Fixed定位的框选功能的实现代码
2019/05/13 Javascript
超简单的微信小程序轮播图
2019/11/22 Javascript
[02:12]DOTA2英雄基础教程 变体精灵
2013/12/16 DOTA
Python全排列操作实例分析
2018/07/24 Python
Python脚本完成post接口测试的实例
2018/12/17 Python
Python求两点之间的直线距离(2种实现方法)
2019/07/07 Python
Python上下文管理器用法及实例解析
2019/11/11 Python
Python RabbitMQ实现简单的进程间通信示例
2020/07/02 Python
Python paramiko使用方法代码汇总
2020/11/20 Python
亚马逊印度站:Amazon.in
2017/10/15 全球购物
体育纪念品、亲笔签名的体育收藏品:Steiner Sports
2020/07/31 全球购物
介绍Ibatis的核心类
2013/11/18 面试题
团员年度个人总结
2015/02/26 职场文书
中学生社会实践教育活动总结
2015/05/06 职场文书
ORACLE数据库应用开发的三十个注意事项
2021/06/07 Oracle
微信小程序scroll-view不能左右滑动问题的解决方法
2021/07/09 Javascript
pd.drop_duplicates删除重复行的方法实现
2022/06/16 Python