用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,登录网站

小程序社区 首页 教程 实战教程 查看内容

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

Rolan 2020-5-19 00:42

随着小程序应用越来越广泛,国际化支持逐渐成了刚需。官方文档给出了一个国际化方案,但觉得配置起来稍微有点复杂,对项目结构还有一定的要求。如果是旧项目改动成本太大,遂决定自己实现一个小程序国际化方案。源码 ...

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

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

源码地址: github.com/cachecats/m…

一、项目结构

整体目录结构如下图:

  • 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.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 中的使用分三步:

  1. 首先引入 LangUtils.js

  2. 然后在 data 中定义变量 lang ,通过 ... 对象的解构赋值,把语言文件中对应模块定义的变量都赋值给 lang ,方便调用。如果是 settings 模块,可以这样写: lang: {...LangUtils.getLangSrc().settings} 。也可以只写个空对象: lang: {} ,然后在 onShow() 方法里对 lang 赋值。

  3. 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 方法里都要执行相似的逻辑,以后有时间会做优化。

项目地址: github.com/cachecats/m…

鲜花
鲜花
鸡蛋
鸡蛋
分享至 : QQ空间
收藏
原作者: solocoder 来自: 掘金