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


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 相关文章推荐
可缩放Reloaded-一个针对可缩放元素的复用组件
Mar 10 Javascript
Display SQL Server Login Mode
Jun 21 Javascript
javascript学习笔记(一) 在html中使用javascript
Jun 18 Javascript
使用jQuery内容过滤选择器选择元素实例讲解
Apr 18 Javascript
node.js中的fs.createWriteStream方法使用说明
Dec 17 Javascript
在JavaScript中处理数组之reverse()方法的使用
Jun 09 Javascript
详解JavaScript异步编程中jQuery的promise对象的作用
May 03 Javascript
JS经典正则表达式笔试题汇总
Dec 15 Javascript
Vue实现自带的过滤器实例
Mar 09 Javascript
简单说说angular.json文件的使用
Oct 29 Javascript
解决layui数据表格排序图标被超出的表头挤出去的问题
Sep 19 Javascript
将RGB值转换为灰度值的简单算法
Oct 09 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 5.5版本的array_column()函数
2014/10/24 PHP
php合并数组中相同元素的方法
2014/11/13 PHP
php提示Warning:mysql_fetch_array() expects的解决方法
2014/12/16 PHP
基于PHP代码实现中奖概率算法可用于刮刮卡、大转盘等抽奖算法
2015/12/20 PHP
CakePHP框架Model函数定义方法示例
2017/08/04 PHP
JS实现多物体缓冲运动实例代码
2013/11/29 Javascript
Node.js node-schedule定时任务隔多少分钟执行一次的方法
2015/02/10 Javascript
JS实现文件动态顺序载入的方法
2015/03/07 Javascript
JS中正则表达式只有3种匹配模式(没有单行模式)详解
2016/07/28 Javascript
本地Bootstrap文件字体图标引入却无法显示问题的解决方法
2020/04/18 Javascript
Vue.js基础知识小结
2017/01/13 Javascript
详解Node.js开发中的express-session
2017/05/19 Javascript
微信小程序分享海报生成的实现方法
2018/12/10 Javascript
jQuery表单元素过滤选择器用法实例分析
2019/02/20 jQuery
详解jquery和vue对比
2019/04/16 jQuery
送你43道JS面试题(收藏)
2019/06/17 Javascript
vue - vue.config.js中devServer配置方式
2019/10/30 Javascript
利用React高阶组件实现一个面包屑导航的示例
2020/08/23 Javascript
在Python的Django框架中包装视图函数
2015/07/20 Python
pandas数据处理基础之筛选指定行或者指定列的数据
2018/05/03 Python
Python使用grequests(gevent+requests)并发发送请求过程解析
2019/09/25 Python
python GUI库图形界面开发之PyQt5结合Qt Designer创建信号与槽的详细方法与实例
2020/03/08 Python
Softmax函数原理及Python实现过程解析
2020/05/22 Python
python如何爬取网页中的文字
2020/07/28 Python
欧铁通票官方在线销售网站:Eurail.com
2017/10/14 全球购物
来自Ocado的宠物商店:Fetch
2018/07/10 全球购物
大学生职业规划书的范本
2014/02/18 职场文书
工程技术员岗位职责
2014/03/02 职场文书
人力资源管理专业应届生求职信
2014/04/24 职场文书
公司活动总结范文
2014/07/01 职场文书
党员对照检查材料思想汇报
2014/09/16 职场文书
2014小学一年级班主任工作总结
2014/12/05 职场文书
个人原因辞职信模板
2015/05/13 职场文书
党员学习中国梦心得体会
2016/01/05 职场文书
2019最新激励员工口号大全!
2019/06/28 职场文书
2019职场单身人才调研报告:互联网行业单身比例最高
2019/08/07 职场文书