Skip to content

Commit

Permalink
[CE-343] Enable i18n in operator dashboard
Browse files Browse the repository at this point in the history
Support language change in operator dashboard.

Change-Id: Iae84884f919f554e2a46de14687e386dcd155b74
Signed-off-by: Haitao Yue <hightall@me.com>
  • Loading branch information
hightall committed Apr 19, 2018
1 parent 60ca1af commit fc0da0a
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/themes/react/static/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"precommit": "npm run lint-staged",
"start": "cross-env ESLINT=none roadhog dev",
"start:no-proxy": "cross-env NO_PROXY=true ESLINT=none roadhog dev",
"build": "cross-env ESLINT=none roadhog build",
"build": "cross-env ESLINT=none COMPRESS=none roadhog build",
"build:dev": "cross-env ESLINT=none COMPRESS=none roadhog build",
"site": "roadhog-api-doc static && gh-pages -d dist",
"analyze": "cross-env ANALYZE=true roadhog build",
Expand Down
9 changes: 6 additions & 3 deletions src/themes/react/static/dashboard/src/common/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
SPDX-License-Identifier: Apache-2.0
*/
import { IntlProvider, defineMessages } from 'react-intl';
import { isUrl } from '../utils/utils';
import enLocale from '../locales/en-US';
import { isUrl, getLocale } from '../utils/utils';

const intlProvider = new IntlProvider({ locale: enLocale.locale, messages: enLocale.messages }, {});
const currentLocale = getLocale();
const intlProvider = new IntlProvider(
{ locale: currentLocale.locale, messages: currentLocale.messages },
{}
);
const { intl } = intlProvider.getChildContext();

const messages = defineMessages({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
SPDX-License-Identifier: Apache-2.0
*/
import React, { PureComponent } from 'react';
import { Menu, Icon, Spin, Dropdown, Avatar, Divider } from 'antd';
import { Menu, Icon, Spin, Dropdown, Avatar, Divider, Button } from 'antd';
import Debounce from 'lodash-decorators/debounce';
import { Link } from 'dva/router';
import styles from './index.less';
import { getLang } from '../../utils/utils';

const language = getLang();
export default class GlobalHeader extends PureComponent {
componentWillUnmount() {
this.triggerResizeEvent.cancel();
Expand All @@ -23,6 +25,10 @@ export default class GlobalHeader extends PureComponent {
event.initEvent('resize', true, false);
window.dispatchEvent(event);
}
changeLanguage = () => {
localStorage.setItem('language', language === 'en' ? 'zh-CN' : 'en');
window.location.reload();
};
render() {
const { collapsed, isMobile, logo, onMenuClick } = this.props;
const menu = (
Expand All @@ -46,6 +52,9 @@ export default class GlobalHeader extends PureComponent {
onClick={this.toggle}
/>
<div className={styles.right}>
<Button size="small" onClick={this.changeLanguage}>
{language === 'en' ? '中文' : 'En'}
</Button>
{window.username ? (
<Dropdown overlay={menu}>
<span className={`${styles.action} ${styles.account}`}>
Expand Down
6 changes: 5 additions & 1 deletion src/themes/react/static/dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
"Menu.Overview": "Overview",
"Menu.Host": "Host",
"Menu.Chain": "Chain",
"Menu.UserManagement": "User Management"
"Menu.UserManagement": "User Management",
"Overview.Title.Host": "Host",
"Overview.Title.Cluster": "Cluster",
"Overview.Title.Status": "Status",
"Overview.Title.Type": "Type"
}
6 changes: 5 additions & 1 deletion src/themes/react/static/dashboard/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
"Menu.Overview": "系统概况",
"Menu.Host": "主机管理",
"Menu.Chain": "链管理",
"Menu.UserManagement": "用户管理"
"Menu.UserManagement": "用户管理",
"Overview.Title.Host": "主机",
"Overview.Title.Cluster": "集群",
"Overview.Title.Status": "状态",
"Overview.Title.Type": "类型"
}
7 changes: 4 additions & 3 deletions src/themes/react/static/dashboard/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@ import zhCN from 'antd/lib/locale-provider/zh_CN';
import dynamic from 'dva/dynamic';
import { getRouterData } from './common/router';
import styles from './index.less';
import enLocale from './locales/en-US';
import { getLocale } from './utils/utils';

const { ConnectedRouter } = routerRedux;
dynamic.setDefaultLoadingComponent(() => {
return <Spin size="large" className={styles.globalSpin} />;
});

addLocaleData(enLocale.data);
const currentLocale = getLocale();
addLocaleData(currentLocale.data);
function RouterConfig({ history, app }) {
const routerData = getRouterData(app);
const BasicLayout = routerData['/'].component;
return (
<IntlProvider locale={enLocale.locale} messages={enLocale.messages}>
<IntlProvider locale={currentLocale.locale} messages={currentLocale.messages}>
<LocaleProvider locale={zhCN}>
<ConnectedRouter history={history}>
<Switch>
Expand Down
64 changes: 54 additions & 10 deletions src/themes/react/static/dashboard/src/routes/Overview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,31 @@
import React, { Component, Fragment } from 'react';
import { Row, Col, Card, Radio } from 'antd';
import { connect } from 'dva';
import { defineMessages, FormattedMessage } from 'react-intl';
import { Pie } from 'components/Charts';
import styles from './index.less';

const messages = defineMessages({
title: {
host: {
id: 'Overview.Title.Host',
defaultMessage: 'Host',
},
cluster: {
id: 'Overview.Title.Cluster',
defaultMessage: 'Cluster',
},
status: {
id: 'Overview.Title.Status',
defaultMessage: 'Status',
},
type: {
id: 'Overview.Title.Type',
defaultMessage: 'Type',
},
},
});

@connect(({ overview, loading }) => ({
overview,
loadingClusterStatus: loading.effects['overview/fetchClusterStatus'],
Expand Down Expand Up @@ -48,26 +70,37 @@ export default class Analysis extends Component {
loading={loadingHostStatus}
className={styles.pieChartCard}
bordered={false}
title="Host"
title={<FormattedMessage {...messages.title.host} />}
bodyStyle={{ padding: 24 }}
style={{ marginTop: 24, minHeight: 409 }}
extra={
<div className={styles.pieChartCardExtra}>
<div className={styles.pieChartTypeRadio}>
<Radio.Group value={hostTypeValue} onChange={this.hostTypeChange}>
<Radio.Button value="status">Status</Radio.Button>
<Radio.Button value="type">Types</Radio.Button>
<Radio.Button value="status">
<FormattedMessage {...messages.title.status} />
</Radio.Button>
<Radio.Button value="type">
<FormattedMessage {...messages.title.type} />
</Radio.Button>
</Radio.Group>
</div>
</div>
}
>
<h4 style={{ marginTop: 8, marginBottom: 32 }}>
Host <span className={styles.pieChartSubTitle}>{hostTypeValue}</span>
<FormattedMessage {...messages.title.host} />{' '}
<span className={styles.pieChartSubTitle}>
<FormattedMessage {...messages.title[hostTypeValue]} />
</span>
</h4>
<Pie
hasLegend
subTitle={<span className={styles.pieChartSubTitle}>{hostTypeValue}</span>}
subTitle={
<span className={styles.pieChartSubTitle}>
<FormattedMessage {...messages.title[hostTypeValue]} />
</span>
}
total={() => (
<span>
{hostTypeValue === 'type'
Expand All @@ -86,26 +119,37 @@ export default class Analysis extends Component {
className={styles.pieChartCard}
loading={loadingClusterStatus}
bordered={false}
title="Cluster"
title={<FormattedMessage {...messages.title.cluster} />}
bodyStyle={{ padding: 24 }}
style={{ marginTop: 24, minHeight: 409 }}
extra={
<div className={styles.pieChartCardExtra}>
<div className={styles.pieChartTypeRadio}>
<Radio.Group value={clusterTypeValue} onChange={this.clusterTypeChange}>
<Radio.Button value="status">Status</Radio.Button>
<Radio.Button value="type">Types</Radio.Button>
<Radio.Button value="status">
<FormattedMessage {...messages.title.status} />
</Radio.Button>
<Radio.Button value="type">
<FormattedMessage {...messages.title.type} />
</Radio.Button>
</Radio.Group>
</div>
</div>
}
>
<h4 style={{ marginTop: 8, marginBottom: 32 }}>
Cluster <span className={styles.pieChartSubTitle}>{clusterTypeValue}</span>
<FormattedMessage {...messages.title.cluster} />{' '}
<span className={styles.pieChartSubTitle}>
<FormattedMessage {...messages.title[clusterTypeValue]} />
</span>
</h4>
<Pie
hasLegend
subTitle={<span className={styles.pieChartSubTitle}>{clusterTypeValue}</span>}
subTitle={
<span className={styles.pieChartSubTitle}>
<FormattedMessage {...messages.title[clusterTypeValue]} />
</span>
}
total={() => (
<span>
{clusterTypeValue === 'type'
Expand Down
12 changes: 12 additions & 0 deletions src/themes/react/static/dashboard/src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
SPDX-License-Identifier: Apache-2.0
*/
import moment from 'moment';
import enLocale from '../locales/en-US';
import zhLocale from '../locales/zh-CN';

export function fixedZero(val) {
return val * 1 < 10 ? `0${val}` : val;
Expand Down Expand Up @@ -134,3 +136,13 @@ const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-
export function isUrl(path) {
return reg.test(path);
}

export function getLocale() {
return ((window.localStorage && localStorage.getItem('language')) || (navigator.language || navigator.browserLanguage).toLowerCase()) === 'en'
? enLocale
: zhLocale;
}

export function getLang() {
return (window.localStorage && localStorage.getItem('language')) || (navigator.language || navigator.browserLanguage).toLowerCase();
}

0 comments on commit fc0da0a

Please sign in to comment.