效果预览


React Intl 国际化步骤

  1. 创建国际化资源文件
  2. 根据语言获取国际化资源
  3. 引入 react-intl 的 local data
  4. 创建 LocaleProvider 国际化上下文组件
  5. 创建 react-intl 国际化上下文组件
  6. 使用 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;

有了这些资源文件以及相关的封装之后,我们就可以在 LocaleProviderInltProvider 中使用了。

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 编写规范

  1. 必须填写 defaultMessage,并将 defaultMessage 作为中文翻译
  2. id 不得重复
  3. 在使用 intl.formatMessage() 时,必须使用 defineMessages,预定义消息

源码

整个项目源码

资料

react-intl 实现 React 国际化多语言的更多相关文章

  1. [react] 细数 React 的原罪

    Props & onChange 的原罪 .「props & onChange 接口规范」它不是一个典型的「程序接口规范」. 当你拿到一个可视组件的 ref,却没有类似 setProp ...

  2. React.createClass 、React.createElement、Component

    react里面有几个需要区别开的函数 React.createClass .React.createElement.Component 首选看一下在浏览器的下面写法: <div id=" ...

  3. React Native之React速学教程(下)

    概述 本篇为<React Native之React速学教程>的最后一篇.本篇将带着大家一起认识ES6,学习在开发中常用的一些ES6的新特性,以及ES6与ES5的区别,解决大家在学习Reac ...

  4. React Native之React速学教程(中)

    概述 本篇为<React Native之React速学教程>的第一篇.本篇将从React的特点.如何使用React.JSX语法.组件(Component)以及组件的属性,状态等方面进行讲解 ...

  5. React Native之React速学教程(上)

    概述 本篇为<React Native之React速学教程>的第一篇.本篇将从React的特点.如何使用React.JSX语法.组件(Component)以及组件的属性,状态等方面进行讲解 ...

  6. 【React入门】React父子组件传值demo

    公司一直是前后端分离的,最近集团开始推进中后台可视化开发组件(基于React封装),跟师兄聊起来也听说最近对后台开发人员的前端能力也是越来越重视了.所以作为一名后端,了解下前端的框架对自己也是大有好处 ...

  7. 七天接手react项目 系列 —— react 脚手架创建项目

    其他章节请看: 七天接手react项目 系列 react 脚手架创建项目 前面我们一直通过 script 的方式学习 react 基础知识,而真实项目通常是基于脚手架进行开发. 本篇首先通过 reac ...

  8. react实战系列 —— react 的第一个组件

    react 的第一个组件 写了 react 有一个半月,现在又有半个月没写了,感觉对其仍旧比较陌生. 本文分两部分,首先聊一下 react 的相关概念,然后不使用任何语法糖(包括 jsx)或可能隐藏底 ...

  9. WPF 实际国际化多语言界面

    前段时候写了一个WPF多语言界面处理,个人感觉还行,分享给大家.使用合并字典,静态绑定,动态绑定.样式等东西 效果图 定义一个实体类LanguageModel,实际INotifyPropertyCha ...

随机推荐

  1. MRP运算报错-清除预留

    MRP运算报错-清除预留

  2. spark-shell使用指南. - 韩禹的博客

    在2.0版本之前,Spark的主要编程接口是RDD(弹性分布式数据集),在2.0之后,则主推Dataset,他与RDD一样是强类型,但更加优化.RDD接口仍然支持,但为了更优性能考虑还是用Datase ...

  3. 48)PHP,工厂模式

    为啥需要工厂模式啊: (原来是生产类的工具——————————) 工厂类的代码格式: <?php class factory{ //Instance表示“实例”,“对象” static func ...

  4. Rails Create--params说明

    参考:https://ruby-china.github.io/rails-guides/getting_started.html 表单提交后,其字段以参数形式传递给 Rails,然后就可以在控制器动 ...

  5. 004.前端开发知识,前端基础CSS(2020-01-09)

    一.CSS字体样式属性 1.font-size:字号大小 2.font-family:字体 font-family属性用于设置字体.网页中常用的字体有宋体.微软雅黑.黑体等. * { /*font-f ...

  6. aclocal-1.13: command not found

    原因: 将编译好的工程拷贝到系统版本不一样的系统中,再进行编译会出现此类问题. 解决方法: yum install automake autoconf yum install libtool auto ...

  7. linux 有了源码创建git版本库(coding)

    进入目录,比如ewei_shop 执行 git init 瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),当前目录下多了一个.git的目录,如果没有看到 ...

  8. 3)小案例三,加乐前端入口index.php

    之前的代码没有什么改动,唯一改动的就是我在之前的目录结构中加了  index.php作为前端的入口文件 目前,我的文件目录关系是: 然后我的index.php代码内容是: <?php /** * ...

  9. spring mvc 页面form提示语

    <form:form id="inputForm" modelAttribute="bsRabiesNum" action="${ctx}/nu ...

  10. Bringing up interface eth0: Device eth0 does not seem to be present, delaying initialization.FAILED

    1.service network stop 2./etc/sysconfig/network-scripts目录下,删除想要删除的网卡配置,我要删除eth1,所以rm -rf ifcfg-eth1, ...