关于在自行封装的组件库中(使用vue-class-component)使用Vue-i18n无法正常翻译的解决办法

文章目录

  • 介绍
  • 背景
  • 现象1
    • 解决办法
  • 现象2
    • 原因分析
    • 解决办法
  • 最终方案

介绍

大家或多或少都用过别人封装的组件库,甚至有人或者公司内有自行封装的一些公用组件库,而国际化翻译现在已经是各大项目中必不可少的一个插件了,但组件库中使用 i18n 进行翻译的时候可能遇到过以下这种问题,希望我的一点分析可以帮到你们

背景

因公司历史项目使用 Angular 框架原因,所以在做架构迁移时,我们采用了 vue-class-component(github链接) 和 vue-property-decorator(github链接) 平滑的迁移到了 Vue 框架

部分代码如下:

<template>
    <div class="pager">
        <span class="grid-pager">
            {{$t('pager.total', {total: totalRows})}}
        </span>
        <div class="grid-pager">
            <a-pagination 
                size="small" 
                v-model:current="index"
                :total="totalRows" 
                v-model:pageSize="size"
                :pageSizeOptions="pageSizeOptions"
                :showSizeChanger="showSizeChanger"
                :showQuickJumper="showQuickJumper"
                :simple="simple"
                @change="change" />
        </div>
    </div>
</template>

<script lang="ts">
import { Options, Vue, setup } from 'vue-class-component';
import { Composer, useI18n } from 'vue-i18n';
import { Emit, Prop, Watch } from 'vue-property-decorator';
@Options({
    name: 'pager'
})
export default class Pager extends Vue {
    @Prop({ type: Number, }) public totalRows: number;
    @Prop({ type: Number, }) public pagerSize: number;
    @Prop({ type: Number, }) public pageIndex: number;
    @Prop({ type: Array, default: ['20', '50', '100']}) public pageSizeOptions: Array<number>;
    @Prop({ type: Boolean, default: false }) public showSizeChanger: boolean;
    @Prop({ type: Boolean, default: true }) public showQuickJumper: boolean;
    @Prop({ type: Boolean, default: false }) public simple: boolean;
    public index: number = 1;
    public size: number = 20;

    /**
     * change事件
     *
     * @param {number} index 下标
     * @param {number} size 每页条数
     * @returns {{index: number, size: number}} 返回分页器当前页码与当前每页条数
     */
    @Emit()
    public change(index: number, size: number): {index: number, size: number} {
        return {
            index: index - 1,
            size
        };
    }

    /**
     * 监听 pageIndex 属性变化
     *
     * @param {number} newValue 新值
     */
    @Watch('pageIndex')
    public pageIndexChange(newValue: number): void {
        if (newValue >= 0) {
            this.index = newValue + 1;
        }
    }

    /**
     * 监听 pagerSize 属性变化
     * 
     * @param {number} newValue 新值
     */
    @Watch('pagerSize', { immediate: true })
    public pageSizeChange(newValue: number): void {
        if (newValue) {
            this.size = newValue;
        }
    }

    /**
     * 钩子函数
     */
    public mounted(): void {
        if (this.pageIndex || this.pageIndex === 0) {
            this.index = this.pageIndex + 1;
        }
    }
}
</script>
<style lang="scss" scoped></style>

因此我们封装的组件库也是基于此的,若您的项目不是使用该种方式开发的,那我觉得以下部分的内容对您的帮助应该是不多的

同时我们也没有做像现在主流的UI组件库的国际化翻译处理,如 Element UI组件库中既可以兼容 vu-i18n 又可以自行进行翻译(可参考这里)

目前我们只是简单的封装了一个组件到另一个库里,国际化翻译是依赖于本地项目中安装的 vue-i18n 插件进行翻译的,正是因为这个原因才会出现我下面说的情况(后期可能会像组件库一样有自行的翻译方法)

现象1

就以上面的代码为例,若引用该库的项目国际化文件中没有 pager.total 字段时,浏览器控制台就会报错

Not found 'pager.total' key in 'zh_CN' locale messages.

且无法正常翻译
在这里插入图片描述

这是因为在全局国际化翻译文件中没有找到该key值才翻译有误

解决办法

@options 注解中可以直接添加组件级的i18n配置,如下:

@Options({
    name: 'pager',
    i18n: {
        messages: {
            zh_CN: {
                'pager.total': '共{total}条'
            },
            zh_TW: {
                'pager.total': '共{total}條'
            },
            en_US: {
                'pager.total': '{total} entries in total'
            }
        }
    }
})

使用这种方式确实可以使用了,因此我们也没多注意,其实它只是在引用这个组件的项目中也使用 vue-class-component 时才可以生效

现象2

基于上面的修改,直到有一天我们有个新的项目使用了 vue3 + vite + setup 技术栈时,它又没有正常翻译了,浏览器控制台报错和现象1一致

然后就是和同事找原因,issue、google都找遍了,没有发现遇到同样问题的,无奈只好自行查阅源码分析原因

原因分析

首先使用 @options 进行注解对象中的内容,会挂载在 Vue实例的 $options 上,如下:
在这里插入图片描述
因此在注解中设置i18n时可以肯定的是可以传给Vue实例的,那么就得看看I18n中是如何处理这部分内容的了(因源码较复杂,以下只关注$options部分)

可以看到这里 就是处理Vue实例上$options的i18n配置的
在这里插入图片描述
可以看到是 这里 引入了该Mixin,因使用的是v9版本,查看 defineMixinNext 调用位置
在这里插入图片描述
可以看到注释以及if判断都明确指出是 Legacy模式下才会进入这部分处理逻辑,那么现在翻译不生效的原因就非常明了了

但是现在本地项目使用的是 Vue3 + Vite + setup suger 技术栈,那么就必选找一个可以兼容的方式呀,不然这组件库不是白封装了吗 (艹皿艹)

然后就是漫长的翻阅 vue-class-component github issue 的过程

解决办法

关注到这个 issue ,里面提到:

Composition functions are available in class property initializers by wrapping setup helper.

也就是说,在V8版本中我们是可以使用 setup 的

而翻阅 Vue-i18n 官网,可以看到在组合式API部分可以在setup中设置组件级的翻译内容
在这里插入图片描述
这样的话,方法就显而易见了,只要在 setup 中设置组件级的翻译内容即可,如下:

public componentSetup = setup(() => {
	const i18n: Composer = useI18n({
		locale: 'zh_CN',
		messages: {
			zh_CN: {
				'pager.total1': '共{total}条'
			},
			zh_TW: {
				'pager.total': '共{total}條'
			},
			en_US: {
				'pager.total': '{total} entries in total'
			}
		},
	});
	return {
		i18n
	};
});

结果一试,还是原来的问题,控制台报错,页面没有正常显示,继续翻文档可以看到 这里 提到:
在这里插入图片描述
大致意思就是如果你在 useI18n 中 设置了那些字段时,添加 useScope: 'global' 配置将会将这些字段合并到全局作用域中,这不就是我们想要的吗! (✪ω✪)

public componentSetup = setup(() => {
	const i18n: Composer = useI18n({
		locale: 'zh_CN',
		messages: {
			zh_CN: {
				'pager.total1': '共{total}条'
			},
			zh_TW: {
				'pager.total': '共{total}條'
			},
			en_US: {
				'pager.total': '{total} entries in total'
			}
		},
		useScope: 'global'
	});
	return {
		i18n
	};
});

运行项目并打印全局i18n实例,你会发现组件中的翻译已成功加入全局翻译文件中,且页面也显示正常了
在这里插入图片描述
在这里插入图片描述

最终方案

根据现象1分析得出如果使用 Legacy 模式时可以读取 @Options 注解中的翻译内容
根据现象2分析得出如果使用 Composition 模式时可以读取 setup() 回调中的翻译内容

那么就可以兼容这两种方式使该组件以任何模式引入时都可以正常翻译了,完整代码如下:

<template>
    <div class="pager">
        <span class="grid-pager">
            {{$t('pager.total', {total: totalRows})}}
        </span>
        <div class="grid-pager">
            <a-pagination 
                size="small" 
                v-model:current="index"
                :total="totalRows" 
                v-model:pageSize="size"
                :pageSizeOptions="pageSizeOptions"
                :showSizeChanger="showSizeChanger"
                :showQuickJumper="showQuickJumper"
                :simple="simple"
                @change="change" />
        </div>
    </div>
</template>

<script lang="ts">
import { Options, Vue, setup } from 'vue-class-component';
import { Composer, useI18n } from 'vue-i18n';
import { Emit, Prop, Watch } from 'vue-property-decorator';
@Options({
    name: 'pager',
    // 兼容选项式API模式
    i18n: {
        messages: {
            zh_CN: {
                'pager.total': '共{total}条'
            },
            zh_TW: {
                'pager.total': '共{total}條'
            },
            en_US: {
                'pager.total': '{total} entries in total'
            }
        }
    }
})
export default class Pager extends Vue {
    @Prop({ type: Number, }) public totalRows: number;
    @Prop({ type: Number, }) public pagerSize: number;
    @Prop({ type: Number, }) public pageIndex: number;
    @Prop({ type: Array, default: ['20', '50', '100']}) public pageSizeOptions: Array<number>;
    @Prop({ type: Boolean, default: false }) public showSizeChanger: boolean;
    @Prop({ type: Boolean, default: true }) public showQuickJumper: boolean;
    @Prop({ type: Boolean, default: false }) public simple: boolean;
    public index: number = 1;
    public size: number = 20;

	// 兼容组合式API模式
	public componentSetup = setup(() => {
        const i18n: Composer = useI18n({
            locale: 'zh_CN',
            messages: {
                zh_CN: {
                    'pager.total': '共{total}条'
                },
                zh_TW: {
                    'pager.total': '共{total}條'
                },
                en_US: {
                    'pager.total': '{total} entries in total'
                }
            },
            // 将当前翻译内容合并到全局翻译文件中
            useScope: 'global'
        });
        return {
            i18n
        };
    });

    /**
     * change事件
     *
     * @param {number} index 下标
     * @param {number} size 每页条数
     * @returns {{index: number, size: number}} 返回分页器当前页码与当前每页条数
     */
    @Emit()
    public change(index: number, size: number): {index: number, size: number} {
        return {
            index: index - 1,
            size
        };
    }
}
</script>
<style lang="scss" scoped></style>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文章解读与仿真程序复现思路——太阳能学报EI\CSCD\北大核心《绿电交易场景下计及温控负荷的高铁站两阶段调度策略》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

成人高考专升本专业有哪些?深职训学校帮您圆梦

成人高考专升本专业选择多样化 成人高考专升本考试是成人高考的一种考试形式&#xff0c;主要面向已经参加工作的人员&#xff0c;旨在选拔具有高等教育需求的成人考生&#xff0c;录取到高等学校继续深造。成人高考专升本考试的专业选择非常多样化&#xff0c;涵盖了人文社科…

Python酷库之旅-第三方库Pandas(006)

目录 一、用法精讲 10、pandas.DataFrame.to_excel函数 10-1、语法 10-2、参数 10-3、功能 10-4、返回值 10-5、说明 10-6、用法 10-6-1、数据准备 10-6-2、代码示例 10-6-3、结果输出 11、pandas.ExcelFile类 11-1、语法 11-2、参数 11-3、功能 11-4、返回值 …

RNN文献综述

循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一种专门用于处理序列数据的神经网络模型。它在自然语言处理、语音识别、时间序列预测等领域有着广泛的应用。本文将从RNN的历史发展、基本原理、应用场景以及最新研究进展等方面进行综述。 历…

大数据平台之数据同步

数据同步也成为CDC (Chanage Data Capture) 。Change Data Capture (CDC) 是一种用于跟踪和捕获数据库中数据变更的技术&#xff0c;它可以在数据发生变化时实时地将这些变更捕获并传递到下游系统。以下是一些常用的开源 CDC 方案&#xff1a; 1. Flink CDC Flink CDC 是基于 …

Linux——目录结构

基本介绍 Linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录"/"&#xff0c;然后在根目录下再创建其他的目录 在Linux中&#xff0c;有一句经典的话&#xff1a;在Linux世界里&#xff0c;一切皆文件 Linux中根目录下的目录 具体的…

案例精选 | 聚铭网络助力南京市玄武区教育局构建内网日志审计合规体系

南京市玄武区教育局作为江苏省教育领域的先锋机构&#xff0c;其工作重点涵盖了教育政策的实施、教育现代化与信息化的融合、教育资源的优化、教育质量的提升以及教育公平的促进。在这一背景下&#xff0c;网络安全管理成为了确保教育信息化顺利推进的关键环节之一。 根据玄武…

二进制求和、字符串相加-sting类题型

67. 二进制求和 - 力扣&#xff08;LeetCode&#xff09; 两个题目方法完全一样 用两个数据的末尾位相加&#xff0c;从末尾位开始逐位相加&#xff0c;记录进位&#xff1b; class Solution { public:string addBinary(string a, string b) {int end1 a.size() - 1;int end…

【Qwen2部署实战】Ollama上的Qwen2-7B:一键部署大型语言模型指南

系列篇章&#x1f4a5; No.文章1【Qwen部署实战】探索Qwen-7B-Chat&#xff1a;阿里云大型语言模型的对话实践2【Qwen2部署实战】Qwen2初体验&#xff1a;用Transformers打造智能聊天机器人3【Qwen2部署实战】探索Qwen2-7B&#xff1a;通过FastApi框架实现API的部署与调用4【Q…

做有一个有表情且会动的 Finder

作为一只合格的互联网巡回猎犬&#xff0c;今天给大家分享一个有趣且无聊的小工具&#xff0c;摸鱼发呆必备&#xff0c;可以说是一件「无用良品」了。 软件介绍 Mouse Finder 长的跟访达差不多&#xff0c;功能也一样&#xff0c;但有一个重要区别&#xff1a;眼睛会跟随鼠标…

YOLOv8数据集可视化[目标检测实践篇]

先贴代码,后面再补充解析。 这个篇章主要是对标注好的标签进行可视化,虽然比较简单,但是可以从可视化代码中学习到YOLOv8是如何对标签进行解析的。 下面直接贴代码: import cv2 import numpy as np import osdef read_det_labels(label_file_path):with open(labe…

DAY20-力扣刷题

1.填充每个节点的下一个右侧节点指针 116. 填充每个节点的下一个右侧节点指针 - 力扣&#xff08;LeetCode&#xff09; 方法一&#xff1a;层次遍历 class Solution {public Node connect(Node root) {if (root null) {return root;}// 初始化队列同时将第一层节点加入队列…

动手学深度学习(Pytorch版)代码实践 -循环神经网络-51序列模型

51序列模型 import torch from torch import nn from d2l import torch as d2l import matplotlib.pyplot as pltT 1000 # 总共产生1000个点 time torch.arange(1, T 1, dtypetorch.float32) x torch.sin(0.01 * time) torch.normal(mean0, std0.2, size(T,)) d2l.plot(…

【IT领域新生必看】Java编程中的神奇对比:深入理解`equals`与`==`的区别

文章目录 引言什么是操作符&#xff1f;基本数据类型的比较示例&#xff1a; 引用类型的比较示例&#xff1a; 什么是equals方法&#xff1f;equals方法的默认实现示例&#xff1a; 重写equals方法示例&#xff1a; equals与的区别比较内容不同示例&#xff1a; 使用场景不同示…

CSS position属性之relative和absolute

目录 1 参考文章2 五个属性值3 position:static4 position:relative&#xff08;相对&#xff09;5 position:absolute&#xff08;绝对&#xff09; 1 参考文章 https://blog.csdn.net/lalala_dxf/article/details/123566909 https://blog.csdn.net/WangMinGirl/article/deta…

番外篇 | 手把手教你如何去更换YOLOv5的检测头为IDetect | 源于RCS-YOLO

前言:Hello大家好,我是小哥谈。凭借速度和准确性之间的出色平衡,YOLO框架已成为最有效的目标检测算法之一。然而,在脑肿瘤检测中很少研究使用YOLO网络的性能。对此本文提出了一种基于RCS-YOLO的重新参数化卷积的新型YOLO架构。与YOLOv7相比,RCS-YOLO的精度提高了2.6%,推理…

MWC上海展 | 创新微MinewSemi携ME54系列新品亮相Nordic展台

6月28日&#xff0c; 2024MWC上海圆满落幕&#xff0c;此次盛会吸引了来自全球124个国家及地区的近40,000名与会者。本届大会以“未来先行&#xff08;Future First&#xff09;”为主题&#xff0c;聚焦“超越5G”“人工智能经济”“数智制造”三大子主题&#xff0c;探索讨论…

苹果电脑清理app垃圾高效清理,无需专业知识

在我们的日常使用中&#xff0c;苹果电脑以其优雅的设计和强大的功能赢得了广泛的喜爱。然而&#xff0c;即便是最高效的设备&#xff0c;也无法免俗地积累各种不必要的文件和垃圾&#xff0c;特别是app垃圾。所以&#xff0c;苹果电脑清理app垃圾高效清理&#xff0c;对于大多…

数据的存储方式——大小端序

大小端存储的故事源自于《格列佛游记》&#xff08;Gullivers Travels&#xff09;&#xff0c;这是爱尔兰作家乔纳森斯威夫特&#xff08;Jonathan Swift&#xff09;于1726年所著的一部讽刺小说。在其中&#xff0c;主人公格列佛&#xff08;Lemuel Gulliver&#xff09;游历…

三相感应电机的建模仿真(2)基于ABC相坐标系S-Fun的仿真模型

1. 概述 2. 三相感应电动机状态方程式 3. 基于S-Function的仿真模型建立 4. 瞬态分析实例 5. 总结 6. 参考文献 1. 概述 前面建立的三相感应电机在ABC相坐标系下的数学模型是一组周期性变系数微分方程&#xff08;其电感矩阵是转子位置角的函数&#xff0c;转子位置角随时…