随着应用广度不断增加,有时候我们需要设置多种语言,最近帮朋友做一个网站用到react-intl这个库,还是挺好用的,这里跟大家分享一下。
首先我们来明确一下它的原理,这样比较好理解,其实也比较简单,就是把需要展示的文本赋给一个key或者id,在页面中使用变量去获取这个文本,那么多种语言自然就对应了多套设置。下面所讲的都是使用方法而已,react为例。
一、文件配置
lang // 文件夹
├── en-US.js
├── ja-JP.js
├── zh-CN.js
当然你还可以有更多语言包,每个js的内容就是赋值导出。
// zh-CN.js
export default {
'common.button.ok': `确定`,
'common.button.cancel': `取消`,
'common.button.search': `搜索`,
}
// en-US.js
export default {
'common.button.ok': `Yes`,
'common.button.cancel': `Cancel`,
'common.button.search': `Search`,
}
二、引入
对于一个pc网站来说,用户对语言的设置可以在页面的localStorage进行存储,可能app上会存储到数据库,这个无伤大雅。
// 顶部引入provider
import { IntlProvider } from 'react-intl';
// 定义语言类型
import zhJSON from '../../lang/zh-CN';
import enJSON from '../../lang/en-US';
const messages: any = {
'zh-CN': zhJSON,
'en-US': enJSON,
}
// 获取语言类型:url获取->本地存储->默认
const defaultLanguage = url?.includes('lang=') ? url?.split('lang=')[1] : '';
const defaultLang = defaultLanguage || localStorage.getItem('language') || 'en-US'
三、使用,钩子调用方式
react-intl提供了一系列的钩子,我们可以通过实例化useIntl
链式调用formatMessage
获得语言数据。
// 顶部引入
import { useIntl } from 'react-intl';
// 初始化
const intl = useIntl();
// 在组件中使用,还记得配置文件中的key吗?formatMessage是它的api,你可以理解用这个key通过api来获得数据
return (
<div>
<h1>{intl.formatMessage({ id: 'common.button.search' })}</h1>
</div>
)
四、IntlProvider,组件调用方式
通常需要在组件层级的最顶层包裹一个 IntlProvider
组件,以便在整个应用程序中提供国际化的上下文信息。IntlProvider
组件会将国际化相关的配置信息传递给整个应用程序,使得各个组件能够访问国际化功能。
使用<IntlProvider />
组件包裹住需要您需要进行语言国际化的组件,用法和React-redux的<Provider />
差不多,当<IntlProvider />
包裹住某个组件的时候,这个组件本身和组件内部包含的子组件就可以获得所有React-intl提供的接口以及在<IntlProvider />
中引入的locale配置文件的内容。
return (
<Context.Provider
value={{
lang,
... // 其他数据
}}
>
// 把语言类型传入
<IntlProvider locale={lang} messages={messages[lang]}>
{/* 其他组件 */}
</IntlProvider>
</Context.Provider>
<IntlProvider />
需要传递两个参数:
locale是传递需要国际化的语言的缩写,通过这个参数可以确定格式化日期,数字,量词的时候按照哪一种语言的规则,这个是规则是intl提供的,一般浏览器会内置这个库,但是在Safari和IE11之前需要自己安装,安装的方法前面已经提及,请自己翻阅。
messages是用于传递刚刚我们在第3步中定义的配置文件的,从示例代码中我们可以看出,首先我们使用Import语句引入了配置文件,然后将配置文件的内容传递给了messages这个参数,此时组件中的所有组件都可以拿到配置文件中的内容了。
另外我们知道,provider可以嵌套,<IntlProvider />
同样,也就是说,在一个<IntlProvider />
内部还可以有N个<IntlProvider />
,这个功能的实际意义就是可以在英文网站中嵌套一个中文的或者德语的或者法语的板块,应用起来会更加灵活一些。
前面我们使用钩子调用,现在直接使用组件了。
// 1、api调用的方式
{intl.formatMessage({ id: 'superHello' })}
// 2、组件方式
<FormattedMessage id='superHello' />
五、其他用法
1、语言变量
在语言配置中很多时候都会涉及变量,用于动态展示,这个也是可以接受的。如下传入姓名的方式,两种调用方式都能实现。
// 在zh-CN.js,假设有这么一条数据
export default {
'superHello': `你好,我的名字叫${someone}`,
}
// 1、api调用的方式
{intl.formatMessage({ id: 'superHello' },{someone:'姓名'})}
// 2、组件方式
<FormattedMessage
id='superHello'
description='say hello to Howard.'
defaultMessage='Hello, {someone}'
values={
someone:this.props.name, // props里的取值
}
/>
2、钩子和组件
我们发现钩子和组件,功能都是是一一对应的,下来我们再看下react-intl提供了一些其他的内部方法支持多语言的模式,比如formatDate
,在英文环境下可能会显示为 “July 24, 2024″,而在中文环境下可能会显示为 “2024年7月24日”。
<p>{intl.formatDate(new Date(), { year: 'numeric', month: 'long', day: '2-digit' })}</p>
除此之外,还有<FormattedTime>
、<FormattedNumber>
组件用于格式化时间和数字,根据当前语言和地区显示正确的格式,有兴趣可以一试。
3、高阶组件
injectIntl
高阶组件,用于在类组件中访问国际化功能。通过 injectIntl
高阶组件,您可以将国际化函数作为 props 注入到组件中。
有同学说希望在没有包裹 IntlProvider
的情况下使用 FormattedMessage
组件,可以考虑使用 injectIntl
高阶组件来包装组件。injectIntl
可以将国际化相关的信息传递给组件,使得组件能够正常使用 FormattedMessage
组件。这样使用也会更灵活。(个人感觉还是在入口provider比较省事儿)
import React from 'react';
import { injectIntl, FormattedMessage } from 'react-intl';
function MyComponent(props) {
return ( <div> <FormattedMessage id="greeting" /> </div> );
}
export default injectIntl(MyComponent);
这里阐述了react-intl在React中的基本使用方法,还是很方便的。不得不说现在的库是真的方便。