今天来介绍一个非常international的东西。

i18n
国际化(internationalization)的简称。之所以叫i18n,是因为字母i和n之间有18个字母,所以才叫i18n。不要认为这是一个高大上的名词,其实就是因为懒才简写的。hiahiahia...

因为本系列是以React为中心,所以只介绍React项目中的国际化解决方案。当然还有很多很多...很多别的国际化解决方案,但是不是所有的轮子都适合React这辆开往幼儿园的车。
实际上国际化在日常项目中用的没那么频繁,除非有业务需求,比如要做一个非常international的项目。目前在React中比较热门的两个包就是react-intl-universal 和 react-intl。因为本文重点介绍对象是前者,所以我们先简单介绍下后者。当然在这里不会把它的使用方法列出来,而是把它的缺点列出来,为什么呢?因为笔者懒啊!
react-intl不足的地方主要是两个:

它只能用于视图层。举个例子,比如React.Comoponent对象,但是对于Vanilla JS就会显得很无力了,因为它无法在Vanilla JS中实例化。(这里会有人感到奇怪,Vanilla JS是什么鬼?哈哈...百gu度ge吧,不会发现新大陆)!

其次

想使用国际化方法,我们必须要利用它的一个方法将自己的组件转化成另外一个class。这就比较蛋疼了,例子如下:

import { injectIntl } from 'react-intl';
class MyComponent extends Component {render() {const intl = this.props;const title = intl.formatMessage({ id: 'title' });return (<div>{title}</div>);}
};
export default injectIntl(MyComponent);

看我笔者第一篇文章的朋友应该有印象:所有被包裹过的组件,如果你想获得原本的组件的对象,那得调用相应的方法。这里也不例外,如果我们想获取组件的原对象,那就得这么做:

class MyComponent {...}
export default injectIntl(MyComponent, {withRef: true});class App {render() {<MyComponent ref="my"/>}getMyInstance() {console.log('getMyInstance', this.refs.my.getWrappedInstance());}
}

这样写会不会觉得太麻烦了...
所以Alibaba前端组就按捺不住了,然后就搞出了自己的react-intl-universal。看名字不就是在react-intl后面加个universal吗?的确是这样,不过笔者不清楚这个框架的核心逻辑是不是参考的react-intl,但是单从名字来看就有点"可疑"了,翻译就是react-intl的通用版(当然,纯属意淫,一笑而过!)。

react-intl-universal

作为一个国际化解决方案,首先实现国际化是它的基本功能。其次它还有一些别的功能,比如文本格式化、货币格式化、时间格式化等等,我相信这些都是我们页面开发经常使用到的功能。

i18n

首先来看一下它的技术功能:国际化
react-intl-universal采用了与组件无关的方法来实现国际化。国际化的本质其实就是将我们预先设置好的不同语言的句子按照语言环境显示在页面上。

import intl from 'react-intl-universal';

通过intl这个对象来实现初始化和国际化处理。我们可以认为这个intl是一个单例对象。我们在App启动的时候对其进行初始化,尔后在别的地方再次导入的时候仍然是一个已经初始化过的对象。在这种情况下,国际化处理就会变得异常简单。其次就是准备多语言句子了,传统的在前端处理这个问题是将不同语言的句子放在不同的json文件中再导出,文件结构如下:

这样我们就可以在App启动或者切换语言的时候导入相应的json对象了。

首先是API介绍

intl对象主要有三个常用的用于国际化处理的API,determineLocale、init、get

  • determineLocale
    看到方法名就应该知道它是用来干什么了。它用来确定在整个体系中使用的是哪种语言。看代码:
let currentLocale = intl.determineLocale({urlLocaleKey: "lang",cookieLocaleKey: "lang"
});

react-intl-universal确定语言的方式有三种,一个是通过urlLocaleKey,即lang关键字从url中获取是哪种语言。比如:http://localhost?lang=en-US,因为lang对应的值是en_US,所以语言为英文。其次是从Cookie获取,因为Cookie也是以键值对形式存储的,所以会检查当前域下的Cookie是否有对应的lang。如果上述两种都没有,那么会默认使用浏览器当前的语言类型。当然上述的urlLocaleKey和cookieLocaleKey是可以自定义的,不是固定的lang.

  • init

init方法即用来初始化intl对象。初始化参数主要是两个,一个是currentLocale即当前的语言,另一个是locales即当前语言对应的json对象,比如{"en-US":{"key1":"value1"} 或者 {"zh-CN":{"key1":"值1"}}

  • get
    get方法就相对简单,就是根据键去intl中获取对应的值,这里不做过多解释。

完整的初始化过程如下:

class App extends Component{....componentDidMount() {this.loadLocales();}loadLocales() {const _self = this;let currentLocale = intl.determineLocale({  //如果cookie和url中均没有相关参数,那么以浏览器语言为准urlLocaleKey: "lang",cookieLocaleKey: "lang"});http.get(`locales/${currentLocale}.json`)   //理解为按需加载并且locales文件夹需要放在public文件下供http访问.then(res => {return intl.init({currentLocale,locales: {[currentLocale]: res.data //如果key是变量,那么需要用[]包一下}});}).then(() => {_self.setState({initDone: true});});}....
}

然后在需要国际化的地方这么使用

import intl from 'react-intl-universal';
<p>{intl.get('name')}</p>

是不是很简单? 而且完全避免了react-intl的两个缺点。

格式化工具

前面说了react-intl-universal不仅仅可以用来做国际化处理,还可以用来做简单的文本格式化处理。下面我们列举几个常用的。

Html Snippet

假如我们的json文件中有这么一段

...
"red": "<p style='color:red'>红色</p>",
...

如果我们直接用get方法获取的话,那么会直接把<p style='color:red'>红色</p>给打印出来。如果我们想将它以html片段的形式打印出来的话,就使用getHTML方法,它在获取到句子的时候会进行解析并生成最终的Html Snippet。

Default Message

缺省值其实就是默认值,是对于json键值对的默认值。将入我们去获取一个json中没有的键值对那么系统就会报错。如何去规避这个问题呢?react-intl-universal给我们提供了这样一个方法:

intl.get('not-exist-key').defaultMessage('default message')

这是一个链式调用。如果json中没有not-exist-key这个键,那就会默认返回defaultMessage的参数。简写是intl.get('not-exist-key').d('default message')

Message With Variables

假如某个句子包含了一个变量怎么办?比如一个用户名,我们只有在用户登录的时候才知道他的用户名。

{"me": "你好,我是{me}"
}

此时就用到了get放的第二个参数。对于上面的例子,我们可以这样处理:

<p>{intl.get('me', {'me': '皮卡丘'})}</p>

get方法会找出句子中被{}包住的变量me,然后在第二个参数(json对象)找出me对应的值皮卡丘并将{me}整个用皮卡丘替换。另外需要注意的是,json对象只能为一层,不可嵌套

Display Currency

它还可以用来格式化货币。假如有这么一段句子

{"price": "这件衣服是 {price,number,CNY} 人民币",
}

如果我们想将一个数字以人民币的形式写进去的话可以这么做:

{intl.get('price', {'price': 1000})}

最终显示结果是:这件衣服是 ¥1,000 人民币
其实它做了两件事:一个是加符号,另一个是加分隔符。同时CNY表示人民币,USD表示美元

Display Dates

然后是日期的处理。假如有这么一段话:

{"date": "今天是{date,date,full}"
}

然后我们这么使用它的话:

<p>{intl.get('date',{'date':new Date()})}</p>

显示结果是今天是2018年12月3日星期一。其实{date,date,full}这段指令就是将date变量替换成对应日期(new Date())并以long形式展示。

同时日期展示形式有四种

  • short: shows date as shortest as possible
  • medium: shows short textual representation of the month
  • long: shows long textual representation of the month
  • full: shows dates with the most detail

他们之间有什么不同呢?我们用刚刚的例子做个展示:

  • short: 今天是18/12/3
  • medium: 今天是2018年12月3日
  • long: 今天是2018年12月3日
  • full: 今天是2018年12月3日星期一

Display Times

最后是时间。我们按部就班来。假如有这么一段话:

{"time": "现在时间是{time,time,short}"
}

然后我们这么使用它的话:

 <p>{intl.get('time',{'time':new Date()})}</p>

显示结果是现在时间是下午5:54。其实{time,time,short}这段指令就是将time变量替换成对应日期(new Date())并以short形式展示。

但是时间展示形式只有三种,它没有full

  • short: shows date as shortest as possible
  • medium: shows short textual representation of the month
  • long: shows long textual representation of the month

他们之间有什么不同呢?我们用刚刚的例子做个展示:

  • short: 现在时间是下午5:54
  • medium: 现在时间是下午5:58:22
  • long: 现在时间是GMT+8 下午5:58:50

上述贴出来的示例都是在中文环境下。如果有兴趣的朋友可以把整个例子download下来本地运行下,边看边写,受益匪浅。好了,收拾下班咯...

[ 一起学React系列 -- 10 ] i18n相关推荐

  1. [ 一起学React系列 -- 11 ] React-Router4 (1)

    2019年不知不觉已经过去19天了,有没有给自己做个总结?有没有给明年做个计划? 当然笔者已经做好了明年的工作.学习计划:同时也包括该系列博客剩下的博文计划,目前还剩4篇:分别是两篇React-Rou ...

  2. [ 一起学React系列 -- 6 ] 秘术之时间旅行-1

    标题看起来挺新颖的,笔者都觉得很高大上是不是哈哈... 抛转 时间旅行在生活中是一个非常吸引人的概念,虽然现在无法实现但说不定未来的某天就实现了!然后就穿梭会过去杀掉小时候的自己然后就开始懵逼自己是谁 ...

  3. 时间旅行java_[ 一起学React系列 -- 7 ] 秘术之时间旅行-2

    距离上一次更新已经有半个月了,这半个月来主要在忙两件事:一个是最近老板给了个自动化测试任务,另一个是和学校的弟弟一起搞一个微信小游戏...emmmm!其实主要是懒!!! 本篇是作为上篇的续集,不知道看 ...

  4. 前端小白学React系列之——浅仿一下炒股软件(雪球)

    前言 React是用于构建用户界面的JavaScript库,React组件化一直是React项目开发的重要学习过程.最近自己也在刚开始学习React组件化开发,就打算通过写一个小项目来巩固自己的学习成 ...

  5. 防火墙Mangle标记案例--从零开始学RouterOS系列10

    本章主要讲如何进行连接标记和包标记,可以用来做队列Queue调用. 那么如何进行包标记,我们先理解一下自己的需求. 1.标记DNS连接和包(双向) 2.标记我们192.168.11.0/24网段的所有 ...

  6. 狂神学习系列10:Vue

    狂神学习系列10:Vue 声明: 本文章是基于狂神的课程所编写,本人才疏学浅,内容仅作参考 项目和markdown文件资料: 06_Vue: 基于狂神说vue的项目及笔记 文章目录 狂神学习系列10: ...

  7. 一起学WPF系列(2):第一个WPF应用程序

    概述 Windows Presentation Foundation (WPF) 是下一代显示系统,用于生成能带给用户震撼视觉体验的 Windows 客户端应用程序.使用 WPF,您可以创建广泛的独立 ...

  8. 文科生学python系列_文科生学 Python 系列 3:函数

    文科生学Python系列3:函数​www.jianshu.com 还是第二课的内容 函数是一段可以重复使用的代码,往往是为了解决某个特定的人物.在 Python 中有两种函数:内置函数和自定义函数. ...

  9. 工具坐标6点法_轻松学机器人系列之各坐标系关系

    更多内容请点击上方安德鲁机器人关注.转载请先后台留言,请支持原创!谢谢 难得的机会让胖老师Johnny Pan跟大家开个车,可能速度有点快,各位系好安全带坐好.关于胖老师Johnny Pan这里就不作 ...

最新文章

  1. 读论文之《基于EV10AQ190的高速ADC接口设计》
  2. Metasploit发布了新版本5.0.83
  3. python css和xpath_Selenium系列教程(四)css、xpath定位(基于 Python)
  4. 谈区块链的时候别忘记了“新零售”
  5. 2017 idea 代码字体加粗
  6. python 通信调制方式_python实现BPSK调制信号解调
  7. 笔记本电脑进入BIOS设置快捷键大全
  8. 华为云数据迁移工具解决方案:腾讯云迁移到华为云
  9. 访问服务器显示无法访问目标主机,ip无法访问目标主机
  10. 程序员视角m1 Macbook air使用指南和指令备忘录
  11. android svg 线条动画教程,简单的SVG线条动画
  12. 威尔逊定理公式的理解
  13. システム関連の完了コード
  14. solidworks渲染材质库_solidworks渲染材质参数
  15. DataView的用法
  16. vs2019 fatal error C1090: PDB API “3“
  17. MATLAB代码:基于雨流计数法的源-荷-储双层协同优化配置
  18. flutter doctor问题 Flutter plugin not installed this adds Flutter specific functionality
  19. 半导体器件基础01:关于PN结的那些事(3)
  20. vijos 1167 南蛮图腾(打印图案)

热门文章

  1. 转载模板声明中template typename T和template class T
  2. 微服务限流Sentinel讲解(三)
  3. 时序数据采样、原始循环神经网络RNN、RNN梯度爆炸原因推导
  4. 新手探索NLP(一)
  5. 数据库学习之(6)了解数据库触发器
  6. Hibernate-day04
  7. Windows下安装 openpyxl
  8. Wireshark非标准分析port无流量
  9. 关于TableLayoutPanel里放入控件无法将Dock设为Fill的解决办法
  10. 《LeetCode力扣练习》剑指 Offer 25. 合并两个排序的链表 Java