【高阶用法】uniapp的i18n/修复/增强/App无重启更换语言

news2024/12/24 9:59:43

痛点

在i18n多语言模块使用过程中,发现下面几个问题,需要解决

1)uni-best框架下,$t功能函数无法实时的切换语言,可能跟使用有关

2)uni-best建议的translate方式在vue块外使用太繁琐,希望不用导入,直接书写$t使用。统一逻辑,减少复杂度

3)uniapp默认的多语言模式在APP下会重启,造成的体验不好

目标

需要完成的目标如下

1)将多语言模块放到公共区域,可能会导致原生标题无法正常切换语音。这个无所谓,因为标题栏已经custom定制并组件化了

2)修复无法正常实时切换语言的$t,这个可能跟使用方式有关,anyway,让它能按原模式正常工作

3)在任何地方都可以使用$t功能,无论是template还是script部分

4)不用重启直接刷新界面

实现

uni-best的translate方法代码实现了一个很好的思路,只是无法支持占位符的功能。让我们改进它

/**
 * 任意文件使用$t翻译方法,需要在app里全局导入
 * @param { string } localeKey 多语言的key,eg: "app.name"
 */
export const translate = (localeKey: string, opt: Record<string, any> = {}) => {
  if (!localeKey) {
    console.error(`[i18n] Function translate(), localeKey param is required`)
    return ''
  }
  const locale = uni.getLocale()
  const message = messages[locale]
  if (Object.keys(message).includes(localeKey)) {
    const template = message[localeKey]
    // 使用 Object.keys 遍历 params 对象,替换模板中的大括号占位符
    return Object.keys(opt).reduce(
      (acc, key) => acc.replace(new RegExp(`{${key}}`, 'g'), opt[key]),
      template
    )
  }
  return localeKey // 转换不了则原样输出
}

然后在main.ts里把它挂载到全局

import { message, alert, confirm, translate } from '@/utils'

...

export function createApp() {
  const app = createSSRApp(App)

...

  app.use(i18n)

  app.config.globalProperties.$t = translate // 覆盖不能正常工作的$t函数
  // #ifdef MP-WEIXIN
  // 由于微信小程序的运行机制问题,需声明如下一行,H5和APP非必填
  app.config.globalProperties._i18n = i18n
  // #endif

  return {
    app
  }
}

至于在任意位置使用,让我们把translate挂载到代码部分的全局

// 安装到全局,覆盖不能正常工作的$t
;(function (global) {
  console.log('install')
  ;(global as any).$t = translate
})(this || window || globalThis)

下面是最终完成的i18n.ts模块,添加了语言切换功能的导出。

API.tools.locale.request是后端的语言切换代码,实现前后端语言统一切换,目前只导入了3种语言,需要其它语言可以自行增加

/**
 * ccframe i18n模块
 * 注意:由于某种未知的原因,uni-best的$t()翻译方法有无法切换语音以及安卓出错的问题,因此使用导出的translate方法进行动态翻译
 * @Jim 24/09/20
 */

import { createI18n } from 'vue-i18n'

import en from '@/datas/en.json'
import zhHans from '@/datas/zh-Hans.json'
import zhHant from '@/datas/zh-Hant.json'

const messages = {
  en,
  'zh-Hant': zhHant,
  'zh-Hans': zhHans // key 不能乱写,查看截图 screenshots/i18n.png
}

const i18n = createI18n({
  legacy: false, // 解决空白报错问题
  locale: uni.getLocale(), // 获取已设置的语言,fallback 语言需要再 manifest.config.ts 中设置
  messages
})

type LocaleType = 'en' | 'zh-Hant' | 'zh-Hans'

i18n.global.locale.value = import.meta.env.VITE_FALLBACK_LOCALE

/**
 * 任意文件使用$t翻译方法,需要在app里全局导入
 * @param { string } localeKey 多语言的key,eg: "app.name"
 */
export const translate = (localeKey: string, opt: Record<string, any> = {}) => {
  if (!localeKey) {
    console.error(`[i18n] Function translate(), localeKey param is required`)
    return ''
  }
  const locale = uni.getLocale()
  const message = messages[locale]
  if (Object.keys(message).includes(localeKey)) {
    const template = message[localeKey]
    // 使用 Object.keys 遍历 params 对象,替换模板中的大括号占位符
    return Object.keys(opt).reduce(
      (acc, key) => acc.replace(new RegExp(`{${key}}`, 'g'), opt[key]),
      template
    )
  }
  return localeKey // 转换不了则原样输出
}

const langMapper: Record<string, string> = {
  'zh-Hans': 'zh-CN',
  'zh-Hant': 'zh-TW',
  en: 'en-US'
}

export const setLocale = async (locale: LocaleType) => {
  await API.tools.locale.request({ lang: langMapper[locale] })
  // #ifdef APP-PLUS
  setTimeout(() => {
    // 如果是APP,需要等待重新启动页面
    i18n.global.locale.value = locale
    uni.setLocale(locale)
  }, 300)
  // #endif
  // #ifndef APP-PLUS
  i18n.global.locale.value = locale
  uni.setLocale(locale)
  // #endif

  // currentLang.value = locale
}

// 安装到全局,覆盖不能正常工作的$t
;(function (global) {
  console.log('install')
  ;(global as any).$t = translate
})(this || window || globalThis)

export default i18n

/** 非vue 文件使用 i18n
export const testI18n = () => {
  console.log(t('app.name'))
  // 下面同样生效
  uni.showModal({
    title: 'i18n 测试',
    content: t('app.name')
  })
} */

然后就可以简单愉快的使用多语言功能了。

页面上$t('login.enterPhone')根据语言显示“输入手机号码”:

          <up-input

            fontSize="32rpx"

            :placeholder="$t('login.enterPhone')"

            border="surround"

            v-model="data.userMobile"

            style="letter-spacing: 2rpx"

            @change="data.mobileErr = ''"

            type="number"

            maxlength="11"

          />
代码片段,这个是form表单验证公共库里的使用:
 

  required(error?: string): Validator {

    this.push({

      required: true,

      validator: (rule: any, val: any, callback: (error?: Error) => void) => {

        // 补充验证模式

        return val !== undefined && val !== null && val !== ''

      },

      message:

        error ??

        (this.labelText

          ? $t('utils.validator.required') + this.labelText

          : $t('utils.validator.notEmpty')),

      trigger: ['change', 'blur']

    })

    return this

  }

$t('utils.validator.required')根据语言输出:请输入
$t('utils.validator.notEmpty')根据语言输出:内容不能为空

完善Typescript类型定义

这样使用起来,还有那么一点不舒服,就是在script中使用$t时,会报错类型找不到红红的一片(实际编译没问题)。对于代码强迫症人会有点一点受不了,那么让这个错误的爆红消失掉:

unibest里原本带了i18n.d.ts文件,把我们挂载到script全局的定义添加进去:
 

/* eslint-disable no-unused-vars */
export {}

declare module 'vue' {
  interface ComponentCustomProperties {
    $t: (key: string, opt?: Record<string, any>) => string
    // $tm: (key: string, opt?: Record<string, any>) => [] | { [p: string]: any }
  }
}

declare global {
  function $t(localeKey: string, opt?: Record<string, any>): string
}

刷新一下vscode,不爆红了,完美~

--------------------------------------- [ 2024/9/21 分界线] ---------------------------------------------

UNIAPP 安卓/IOS模式不用重启界面直接切换语言

经过前面的折腾,发现可以直接绕过uni.getLocale和uni.setLocale来实现语言切换了。这样等于就是解决了uniapp官方框架下必须重启APP才能更换语言的软肋

导出切换语言功能:
setStorageSync是我将语言保存到存储,以便系统启动时按照指定的语言启动

export const getLocale = () => i18n.global.locale.value

export const setLocale = async (locale: LocaleType) => {
  await API.tools.locale.request({ lang: langMapper[locale] })
  uni.setStorageSync(Global.STOAGE_LOCALE, locale)
  i18n.global.locale.value = locale
}

调用:

const switchLang = async () => {
  // 切换应用语言到 {langName} 吗?应用将重启以更改语言(新技术不用重启)
  if (utils.getLocale() !== 'zh-Hans') {
    await utils.setLocale('zh-Hans')
  } else {
    await utils.setLocale('en')
  }
}

这个方法虽然可以直接切换,但是有个条件,就是官方的组件无法依赖默认的。好在大部分组件都提供了默认占位作为参数可以传入,因此像对话框这类基本组件只需要使用时添加多几个国际化参数即可

效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2158503.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

verilog中非阻塞多个if 优先级判断。

always(posedge clk)beginz < 0;if(sel0)z < a;if(sel1)z < b;if(sel2)z < c;if(sel3)z < d;end 比如上述代码&#xff0c;最后一级的优先级最高。

深入理解 JavaScript 三大作用域:全局作用域、函数作用域、块级作用域

一. 作用域 对于多数编程语言&#xff0c;最基本的功能就是能够存储变量当中的值、并且允许我们对这个变量的值进行访问和修改。那么有了变量之后&#xff0c;应该把它放在哪里、程序如何找到它们&#xff1f;是否需要提前约定好一套存储变量、访问变量的规则&#xff1f;答案…

Teams会议侧边栏应用开发-会议转写

Teams应用开发&#xff0c;主要是权限比较麻烦&#xff0c;大量阅读和实践&#xff0c;摸索了几周&#xff0c;才搞明白。现将经验总结如下&#xff1a; 一、目标&#xff1a;开发一个Teams会议的侧边栏应用&#xff0c;实现会议的实时转写。 二、前提&#xff1a; 1&#x…

株洲芦淞大桥事故的深刻反思

株洲芦淞大桥事故的深刻反思 2024年9月23日清晨&#xff0c;株洲芦淞大桥上发生了一起令人痛心的交通事故&#xff0c;一辆白色小汽车被出租车追尾后失控&#xff0c;冲向对向车道&#xff0c;最终酿成6人死亡、多人受伤的惨剧。 这起事故不仅给受害者家庭带来了无法弥补的伤…

【Python机器学习系列】开发Streamlit应用程序并部署机器学习模型(案例+源码)

这是我的第357篇原创文章。 一、引言 近年来&#xff0c;随着机器学习和人工智能技术的迅猛发展&#xff0c;越来越多的研究者选择将他们的模型以应用程序&#xff08;App&#xff09;的形式进行部署&#xff0c;从而使审稿人和其他研究者可以通过简单的界面&#xff0c;输入相…

9月23日

头文件 // My_string.h #ifndef MY_STRING_H #define MY_STRING_H#include <cstring> #include <algorithm>class My_string { private:char* data;size_t length;void resize(size_t new_length) {size_t new_capacity std::max(new_length 1, length);char* n…

一种求解城市场景下无人机三维路径规划的高维多目标优化算法,MATLAB代码

在城市环境下进行无人机三维路径规划时&#xff0c;需要考虑的因素包括高楼、障碍物、飞行安全和效率等。为了解决这些问题&#xff0c;研究者们提出了多种算法&#xff0c;包括基于智能优化算法的方法。 首先&#xff0c;无人机航迹规划问题的数学模型需要考虑无人机的基本约…

用Flowise+OneAPI+Ollama做一个在线翻译工作流

用FlowiseOneAPIOllama做一个在线翻译工作流&#xff0c;输入一种语言&#xff0c;马上翻译成另外一种语言&#xff0c;使用到的结点主要有&#xff0c;ChatLLM、提示词模板还有LLM Chain。 一、设置OneAPI和Ollama 1、Ollama的安装及配置&#xff0c;请参考&#xff1a;在ub…

三种委派 非约束委派 约束委派 基于资源的约束委派 概念

前言 简单记录下委派攻击的概念。具体的攻击演示/复现这里没有。 强烈建议反复通读《域渗透攻防指南》P242开始的4.5&#xff01;&#xff01;&#xff01; 以前看gitbook那个学的&#xff0c;yysy&#xff0c;真的不怎么适合零基础的看。 趁课上认真看了看4.5章&#xff0c…

如何快速免费搭建自己的Docker私有镜像源来解决Docker无法拉取镜像的问题(搭建私有镜像源解决群晖Docker获取注册表失败的问题)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 Docker无法拉取镜像 📒📒 解决方案 📒🔖 方法一:免费快速搭建自己的Docker镜像源🎈 部署🎈 使用🔖 备用方案⚓️ 相关链接 🚓️📖 介绍 📖 在当前的网络环境下,Docker镜像的拉取问题屡见不鲜(各类Nas查询…

【编程基础知识】MySQL中什么叫做聚簇索引、非聚簇索引、回表、覆盖索引

一、引言 在数据库的奇妙世界里&#xff0c;索引是提升查询速度的超级英雄。就像图书馔的目录帮助我们快速找到书籍一样&#xff0c;MySQL中的索引加速了数据检索的过程。本文将带你深入了解MySQL中的聚簇索引、非聚簇索引、回表操作以及覆盖索引&#xff0c;探索它们如何影响…

机器人顶刊IEEE T-RO发布无人机动态环境高效表征成果:基于粒子的动态环境连续占有地图

摘要&#xff1a;本研究有效提高了动态环境中障碍物建模的精度和效率。NOKOV度量动作捕捉系统助力评估动态占用地图在速度估计方面的性能。 近日&#xff0c;上海交通大学、荷兰代尔夫特理工研究团队在机器人顶刊IEEE T-RO上发表题为Continuous Occupancy Mapping in Dynamic …

Keysight 下载信源 Visa 指令

用于传输原始的IQ数据 file.wiq 或者 file.bin wave_bin:bytes with open("./WaveForm.wfm","rb") as f:wave_bin f.read()log.info("File:WaveForm.wfm Size:%d Bytes"%len(wave_bin)) IMPL.sendCommand(":MEM:DATA \"WFM1:FILE1\&q…

每日OJ题_牛客_杨辉三角(动态规划)

目录 牛客_杨辉三角&#xff08;动态规划&#xff09; 解析代码 牛客_杨辉三角&#xff08;动态规划&#xff09; 杨辉三角_牛客题霸_牛客网 解析代码 最基础的 dp 模型&#xff0c;按照规律模拟出来杨辉三角即可。 #include <iostream> using namespace std;int dp…

企业上云不迷茫,香港电讯助力企业上云全攻略

在全球政策和市场双重驱动下&#xff0c;云计算产业正迎来前所未有的增长浪潮。据中国信通院《云计算白皮书&#xff08;2023年&#xff09;》1显示&#xff0c;2022年全球云计算市场规模已达到4,910亿美元&#xff0c;同比增长率高达百分之十九。而在中国市场&#xff0c;这一…

带线无人机现身俄罗斯抗干扰技术详解

带线无人机在俄罗斯的出现&#xff0c;特别是其光纤制导技术的应用&#xff0c;标志着无人机抗干扰技术的一大进步。以下是对俄罗斯带线无人机抗干扰技术的详细解析&#xff1a; 一、带线无人机抗干扰技术背景 技术突破&#xff1a;俄军成功研发了光纤制导无人机&#xff0c;…

数据链路层协议 —— 以太网协议

目录 1.数据链路层解决的问题 2.局域网通信方式 以太网 令牌环网 无线局域网 3.以太网协议 以太网帧格式 对比理解Mac地址和IP地址 认识MTU MTU对IP协议的影响 MTU对UDP的影响 MTU对TCP的影响 基于以太网协议的报文转发流程 交换机的工作原理 4.ARP协议 ARP协议…

springboot+vue高校两校区通勤校车预约系统的设计与实现

目录 用户功能管理员功能系统实现截图技术介绍核心代码部分展示使用说明详细视频演示源码获取 用户功能 登录注册&#xff1a;允许用户创建账户并登录系统。 首页&#xff1a;展示系统主要功能和通勤车相关的重要信息。 个人中心&#xff1a;用户可以查看和编辑自己的个人信息…

ios swift5 UITextView占位字符,记录限制字数

文章目录 截图代码&#xff1a;具体使用代码&#xff1a;CustomTextView 截图 代码&#xff1a;具体使用 scrollView.addSubview(contentTextView)contentTextView.placeholderLabel.text LocalizableManager.localValue("write_comment")contentTextView.maxCharac…

分享两个虚拟试衣工具,一个在线,一个离线,还有ComfyUI插件

SAM &#xff0c;对不住了&#xff01; 我没记错的话&#xff0c;OpenAI CEO&#xff0c;性别男&#xff0c;取向男&#xff0c;配偶男。 这又让我联想到了苹果CEO库克... 所以OpenAI和Apple可以一啪即合。 钢铁直男老马就和他们都不对付~~ 开个玩笑&#xff0c;聊…