最近在给大前端项目增加国际化支持,国际化也叫本地化,简单来说就是让页面可以切换语言来使不同语言的人能看懂。
现在社区也很多优秀的国际化解决方案。这些解决方案通常和相应技术栈绑定。但其原理基本是一致的,从我的理解来看,都是将页面的文字提出来统一管理,给页面“挖坑”,用id占位置,在不同语言环境下给这个坑填上不同的文字。以react-intl为例子。
React-intl
1.安装
npm install --save react-intl
2.配置多语言映射关系
可以在项目中新建文件夹locale统一管理,例如:
en_US.js
const en_US = {
"menu" : "Menu",
"hello" : "Hello
}
export {
en_US
}
zh_CN.js
const en_US = {
"menu" : "菜单",
"hello" : "你好
}
export {
en_US
}
index.js
index.js
import { zh_CN } from './zh_CN';
import { en_US } from './en_US';
console.log('enUS', enUS);
function loadLocale(lang) {
let locale = null;
let message = null;
switch (lang) {
case 'en-US':
locale = 'en-US';
message = en_US;
antLocale = enUS;
break;
case 'zh-CN':
locale = 'zh-CN';
message = zh_CN;
antLocale = zhCN;
break;
default:
locale = 'zh-CN';
message = zh_CN;
antLocale = zhCN;
break;
}
return { locale, messagee };
}
export { loadLocale };
3.全局配置
在入口组件中引入国际化容器IntlProvider,并包裹组件,例如:
Main.jsx
import React, { Component } from 'react';
import ReactDOM, { render } from 'react-dom';
import { IntlProvider } from 'react-intl';
import { loadLocale } from './locale/index';
import Content from './Content.jsx'
class Index extends Component {
constructor(props) {
super(props);
this.state = {
lang: 'zh-CN',
};
}
render() {
const { lang } = this.state;
const { locale, message } = loadLocale(lang);
return (
<IntlProvider locale={locale} messages={message}>
<Content />
</IntlProvider>
</div>
);
}
}
ReactDOM.render(
<Index />
document.getElementById('root')
);
其中message也就是id和字符串的对应关系
4.在组件中使用
有两种使用方式
组件方式
用 <FormattedMessage/>
代替字符串在组件中的位置,并配置相关组件属性,例如:
Conten.jsx
import React from 'react';
import { FormattedMessage } from 'react-intl';
class Content extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<FormattedMessage id="hello" />
</div>
);
}
}
export default Content;
此时,<FormattedMessage id="hello" />
会根据id和外层的 <IntlProvider>
组件的locale和message寻找当前语言对应id的字符串,也就是‘你好’。
函数方式
用injectIntl()处理组件,向组件注入intl对象,intl的intl.formatMessage可以
例如:
Conten.jsx
import React from 'react';
import { injectIntl } from 'react-intl';
class Content extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
const { intl } = props
return (
<div>
{
intl.formatMessage({ id : hello})
}
</div>
);
}
}
const ContenIntl = injectIntl(Content)
export default ContenIntl;
同样的,intl.formatMessage({ id : hello})会在当前语言环境下返回‘你好’。
5.在非组件中使用
在组件中使用没有问题,但是在非组件中(例如Store)如何使用呢?react-intl提供了方法在非组件环境创建intl对象。
createIntlCache创建一个缓存实例以供跨语言环境全局使用。 createIntl则可以创建一个intl对象供全局使用。
import { createIntl, createIntlCache } from 'react-intl';
import { zh_CN } from './zh_CN';
const cache = createIntlCache();
const message =
const intl = createIntl(
{
locale: 'zh-CN',
messages: zh_CN,
},
cache
);
export { intl };
此时创建出的intl可以供全局使用,用法和在组件中的函数方式一样:intl.formatMessage({ id : hello})
6.复杂字符串
以上介绍了简单字符串的国际化,都是通过id来实现,但对于一些复杂的字符串,例如包含不同时间格式和不同数字格式的复杂字符串,则需要通过value,并将message写成类似模板字符串的形式。
//定义复杂字符串
en_US = {
'info' : 'hello,{name}, today is {currentDate, date} ,your earnings today are {currentNumber,number} '
}
zh_CN = {
'info' : '你好,{name}, 今天是{currentDate, date} ,你今天的收益为{currentNumber, number} '
}
//传值
<FormattedMessage
id="info"
values={{
number: 98949,
name: '小鱼',
date: Date.now(),
}}
/>
这里的{}相当于一个占位符,react-intl在处理的时候,会将传入的values的属性填入指定的位置,这里的date、number则是声明值的类型。
此时,在en-US环境下,字符串为 hello,小鱼, today is 1/10/2022 ,your earnings today are 98,949
,在zh-CN环境下,字符串为你好,小鱼, 今天是2022/1/10 ,你今天的收益为98,949
.我们可以看到出现了不同的时间和数字格式。