react-intl 实现 React 国际化多语言
效果预览

React Intl 国际化步骤
- 创建国际化资源文件
- 根据语言获取国际化资源
- 引入 react-intl 的 local data
- 创建 LocaleProvider 国际化上下文组件
- 创建 react-intl 国际化上下文组件
- 使用 react-intl's components & apis,进行国际化开发
1. 创建国际化资源文件
目前我们管理资源文件的方式是在 src/locales 文件夹下:
.
├── en-US.js
├── en-US.messages.js
├── zh-Hans.js
└── zh-Hans.messages.js
*.messages.js 是我们的资源文件(这里我们采用了 js 格式,你也可以使用 json 等等),返回的是一个对象,key 为我们翻译用的 id,value 为具体语言的翻译,内容是:
export default {
'page.localeProvider.react': '{ name }, a JavaScript library for building user interfaces.',
'page.localeProvider.react.html': '<p>{ name } makes it painless to create interactive UIs. Design simple views for each state in your application, and { name } will efficiently update and render just the right components when your data changes.</p><p>Declarative views make your code more predictable and easier to debug.</p>',
'page.localeProvider.unreadCount': 'You have {unreadCount} new {notifications}',
'page.localeProvider.title.date': 'Current date: ',
'page.localeProvider.title.time': 'Current time: ',
'page.localeProvider.title.relative': 'Relative current time: ',
'page.localeProvider.title.number': 'Comma number: ',
'page.localeProvider.title.price': 'Price: ',
'page.localeProvider.title.percent': 'Percent: ',
};
en-US.js 文件封装了 messages、locale 等国际化上下文组件需要的内容:
import appLocaleData from 'react-intl/locale-data/en';
// 引入组件多语言
import paginationLocale from '@/components/pagination/locales/en-US';
import messages from './en-US.messages';
window.appLocale = {
// 合并所有 messages, 加入组件的 messages
messages: Object.assign({}, messages, {
Pagination: paginationLocale,
}),
// locale
locale: 'en-US',
// react-intl locale-data
data: appLocaleData,
// 自定义 formates
formats: {
date: {
normal: {
hour12: false,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
},
},
// 货币
money: {
currency: 'USD',
},
},
};
export default window.appLocale;
有了这些资源文件以及相关的封装之后,我们就可以在 LocaleProvider
和 InltProvider
中使用了。
2. 根据语言加载国际化资源
上一步我们创建了不同语言版本的国际化资源文件,我们还需要一个函数能够根据语言,加载对应的资源文件:
/**
* 获取国际化资源文件
*
* @param {any} lang
* @returns
*/
function getLocale(lang) {
let result = {};
switch (lang) {
case 'zh-CN':
result = require('./locales/zh-Hans');
break;
case 'en-US':
result = require('./locales/en-US');
break;
default:
result = require('./locales/zh-Hans');
}
return result.default || result;
}
3. 引入 react-intl 的 local data
import { addLocaleData } from 'react-intl';
...
render() {
const appLocale = getLocale('en-US');
addLocaleData(...appLocale.data);
...
}
react-intl 在做国际化的时候需要一些特有的 local data,主要是进行相对时间翻译时,比如昨天、今天、明天、几分钟前、几个月前之类的。
我们通过 addLocaleData
这个方法加载相关内容,大家可以根据实际情况加载需要的 locale-data。
4. 创建 LocaleProvider 国际化上下文组件
为了组件能够国际化资源信息,我们需要一个 LocaleProvider 组件,用它来提供国际化的上下文,具体用法:
export default class LocaleProvider extends React.Component {
static propTypes = {
children: PropTypes.any,
locale: PropTypes.object,
};
static childContextTypes = {
// 语言信息
locale: PropTypes.object,
};
getChildContext() {
return {
locale: {
...this.props.locale,
},
};
}
render() {
return React.Children.only(this.props.children);
}
}
5. 创建 react-intl 国际化上下文组件
为了能够使用 react-intl 进行国际化,跟 redux 这些框架一样,我们需要一个 Provider Component,用它来提供国际化的上下文,具体用法:
...
import { addLocaleData, IntlProvider } from 'react-intl';
import LocaleProvider from '@/components/locale-provider';
import Home from '@/views/home';
...
render() {
// 根据语言获取国际化资源
const appLocale = getLocale('en-US');
addLocaleData(...appLocale.data);
return (
<LocaleProvider locale={appLocale}>
<IntlProvider
locale={appLocale.locale}
messages={appLocale.messages}
formats={appLocale.formats}
>
<Home />
</IntlProvider>
</LocaleProvider>
);
}
LocaleProvider 有三个配置参数:
locale, <object>, 国际化资源.
IntlProvider 有三个配置参数:
locale, <string>, 语言标记,例如 'zh-CN' 'en-US'
messages, <object>, 国际化所需的 key-value 对象
formats, <object>, 自定义 format,比如日期格式、货币等
在定义好 IntlProvider
之后,我们就可以在页面使用它提供的 api 或者组件来进行国际化了。
6. 使用 react-intl's components & apis
react-intl 提供了丰富的组件和 api 来完成页面部分的国际化。
字符串的格式化
a. <FormattedMessage />
这个组件用于格式化字符串,是所有的组件中使用频率最高的组件。除了可以根据配置输出不同语言的简单字符串之外,还可以输出包含动态变化的参数的复杂字符串,具体的用法在后面的例子中会慢慢叙述。
比如我们在 *.message.js 配置文件中写了如下内容:
export default {
'page.localeProvider.react': '{ name }, a JavaScript library for building user interfaces.',
};
使用这个组件的时候,我们这么写:
<FormattedMessage
tagName="p"
id="page.localeProvider.react"
values={{
name: 'React',
}}
defaultMessage="{name} 是一个用于构建用户界面的 JAVASCRIPT 库。"
description="{name} 是什么?"
/>
- id 指代的是这个字符串在配置文件中的属性名
- description 指的是对于这个位置替代的字符串的描述,便于维护代码,不写的话也不会影响输出的结果
- defaultMessage 当在locale配置文件中没有找到这个id的时候,输出的默认值
- tagName 实际生成的标签,默认是
span
- values 动态参数. 格式为对象
输出的结果:
<p>React, a JavaScript library for building user interfaces.</p>
b. <FormattedHTMLMessage />
这个组件的用法和完全相同,唯一的不同就是输出的字符串可以包含HTML标签。
日期时间
a. <FormattedDate />
用于格式化日期,能够将一个时间戳格式化成不同语言中的日期格式。
传入时间戳作为参数:
<FormattedDate
value={new Date(1459832991883)}
/>
输出结果:
<!-- 英文 -->
<span>4/5/2016</span>
<!-- 中文 -->
<span>2016/5/4</span>
b. <FormattedTime>
用于格式化时间,效果与<FormattedDate />
相似。
传入时间戳作为参数:
<FormattedTime
value={new Date(1459832991883)}
/>
输出结果:
<!-- 英文 -->
<span>1:09 AM</span>
<!-- 中文 -->
<span>上午1:09</span>
c. <FormattedRelative />
通过这个组件可以显示传入组件的某个时间戳和当前时间的关系,比如“10 minutes ago”。
传入时间戳作为参数:
<FormattedRelative
value={Date.now()}
/>
输出结果:
<!-- 英文 =>> 运行时的输出结果: -->
<span>now</span>
<!-- 英文 =>> 10秒之后的输出结果: -->
<span>10 seconds ago</span>
<!-- 英文 =>> 1分钟之后的输出结果: -->
<span>1 minute ago</span>
<!-- 中文 =>> 运行时的输出结果: -->
<span>现在</span>
<!-- 中文 =>> 10秒之后的输出结果: -->
<span>10秒前</span>
<!-- 中文 =>> 1分钟之后的输出结果: -->
<span>1分钟前</span>
数字量词
a. <FormattedPlural />
这个组件可用于格式化量词,在中文的语境中,其实不太会用得到,比如我们说一个鸡腿,那么量词就是‘个’,我们说两个鸡腿,量词还是‘个’,不会发生变化。但是在英文的语言环境中,描述一个苹果的时候,量词是apple,当苹果数量为两个时,就会变成apples,这个组件的作用就在于此。
传入组件的参数中,value为数量,其他的为不同数量时对应的量词,在下面的例子中,一个的时候量词为message,两个的时候量词为messages。实际上可以传入组件的量词包括 zero, one, two, few, many, other 已经涵盖了所有的情况。
结合 <FormattedMessage />
运用:
const unreadCount = 10;
const unreadCount2 = 1;
...
<p>
<FormattedMessage
id="page.localeProvider.unreadCount"
defaultMessage={'你有{ unreadCount }条新信息'}
values={{
unreadCount: (
<strong
style={{
color: '#f30',
fontWeight: 'normal',
}}
>
<FormattedNumber
value={unreadCount}
/>
</strong>
),
notifications: (
<FormattedPlural
value={unreadCount}
one="notification"
other="notifications"
/>
),
}}
/>
</p>
<p>
<FormattedMessage
id="page.localeProvider.unreadCount"
defaultMessage={'你有{ unreadCount2 }条新信息'}
values={{
unreadCount: (
<strong
style={{
color: '#f30',
fontWeight: 'normal',
}}
>
<FormattedNumber
value={unreadCount2}
/>
</strong>
),
notifications: (
<FormattedPlural
value={unreadCount2}
one="notification"
other="notifications"
/>
),
}}
/>
</p>
输出结果:
<!-- 英文 -->
<p>You have 10 new notifications</p>
<p>You have 1 notification</p>
<!-- 中文 -->
<p>你有10条新信息</p>
<p>你有1条新信息</p>
b. <FormattedNumber />
这个组件最主要的用途是用来给一串数字标逗号,比如10000这个数字,在中文的语言环境中应该是1,0000,是每隔4位加一个逗号,而在英语的环境中是10,000,每隔3位加一个逗号。
传入数字作为参数:
<FormattedNumber
value={1000}
/>
输出结果:
<span>1,000</span>
<FormattedNumber />
输出百分比
传入小数作为参数:
<FormattedNumber
value={0.5}
style="percent"
/>
输出结果:
<span>50%</span>
<FormattedNumber />
输出货币
传入数字作为参数:
// locale.formats.money.currency 是 /locales/*.js 国际化资源配置的货币信息。中文: 'CNY'; 英文: 'USD'
<FormattedNumber
value={123456.78}
style="currency"
currency={locale.formats.money.currency}
/>
输出结果:
<!-- 英文 -->
<span>$123,456.78</span>
<!-- 中文 -->
<span>¥123,456.78</span>
注:项目在中文情况下也是每隔3位加一个逗号,具体原因详,如果有知道原因的请告知。
组件国际化
1. 创建获取上下文国际化资源函数
/**
* 获取 组件的语言配置
*
* @param {any} props 属性
* @param {any} context 上下文
* @param {any} componentName 组件名. 对应 context.locale.messages 中的 key 值
* @param {any} getDefaultLocale
*/
function getComponentLocale(props, context, componentName, getDefaultLocale) {
let locale = {};
// 如果 context 上下文中有多语言配置. 则取 context 上下文中的多语言值.
// 否则, 取默认值的多语言值.
if (context && context.locale && context.locale.messages[componentName]) {
locale = context.locale.messages[componentName];
} else {
const defaultLocale = getDefaultLocale();
locale = defaultLocale.default || defaultLocale;
}
let result = {
...locale,
};
// 如果属性有语言配置项, 则合并.
if (props.locale) {
result = {
...result,
...props.locale,
};
if (props.locale.lang) {
result.lang = {
...locale.lang,
...props.locale.lang,
};
}
}
return result;
}
2. 创建国际化的组件
...
import { getComponentLocale } from '../_utils/getLocale';
...
export default class Pagination extends React.Component {
// context 上下文
static contextTypes = {
locale: PropTypes.object,
};
render() {
const currentlocale = getComponentLocale(this.props, this.context, 'Pagination', () => {
require('./locales/zh-CN');
});
return (
<div className="pagination">
<div className="pagination__wrapper">
<div className="pagination__button__prev">
<a>{currentlocale.prevText}</a>
</div>
<div className="pagination__button__next">
<a>{currentlocale.nextText}</a>
</div>
</div>
</div>
);
}
}
国际化规范附录
React Intl 编写规范
- 必须填写 defaultMessage,并将 defaultMessage 作为中文翻译
- id 不得重复
- 在使用 intl.formatMessage() 时,必须使用 defineMessages,预定义消息
源码
整个项目源码
资料
react-intl 实现 React 国际化多语言的更多相关文章
- [react] 细数 React 的原罪
Props & onChange 的原罪 .「props & onChange 接口规范」它不是一个典型的「程序接口规范」. 当你拿到一个可视组件的 ref,却没有类似 setProp ...
- React.createClass 、React.createElement、Component
react里面有几个需要区别开的函数 React.createClass .React.createElement.Component 首选看一下在浏览器的下面写法: <div id=" ...
- React Native之React速学教程(下)
概述 本篇为<React Native之React速学教程>的最后一篇.本篇将带着大家一起认识ES6,学习在开发中常用的一些ES6的新特性,以及ES6与ES5的区别,解决大家在学习Reac ...
- React Native之React速学教程(中)
概述 本篇为<React Native之React速学教程>的第一篇.本篇将从React的特点.如何使用React.JSX语法.组件(Component)以及组件的属性,状态等方面进行讲解 ...
- React Native之React速学教程(上)
概述 本篇为<React Native之React速学教程>的第一篇.本篇将从React的特点.如何使用React.JSX语法.组件(Component)以及组件的属性,状态等方面进行讲解 ...
- 【React入门】React父子组件传值demo
公司一直是前后端分离的,最近集团开始推进中后台可视化开发组件(基于React封装),跟师兄聊起来也听说最近对后台开发人员的前端能力也是越来越重视了.所以作为一名后端,了解下前端的框架对自己也是大有好处 ...
- 七天接手react项目 系列 —— react 脚手架创建项目
其他章节请看: 七天接手react项目 系列 react 脚手架创建项目 前面我们一直通过 script 的方式学习 react 基础知识,而真实项目通常是基于脚手架进行开发. 本篇首先通过 reac ...
- react实战系列 —— react 的第一个组件
react 的第一个组件 写了 react 有一个半月,现在又有半个月没写了,感觉对其仍旧比较陌生. 本文分两部分,首先聊一下 react 的相关概念,然后不使用任何语法糖(包括 jsx)或可能隐藏底 ...
- WPF 实际国际化多语言界面
前段时候写了一个WPF多语言界面处理,个人感觉还行,分享给大家.使用合并字典,静态绑定,动态绑定.样式等东西 效果图 定义一个实体类LanguageModel,实际INotifyPropertyCha ...
随机推荐
- springboot集成websocket实现大文件分块上传
遇到一个上传文件的问题,老大说使用http太慢了,因为http包含大量的请求头,刚好项目本身又集成了websocket,想着就用websocket来做文件上传. 相关技术 springboot web ...
- IMX6Q开发板Linux-QT挂载U盘及TF卡
本文基于:迅为-iMX6开发板Linux-QT挂载U盘及TF卡 如下图所示,qt 启动之后,在超级终端中使用命令“mknod /dev/sda1 b 8 1”创建 U盘的设备节点,如下图所示. 插入 ...
- 共克时艰,停工不停学 Serverless 在线课堂免费开课
二月份,Serverless 团队联合腾讯云大学与云+社区免费推出 Serverless 在线直播课程,课程涵盖 Serverless 架构解密.技术解析以及不同应用场景下的最佳实战指导,让你从 0 ...
- RAID和LVM
EXT家族支持度最广,但创建文件系统慢修复慢存储容量有限 XFS同样是日志文件系统:容量大,支持大存储高性能,创建/修复文件系统快inode与block都是系统需要用到时,才动态配置产生 基本分区(静 ...
- Office 365管理中心门户
一.使用Office 365管理员账户登陆到由世纪互联运营的Office 365 登陆地址 https://portal.partner.microsoftonline.cn 1.登陆完成后,选择左上 ...
- 多对多表创建、forms组件、cookie与session
多对多表的三种创建方式 1.全自动(较为推荐) 优势:不需要你手动创建第三张表 不足:由于第三张表不是你手动创建的,所以表字段是固定的无法扩展 class Book(models.Model): ti ...
- P2967 [USACO09DEC]视频游戏的麻烦Video Game Troubles
冲刺阶段的首篇题解! 题目链接:P2967 [USACO09DEC]视频游戏的麻烦Video Game Troubles: 题目概述: 总共N个游戏平台,金额上限V元,给出每个游戏平台的价钱和其上游戏 ...
- Android下的鉴权实现方案
软件原理 不赘述,参考: 软件License认证方案的设计思路 License文件离线鉴权 机械指纹,不可逆的加密算法,如MD5 功能鉴权,可逆的不对称加密算法,服务端公钥加密,app端私钥解密,如R ...
- Facebook要做约会服务,国内社交眼红吗?
看看现在的各种相亲趣事就能深深感悟到,中国还是以家庭为重的国家.在传统文化的浸染下,国人始终是将家庭摆在第一位.而对于欧美等发达国家来说,他们固然也以家庭为重,但更注重的是男女之间的关系定位--恋爱也 ...
- JDBC原理之层次结构
目录 JDBC的层次结构 前言 Collection角色 Statement角色 ResultSet角色 JDBC工作的基本流程 JDBC的层次结构 前言 JDBC API提供了以下接口和类: Dri ...