在做react项目时,用到了国际化。本想使用i8next等第三方国际化文件,但想了想作为react项目应该有自持的js作为国际化的支持。于是在github上搜索了一下,发现了两个:
一个是react-intl,从星级可以看出是react最常用的一种国际化,最大的好处是它用props的方式注入语言包,也就是可以在不刷新页面的情况下直接更改显示的语言。
但是只支持React.Component,也就是貌似只能在React.Compoent中使用,并不能解决组件以外的国际化以及表单校验的国际化,比如我用react+antd搭建的项目,如果想使用antd的表格组件那么,效果如下
我会这么使用:
record.uid}
dataSource={this.state.list}
columns={this.state.columns}
rowSelection={rowSelection}
pagination={{
showSizeChanger: true,
// showQuickJumper: true,
total: this.state.list.length, // 数据总数
pageSize: this.state.pageSize, // 每页条数
current: this.state.current, // 当前页码
showTotal: ((total) => {
return `Total: ${total} items`;
})
}}
loading={this.state.loading}
onChange={this.handleTableChange}
onRow={(record, rowkey) => {
return {
onClick: this.showRow.bind(this, record, rowkey)
}
}} />;
为了美观,并不是所有的东西都会定义在一个组件中,现在我把table组件中的column抽离出来,形成了一个单独的文件
称为columns.js
const columns = [
{
title: "Start NAS IP",
dataIndex: "startNASIp",
key: "startNASIp",
sorter: true
},
{
title: "End NAS IP",
dataIndex: "endNASIp",
key: "endNASIp",
sorter: true
},
{
title: "Nas Name",
dataIndex: "nasName",
key: "nasName",
sorter: true
},
{
title: "Description",
dataIndex: "description",
key: "description",
sorter: true
},
{
title: "DM Attributes",
dataIndex: "dm_attributes",
key: "dm_attributes",
sorter: true
},
];
export default columns
那么我在列表组建中引入这个js文件即可使用,效果就像上面的那样。
我现在的需求就会变成怎样使用react-intl或者react-intl-universal 怎样让一个普通的js非组件化的文件也能实现国际化呢?
在网上搜罗了一番,千篇一律,只是谈到了react-intl-universal的一般用法,简单的在组件中使用,官方也给出了例子,好多的博客也都是参考官网做的例子。没有我想要的效果。
先看一看网上千篇一律的基本实现方法吧。
1.安装react-intl-universal
对,无论使用什么第三方组件,第一步肯定是安装/下载
使用webpack时,我们直接使用npm/yarn去直接安装。因为国际化文件是需要打包发布到我们的生产环境的,所以会安装到dependencies中
npm i react-intl-universal -s
2.引入react-intl-universal
先看一下结构目录,我是使用create-react-app去创建的react应用,目录结构都是一样的,删除了index.js中原始的东西,然后加入了App.js
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render( , document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
App.js便是我的整个应用的入口文件,定义如下
import React, { Component } from 'react';
import { BrowserRouter, browserHistory } from 'react-router-dom'
import { Provider } from 'react-redux'
import { emit } from "./components/utils/emit";
import intl from 'react-intl-universal';
import hisroty from './history/History'
import Layouts from '../src/layouts/Layouts'
import store from './stores/store'
import locales from './locales/locales'
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
antdLang: locales.en_US, // 修改antd 组件的国际化
}
}
componentDidMount() {
emit.on('change_language', lang => this.loadLocales(lang)); // 监听语言改变事件
this.loadLocales(); // 初始化语言
}
loadLocales(lang = 'en-US') {
intl.init({
currentLocale: lang, // 设置初始语音
locales,
}).then(() => {
this.setState({
antdLang: lang === 'zh-CN' ? locales.zh_CN : locales.en_US
});
});
}
render() {
return (
);
}
}
export default App;
emit.on用于监听国际化语言发生变化,在切换国际化语言时,就会重新加载设置的语言this.loadLocales()。
intl.init用于初始化默认的语言设置,这里我默认的是英文。
locales.js中定义了引入的国际化文件
import en_US from './en_US.json'
import zh_CN from './zh_CN.json'
const locales = {
'en-US': en_US,
'zh-CN': zh_CN,
};
export default locales
en_US.json
{
"samp": {
"index": {
"logout": "Logout"
},
"policyEngine": {
"title": "Policy Engine",
"nasClients": {
"title": "Nas Clients",
"item": {
"nasName": "NAS Name",
"startNASIp": "Start NAS IP",
"endNASIp": "End NAS IP",
"description": "Description",
"dm_attributes": "DM Attributes"
}
}
}
}
}
zh_CH.json
{
"samp": {
"index":{
"logout":"退出"
},
"policyEngine": {
"title": "策略中心",
"nasClients": {
"title": "NAS客户端",
"listTitle": "Nas客户端列表",
"item": {
"nasName": "NAS名字",
"startNASIp": "NAS起始IP",
"endNASIp": "NAS结束IP",
"description": "描述",
"dm_attributes": "DM属性"
}
}
}
}
}
在这里监听时间使用了第三方组件events.js。emit的定义如下:
import EventEmitter from 'events'
const emit = new EventEmitter();
export { emit };
这样准备工作基本上完成了。接下来就是怎么使用了
应用中我会分为,登录功能和主页面,现在在主页面中使用国际化切换来改变不同的显示。
我在IndexLayout中定义了国际化切换操作,并且使用logout作为效果展示。
首先需要在IndexLayout.js中导入
import intl from 'react-intl-universal';
然后在页面使用intl.get("youKey")来绑定
{intl.get("samp.index.logout")}
现在看一下页面展示情况,目前是英文,显示的也是英文
当我切换语言时,绑定了事件,前面我们已经在App.js中使用emit去监听语言切换的事件,那么在切换语言方法中,应该去触发这个事件,才能让国际化语言发生变化。
//国际化
handleChange = (val) => {
console.log("val:",val)
// 发送消息
emit.emit('change_language', val);
}
这样就完成了国际化的切换,并且可以正常展示
刚开始看到这种效果时,欣喜若狂。注意,这里的intl.get操作是在组件中使用的。
天真的我就觉得在所有文件中应该都能使用,于是我就常识性的在非组件的js文件中使用,发现并不起作用,比如我定义的table的列名也及时表头的显示:
import intl from 'react-intl-universal';
const columns = [
{
title: intl.get("samp.policyEngine.nasClients.item.startNASIp"),
dataIndex: "startNASIp",
key: "startNASIp",
sorter: true
},
{
title: intl.get("samp.policyEngine.nasClients.item.endNASIp"),
dataIndex: "endNASIp",
key: "endNASIp",
sorter: true
},
{
title: intl.get("samp.policyEngine.nasClients.item.nasName"),
dataIndex: "nasName",
key: "nasName",
sorter: true
},
{
title: intl.get("samp.policyEngine.nasClients.item.description"),
dataIndex: "description",
key: "description",
sorter: true
},
{
title: intl.get("samp.policyEngine.nasClients.item.dm_attributes"),
dataIndex: "dm_attributes",
key: "dm_attributes",
sorter: true
},
];
export default columns
发现,我曹,表头没有了????
这时何等的我曹-----------
于是就想打印一下看看到底是什么鬼
发现,结果全是空???
想了想应该是TM不支持。然后就去antd官网找了一下,官方针对antd的组件提供了国际化支持,但那不是我要的
https://ant.design/docs/react/i18n
我把columns的定义移到component中,发现是可以国际化的,但是放到单独的js中却是不支持的
比如,我修改了table的column的绑定
record.uid}
dataSource={this.state.list}
columns={columns}
rowSelection={rowSelection}
pagination={{
showSizeChanger: true,
// showQuickJumper: true,
total: this.state.list.length, // 数据总数
pageSize: this.state.pageSize, // 每页条数
current: this.state.current, // 当前页码
showTotal: ((total) => {
return `Total: ${total} items`;
})
}}
loading={this.state.loading}
onChange={this.handleTableChange}
onRow={(record, rowkey) => {
return {
onClick: this.showRow.bind(this, record, rowkey)
}
}} />;
并且在render函数中定义了
const columns = [
{
title: intl.get("samp.policyEngine.nasClients.item.startNASIp"),
dataIndex: "startNASIp",
key: "startNASIp",
sorter: true
},
{
title: intl.get("samp.policyEngine.nasClients.item.endNASIp"),
dataIndex: "endNASIp",
key: "endNASIp",
sorter: true
},
{
title: intl.get("samp.policyEngine.nasClients.item.nasName"),
dataIndex: "nasName",
key: "nasName",
sorter: true
},
{
title: intl.get("samp.policyEngine.nasClients.item.description"),
dataIndex: "description",
key: "description",
sorter: true
},
{
title: intl.get("samp.policyEngine.nasClients.item.dm_attributes"),
dataIndex: "dm_attributes",
key: "dm_attributes",
sorter: true
},
];
然后尝试了一下,确实可以
但这就与我最初的设计有出入,显然是不合适的。
于是就想到,既然可以在组件中使用,那我能不能定义一个管道或者定义一个中间件去实现,这种组件到非组件之间的转换呢?
定义了一个用于转换的js文件,用法很简单,就是在非组件中引入组件js,然后在组件中进行国际化,在返回国际化后的值,就可以了。
于是定义了一个IntlTranslation.js
import React, { Component } from 'react';
import intl from 'react-intl-universal';
class IntlTranslation extends Component {
constructor(props) {
super(props);
this.state = { }
}
render() {
return (
{intl.get(this.props.intlKey)}
);
}
}
export default IntlTranslation;
然后修改了一下columns.js,
import React from 'react';
import IntlTranslation from '../../../components/utils/IntlTranslation'
const columns = [
{
title: ,
dataIndex: "startNASIp",
key: "startNASIp",
sorter: true
},
{
title: ,
dataIndex: "endNASIp",
key: "endNASIp",
sorter: true
},
{
title: ,
dataIndex: "nasName",
key: "nasName",
sorter: true
},
{
title: ,
dataIndex: "description",
key: "description",
sorter: true
},
{
title: ,
dataIndex: "dm_attributes",
key: "dm_attributes",
sorter: true
},
];
export default columns
测试了一下,居然好用!!!!!!!!!!!
目前只想到这种解决方案,也许react-intl-universal能实现,但是没有发现有类似的demo。如果你有解决方法,欢迎留言指导。
你可能感兴趣的:(React,组件非组件)