Fusion组件库是如何支持多语言能力的

随着国际化发展,多语言的需求越来越常见,单一的语言已经远不能满足需求了。作为一个组件库,支持多语言也是基本能力。 多语言功能的本质其实是文本的替换,一个词汇“OK”,在英文语境下是“OK”,日语语境下是“確認”,中文语境下可能是“确定”也可能是“确认”“好的”等等。

本文将以简单组件为切入点,向大家展示Fusion组件库是如何支持多语言能力的。

单组件的多语言

我们以一个常见的组件Search举例,用户输入内容后可通过点击“搜索”、“清除”按钮触发相应的事件,简化代码后如下:

class Search extends React.Component {render() {return (<div><input /><button>搜索</button><button>清除</button></div>);}
}export default Search;
复制代码

多语言处理最简单直接的办法是直接替换文本,不同语言环境下可能要将“搜索”替换为“search”、“サーチ”,将“清除”替换为“clear”、"クリア"等。同时作为一个组件库,涉及到的大多是简单词汇而不是句子,因此我们首选配置化的方式:

// 抽取语言包
// search-en-us.js
{search: 'search',clear: 'clear'
}
// search-zh-cn.js
{search: '搜索',clear: '清除'
}
复制代码
import searchZhCN from 'search-zh-cn';class Search extends React.Component {static propTypes = {locale: PropTypes.object};static defaultProps = {locale: searchZhCN};render() {return (<div><input /><button>{locale.search}</button><button>{locale.clear}</button></div>);}
}export default Search;
复制代码

这样就实现了单个组件Search的多语言支持。

但是,为每个组件对应一个语言包文件的做法显然很不方便。Fusion Next作为一个PC端的React组件库有50+组件,内置词汇70多条,目前有13个组件需要国际化语言能力。

以语种为单位,将同一种语言下的映射关系放到一个文件里进行处理的方式更为高效。

多组件的多语言

为便于维护管理,增强可拓展性,我们以语种为单位抽取语言包。将同一语种下所有组件的语言对象{key: '文案'}放到一起,以displayName作为key,语言对象作为value,调整语言包如下:

// 抽取语言包
// zh-cn.js
{Search: {search: '搜索',clear: '清除'},Dialog: {},...
}
复制代码

这也是Fusion现在语言包的结构 unpkg.com/@alifd/next… 由于语言包结构的调整,需要同时修改Search组件语言对象的默认值:

import zhCN from 'zh-cn';class Search extends React.Component {...static defaultProps = {locale: zhCN.Search}...
}export default Search;
复制代码

在使用时,用户将语言包对象以props参数的形式传给组件即可直接改变文案:

import jaJP from 'xxxx/ja-jp.js';<Search locale={jaJP.Search}>
<Dialog locale={jaJP.Dialog}>
复制代码

然而,在web应用越来越复杂的现在,很多项目里里可能会用到几十甚至上百个组件,这样给每个组件手动传locale参数的方式一方面比较蠢,另一方面开发者需要关心locale参数,在语言切换时改变值的内容。

并且语言的设置大都是以项目(或者页面)为单位的,有没有更聪明、对开发者更友好的使用方式呢?

一键设置语言

如果你使用过Fusion Next或者体验过多语言demo,就可以发现使用方式是这样的:

import zhCN from 'zh-cn';<ConfigProvider locale={zhCN}><Search /><Dialog />
</ConfigProvider>
复制代码

使用者在使用时基础组件时不用关心locale的变化,子组件们共享了<ConfigProvider>组件上传入的语言配置,更改这一配置可以一键设置子组件的语言包。如何实现的这一功能呢?

React中,如果不想通过逐层传递props或者state的方式来传递数据,不如考虑考虑Context。

1. React Context共享上下文数据

借助Context可以实现跨层级的组件数据传递。

它的使用场景是生产者消费者模式,在上面的例子中,<ConfigProvider>就是生产者,<Search> <Dialog>组件就是消费者。 他们分别通过一系列属性方法(childContextTypes属性 getChildContext方法/contextTypes属性),建立起一条通信线。

// 生产者
class ConfigProvider extends React.Component {// 声明Context对象static childContextTypes = {nextLocale: PropTypes.object}// 返回Context对象getChildContext () {return {nextLocale: {}}}render () {return this.props.children;}
}
复制代码
// 消费者
import zhCN from 'zh-cn';class Search extends React.Component {static propTypes = {locale: PropTypes.object};static defaultProps = {locale: zhCN.Search};// 声明需要使用的Context属性static contextTypes = {nextLocale: PropTypes.object};render() {const locale = Object.assign({}, nextLocale['Search'], locale);return (<div><input /><button>{locale.search}</button><button>{locale.clear}</button></div>);}
}export default Search;
复制代码

这样,直接给<ConfigProvider>传递国际化参数,就可以改变其子组件所使用的语言包。

数据传递的问题解决了,按照这个思路对组件进行改造就可以完美支持一键切换语言了~ 事实上,这个解决方案通用性很强,只要子组件(包括自定义组件)都按上面的方式进行改造,就可以支持语言包的切换。

但同时我们也发现,改造工作高度重复,都是新增contextTypes静态属性、对props和context上的locale进行merge。有没有对开发者(基础组件开发者、业务组件开发者)更友好的方式来降低这部分重复性工作呢?

2.子组件的统一处理

Fusion为Util类组件ConfigProvider增加了一个静态方法ConfigProvider.config(Component),在这个函数里进行对于locale的改造工作,它返回一个新的受控制的高阶组件(HOC)NewComponent。

NewComponent 相当于被 ConfigProvider 代理了一层。

在ConfigProvider.config()这个函数里

  • 为组件新增contextTypes静态属性,以便接收来自父组件的context;
  • 为组件props、context传入的locale进行merge,以便分发处理语言包文案;

这样,只要子组件经过该函数处理,就可以让ConfigProvider“遥控”语言包切换

import zhCN from 'zh-cn';class Search extends React.Component {static propTypes = {locale: PropTypes.object};static defaultProps = {locale: zhCN.Search};render() {return (<div><input /><button>{locale.search}</button><button>{locale.clear}</button></div>);}
}
// 经过统一处理
export default ConfigProvider.config(Search);
复制代码

ConfigProvider.config(Component)的语言包文案分发处理逻辑简化如下:

// ConfigProvider.jsx
function config(Component) {class ConfigedComponent extends React.Component {static propTypes = {...(Component.propTypes || {}),locale: PropTypes.object,};static contextTypes = {...(Component.contextTypes || {}),nextLocale: PropTypes.object,};render() {// 组件props上直接设置const { locale } = this.props;// ConfigProvider"遥控"设置const { nextLocale = {} } = this.context;// 组件上直接设置语言包,优先级高于在父组件ConfigProvider上设置。const newLocale = Object.assign({},nextLocale[Component.displayName],locale);return (<Component locale={newLocale}/>);}}return ConfigedComponent;
}
复制代码

这样就基本完成了组件库的多语言能力建设,这也是Fusion Next组件库的多语言支持的思路。

除此之外,ConfigProvider还有内置了其他通用能力,例如组件的镜像反转RTL,pure render开关、修改样式的默认前缀等,更多可以查看 ConfigProvider源代码 和 使用文档 了解。

相关链接

  • Fusion 多语言切换demo: codepen.io/aboutblank/…
  • Fusion ConfigProvider: fusion.design/component/c…
  • github: github.com/alibaba-fus…

转载于:https://juejin.im/post/5c6bb4d4f265da2dbd7ff1e0

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

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

相关文章

mysql 存储过程 replace_mysql replace存储过程

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航&#xff0c;为用户…

注解版poi操作工具

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

Kali Linux 2019.1 发布,Metasploit 更新到 5.0 版本

百度智能云 云生态狂欢季 热门云产品1折起>>> Kali Linux 2019.1 发布了&#xff0c;Kali 前身 BackTrack&#xff0c;它是一个基于 Debian 的 Linux 发行版&#xff0c;主要用于信息安全行业&#xff0c;其包含了一系列安全、渗透测试和取证工具。此版本 Linux 内核…

peewee mysql_scrapy中利用peewee插入Mysql

前两天老大布置一个任务&#xff0c;说爬下来的数据要存入数据库中&#xff0c;丢给我一个peewee&#xff0c;说用这个。当时的我两眼一抹黑&#xff0c;这是个什么东西呀&#xff0c;我知道scrapy的数据存入数据库是在pipelines中进行设置但是peewee是什么东西呢。经过两天不懈…

Java版数据结构与算法——线性表

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

基于 CODING 的 Spring Boot 持续集成项目

本文作者&#xff1a;CODING 用户 - 廖石荣 持续集成的概念 持续集成(Continuous integration,简称 CI&#xff09;是一种软件开发实践&#xff0c;即团队开发成员经常集成他们的工作&#xff0c;通常每个成员每天至少集成一次&#xff0c;也就意味着每天可能会发生多次集成。每…

lvs mysql 端口_LVS配置及多端口服务配置

一、5、各主机IP地址&#xff1a;主机IP网关Client192.168.86.116RouterF0/0:192.168.x.xFo/1:192.168.xx.xxF0/1DirectorEth0:192.168.86.111/24(DIP)Eth0:1:192.168.86.254/32(VIP)F0/1Real 1Eth0:192.168.86.112/24(DIP)lo:1:192.168.86.254/32(VIP)F0/1Real 2Eth0:192.168.…

Mybatis组成部分

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

Stream流与Lambda表达式(一) 杂谈

一、流 转换为数组、集合 package com.java.design.java8.Stream;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;import java.util.A…

一年java工作经验-面试总结

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

linux mysql python包_03_mysql-python模块, linux环境下python2,python3的

---恢复内容开始---1、Python2 正常[rootIP ~]#pip install mysql-pythonDEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 wont be maintained after that date. A future version of pip will drop …

我的这套VuePress主题你熟悉吧

最近熬了很多个夜晚, 踩坑无数, 终于写出了用VuePress驱动的主题. 只需体验三分钟&#xff0c;你就会跟我一样&#xff0c;爱上这款主题. vuepress-theme-indigo-material, 已经发布到npm, 请客官享用~~ 介绍 vuepress-theme-indigo-material 的原主题是hexo-theme-indigo, git…

两年Java工作经验应该会些什么技术

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

centos 6 mysql 5.7.13 编译安装_Centos 6.5 下面 源码编译 安装 Mysql 5.7.13

安装软件依赖包yum -y install gcc gcc-c ncurses ncurses-devel cmake下载软件包cd /usr/local/srcwget https://downloads.mysql.com/archives/get/file/mysql-5.7.13.tar.gz --no-check-certificate下载 boost 库&#xff0c;MySQL 5.7.5 开始Boost库是必需的cd /usr/loca…

LeetCode 237. 删除链表中的节点(Python3)

题目&#xff1a; 请编写一个函数&#xff0c;使其可以删除某个链表中给定的&#xff08;非末尾&#xff09;节点&#xff0c;你将只被给定要求被删除的节点。 现有一个链表 -- head [4,5,1,9]&#xff0c;它可以表示为: 示例 1: 输入: head [4,5,1,9], node 5 输出: [4,1,9…

使用Uniapp随手记录知识点

使用uniapp随手记录知识点 1 组件内置组件扩展组件 2 vuex状态管理使用流程mapState 辅助函数gettersMutation 1 组件 内置组件 内置组件内主要包含一些基础的view button video scroll-view等内置基础组件&#xff0c;满足基础场景 扩展组件 扩展组件是uniapp封装了一些成…

一年Java经验应该会些什么

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

mysql查询各类课程的总学分_基于jsp+mysql的JSP学生选课信息管理系统

运行环境: 最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。IDE环境&#xff1a; Eclipse,Myeclipse,IDEA都可以硬件环境&#xff1a; windows 7/8/10 2G内存以上(推荐4G&#xff0c;4G以上更好)可以实现&#xff1a; 学生&#xff0c;教师角色的…

80端口占用分析

SQL Server 2008 里面的组件——SQL Server Reporting Services (MSSQLSERVER)。是 SQL Server 的日志系统&#xff0c;就是他好端端的突然占用了80端口&#xff0c;而且对于普通人来讲&#xff0c;这个组件的作用没啥用&#xff0c;关掉也是节约资源。 关闭服务 ReportServer …

三年java经验应该会什么?

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…