微信小程序-切换语言(国际化i18n)的方法封装

文章介绍了如何在微信小程序中实现多语言切换功能,通过封装i18n类,加载翻译文件,设置和获取语言,以及切换和注入翻译到页面组件中。代码示例展示了从创建翻译文件、初始化插件到在Page和Component中应用的完整流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小程序切换语言封装

最近做的一个小程序的项目, 涉及到了多语言的切换, 就想到了之前vue用的多语言插件i18n, 就尝试着在微信开放社区搜了一下, 没有具体的实现, 但是提供了大致的实现思路, 如下:
在这里插入图片描述
又结合了很多大佬的分享经验, 试着去封装了一个微信的i18n方法


🧐如何实现?

首先, 我们需要明确一下需要实现的功能

  1. 加载翻译文件的方法 loadTranslations 为i18n加载翻译文件(翻译文件单独抽离出来)
  2. 设置默认语言的方法 setLocale 用来设置一个默认的语言
  3. 获取当前语言的方法 getLocale 用来获取当前设置的语言
  4. 切换当前语言的方法 toggleLanguage 用来切换当前的语言
  5. 获取当前语言对应的翻译文件 getLanguage 用来获取对应语言的翻译文件
  6. 将翻译注入页面/组件的方法 effect 用来使页面/组件拿到当前语言对应的翻译文件
  7. 动态添加语言的方法 mergeTranslations 可以动态的添加语言

具体实现代码如下:

// i18n.js
class t {
  locale;
  locales;
  context;
  constructor(t) {
    this.locale = "", this.locales = t || {}
  }
  setLocale(t) {
    this.locale = t
  }
  getLocale() {
    return this.locale
  }
  loadTranslations(t) {
    return this.locales = t, this.context && this.effect(this.context)
  }
  mergeTranslations(t) {
    for (const e in t) this.locales[e] ? this.locales[e] = { ...this.locales[e], ...t[e] } : this.locales[e] = t[e];
    return this.context && this.effect(this.context)
  }
  getLanguage() {
    return this.locales[this.locale]
  }
  effect(t) {
    if (this.context = t, t.setData) return new Promise((e => { t.setData({ $t: this.getLanguage() }, (() => { e(t.$t) })) }))
  }
  toggleLanguage(t) {
    return this.setLocale(t), this.effect(this.context)
  }
}
const e = new t;
export { t as I18n, e as default, e as i18nInstance };

🧐如何使用?

  1. 首先我们要创建对应的翻译文件
    根目录下创建 lang 文件夹, 用来放翻译的文件, 有几种语言就分别创建几种语言对应的js文件, 以及一个入口文件 index.js
    在这里插入图片描述
    我需要四种语言, 所以要有四种语言对应的翻译文案, 以及一个入口文件, 文件具体内容如下:
    在这里插入图片描述
    语言对应的翻译文件, 导出一个大的对象, 大对象里面是一个一个模块的小的对象, 接着就是用到的翻译文案, 因此这四个文件需要尽可能保持一致, 不然就会导致某些文案没有对应的语言翻译

  2. 我们要将这些文件, 放到入口文件里统一处理:

import cnLocale from './cn';
import twLocale from './tw';
import enLocale from './en';
import ptLocale from './pt';

const messages = {
  cn: {
    ...cnLocale,
  },
  tw: {
    ...twLocale,
  },
  en: {
    ...enLocale,
  },
  pt: {
    ...ptLocale,
  }
};

export default messages;
  1. 初始化插件
// app.js
import message from "./lang/index";
import { i18nInstance, I18n } from "./utils/i18n";

App({
  renderI18nData: {},
  globalData: {
    currentLanguage: '',
  },
  onLaunch() {
    /**
     * i18nInstance.loadTranslations();  ->load translations for i18nInstance
     * i18nInstance.setLocale();  ->set default language
     * i18nInstance.getLocale();  ->get current language name
     * i18nInstance.toggleLanguage();  ->toggle language quickly
     * i18nInstance.effect(context: any);  ->必须指定page和components传递的context为this, 该方法会在this.data中设置一个$t属性
     * i18nInstance.mergeTranslations(); ->merge new locales into origin locales
     */
    const curL = this.getCurrentLanguage();
    
    i18nInstance.setLocale(curL);
    i18nInstance.loadTranslations(message);
    i18nInstance.effect(this);

    this.watch('currentLanguage',()=> {
      this.eachRenderI18nCallback();
    })
  },
  getCurrentLanguage() {
    return wx.getStorageSync('appLanguage') || i18nInstance.getLocale() || 'tw';;
  },
  switchLanguage(language) {
    wx.setStorageSync('appLanguage', language);
    i18nInstance.toggleLanguage(language);
    this.setGlobalData('currentLanguage',language);
  },
  setGlobalData(keyName,value) {
    this.globalData[keyName] = value;
  },
  watch(keyName,method = ()=> {},value) {
    let globalModel = this.globalData;
    Object.defineProperty(globalModel,keyName,{
      configurable: true,
      enumerable: true,
      set: function (_value) {
        value = _value;
        method(value);
      },
      get: function () {
        return value;
      }
    })
  },
  getCurrentI18n() {
    let lanModel = new I18n;
    const curL = i18nInstance.getLocale() || 'tw';
    
    lanModel.setLocale(curL);
    lanModel.loadTranslations(message);

    return lanModel;
  },
  renderI18nData(_this,callback,type) {
    const recordKey = _this.__wxExparserNodeId__ || _this.is || _this.route;

    _this.setData({$t: i18nInstance.getLanguage()});
    
    this.renderI18nData[recordKey] = {
      _this: _this,
      callback: callback
    };
  },
  eachRenderI18nCallback() {
    for (const key in this.renderI18nData) {
      if (Object.hasOwnProperty.call(this.renderI18nData, key)) {
        const element = this.renderI18nData[key];
        element._this.setData({$t: i18nInstance.getLanguage()});
        element.callback && element.callback();
      }
    }
  },
  handleLanguageChange() {
    // 获取当前页面实例,并重新渲染页面
    const pages = getCurrentPages();

    pages.forEach(page => {
      if (page.renderPage) {
        page.renderPage();
      }
    })
  }
})

之所以这么实现, 是因为page和component一起使用多语言时候会出问题, 传入了两个或者多个this, 导致i18n不知道该将翻译文件注入到哪里, 进而导致无法切换语言, 所以放到了 app.js 里面统一处理, 也更加符合逻辑;

  1. page/component 的具体使用
// page的使用
---------xxx.js
import i18nInstance from '../../utils/i18n';

onLoad(options) {
  i18nInstance.effect(this);
  ...
  // js 里通过 this.data.$t.route.test; (举个🌰) 来获取翻译文件
}
---------xxx.wxml
 <text>{{ $t.route.test}}</text>



// component的使用, 与page只有初始化不同, 使用翻译文件方法相同
---------xxx.js
const app = getApp();

Component({
  options: {
    addGlobalClass: true
  },
  properties: {},
  ready() {
    app.renderI18nData(this, ()=>{});
  }
})

因为没有vue的重定向组件用来重新加载页面, 我们需要在切换语言的页面手动刷新接口并把当前的语言传递给服务端
我用的方法是, 把当前的语言添加到请求头, 这样下发的数据就是对应语言的数据啦

import i18nInstance from '../utils/i18n';

axios.interceptors.request.use((request) => {
  const currentLe = i18nInstance.getLocale();
        
  const languageMap = {
    cn: 'zh_CN',
    tw: 'zh_TW',
    en: 'en_US',
    pt: 'pt_PT'
  }
  request.headers['lang'] = languageMap[currentLe];
 
  ...
}, (error) => {
  return Promise.reject(error);
})

🎉🎉
最后, 我们的小程序就能正常的切换多语言啦🥳
欢迎大家一起讨论学习😊~

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值