From c7e50f223de52a95e8ce8998725da87edb4791f7 Mon Sep 17 00:00:00 2001 From: jsers Date: Wed, 1 Apr 2020 18:37:52 +0800 Subject: [PATCH 1/6] feat: add English translation --- web/package-lock.json | 98 ++++ web/package.json | 1 + web/src/@types/index.d.ts | 2 + web/src/app.tsx | 112 +++-- web/src/components/Auth/Login.tsx | 20 +- web/src/components/Auth/Register.tsx | 13 +- web/src/components/BaseComponent/index.jsx | 123 ----- web/src/components/BaseComponent/style.less | 3 - web/src/components/DateInput/index.tsx | 7 +- .../components/EndpointList/BatchSearch.tsx | 11 +- web/src/components/EndpointList/CopyTitle.tsx | 38 +- web/src/components/EndpointList/Edit.tsx | 12 +- web/src/components/EndpointList/index.tsx | 27 +- web/src/components/FetchTable/index.tsx | 2 +- web/src/components/Graph/Graph/Info.tsx | 9 +- web/src/components/Graph/Graph/Legend.tsx | 12 +- web/src/components/Graph/Graph/index.tsx | 16 +- .../Graph/GraphConfig/GlobalOperationbar.tsx | 10 +- .../Graph/GraphConfig/GraphConfigForm.tsx | 53 +-- .../Graph/GraphConfig/GraphConfigInner.tsx | 24 +- .../components/Graph/GraphConfig/Tagkv.tsx | 19 +- .../components/Graph/GraphConfig/index.tsx | 3 +- web/src/components/Graph/config.tsx | 2 +- .../components/Layout/CreateIncludeNsTree.tsx | 2 +- web/src/components/Layout/index.tsx | 28 +- web/src/components/ModalControl/index.tsx | 38 +- web/src/components/Multipicker/index.jsx | 19 +- web/src/components/ProfileForm/index.tsx | 36 +- web/src/components/hooks/useFormatMessage.tsx | 22 + web/src/locales/en.ts | 433 +++++++++++++++++ web/src/locales/zh.ts | 435 ++++++++++++++++++ .../Monitor/Collect/BatchCloneToNidModal.tsx | 3 +- .../Monitor/Collect/CollectForm/LOGForm.tsx | 125 +++-- .../Monitor/Collect/CollectForm/PORTForm.tsx | 46 +- .../Monitor/Collect/CollectForm/PROCForm.tsx | 48 +- .../pages/Monitor/Collect/CollectFormMain.tsx | 13 +- web/src/pages/Monitor/Collect/config.tsx | 2 +- web/src/pages/Monitor/Collect/index.tsx | 70 +-- web/src/pages/Monitor/Dashboard/Graphs.tsx | 19 +- .../pages/Monitor/Dashboard/HostSelect.tsx | 19 +- .../pages/Monitor/Dashboard/MetricSelect.tsx | 40 +- .../Monitor/Dashboard/SubscribeModal.tsx | 25 +- web/src/pages/Monitor/Dashboard/index.tsx | 17 +- web/src/pages/Monitor/History/Detail.tsx | 37 +- web/src/pages/Monitor/History/List.tsx | 50 +- web/src/pages/Monitor/History/index.tsx | 5 +- web/src/pages/Monitor/History/style.less | 2 +- web/src/pages/Monitor/Screen/AddModal.tsx | 5 +- web/src/pages/Monitor/Screen/ModifyModal.tsx | 5 +- .../Monitor/Screen/ScreenDetail/AddModal.tsx | 5 +- .../Screen/ScreenDetail/BatchMoveSubclass.tsx | 17 +- .../Screen/ScreenDetail/ModifyModal.tsx | 5 +- .../Screen/ScreenDetail/RenderGraph.tsx | 9 +- .../Monitor/Screen/ScreenDetail/index.tsx | 41 +- web/src/pages/Monitor/Screen/index.tsx | 39 +- web/src/pages/Monitor/Silence/Add.tsx | 15 +- web/src/pages/Monitor/Silence/CustomForm.tsx | 30 +- web/src/pages/Monitor/Silence/DetailModal.tsx | 5 +- web/src/pages/Monitor/Silence/index.tsx | 44 +- web/src/pages/Monitor/Strategy/Add.tsx | 7 +- .../Strategy/BatchImportExportModal.tsx | 7 +- .../pages/Monitor/Strategy/BatchModModal.tsx | 19 +- web/src/pages/Monitor/Strategy/Clone.tsx | 7 +- web/src/pages/Monitor/Strategy/Modify.tsx | 7 +- .../pages/Monitor/Strategy/SettingFields.tsx | 56 +-- .../Strategy/SettingFields/Actions/index.tsx | 35 +- .../SettingFields/AlarmUpgrade/index.tsx | 25 +- .../SettingFields/Expressions/Expression.tsx | 154 +++---- .../SettingFields/Expressions/config.tsx | 29 +- .../SettingFields/Expressions/index.tsx | 42 +- .../Strategy/SettingFields/Filters/Filter.tsx | 11 +- .../SettingFields/Filters/FilterFormModal.tsx | 86 ++-- .../Strategy/SettingFields/Filters/index.tsx | 39 +- web/src/pages/Monitor/Strategy/index.tsx | 64 +-- .../ServiceTree/EndpointMgmt/BatchDel.tsx | 14 +- .../ServiceTree/EndpointMgmt/BatchImport.tsx | 17 +- .../pages/ServiceTree/EndpointMgmt/index.tsx | 24 +- .../pages/ServiceTree/Endpoints/BatchBind.tsx | 18 +- .../ServiceTree/Endpoints/BatchUnbind.tsx | 16 +- web/src/pages/ServiceTree/Endpoints/index.tsx | 23 +- web/src/pages/ServiceTree/Node/index.tsx | 40 +- web/src/pages/User/List/CreateUser.tsx | 9 +- web/src/pages/User/List/PutPassword.tsx | 13 +- web/src/pages/User/List/PutProfile.tsx | 7 +- web/src/pages/User/List/index.tsx | 52 ++- web/src/pages/User/Team/AddTeam.tsx | 11 +- web/src/pages/User/Team/PutTeam.tsx | 21 +- web/src/pages/User/Team/TeamForm.tsx | 31 +- web/src/pages/User/Team/index.tsx | 35 +- 89 files changed, 2163 insertions(+), 1127 deletions(-) delete mode 100644 web/src/components/BaseComponent/index.jsx delete mode 100644 web/src/components/BaseComponent/style.less create mode 100644 web/src/components/hooks/useFormatMessage.tsx create mode 100644 web/src/locales/en.ts create mode 100644 web/src/locales/zh.ts diff --git a/web/package-lock.json b/web/package-lock.json index c298dd92..fc2a4779 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -2313,6 +2313,43 @@ "resize-detector": "^0.2.0" } }, + "@formatjs/intl-displaynames": { + "version": "1.2.2", + "resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-displaynames/download/@formatjs/intl-displaynames-1.2.2.tgz", + "integrity": "sha1-0PDt662WZgGW0oL2CaEWmoiifUo=", + "requires": { + "@formatjs/intl-utils": "^2.2.0" + } + }, + "@formatjs/intl-listformat": { + "version": "1.4.2", + "resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-listformat/download/@formatjs/intl-listformat-1.4.2.tgz", + "integrity": "sha1-7YJQEH6E+qn+n6/YYCAi6NnWoXk=", + "requires": { + "@formatjs/intl-utils": "^2.2.0" + } + }, + "@formatjs/intl-relativetimeformat": { + "version": "4.5.10", + "resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-relativetimeformat/download/@formatjs/intl-relativetimeformat-4.5.10.tgz", + "integrity": "sha1-XCN3XaQ2bo43Y8kAJwcR1CoPT7c=", + "requires": { + "@formatjs/intl-utils": "^2.2.0" + } + }, + "@formatjs/intl-unified-numberformat": { + "version": "3.3.0", + "resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-unified-numberformat/download/@formatjs/intl-unified-numberformat-3.3.0.tgz", + "integrity": "sha1-BpI0apzUMquyzZtoed3WWSWFZBo=", + "requires": { + "@formatjs/intl-utils": "^2.2.0" + } + }, + "@formatjs/intl-utils": { + "version": "2.2.0", + "resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-utils/download/@formatjs/intl-utils-2.2.0.tgz", + "integrity": "sha1-um4S/mT/f9FgvjkgB8R9JLeuXHU=" + }, "@hot-loader/react-dom": { "version": "16.8.6", "resolved": "https://registry.npmjs.org/@hot-loader/react-dom/-/react-dom-16.8.6.tgz", @@ -2402,6 +2439,11 @@ "hoist-non-react-statics": "^3.3.0" } }, + "@types/invariant": { + "version": "2.2.31", + "resolved": "http://registry.npm.xiaojukeji.com/@types/invariant/download/@types/invariant-2.2.31.tgz", + "integrity": "sha1-RETAMATyFSidvKOFZThDQxfdKLI=" + }, "@types/lodash": { "version": "4.14.149", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", @@ -7952,6 +7994,28 @@ "ipaddr.js": "^1.9.0" } }, + "intl-format-cache": { + "version": "4.2.22", + "resolved": "http://registry.npm.xiaojukeji.com/intl-format-cache/download/intl-format-cache-4.2.22.tgz", + "integrity": "sha1-tafory9Dnq/r0MQOP+bNilTnnR0=" + }, + "intl-messageformat": { + "version": "8.2.3", + "resolved": "http://registry.npm.xiaojukeji.com/intl-messageformat/download/intl-messageformat-8.2.3.tgz", + "integrity": "sha1-CQ6T8uX347l8fOmpTfqZLz0OjE8=", + "requires": { + "intl-format-cache": "^4.2.22", + "intl-messageformat-parser": "^4.1.1" + } + }, + "intl-messageformat-parser": { + "version": "4.1.1", + "resolved": "http://registry.npm.xiaojukeji.com/intl-messageformat-parser/download/intl-messageformat-parser-4.1.1.tgz", + "integrity": "sha1-M6OsGFSoua3Bjfxz2wGKv5G+TDI=", + "requires": { + "@formatjs/intl-unified-numberformat": "^3.3.0" + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -11421,6 +11485,40 @@ "source-map": "^0.7.3" } }, + "react-intl": { + "version": "4.2.2", + "resolved": "http://registry.npm.xiaojukeji.com/react-intl/download/react-intl-4.2.2.tgz", + "integrity": "sha1-VLQGXHTXd8RtnURZASSqkm39nCE=", + "requires": { + "@formatjs/intl-displaynames": "^1.2.2", + "@formatjs/intl-listformat": "^1.4.2", + "@formatjs/intl-relativetimeformat": "^4.5.10", + "@formatjs/intl-unified-numberformat": "^3.3.0", + "@formatjs/intl-utils": "^2.2.0", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/invariant": "^2.2.31", + "hoist-non-react-statics": "^3.3.2", + "intl-format-cache": "^4.2.22", + "intl-messageformat": "^8.2.3", + "intl-messageformat-parser": "^4.1.1", + "shallow-equal": "^1.2.1" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "http://registry.npm.xiaojukeji.com/hoist-non-react-statics/download/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha1-7OCsr3HWLClpwuxZ/v9CpLGoW0U=", + "requires": { + "react-is": "^16.7.0" + } + }, + "shallow-equal": { + "version": "1.2.1", + "resolved": "http://registry.npm.xiaojukeji.com/shallow-equal/download/shallow-equal-1.2.1.tgz", + "integrity": "sha1-TBar+lYEOqINBQMk76aJQLDaedo=" + } + } + }, "react-is": { "version": "16.8.6", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", diff --git a/web/package.json b/web/package.json index 5c1abd50..5d164705 100644 --- a/web/package.json +++ b/web/package.json @@ -38,6 +38,7 @@ "react-dom": "^16.8.6", "react-highlight": "^0.12.0", "react-hot-loader": "^4.8.7", + "react-intl": "^4.2.2", "react-router-dom": "4.x", "react-sortable-hoc": "^1.8.3", "react-syntax-highlighter": "^7.0.4", diff --git a/web/src/@types/index.d.ts b/web/src/@types/index.d.ts index d1713357..2b916b99 100644 --- a/web/src/@types/index.d.ts +++ b/web/src/@types/index.d.ts @@ -4,3 +4,5 @@ declare module 'd3'; declare module 'd3-scale-chromatic'; declare module '@d3-charts/ts-graph'; declare module 'react-sortable-hoc'; +declare module 'rc-calendar'; +declare module 'rc-calendar/lib/locale/en_US'; diff --git a/web/src/app.tsx b/web/src/app.tsx index 3382f973..6b52d8a7 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -1,9 +1,16 @@ -import React from 'react'; +import React, { useState } from 'react'; import { HashRouter, Switch, Route, Redirect } from 'react-router-dom'; import { hot } from 'react-hot-loader/root'; +import { ConfigProvider } from 'antd'; +import antdZhCN from 'antd/lib/locale/zh_CN'; +import antdEnUS from 'antd/lib/locale/en_US'; +import { IntlProvider } from 'react-intl'; +import _ from 'lodash'; import { Page403, Page404 } from '@cpts/Exception'; import { Login, Register, PrivateRoute } from '@cpts/Auth'; -import Layout from './components/Layout'; +import Layout from '@cpts/Layout'; +import intlZhCN from './locales/zh'; +import intlEnUS from './locales/en'; import Monitor from './pages/Monitor'; import ServiceTree from './pages/ServiceTree'; import User from './pages/User'; @@ -13,87 +20,120 @@ interface Props { habitsId: string; } +interface LocaleMap { + [index: string]: any, +} + +const localeMap: LocaleMap = { + zh: { + antd: antdZhCN, + intl: 'zh', + intlMessages: intlZhCN, + }, + en: { + antd: antdEnUS, + intl: 'en', + intlMessages: intlEnUS, + }, +}; +const defaultLanguage = window.localStorage.getItem('language') || navigator.language.substr(0, 2); + function App({ habitsId }: Props) { + const [language, setLanguage] = useState(defaultLanguage); + const intlMessages = _.get(localeMap[language], 'intlMessages', intlZhCN); const menuConf = [ { - name: '监控对象', + name: intlMessages['menu.endpoints'], path: 'sTree', icon: 'cluster', children: [ { - name: '全部对象', + name: intlMessages['menu.endpoints.all'], path: 'endpointMgmt', }, { - name: '节点下对象', + name: intlMessages['menu.endpoints.node'], path: 'endpoints', }, { - name: '树节点管理', + name: intlMessages['menu.endpoints.node.manage'], path: 'node', }, ], }, { - name: '监控报警', + name: intlMessages['menu.monitor'], path: 'monitor', icon: 'icon-speed-fast', children: [ { - name: '监控看图', + name: intlMessages['menu.monitor.dashboard'], path: 'dashboard', }, { - name: '监控大盘', + name: intlMessages['menu.monitor.screen'], path: 'screen', }, { - name: '报警策略', + name: intlMessages['menu.monitor.strategy'], path: 'strategy', }, { - name: '报警历史', + name: intlMessages['menu.monitor.history'], path: 'history', }, { - name: '报警屏蔽', + name: intlMessages['menu.monitor.silence'], path: 'silence', }, { - name: '采集配置', + name: intlMessages['menu.monitor.collect'], path: 'collect', }, ], }, { - name: '用户管理', + name: intlMessages['menu.users'], path: 'user', icon: 'icon-users2', children: [ { - name: '用户管理', + name: intlMessages['menu.users.users'], path: 'list', }, { - name: '团队管理', + name: intlMessages['menu.users.teams'], path: 'team', }, ], }, ]; + return ( - - - - - - - + + + - } /> - - - - - } /> + + + + + { + setLanguage(newLanguage); + window.localStorage.setItem('language', newLanguage); + }} + > + + } /> + + + + + } /> + + - - - + + + ); } diff --git a/web/src/components/Auth/Login.tsx b/web/src/components/Auth/Login.tsx index b2b1583f..14b17210 100644 --- a/web/src/components/Auth/Login.tsx +++ b/web/src/components/Auth/Login.tsx @@ -4,13 +4,14 @@ import { Card, Form, Input, Icon, Button, Checkbox } from 'antd'; import { FormProps } from 'antd/lib/form'; import queryString from 'query-string'; import _ from 'lodash'; +import { injectIntl, WrappedComponentProps } from 'react-intl'; import { appname } from '@common/config'; import auth from './auth'; import './style.less'; const FormItem = Form.Item; -class Login extends Component { +class Login extends Component { handleSubmit = (e: FormEvent) => { e.preventDefault(); const { history, location } = this.props; @@ -47,6 +48,7 @@ class Login extends Component { const { history } = this.props; const { getFieldDecorator } = this.props.form!; const isAuthenticated = auth.getIsAuthenticated(); + const { formatMessage } = this.props.intl; if (isAuthenticated) { history.push({ @@ -58,20 +60,20 @@ class Login extends Component {
-
账户登录
+
{formatMessage({ id: 'login.title' })}
{getFieldDecorator('username', { - rules: [{ required: true, message: '请输入你的用户名!' }], + rules: [{ required: true }], })( - } placeholder="用户名" />, + } placeholder={formatMessage({ id: 'user.username' })} />, )} {getFieldDecorator('password', { - rules: [{ required: true, message: '请输入你的密码!' }], + rules: [{ required: true }], })( - } type="password" placeholder="密码" />, + } type="password" placeholder={formatMessage({ id: 'user.password' })} />, )} @@ -79,10 +81,10 @@ class Login extends Component { valuePropName: 'checked', initialValue: false, })( - 使用LDAP账号登录, + {formatMessage({ id: 'login.ldap' })}, )}
@@ -93,4 +95,4 @@ class Login extends Component { } } -export default Form.create()(Login); +export default injectIntl(Form.create()(Login)); diff --git a/web/src/components/Auth/Register.tsx b/web/src/components/Auth/Register.tsx index cbec0aca..d70daa02 100644 --- a/web/src/components/Auth/Register.tsx +++ b/web/src/components/Auth/Register.tsx @@ -2,17 +2,19 @@ import React, { Component, FormEvent } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { Card, Button, message } from 'antd'; import queryString from 'query-string'; +import { injectIntl, WrappedComponentProps } from 'react-intl'; import ProfileForm from '@cpts/ProfileForm'; import request from '@common/request'; import api from '@common/api'; import { appname } from '@common/config'; import './style.less'; -class Register extends Component { +class Register extends Component { profileForm: any; // TODO useRef handleSubmit = (e: FormEvent) => { e.preventDefault(); const { location, history } = this.props; + const { formatMessage } = this.props.intl; const query = queryString.parse(location.search); this.profileForm.validateFields((err: any, values: any) => { if (!err) { @@ -23,7 +25,7 @@ class Register extends Component { token: query.token, }), }).then(() => { - message.success('注册成功!'); + message.success(formatMessage({ id: 'msg.submit.success' })); history.push({ pathname: '/', }); @@ -34,19 +36,20 @@ class Register extends Component { render() { const prefixCls = `${appname}-register`; + const { formatMessage } = this.props.intl; return (
-
账户注册
+
{formatMessage({ id: 'register' })}
{ this.profileForm = ref; }} />
@@ -55,4 +58,4 @@ class Register extends Component { } } -export default Register; +export default injectIntl(Register); diff --git a/web/src/components/BaseComponent/index.jsx b/web/src/components/BaseComponent/index.jsx deleted file mode 100644 index 6b69a7d2..00000000 --- a/web/src/components/BaseComponent/index.jsx +++ /dev/null @@ -1,123 +0,0 @@ -import React, { Component } from 'react'; -import { Table } from 'antd'; -import _ from 'lodash'; -import queryString from 'query-string'; -import api from '@common/api'; -import * as config from '@common/config'; -import request from '@common/request'; -import './style.less'; - -export default class BaseComponent extends Component { - constructor(props) { - super(props); - this.api = api; - this.config = config; - this.prefixCls = config.appname; - this.request = request; - this.otherParamsKey = []; - this.state = { - loading: false, - pagination: { - current: 1, - pageSize: 10, - showSizeChanger: true, - }, - data: [], - searchValue: '', - }; - } - - handleSearchChange = (value) => { - this.setState({ searchValue: value }, () => { - this.reload({ - query: value, - }, true); - }); - } - - handleTableChange = (pagination) => { - const { pagination: paginationState } = this.state; - const pager = { - ...paginationState, - current: pagination.current, - pageSize: pagination.pageSize, - }; - this.setState({ pagination: pager }, () => { - this.reload({ - limit: pagination.pageSize, - page: pagination.current, - }); - }); - } - - reload(params) { - this.fetchData(params); - } - - fetchData(newParams = {}, backFirstPage = false) { - const url = this.getFetchDataUrl(); - - if (!url) return; - const othenParams = _.pick(this.state, this.otherParamsKey); - const { pagination, searchValue } = this.state; - const params = { - limit: pagination.pageSize, - p: backFirstPage ? 1 : pagination.current, - query: searchValue, - ...othenParams, - ...newParams, - }; - - this.setState({ loading: true }); - // TODO: Method 'fetchData' expected no return value. - // eslint-disable-next-line consistent-return - return this.request(`${url}?${queryString(params)}`).then((res) => { - const newPagination = { - ...pagination, - current: backFirstPage ? 1 : pagination.current, - total: res.total, - }; - let data = []; - if (_.isArray(res.list)) { - data = res.list; - } else if (_.isArray(res)) { - data = res; - } - this.setState({ - data, - pagination: newPagination, - }); - return data; - }).finally(() => { - this.setState({ loading: false }); - }); - } - - renderTable(params) { - const { loading, pagination, data } = this.state; - return ( - `共 ${total} 条数据`, - pageSizeOptions: config.defaultPageSizeOptions, - onChange: () => { - if (this.handlePaginationChange) this.handlePaginationChange(); - }, - }} - rowClassName={(record, index) => { - if (index % 2 === 1) { - return 'table-row-bg'; - } - return ''; - }} - dataSource={data} - onChange={this.handleTableChange} - {...params} - /> - ); - } -} diff --git a/web/src/components/BaseComponent/style.less b/web/src/components/BaseComponent/style.less deleted file mode 100644 index 6565604e..00000000 --- a/web/src/components/BaseComponent/style.less +++ /dev/null @@ -1,3 +0,0 @@ -.table-row-bg { - background: #f9f9f9; -} diff --git a/web/src/components/DateInput/index.tsx b/web/src/components/DateInput/index.tsx index 51d4498d..0217560c 100644 --- a/web/src/components/DateInput/index.tsx +++ b/web/src/components/DateInput/index.tsx @@ -134,17 +134,14 @@ export default class DateInput extends Component { ...locale, }} selectedValue={selectedValue} - onOk={(mDate) => { + onOk={(mDate: any) => { onChange(mDate.toDate()); this.closePopover(); }} onClear={() => { this.closePopover(); }} - // onChange={(mDate) => { - // this.setState({ tempSelectedValue: mDate.format(momentFormat) }); - // }} - onSelect={(mDate) => { + onSelect={(mDate: any) => { if (mDate && mDate.format() !== 'Invalid date') { this.setState({ tempSelectedValue: mDate.format(momentFormat) }); } diff --git a/web/src/components/EndpointList/BatchSearch.tsx b/web/src/components/EndpointList/BatchSearch.tsx index 3d5d5677..eb808102 100644 --- a/web/src/components/EndpointList/BatchSearch.tsx +++ b/web/src/components/EndpointList/BatchSearch.tsx @@ -3,6 +3,7 @@ import { Modal, Form, Input, Radio } from 'antd'; import { FormProps } from 'antd/lib/form'; import _ from 'lodash'; import ModalControl from '@cpts/ModalControl'; +import { FormattedMessage } from 'react-intl'; interface Props { field: string, @@ -18,7 +19,7 @@ const FormItem = Form.Item; const RadioGroup = Radio.Group; class BatchSearch extends Component { - static defaultProps = { + static defaultProps: any = { field: 'ident', batch: '', title: '', @@ -54,17 +55,17 @@ class BatchSearch extends Component { onCancel={this.handleCancel} >
- + }> {getFieldDecorator('field', { initialValue: field, })( - 标识 - 别名 + + , )} - + }> {getFieldDecorator('batch', { initialValue: _.replace(batch, /,/g, '\n'), })( diff --git a/web/src/components/EndpointList/CopyTitle.tsx b/web/src/components/EndpointList/CopyTitle.tsx index f667e47d..ae7b3168 100644 --- a/web/src/components/EndpointList/CopyTitle.tsx +++ b/web/src/components/EndpointList/CopyTitle.tsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Dropdown, Menu, Modal, Input, Icon, message } from 'antd'; import _ from 'lodash'; +import { FormattedMessage } from 'react-intl'; import clipboard from '@common/clipboard'; import request from '@common/request'; import api from '@common/api'; @@ -14,16 +15,10 @@ interface Props { hasSelected: boolean; } -export default class CopyTitle extends Component { +class CopyTitle extends Component { static contextTypes = { getSelectedNode: PropTypes.func, - }; - - static propTypes = { - data: PropTypes.array, - selected: PropTypes.array, - dataIndex: PropTypes.string.isRequired, - hasSelected: PropTypes.bool, + intl: PropTypes.any, }; static defaultProps = { @@ -33,7 +28,7 @@ export default class CopyTitle extends Component { }; handleCopyBtnClick = async (dataIndex: string, copyType: string) => { - const { getSelectedNode } = this.context; + const { getSelectedNode, intl } = this.context; const { data, selected } = this.props; let tobeCopy = []; @@ -47,13 +42,14 @@ export default class CopyTitle extends Component { } tobeCopy = _.map(allData, item => item[dataIndex]); } else if (copyType === 'currentPage') { + console.log('dataIndex', dataIndex); tobeCopy = _.map(data, item => item[dataIndex]); } else if (copyType === 'selected') { tobeCopy = _.map(selected, item => item[dataIndex]); } if (_.isEmpty(tobeCopy)) { - message.warning('复制的对象为空'); + message.warning(intl.formatMessage({ id: 'endpoints.copy.empty' })); return; } @@ -61,10 +57,14 @@ export default class CopyTitle extends Component { const copySucceeded = clipboard(tobeCopyStr); if (copySucceeded) { - message.success(`复制成功${tobeCopy.length}条记录!`); + if (intl.locale === 'zh') { + message.success(`复制成功${tobeCopy.length}条记录`); + } else if (intl.locale === 'en') { + message.success(`Successful copy ${tobeCopy.length} items`); + } } else { Modal.warning({ - title: '复制失败,请手动复制', + title: intl.formatMessage({ id: 'endpoints.copy.error' }), content: , }); } @@ -81,13 +81,19 @@ export default class CopyTitle extends Component { overlay={ - this.handleCopyBtnClick(dataIndex, 'selected')}>复制已选 + this.handleCopyBtnClick(dataIndex, 'selected')}> + + - this.handleCopyBtnClick(dataIndex, 'currentPage')}>复制当前页 + this.handleCopyBtnClick(dataIndex, 'currentPage')}> + + - this.handleCopyBtnClick(dataIndex, 'all')}>复制所有 + this.handleCopyBtnClick(dataIndex, 'all')}> + + } @@ -112,3 +118,5 @@ export default class CopyTitle extends Component { ); } } + +export default CopyTitle; diff --git a/web/src/components/EndpointList/Edit.tsx b/web/src/components/EndpointList/Edit.tsx index 2b982de2..55cf2132 100644 --- a/web/src/components/EndpointList/Edit.tsx +++ b/web/src/components/EndpointList/Edit.tsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import { Modal, Form, Input, message } from 'antd'; import { FormProps } from 'antd/lib/form'; import _ from 'lodash'; +import { injectIntl, FormattedMessage, WrappedComponentProps } from 'react-intl'; import ModalControl from '@cpts/ModalControl'; import { Endpoint } from '@interface'; import request from '@common/request'; @@ -19,7 +20,7 @@ interface Props { const FormItem = Form.Item; -class SingleEdit extends Component { +class SingleEdit extends Component { static defaultProps = { title: '', visible: true, @@ -29,7 +30,6 @@ class SingleEdit extends Component { }; handleOk = () => { - const { title } = this.props; this.props.form!.validateFields((err, values) => { if (!err) { request(`${api.endpoint}/${values.id}`, { @@ -38,7 +38,7 @@ class SingleEdit extends Component { alias: values.alias, }), }).then(() => { - message.success(`${title}成功`); + message.success(this.props.intl.formatMessage({ id: 'msg.modify.success' })); this.props.onOk(); this.props.destroy(); }); @@ -68,10 +68,10 @@ class SingleEdit extends Component { e.preventDefault(); this.handleOk(); }}> - + }> {data.ident} - + }> {getFieldDecorator('alias', { initialValue: data.alias, })( @@ -84,4 +84,4 @@ class SingleEdit extends Component { } } -export default ModalControl(Form.create()(SingleEdit)); +export default ModalControl(Form.create()(injectIntl(SingleEdit))); diff --git a/web/src/components/EndpointList/index.tsx b/web/src/components/EndpointList/index.tsx index 788b0e2b..afc9c5f5 100644 --- a/web/src/components/EndpointList/index.tsx +++ b/web/src/components/EndpointList/index.tsx @@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'; import { Row, Col, Input, Button, Dropdown, Menu, Checkbox, Icon } from 'antd'; import { ColumnProps } from 'antd/lib/table'; import _ from 'lodash'; +import { FormattedMessage } from 'react-intl'; import FetchTable from '@cpts/FetchTable'; import request from '@common/request'; import api from '@common/api'; @@ -35,6 +36,7 @@ interface State { class index extends Component { static contextTypes = { habitsId: PropTypes.string, + intl: PropTypes.any, }; static defaultProps = { @@ -55,7 +57,8 @@ class index extends Component { handelBatchSearchBtnClick = () => { BatchSearch({ - title: '批量过滤', + title: this.context.intl.formatMessage({ id: 'endpoints.batch.filter' }), + language: this.context.intl.locale, field: this.state.field, batch: this.state.batch, onOk: (field: string, batch: string) => { @@ -127,7 +130,7 @@ class index extends Component { data={_.get(this.fetchtable, 'state.data')} selected={this.state.selectedRows} > - 标识 + ), dataIndex: 'ident', @@ -149,11 +152,11 @@ class index extends Component { ); }, }, { - title: '别名', + title: , dataIndex: 'alias', }, { - title: '操作', - width: 100, + title: , + width: 150, render: (_text, record) => { return this.props.renderOper(record); }, @@ -161,7 +164,7 @@ class index extends Component { ]; if (displayBindNode) { fullColumns.splice(2, 0, { - title: '挂载节点', + title: , dataIndex: 'nodes', render(text) { return ( @@ -195,7 +198,7 @@ class index extends Component { searchValue: value, }); }} - placeholder="快速过滤" + placeholder="Search" /> { }); }} > - 显示挂载节点 +
@@ -223,13 +226,15 @@ class index extends Component { overlay={ - { this.props.exportEndpoints(_.get(this.fetchtable, 'state.data')); }}>导出 Excel + { this.props.exportEndpoints(_.get(this.fetchtable, 'state.data')); }}> + + {this.props.renderBatchOper(this.state.selectedIdents)} } > - + diff --git a/web/src/components/FetchTable/index.tsx b/web/src/components/FetchTable/index.tsx index cba4fabb..f0baace6 100644 --- a/web/src/components/FetchTable/index.tsx +++ b/web/src/components/FetchTable/index.tsx @@ -166,7 +166,7 @@ export default class FetchTable extends Component { pagination={{ ...this.state.pagination, showTotal: (total) => { - return `共 ${total} 条数据`; + return `Total ${total} items`; }, pageSizeOptions: config.defaultPageSizeOptions, }} diff --git a/web/src/components/Graph/Graph/Info.tsx b/web/src/components/Graph/Graph/Info.tsx index f31b00c7..342cb3c7 100644 --- a/web/src/components/Graph/Graph/Info.tsx +++ b/web/src/components/Graph/Graph/Info.tsx @@ -28,15 +28,15 @@ export default class Info extends Component { return (
  • - 指标: + Metric: {groupName}
  • - 采集周期: + Step: {firstItem.step ? `${firstItem.step} s` : '无'}
  • - 时间范围: + Time: {moment(Number(start)).format(config.timeFormatMap.moment)} - @@ -46,7 +46,7 @@ export default class Info extends Component { { unit ?
  • - 单位: + Unit: {unit}
  • : null } @@ -61,7 +61,6 @@ export default class Info extends Component { {this.props.children} diff --git a/web/src/components/Graph/Graph/Legend.tsx b/web/src/components/Graph/Graph/Legend.tsx index d6dbb9bb..5ffa43d4 100644 --- a/web/src/components/Graph/Graph/Legend.tsx +++ b/web/src/components/Graph/Graph/Legend.tsx @@ -91,7 +91,7 @@ export default class Legend extends Component { const copySucceeded = clipboard(currentCounter); if (!copySucceeded) { Modal.info({ - title: '复制失败,请手动选择复制', + title: 'Copy failed, please manually select copy', content: (

    {currentCounter}

    ), @@ -132,17 +132,17 @@ export default class Legend extends Component { const firstData = data[0]; const columns: ColumnProps[] = [ { - title: 曲线({data.length}) , + title: Series({data.length}) , dataIndex: 'tags', filterDropdown: (
    - +
    ), filterDropdownVisible: this.state.filterDropdownVisible, @@ -224,7 +224,7 @@ export default class Legend extends Component { if (_.get(firstData, 'isSameMetric') === false) { columns.unshift({ - title: '指标', + title: 'Metric', dataIndex: 'metric', width: 60, }); @@ -247,7 +247,7 @@ export default class Legend extends Component { diff --git a/web/src/components/Graph/Graph/index.tsx b/web/src/components/Graph/Graph/index.tsx index 3cefd7b0..4c527a62 100644 --- a/web/src/components/Graph/Graph/index.tsx +++ b/web/src/components/Graph/Graph/index.tsx @@ -191,19 +191,19 @@ export default class Graph extends Component { let errorText = e.err; if (e.statusText === 'error') { - errorText = '网络已断开,请检查网络'; + errorText = 'The network has been disconnected, please check the network'; } else if (e.statusText === 'Not Found') { - errorText = '404 Not Found,请联系管理员'; + errorText = '404 Not Found'; } else if (e.responseJSON) { errorText = _.get(e.responseJSON, 'msg', e.responseText); if (!errorText || e.status === 500) { - errorText = '数据加载异常,请刷新重新加载'; + errorText = 'Data loading exception, please refresh and reload'; } // request entity too large if (e.status === 413) { - errorText = '请求条件过大,请减少条件'; + errorText = 'Request condition is too large, please reduce the condition'; } } @@ -215,17 +215,17 @@ export default class Graph extends Component { checkEndpointCounters(endpointCounters: CounterInterface[], countersMaxLength: number) { let errorText: any = ''; if (!_.get(endpointCounters, 'length', 0)) { - errorText = '暂无数据'; + errorText = 'No data'; } if (endpointCounters.length > countersMaxLength) { errorText = ( - 曲线过多,当前 + Too many series,Current {endpointCounters.length} - 上限 + cap {countersMaxLength} - ,请减少曲线 + ,Please reduce the number of series ); } diff --git a/web/src/components/Graph/GraphConfig/GlobalOperationbar.tsx b/web/src/components/Graph/GraphConfig/GlobalOperationbar.tsx index 3230d7c7..c4850be1 100644 --- a/web/src/components/Graph/GraphConfig/GlobalOperationbar.tsx +++ b/web/src/components/Graph/GraphConfig/GlobalOperationbar.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import _ from 'lodash'; import moment from 'moment'; import { Button, Select, DatePicker } from 'antd'; @@ -102,19 +103,22 @@ export default class GlobalOperationbar extends Component {
    { this.props.refreshVisible ? - : null + : null } this.handleAggregateChange(currentMetric, val)} > - - - - + + + + @@ -631,7 +632,7 @@ export default class GraphConfigForm extends Component { } style={{ marginBottom: 0 }} > - + */} { readOnly value={_.join(_.slice(selectedTagv, 0, 40), ', ')} size="default" - placeholder="若无此tag,请留空" + // placeholder="若无此tag,请留空" onClick={() => { show(tagk); }} @@ -706,12 +707,12 @@ export default class GraphConfigForm extends Component { } style={{ marginBottom: 5 }} > {_.get(metricObj.counterList, 'length')} - 条 + { this.setState({ counterListVisible: !this.state.counterListVisible }); @@ -752,7 +753,7 @@ export default class GraphConfigForm extends Component { } style={{ marginBottom: 5 }} required > @@ -772,24 +773,24 @@ export default class GraphConfigForm extends Component { } style={{ marginBottom: 5 }} > } style={{ marginTop: 5, marginBottom: 0 }} required > - { @@ -838,7 +839,7 @@ export default class GraphConfigForm extends Component { } style={{ marginBottom: 5 }} > {
    @@ -241,7 +242,7 @@ export default class GraphConfigInner extends Component { }
    - 聚合: +
    { _.get(data.metrics, '[0].aggrFunc') ?
    - 聚合维度: +
    : null } -
    + {/*
    采样函数: -
    +
    */}
    Legend diff --git a/web/src/components/Graph/GraphConfig/Tagkv.tsx b/web/src/components/Graph/GraphConfig/Tagkv.tsx index 0a5385df..df3cb3b5 100644 --- a/web/src/components/Graph/GraphConfig/Tagkv.tsx +++ b/web/src/components/Graph/GraphConfig/Tagkv.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import update from 'react-addons-update'; import _ from 'lodash'; import { Input, Button, Modal, Popover, Switch } from 'antd'; @@ -185,12 +186,12 @@ export default class Tagkv extends Component { />
    - +
    @@ -198,14 +199,14 @@ export default class Tagkv extends Component { { dynamicSwitch ? - 动态值: -
    this.dynamicSelect(tagk, '=all')}>全选 + + this.dynamicSelect(tagk, '=all')}> - { if (e.keyCode === 13) { this.dynamicSelect(tagk, '=+', e.target.value); @@ -213,10 +214,9 @@ export default class Tagkv extends Component { }} />
    } - title="包含" getTooltipContainer={() => this.refs[`${tagk}dynamic`]} > - 包含 + {
    } - title="排除" getTooltipContainer={() => this.refs[`${tagk}dynamic`]} > - 排除 +
    :
    - 动态值 +
    }
    diff --git a/web/src/components/Graph/GraphConfig/index.tsx b/web/src/components/Graph/GraphConfig/index.tsx index 19a77a43..674acf05 100644 --- a/web/src/components/Graph/GraphConfig/index.tsx +++ b/web/src/components/Graph/GraphConfig/index.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import { Modal, Button, message } from 'antd'; import _ from 'lodash'; @@ -113,7 +114,7 @@ export default class GraphConfig extends Component { } destroyOnClose visible={visible} maskClosable={false} diff --git a/web/src/components/Graph/config.tsx b/web/src/components/Graph/config.tsx index 52f399dc..919d29ca 100644 --- a/web/src/components/Graph/config.tsx +++ b/web/src/components/Graph/config.tsx @@ -207,7 +207,7 @@ export const time: { [index: string]: string }[] = [ label: '30天', value: '2592000000', }, { - label: '其它 ', + label: '其它', value: 'custom', }, ]; diff --git a/web/src/components/Layout/CreateIncludeNsTree.tsx b/web/src/components/Layout/CreateIncludeNsTree.tsx index 106c190a..e1e99cab 100644 --- a/web/src/components/Layout/CreateIncludeNsTree.tsx +++ b/web/src/components/Layout/CreateIncludeNsTree.tsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; -export default function CreateIncludeNsTree(WrappedComponent: React.ComponentType, opts?: any) { +export default function CreateIncludeNsTree(WrappedComponent: any, opts?: any) { return class HOC extends React.Component { static contextTypes = { nsTreeVisibleChange: PropTypes.func, diff --git a/web/src/components/Layout/index.tsx b/web/src/components/Layout/index.tsx index 34fe62a0..dc997a74 100644 --- a/web/src/components/Layout/index.tsx +++ b/web/src/components/Layout/index.tsx @@ -2,11 +2,12 @@ import React, { Component } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import PropTypes from 'prop-types'; import { Link, withRouter } from 'react-router-dom'; -import { Layout, Dropdown, Menu, Icon } from 'antd'; +import { Layout, Dropdown, Menu, Icon, Button } from 'antd'; import classNames from 'classnames'; import PubSub from 'pubsub-js'; import _ from 'lodash'; import queryString from 'query-string'; +import { WrappedComponentProps, injectIntl } from 'react-intl'; import { auth } from '@cpts/Auth'; import { MenuConfItem, TreeNode } from '@interface'; import request from '@common/request'; @@ -22,6 +23,8 @@ interface Props { appName: string, menuConf: MenuConfItem[], children: React.ReactNode, + language: string, + onLanguageChange: (language: string) => void, } interface State { @@ -38,7 +41,7 @@ interface State { const { Header, Content, Sider } = Layout; -class NILayout extends Component { +class NILayout extends Component { static childContextTypes = { nsTreeVisibleChange: PropTypes.func.isRequired, getNodes: PropTypes.func.isRequired, @@ -48,9 +51,10 @@ class NILayout extends Component { deleteSelectedNode: PropTypes.func.isRequired, reloadNsTree: PropTypes.func.isRequired, habitsId: PropTypes.string.isRequired, + intl: PropTypes.any.isRequired, }; - constructor(props: Props & RouteComponentProps) { + constructor(props: Props & RouteComponentProps & WrappedComponentProps) { super(props); let selectedNode; try { @@ -177,6 +181,7 @@ class NILayout extends Component { this.fetchTreeData(); }, habitsId: this.props.habitsId, + intl: this.props.intl, }; } @@ -201,7 +206,7 @@ class NILayout extends Component { }); return ( - + { } render() { - const { menuConf } = this.props; + const { menuConf, language, onLanguageChange } = this.props; const { checkAuthenticateLoading, collapsed, selectedNode, nsTreeVisible } = this.state; const prefixCls = `${appname}-layout`; const { dispname, isroot } = auth.getSelftProfile(); @@ -296,6 +301,17 @@ class NILayout extends Component { {nsTreeVisible ? _.get(selectedNode, 'path') : null}
    + @@ -326,4 +342,4 @@ class NILayout extends Component { } } -export default withRouter(NILayout); +export default injectIntl(withRouter(NILayout)); diff --git a/web/src/components/ModalControl/index.tsx b/web/src/components/ModalControl/index.tsx index ba4e44a7..d1165969 100644 --- a/web/src/components/ModalControl/index.tsx +++ b/web/src/components/ModalControl/index.tsx @@ -1,7 +1,31 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { ConfigProvider } from 'antd'; +import _ from 'lodash'; +import antdZhCN from 'antd/lib/locale/zh_CN'; +import antdEnUS from 'antd/lib/locale/en_US'; +import { IntlProvider } from 'react-intl'; +import intlZhCN from '../../locales/zh'; +import intlEnUS from '../../locales/en'; -export default function ModalControlWrap(Component: typeof React.Component) { +interface LocaleMap { + [index: string]: any, +} + +const localeMap: LocaleMap = { + zh: { + antd: antdZhCN, + intl: 'zh', + intlMessages: intlZhCN, + }, + en: { + antd: antdEnUS, + intl: 'en', + intlMessages: intlEnUS, + }, +}; + +export default function ModalControlWrap(Component: any) { return function ModalControl(config: any) { const div = document.createElement('div'); document.body.appendChild(div); @@ -14,7 +38,17 @@ export default function ModalControlWrap(Component: typeof React.Component) { } function render(props: any) { - ReactDOM.render(, div); + ReactDOM.render( + + + + + , + div + ); } render({ ...config, visible: true, destroy }); diff --git a/web/src/components/Multipicker/index.jsx b/web/src/components/Multipicker/index.jsx index b414b3d0..9993d506 100644 --- a/web/src/components/Multipicker/index.jsx +++ b/web/src/components/Multipicker/index.jsx @@ -21,6 +21,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Row, Col, Input, Button, Pagination, Checkbox, Popover, Tag, message } from 'antd'; import _ from 'lodash'; +import { FormattedMessage } from 'react-intl'; import './style.less'; const TextArea = Input.TextArea ? Input.TextArea : Input; @@ -134,7 +135,7 @@ class Multipicker extends Component { if (data.length > 500) { selectedList = selectedList.splice(0, 500); - message.warning('最多只能全选500个'); + message.warning('Can only select a maximum of 500'); } if (searchVal) { selectedList = _.uniq(selected.concat(this.filterData())); @@ -249,12 +250,12 @@ class Multipicker extends Component {
- 已选({selected.length}): + ({selected.length}): - 清除已选项 + { manualEntry && @@ -278,7 +279,7 @@ class Multipicker extends Component { }} />
- +
} @@ -290,7 +291,7 @@ class Multipicker extends Component { this.setState({ manualVisible: !this.state.manualVisible }); }} > - 手动输入 + } @@ -301,15 +302,15 @@ class Multipicker extends Component {
- 选项({data.length}): + ({data.length}): - 全选当前页 + - 全选 +
@@ -317,7 +318,7 @@ class Multipicker extends Component { size="small" type="text" className="keyword" - placeholder="搜索,支持正则" + placeholder="support regular" onChange={this.search} />
diff --git a/web/src/components/ProfileForm/index.tsx b/web/src/components/ProfileForm/index.tsx index 3c9a0189..3f0f4cc0 100644 --- a/web/src/components/ProfileForm/index.tsx +++ b/web/src/components/ProfileForm/index.tsx @@ -1,6 +1,7 @@ import React, { Component, Fragment } from 'react'; import { Form, Input, Switch, Icon } from 'antd'; import { FormProps } from 'antd/lib/form'; +import { injectIntl, WrappedComponentProps } from 'react-intl'; import { UserProfile } from '@interface'; interface Props { @@ -11,8 +12,8 @@ interface Props { const FormItem = Form.Item; -class ProfileForm extends Component { - static defaultProps = { +class ProfileForm extends Component { + static defaultProps: any = { type: 'post', isrootVsible: false, initialValue: {}, @@ -33,47 +34,48 @@ class ProfileForm extends Component { render() { const { type, isrootVsible, initialValue } = this.props; const { getFieldDecorator } = this.props.form!; + const { formatMessage } = this.props.intl; return ( { type === 'post' || type === 'register' ? - + {getFieldDecorator('username', { - rules: [{ required: true, message: '请输入用户名!' }], + rules: [{ required: true }], })( - , + , )} - + {getFieldDecorator('password', { - rules: [{ required: true, message: '请输入密码!' }], + rules: [{ required: true }], })( - , + , )} : null } - + {getFieldDecorator('dispname', { initialValue: initialValue.dispname, - rules: [{ required: true, message: '请输入显示名!' }], + rules: [{ required: true }], })( - , + , )} - + {getFieldDecorator('phone', { initialValue: initialValue.phone, })( - , + , )} - + {getFieldDecorator('email', { initialValue: initialValue.email, })( - , + , )} @@ -85,7 +87,7 @@ class ProfileForm extends Component { { isrootVsible ? - + {getFieldDecorator('is_root', { valuePropName: 'checked', initialValue: initialValue.is_root === 1, @@ -102,4 +104,4 @@ class ProfileForm extends Component { } } -export default Form.create()(ProfileForm as any); +export default Form.create()(injectIntl(ProfileForm)); diff --git a/web/src/components/hooks/useFormatMessage.tsx b/web/src/components/hooks/useFormatMessage.tsx new file mode 100644 index 00000000..e6754b07 --- /dev/null +++ b/web/src/components/hooks/useFormatMessage.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import { useContext } from 'react'; +import { injectIntl } from 'react-intl'; + +export const IntlContext = React.createContext({} as any); + +// turn the old context into the new context +export const InjectIntlContext = injectIntl(({ intl, children }) => ( + + { children } + +)); + +export const getIntl = () => useContext(IntlContext); + +// the format message hook +const useFormatMessage = () => { + const intl = useContext(IntlContext); + return intl.formatMessage; +}; + +export default useFormatMessage; diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts new file mode 100644 index 00000000..92cd346b --- /dev/null +++ b/web/src/locales/en.ts @@ -0,0 +1,433 @@ +export default { + 'login': 'Login', + 'logout': 'Logout', + 'register': 'Register', + 'login.title': 'Login', + 'login.ldap': 'Use LDAP', + + 'form.save': 'Save', + 'form.create': 'Create', + 'form.submit': 'Submit', + 'form.delete': 'Delete', + 'form.login': 'Login', + 'form.goback': 'Go back', + + 'msg.submit.success': 'Submit successfully', + 'msg.modify.success': 'Modify Successfully', + 'msg.create.success': 'Create successfully', + 'msg.add.success': 'Add successfully', + 'msg.delete.success': 'Delete successfully', + 'msg.clone.success': 'Clone successfully', + 'msg.sort.success': 'Sort successfully', + + 'please.select.node': 'Please select the node first', + + 'table.nodata': 'No data', + 'table.create': 'Create', + 'table.operations': 'Operations', + 'table.batch.operations': 'Batch Operations', + 'table.detail': 'Detail', + 'table.modify': 'Modify', + 'table.delete': 'Delete', + 'table.delete.batch': 'Batch delete', + 'table.clone': 'Clone', + 'table.delete.sure': 'Are you sure to delete it?', + 'table.delete.there.sure': 'Are you sure to delete these?', + 'table.ident': 'Ident', + 'table.name': 'Name', + 'table.cate': 'Cate', + 'table.creator': 'Creator', + 'table.lastupdated': 'Last updated', + 'table.note': 'Note', + + 'user.create': 'Create', + 'user.modify': 'Modify', + 'user.username': 'Username', + 'user.dispname': 'Dispname', + 'user.password': 'Password', + 'user.email': 'Email', + 'user.phone': 'Phone', + 'user.reset.password': 'Reset password', + 'user.reset.password.success': 'Reset password successfully', + 'user.invite': 'Invite', + 'user.invite.tips': 'Click to generate a link to invite users', + 'user.isroot': 'is root', + 'password.old': 'Old Password', + 'password.new': 'New Password', + 'token.reset': 'Reset', + 'token.reset.success': 'Reset successfully', + 'invite.user.copy.success': 'Copy succeeded', + 'invite.user.copy.faile': 'Failed, please copy manually', + + 'tree.select.node': 'Please choose the tree node', + 'tree.search': 'Search (space division)', + 'tree.node': 'Node', + 'node.copy.path': 'Copy node path', + 'node.copy.path.success': 'Copy succeeded', + 'node.copy.path.error': 'Copy failed', + 'node.create.tenant': 'Add tenant node', + 'node.create': 'Add node', + 'node.modify': 'Modify node', + 'node.delete': 'Delete node', + 'node.name': 'Name', + 'node.isLeaf': 'Is leaf', + 'node.cate': 'Category', + 'node.color': 'Color', + 'node.note': 'Note', + 'node.cate.create': 'Create node category', + 'node.cate.modify': 'Modify node category', + 'node.display.path': 'Display node', + 'node.rename': 'Rename node', + 'node.rename.newname': 'node name', + 'node.rename.success': 'Rename successfully', + 'node.child.create': 'Create a new node', + 'node.child.create.success': 'Create successfully', + 'node.child.newname': 'node name', + 'node.delete.success': 'Delete successfully', + 'node.leaf.cannot.create': 'Leaf node cannot continue to create child node', + '根节点不能删除': 'Root node cannot delete', + + 'select.all': 'all', + 'select.include': 'include', + 'select.exclude': 'exclude', + 'select.dynamic': 'dynamic value', + 'select.selected': 'selected', + 'select.selected.clear': 'clear', + 'select.manual.input': 'manual', + 'select.total': 'total', + 'select.current.page': 'currentPage', + + '1小时': '1hour', + '2小时': '2hours', + '6小时': '6hours', + '12小时': '12hours', + '1天': '1day', + '2天': '2days', + '7天': '7days', + '30天': '30days', + '其它': 'other', + + 'menu.endpoints': 'Endpoints', + 'menu.endpoints.all': 'All endpoints', + 'menu.endpoints.node': 'Endpoints of node', + 'menu.endpoints.node.manage': 'Node manage', + 'menu.monitor': 'Monitor', + 'menu.monitor.dashboard': 'Dashboard', + 'menu.monitor.screen': 'Screens', + 'menu.monitor.strategy': 'Alarm strategies', + 'menu.monitor.history': 'Alarm events', + 'menu.monitor.silence': 'Alarm silences', + 'menu.monitor.collect': 'Collections', + 'menu.users': 'Users', + 'menu.users.users': 'Users', + 'menu.users.teams': 'Teams', + + 'endpoints.ident': 'Ident', + 'endpoints.alias': 'Alias', + 'endpoints.nodes': 'Nodes', + 'endpoints.batch.filter': 'Batch filter', + 'endpoints.batch.filter.key': 'Key', + 'endpoints.batch.filter.value': 'Value', + 'endpoints.export.excel': 'Export excel', + 'endpoints.import': 'Import endpoints', + 'endpoints.export': 'Export endpoints', + 'endpoints.delete': 'Delete Endpoints', + 'endpoints.bind': 'Bind Endpoints', + 'endpoints.unbind': 'Unbind Endpoints', + 'endpoints.copy.selected': 'Copy the selected', + 'endpoints.copy.currentPage': 'Copy the current page', + 'endpoints.copy.all': 'Copy all', + 'endpoints.copy.empty': 'Copy the object is empty', + 'endpoints.copy.error': 'Failed to copy, please manually copy', + 'endpoints.import.batch.help': 'Each one is an ident::alias', + 'endpoints.modify.alias': 'Modify alias', + 'endpoints.bind.node': 'Node', + 'endpoints.unbind.node': 'Node', + 'endpoints.delete.old.bind': 'Delete old Bind', + + 'team.ident': 'Ident', + 'team.name': 'Name', + 'team.admins': 'Admins', + 'team.members': 'Members', + 'team.mgmt': 'Management mode', + 'team.mgmt.admin': 'Admin', + 'team.mgmt.member': 'Member', + + '周一': 'Mon.', + '周二': 'Tue.', + '周三': 'Wed.', + '周四': 'Thu.', + '周五': 'Fri.', + '周六': 'Sat.', + '周日': 'Sun.', + + 'clone.to.other.node': 'Clone to other node', + 'clone.to.other.node.success': 'Clone to node successfully!', + 'collect.log': 'Log', + 'collect.port': 'Port', + 'collect.proc': 'Proc', + 'collect.common.search': 'Search', + 'collect.common.name': 'Name', + 'collect.common.type': 'Type', + 'collect.common.creator': 'Creator', + 'collect.common.last_updated': 'Last updated', + 'collect.common.node': 'Node', + 'collect.common.step': 'Step', + 'collect.common.step.unit': 'seconds', + 'collect.common.note': 'Note', + + 'collect.log.msg.pattern.empty': 'Pattern is required', + 'collect.log.msg.log.empty': 'Log is required', + 'collect.log.msg.tag.maximum': 'Maximum of three', + 'collect.log.ns': 'NS', + 'collect.log.name': 'Name', + 'collect.log.func': 'Calc func', + 'collect.log.func.cnt': 'Count', + 'collect.log.func.avg': 'Average', + 'collect.log.func.sum': 'Sum', + 'collect.log.func.max': 'Max', + 'collect.log.func.min': 'Min', + 'collect.log.path': 'Path', + 'collect.log.path.dynamic': 'dynamic log', + 'collect.log.path.dynamic.tip.1': 'The time format at the end of the log, eg.', + 'collect.log.path.dynamic.tip.2': "/ cannot be included in $'{}'", + 'collect.log.timeFmt': 'Time format', + 'collect.log.timeFmt.help.1': 'The time format must be the same as the format in the log.', + 'collect.log.timeFmt.help.2': 'Only the first match result is used.', + 'collect.log.step': 'Step', + 'collect.log.step.unit': 'seconds', + 'collect.log.pattern': 'Pattern', + 'collect.log.pattern.tip.1': 'Please Enter regular expression', + 'collect.log.pattern.tip.3': 'eg. cost=(\\d+) , Take \\d+ (the default is the first bracket)', + 'collect.log.tagval.placeholder': 'Not a curve value! Must be enumerable!', + 'collect.log.tags.add': 'Add tag', + 'collect.log.tagName.help.title': 'tagName description', + 'collect.log.tagName.help.1': 'Not allowed to use host, trigger, include', + 'collect.log.tagName.help.2': 'Not allowed to include = , : @', + 'collect.log.tagValue.help.title': 'tagValue description', + 'collect.log.tagValue.help.1': 'Must include parentheses. and the content is used as the value of tagValue, and must be enumerable.', + 'collect.log.tagValue.help.2': 'Not allowed to include = , : @', + 'collect.log.check': 'Check', + 'collect.log.check.btn': 'Check', + 'collect.log.check.btn2': 'Is there a problem with my configuration?', + 'collect.log.check.help': 'Enter a complete log to be monitored, including time.', + 'collect.log.check.help.tip.1': 'The correct: ', + 'collect.log.check.help.tip.2': 'Output regular, tag match result complete and sub-items, and time matching results', + 'collect.log.check.help.tip.3': 'The wrong: ', + 'collect.log.check.help.tip.4': 'Output error message', + 'collect.log.check.add.tip': 'Please check, When adding', + 'collect.log.note': 'Note', + 'collect.batch.import': 'Import', + 'collect.batch.export': 'Export', + + 'collect.port.title': 'Metric', + 'collect.port.name.placeholder': 'Description of the collection, such as web port', + 'collect.port.pattern.msg': 'Only english, numbers, -_.', + 'collect.port.port': 'Port', + 'collect.port.timeout': 'Timeout', + 'collect.port.timeout.unit': 'seconds', + + 'collect.proc.title': 'Metric', + 'collect.proc.name.placeholder': 'Description of the collection, such as nginx', + 'collect.proc.service.pattern.msg': 'Only english, numbers, -_.', + 'collect.proc.type': 'Type', + 'collect.proc.type.cmd': 'Command', + 'collect.proc.type.name': 'Process Name', + 'collect.proc.type.input.pattern.msg': 'Cannot contain Chinese', + + 'graph.subscribe': 'Subscribe', + 'graph.subscribe.node': 'Node', + 'graph.subscribe.screen': 'Screen', + 'graph.subscribe.tag': 'Tag', + 'graph.subscribe.success': 'Subscription successfully', + 'graph.share': 'Share', + 'graph.clear': 'Clear', + 'graph.view': 'View', + 'graph.save': 'Save', + 'graph.machine.list.title': 'Endpoints', + 'graph.machine.list.update': 'Update graphs', + 'graph.metric.list.title': 'Metrics', + 'graph.metric.list.search': 'Search', + 'graph.metric.list.all': 'All', + 'graph.refresh': 'Refresh', + 'graph.config.title': 'Setting', + 'graph.config.graph.title': 'title', + 'graph.config.node': 'node', + 'graph.config.metric': 'metric', + 'graph.config.aggr': 'aggr', + 'graph.config.aggr.sum': 'sum', + 'graph.config.aggr.avg': 'avg', + 'graph.config.aggr.max': 'max', + 'graph.config.aggr.min': 'min', + 'graph.config.aggr.group': 'groupBy', + 'graph.config.series': 'series', + 'graph.config.series.unit': 'pcs', + 'graph.config.cate': 'cate', + 'graph.config.time': 'time', + 'graph.config.threshold': 'threshold', + 'graph.config.link': 'link', + 'graph.config.link.help': 'custom link', + 'graph.config.chartType.targetValue': 'value', + 'graph.config.chartType.current': 'current', + 'graph.config.chartType.unit': 'unit', + 'graph.config.chartType.subType': 'type', + 'graph.config.subType.normal': 'value', + 'graph.config.subType.normal.tip': '(aggr required)', + 'graph.config.subType.solidGauge': 'solidGauge', + 'graph.config.subType.liquidFillGauge': 'liquidFillGauge', + 'graph.config.chartType.valueMap': 'mapType', + 'graph.config.chartType.mapConf': 'map', + 'graph.config.chartType.tableType': 'table', + 'graph.config.chartType.tableType.current': 'current', + 'graph.config.chartType.tableType.stats': 'stats', + 'graph.config.chartType.pieType': 'type', + 'graph.config.chartType.pieType.pie': 'Pie', + 'graph.config.chartType.pieType.donut': 'Donut', + 'graph.config.chartType.tableType.columnsKey': 'columns', + + 'event.tab.alert': 'Alarming', + 'event.tab.all': 'History', + 'event.msg.ignore.success': 'Successfully ignore', + 'event.msg.claim.success': 'Successfully claim', + 'event.msg.claim.all.success': 'Successfully claim all', + 'event.table.time': 'Time', + 'event.table.stra': 'Stra', + 'event.table.node': 'Node', + 'event.table.priority': 'Priority', + 'event.table.notify': 'Notify result', + 'event.table.ignore': 'Ignore', + 'event.table.ignore.sure': 'Are you sure to ignore this alarm?', + 'event.table.claim': 'Claim', + 'event.table.claim.sure': 'Are you sure to claim this alarm?', + 'event.table.shield': 'Shield', + 'event.table.assignees': 'Assignees', + 'event.table.status': 'Status', + 'event.table.status.alert': 'alert', + 'event.table.status.recovery': 'recovery', + 'event.table.claim.all': 'Claim all', + 'event.table.claim.all.sure': 'Are you sure to claim all unrecovered alarms?', + 'event.table.detail.title': 'Detail', + 'event.table.metric': 'Metric', + 'event.table.expression': 'Expression', + 'event.table.scene': 'Scene', + 'event.table.scene.time': 'Time', + 'event.table.scene.value': 'Value', + + 'screen.create': 'Add', + 'screen.tag.add': 'Add tag', + 'screen.tag.batch.modify': 'Batch modify', + 'screen.auto.refresh': 'Auto refresh', + 'screen.col': 'col', + 'screen.tag.graph.add': 'Add graph', + 'screen.tag.graph.add.graph': 'Graph', + 'screen.tag.graph.add.number': 'Number (aggr required)', + 'screen.tag.graph.add.table': 'Table', + 'screen.tag.graph.add.pie': 'Pie', + 'screen.tag.up': 'Up', + 'screen.tag.down': 'Down', + 'screen.tag.batch.modify.tag': 'Active tag', + 'screen.tag.batch.modify.target.node': 'Target node', + 'screen.tag.batch.modify.target.screen': 'Target screen', + 'screen.graph.extraMoreList.share': 'share', + 'screen.graph.extraMoreList.clone': 'clone', + 'screen.graph.extraMoreList.delete': 'delete', + 'screen.graph.extraMoreList.delete.sure': 'Are you sure to delete this chart?', + + 'silence.add': 'Add', + 'silence.metric': 'Metric', + 'silence.bindNode': 'Node', + 'silence.time': 'Time', + 'silence.cause': 'Cause', + 'silence.user': 'User', + 'silence.delete': 'Delete', + 'silence.form.metric': 'Metric', + 'silence.form.endpoints': 'Endpoints', + 'silence.form.tags': 'Tags', + 'silence.form.stime': 'Start time', + 'silence.form.etime': 'End time', + 'silence.cause.default': 'Quick shielding', + + 'stra.add': 'Add', + 'stra.batch.import.success': 'Batch import successfully', + 'stra.advanced': 'Advanced', + 'stra.seconds': 's', + 'stra.minutes': 'min', + 'stra.name': 'Name', + 'stra.priority': 'Priority', + 'stra.metric': 'Metric', + 'stra.notify': 'Notify', + 'stra.batch.modify.excludeNs': 'Modify excluded nodes', + 'stra.batch.modify.notify': 'Modify notify', + 'stra.batch.cloneTo.otherNode': 'Clone to other node', + 'stra.batch.delete': 'Delete', + 'stra.batch.import': 'Import', + 'stra.batch.export': 'Export', + 'stra.node': 'Node', + 'stra.node.exclude': 'Excluded nodes', + 'stra.priority.1': 'P1', + 'stra.priority.2': 'P2', + 'stra.priority.3': 'P3', + 'stra.priority.1.tip': 'P1: Phone, SMS, IM, Email', + 'stra.priority.2.tip': 'P2: SMS, IM, Email', + 'stra.priority.3.tip': 'P3: IM, Email', + 'stra.alertDur': 'Alert duration', + 'stra.trigger': 'Trigger condition', + 'stra.trigger.normal': 'Normal', + 'stra.trigger.and': 'And', + 'stra.preview': 'Preview', + 'stra.preview.duration': 'duration', + 'stra.preview.all': 'each value', + 'stra.preview.happen': 'value', + 'stra.preview.nodata': 'no data', + 'stra.preview.max': 'max', + 'stra.preview.min': 'min', + 'stra.preview.avg': 'avg', + 'stra.preview.sum': 'sum', + 'stra.preview.all.help': 'The disconnection situation is discontinuous. To increase fault tolerance, you can choose happen', + 'stra.tag': 'Tag filter', + 'stra.tag.add': 'Add tag filter', + 'stra.tag.modify': 'Modify tag filter', + 'stra.tag.include': 'include', + 'stra.tag.exclude': 'exclude', + 'stra.action': 'Action', + 'stra.action.d1': 'in', + 'stra.action.d2': 'min', + 'stra.action.d3': 'maximum alarm', + 'stra.action.d4': 'times', + 'stra.notify.team': 'Notify teams', + 'stra.notify.user': 'Notify users', + 'stra.notify.msg.error': 'Must be an alarm receiver or receiving group', + 'stra.notify.callback': 'Notify me of the system I developed (alarm callback, please confirm that it is an address accessible in IDC)', + 'stra.recovery.dur': 'Recovery duration', + 'stra.recovery.dur.help.1': 'Recovered, it will continue to observe for', + 'stra.recovery.dur.help.2': 'seconds, and the recovery notification is sent only when the alarm is not triggered again.', + 'stra.recovery.notify': 'Recovery notify', + 'stra.recovery.notify.checkbox': 'Do not send recovery notifications', + 'stra.period.time': 'Period time', + 'stra.alert.upgrade': 'Alert upgrade', + 'stra.alert.upgrade.checkbox': 'ON', + 'stra.alert.upgrade.d1': 'duration', + 'stra.alert.upgrade.d2': 'unprocessed and unrecovered continuous alarm', + 'stra.alert.upgrade.d3': 'will be use', + 'stra.alert.upgrade.d4': 'send to', + + 'api.name': 'Name', + 'api.url': 'URL', + 'api.viewGraph': 'Open graph', + 'api.alarm': 'Setup alarm', + 'api.batch.viewGraph': 'Batch open graphs', + 'api.batch.alarm': 'Batch setup alarms', + 'api.title': 'Metric', + 'api.protocol': 'Protocol', + 'api.domain': 'Domain', + 'api.port': 'Port', + 'api.path': 'Path', + 'api.header.add': 'Add header', + 'api.expected_code': 'HTTP status code', + 'api.expected_string': 'Expected string', + 'api.unexpected_string': 'Unexpected string', + 'api.timeout': 'Timeout', + 'api.interval': 'Interval', + 'api.region': 'Region', + 'api.comment': 'Comment', +} diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts new file mode 100644 index 00000000..c8fbcc67 --- /dev/null +++ b/web/src/locales/zh.ts @@ -0,0 +1,435 @@ +export default { + 'login': '登录', + 'logout': '退出登录', + 'register': '注册', + 'login.title': '账户登录', + 'login.ldap': '使用LDAP账号登录', + + 'form.save': '保 存', + 'form.create': '创 建', + 'form.submit': '提 交', + 'form.delete': '删 除', + 'form.login': '登 录', + 'form.goback': '返 回', + + 'msg.submit.success': '提交成功', + 'msg.modify.success': '修改成功', + 'msg.create.success': '创建成功', + 'msg.add.success': '添加成功', + 'msg.delete.success': '删除成功', + 'msg.clone.success': '克隆成功', + 'msg.sort.success': '排序成功', + + 'please.select.node': '请先选择左侧服务节点', + + 'table.nodata': '暂无数据', + 'table.create': '创建', + 'table.operations': '操作', + 'table.batch.operations': '批量操作', + 'table.detail': '详情', + 'table.modify': '修改', + 'table.delete': '删除', + 'table.delete.batch': '批量删除', + 'table.clone': '克隆', + 'table.delete.sure': '确定要删除吗?', + 'table.delete.there.sure': '确定要删除这些吗?', + 'table.ident': '英文标识', + 'table.name': '显示名', + 'table.cate': '类别', + 'table.creator': '创建者', + 'table.lastupdated': '修改时间', + 'table.note': '备注', + + 'user.create': '新建用户', + 'user.modify': '修改用户', + 'user.username': '用户名', + 'user.dispname': '显示名', + 'user.password': '密码', + 'user.email': '邮箱', + 'user.phone': '手机', + 'user.reset.password': '重置密码', + 'user.reset.password.success': '重置密码成功', + 'user.invite': '邀请用户', + 'user.invite.tips': '点击生成一个邀请用户的链接', + 'user.isroot': '是否超管', + 'password.old': '旧密码', + 'password.new': '新密码', + 'token.reset': '重置', + 'token.reset.success': '重置成功', + 'invite.user.copy.success': '邀请用户的链接复制成功', + 'invite.user.copy.faile': '复制失败,请手动复制', + + 'tree.select.node': '请先选择左侧节点', + 'tree.search': '搜节点(空格分割)', + 'tree.node': '节点', + 'node.copy.path': '拷贝路径', + 'node.copy.path.success': '拷贝路径成功', + 'node.copy.path.error': '拷贝路径失败', + 'node.create.tenant': '添加租户节点', + 'node.create': '添加节点', + 'node.modify': '修改节点', + 'node.delete': '删除节点', + 'node.name': '节点名称', + 'node.isLeaf': '是否叶子节点', + 'node.cate': '类别', + 'node.color': '颜色', + 'node.note': '备注', + 'node.cate.create': '创建节点类别', + 'node.cate.modify': '修改节点类别', + 'node.display.path': '显示挂载节点', + 'node.rename': '节点重命名', + 'node.rename.newname': '新节点名称', + 'node.rename.success': '节点重命名成功!', + 'node.child.create': '创建子节点', + 'node.child.create.success': '创建子节点成功!', + 'node.child.newname': '子节点名称', + 'node.delete.success': '删除节点成功!', + 'node.leaf.cannot.create': '叶子节点无法继续创建子节点', + '根节点不能删除': '根节点不能删除', + + 'select.all': '全选', + 'select.include': '包含', + 'select.exclude': '排除', + 'select.dynamic': '动态值', + 'select.selected': '已选', + 'select.selected.clear': '清除已选项', + 'select.manual.input': '手动输入', + 'select.total': '选项', + 'select.current.page': '全选当前页', + + '1小时': '1小时', + '2小时': '2小时', + '6小时': '6小时', + '12小时': '12小时', + '1天': '1天', + '2天': '2天', + '7天': '7天', + '30天': '30天', + '其它': '其它', + + 'menu.endpoints': '监控对象', + 'menu.endpoints.all': '全部对象', + 'menu.endpoints.node': '全部对象', + 'menu.endpoints.node.manage': '节点管理', + 'menu.monitor': '监控报警', + 'menu.monitor.dashboard': '监控看图', + 'menu.monitor.screen': '监控大盘', + 'menu.monitor.strategy': '报警策略', + 'menu.monitor.history': '报警历史', + 'menu.monitor.silence': '报警屏蔽', + 'menu.monitor.collect': '采集配置', + 'menu.users': '用户管理', + 'menu.users.users': '用户管理', + 'menu.users.teams': '团队管理', + + 'endpoints.ident': '标识', + 'endpoints.alias': '别名', + 'endpoints.nodes': '挂载节点', + 'endpoints.batch.filter': '批量过滤', + 'endpoints.batch.filter.key': '批量字段', + 'endpoints.batch.filter.value': '批量值', + 'endpoints.export.excel': '导出 Excel', + 'endpoints.import': '导入 Endpoints', + 'endpoints.export': '导出 Endpoints', + 'endpoints.delete': '删除 Endpoints', + 'endpoints.bind': '挂载 Endpoints', + 'endpoints.unbind': '解载 Endpoints', + 'endpoints.copy.selected': '复制已选', + 'endpoints.copy.currentPage': '复制当前页', + 'endpoints.copy.all': '复制所有', + 'endpoints.copy.empty': '复制的对象为空', + 'endpoints.copy.error': '复制失败,请手动复制', + 'endpoints.import.batch.help': '每一条是 ident::alias 拼接在一起', + 'endpoints.modify.alias': '改别名', + 'endpoints.bind.node': '挂载的节点', + 'endpoints.unbind.node': '解除挂载的节点', + 'endpoints.delete.old.bind': '是否删除旧的挂载关系', + + 'team.ident': '英文标识', + 'team.name': '中文名称', + 'team.admins': '管理员', + 'team.members': '普通成员', + 'team.mgmt': '管理方式', + 'team.mgmt.admin': '管理员管理制', + 'team.mgmt.member': '成员管理制', + + '周一': '周一', + '周二': '周二', + '周三': '周三', + '周四': '周四', + '周五': '周五', + '周六': '周六', + '周日': '周日', + + 'clone.to.other.node': '克隆到其他节点', + 'clone.to.other.node.success': '克隆到节点成功成功!', + 'collect.log': '日志', + 'collect.port': '端口', + 'collect.proc': '进程', + 'collect.common.search': '搜索名称', + 'collect.common.name': '采集名称', + 'collect.common.type': '类型', + 'collect.common.creator': '创建者', + 'collect.common.last_updated': '修改时间', + 'collect.common.node': '归属节点', + 'collect.common.step': '采集周期', + 'collect.common.step.unit': '秒', + 'collect.common.note': '备注', + + 'collect.log.msg.pattern.empty': '匹配正则不能为空', + 'collect.log.msg.log.empty': '日志不能为空', + 'collect.log.msg.tag.maximum': 'tags 上限三个', + 'collect.log.ns': '归属节点', + 'collect.log.name': '监控指标名称', + 'collect.log.func': '计算方法', + 'collect.log.func.cnt': '计数:对符合规则的日志进行计数', + 'collect.log.func.avg': '平均:对符合规则的日志抓取出的数字进行平均', + 'collect.log.func.sum': '求和:对符合规则的日志抓取出的数字进行求和', + 'collect.log.func.max': '最大值:对符合规则的日志抓取出的数字取最大值', + 'collect.log.func.min': '最小值:对符合规则的日志抓取出的数字进最小值', + 'collect.log.path': '日志路径', + 'collect.log.path.dynamic': '动态日志', + 'collect.log.path.dynamic.tip.1': '日志末尾自带时间格式,例如', + 'collect.log.path.dynamic.tip.2': "$'{}' 中不能包含 /", + 'collect.log.timeFmt': '时间格式', + 'collect.log.timeFmt.help.1': '时间格式必须和日志中的格式一样, 否则无法采集到数据。', + 'collect.log.timeFmt.help.2': '如日志中出现多段符合时间正则的, 只使用第一个匹配结果。', + 'collect.log.step': '采集周期', + 'collect.log.step.unit': '秒', + 'collect.log.pattern': '匹配正则', + 'collect.log.pattern.tip.1': '请填写正则表达式', + 'collect.log.pattern.tip.2': '如计算方式选择了耗时: 必须包含括号( )', + 'collect.log.pattern.tip.3': '例如 cost=(\\d+) , 则取\\d+的部分(默认以第一个括号为准)', + 'collect.log.tagval.placeholder': '不是曲线值! 匹配结果必须可枚举!', + 'collect.log.tags.add': '新增 tag', + 'collect.log.tagName.help.title': 'tagName 填写说明', + 'collect.log.tagName.help.1': '不允许包含 host、trigger、include', + 'collect.log.tagName.help.2': '不允许包含如下4个特殊字符= , : @', + 'collect.log.tagValue.help.title': 'tagValue 填写说明', + 'collect.log.tagValue.help.1': '必须包含括号。括号中的正则内容被用作tagValue的取值,必须可枚举。', + 'collect.log.tagValue.help.2': '不允许包含如下4个特殊字符= , : @', + 'collect.log.check': '配置验证', + 'collect.log.check.btn': '验证', + 'collect.log.check.btn2': '我的配置是否有问题?', + 'collect.log.check.help': '请输入一行待监控的完整日志,包括时间。', + 'collect.log.check.help.tip.1': '正确匹配:', + 'collect.log.check.help.tip.2': '输出正则匹配结果完整式及子项,输出tag正则匹配结果完整式及子项,以及时间匹配结果', + 'collect.log.check.help.tip.3': '错误匹配:', + 'collect.log.check.help.tip.4': '输出错误信息', + 'collect.log.check.add.tip': '添加采集配置的时候,请验证配置', + 'collect.log.note': '备注', + 'collect.batch.import': '导入采集配置', + 'collect.batch.export': '导出采集配置', + + 'collect.port.title': '端口监控指标', + 'collect.port.name.placeholder': '对采集配置的说明,例如 web端口采集', + 'collect.port.pattern.msg': '只能允许填写英文、数字、中划线、下划线、点', + 'collect.port.port': '端口号', + 'collect.port.timeout': '连接超时', + 'collect.port.timeout.unit': '秒', + + 'collect.proc.title': '进程采集指标', + 'collect.proc.name.placeholder': '对采集配置的说明,例如 nginx进程采集', + 'collect.proc.service.pattern.msg': '只能允许填写英文、数字、中划线、下划线、点', + 'collect.proc.type': '采集方式', + 'collect.proc.type.cmd': '命令行', + 'collect.proc.type.name': '进程名', + 'collect.proc.type.input.pattern.msg': '不能包含中文', + + 'graph.subscribe': '订阅图表', + 'graph.subscribe.node': '所属节点', + 'graph.subscribe.screen': '选择大盘', + 'graph.subscribe.tag': '选择分类', + 'graph.subscribe.success': '图表订阅成功!', + 'graph.share': '分享图表', + 'graph.clear': '清空图表', + 'graph.view': '查看', + 'graph.save': '保存', + 'graph.machine.list.title': '机器列表', + 'graph.machine.list.update': '更新图表', + 'graph.metric.list.title': '指标列表', + 'graph.metric.list.search': '搜索指标', + 'graph.metric.list.all': '全部', + 'graph.refresh': '刷新', + 'graph.config.title': '图表配置', + 'graph.config.graph.title': '标题', + 'graph.config.node': '节点', + 'graph.config.metric': '指标', + 'graph.config.aggr': '聚合', + 'graph.config.aggr.sum': '求和', + 'graph.config.aggr.avg': '均值', + 'graph.config.aggr.max': '最大值', + 'graph.config.aggr.min': '最小值', + 'graph.config.aggr.group': '聚合维度', + 'graph.config.series': '曲线', + 'graph.config.series.unit': '条', + 'graph.config.cate': '分类', + 'graph.config.time': '时间', + 'graph.config.threshold': '阈值', + 'graph.config.link': '下钻', + 'graph.config.link.help': '自定义链接,方便跳转到更深层的大盘、临时图、报警策略等', + 'graph.config.chartType.targetValue': '取值', + 'graph.config.chartType.current': '当前值', + 'graph.config.chartType.unit': '单位', + 'graph.config.chartType.subType': '类型', + 'graph.config.subType.normal': '数值', + 'graph.config.subType.normal.tip': '(必须选择聚合)', + 'graph.config.subType.solidGauge': '仪表盘', + 'graph.config.subType.liquidFillGauge': '容量水位', + 'graph.config.chartType.valueMap': '数值映射', + 'graph.config.chartType.mapConf': '映射关系', + 'graph.config.chartType.tableType': '表格类型', + 'graph.config.chartType.tableType.current': '当前值', + 'graph.config.chartType.tableType.stats': '统计值', + 'graph.config.chartType.pieType': '样式', + 'graph.config.chartType.pieType.pie': 'Pie', + 'graph.config.chartType.pieType.donut': 'Donut', + 'graph.config.chartType.tableType.columnsKey': '显示列', + + 'event.tab.alert': '未恢复报警', + 'event.tab.all': '所有历史报警', + 'event.msg.ignore.success': '忽略报警成功', + 'event.msg.claim.success': '认领报警成功', + 'event.msg.claim.all.success': '一键认领报警成功', + 'event.table.time': '发生时间', + 'event.table.stra': '策略名称', + 'event.table.node': '节点', + 'event.table.priority': '级别', + 'event.table.notify': '通知结果', + 'event.table.ignore': '忽略', + 'event.table.ignore.sure': '确定要忽略这条报警吗?', + 'event.table.claim': '认领', + 'event.table.claim.sure': '确定要认领这条报警吗?', + 'event.table.shield': '屏蔽', + 'event.table.assignees': '认领人', + 'event.table.status': '状态', + 'event.table.status.alert': '报警', + 'event.table.status.recovery': '恢复', + 'event.table.claim.all': '一键认领', + 'event.table.claim.all.sure': '确定认领该节点下所有未恢复的报警吗?', + 'event.table.detail.title': '报警事件详情', + 'event.table.metric': '指标', + 'event.table.expression': '表达式', + 'event.table.scene': '现场值', + 'event.table.scene.time': '时间', + 'event.table.scene.value': '值', + + 'screen.create': '创建大盘', + 'screen.tag.add': '新增分类', + 'screen.tag.batch.modify': '批量修改分类', + 'screen.auto.refresh': '自动刷新', + 'screen.col': '列', + 'screen.tag.graph.add': '新增图表', + 'screen.tag.graph.add.graph': '折线图', + 'screen.tag.graph.add.number': '数值 (必须选择聚合方式)', + 'screen.tag.graph.add.table': '表格', + 'screen.tag.graph.add.pie': '扇形图', + 'screen.tag.up': '上移', + 'screen.tag.down': '下移', + 'screen.tag.batch.modify.tag': '需要移动的分类', + 'screen.tag.batch.modify.target.node': '将要移动到的节点', + 'screen.tag.batch.modify.target.screen': '将要移动到的大盘', + 'screen.graph.extraMoreList.share': '分享图表', + 'screen.graph.extraMoreList.clone': '克隆图表', + 'screen.graph.extraMoreList.delete': '删除图表', + 'screen.graph.extraMoreList.delete.sure': '确定要删除这个图表吗?', + + 'silence.add': '新增屏蔽', + 'silence.metric': '指标', + 'silence.bindNode': '关联节点', + 'silence.time': '屏蔽时间', + 'silence.cause': '屏蔽原因', + 'silence.user': '操作者', + 'silence.delete': '解除', + 'silence.detail.title': '屏蔽详情', + 'silence.form.metric': '屏蔽指标', + 'silence.form.endpoints': '屏蔽 endpoints', + 'silence.form.tags': '屏蔽 tags', + 'silence.form.stime': '开始时间', + 'silence.form.etime': '结束时间', + 'silence.cause.default': '快速屏蔽', + + 'stra.add': '新增报警策略', + 'stra.batch.import.success': '批量导入成功', + 'stra.advanced': '高级', + 'stra.seconds': '秒', + 'stra.minutes': '分钟', + 'stra.name': '名称', + 'stra.priority': '级别', + 'stra.metric': '指标', + 'stra.notify': '报警接收', + 'stra.batch.modify.excludeNs': '修改排除节点', + 'stra.batch.modify.notify': '修改报警接收组', + 'stra.batch.cloneTo.otherNode': '克隆到其他节点', + 'stra.batch.delete': '批量删除', + 'stra.batch.import': '导入策略', + 'stra.batch.export': '导出策略', + 'stra.node': '生效节点', + 'stra.node.exclude': '排除节点', + 'stra.priority.1': '一级报警', + 'stra.priority.2': '二级报警', + 'stra.priority.3': '三级报警', + 'stra.priority.1.tip': '一级报警:发送语音, 短信, IM, 邮件', + 'stra.priority.2.tip': '二级报警:发送短信, IM, 邮件', + 'stra.priority.3.tip': '三级报警:发送IM,邮件', + 'stra.alertDur': '统计周期', + 'stra.trigger': '触发条件', + 'stra.trigger.normal': '常用', + 'stra.trigger.and': '与条件', + 'stra.preview': '预览', + 'stra.preview.duration': '持续', + 'stra.preview.all': '每个值', + 'stra.preview.happen': '次值', + 'stra.preview.nodata': '无数据上报', + 'stra.preview.max': '最大值', + 'stra.preview.min': '最小值', + 'stra.preview.avg': '均值', + 'stra.preview.sum': '求和值', + 'stra.preview.all.help': '断线情况,即为不连续。若要增加容错,可选择happen', + 'stra.tag': 'Tag 过滤', + 'stra.tag.add': '添加筛选条件', + 'stra.tag.modify': '修改筛选条件', + 'stra.tag.include': '包含', + 'stra.tag.exclude': '排除', + 'stra.action': '执行动作', + 'stra.action.d1': '在', + 'stra.action.d2': '分钟内', + 'stra.action.d3': '最多报警', + 'stra.action.d4': '次', + 'stra.notify.team': '报警接收团队', + 'stra.notify.user': '报警接收人', + 'stra.notify.msg.error': '必须存在一个报警接收人或接收组', + 'stra.notify.callback': '通知我自己开发的系统(报警回调, 请确认是 IDC 内可访问的地址)', + 'stra.recovery.dur': '留观时长', + 'stra.recovery.dur.help.1': '告警恢复后持续观察', + 'stra.recovery.dur.help.2': '秒,未再触发阈值才发送恢复通知', + 'stra.recovery.notify': '静默恢复', + 'stra.recovery.notify.checkbox': '不发送恢复通知', + 'stra.period.time': '生效时间', + 'stra.alert.upgrade': '报警升级', + 'stra.alert.upgrade.checkbox': '是否启动报警升级', + 'stra.alert.upgrade.d1': '持续', + 'stra.alert.upgrade.d2': '未处理并且未恢复的持续报警', + 'stra.alert.upgrade.d3': '将以', + 'stra.alert.upgrade.d4': '发送给', + + 'api.name': '采集名称', + 'api.url': '探测目标', + 'api.viewGraph': '看图', + 'api.alarm': '报警', + 'api.batch.viewGraph': '批量看图', + 'api.batch.alarm': '批量报警', + 'api.title': '监控指标', + 'api.protocol': '协议', + 'api.domain': '域名', + 'api.port': '端口', + 'api.path': '路径', + 'api.header.add': '添加 header', + 'api.expected_code': '状态码', + 'api.expected_string': '包含字符串', + 'api.unexpected_string': '不包含字符串', + 'api.timeout': '超时', + 'api.interval': '采集周期', + 'api.region': '探测源Region', + 'api.comment': '备注', +} diff --git a/web/src/pages/Monitor/Collect/BatchCloneToNidModal.tsx b/web/src/pages/Monitor/Collect/BatchCloneToNidModal.tsx index 5301ca24..59fd2ea1 100644 --- a/web/src/pages/Monitor/Collect/BatchCloneToNidModal.tsx +++ b/web/src/pages/Monitor/Collect/BatchCloneToNidModal.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Modal, Form, TreeSelect } from 'antd'; import { FormProps } from 'antd/lib/form'; import _ from 'lodash'; @@ -63,7 +64,7 @@ class BatchCloneToNidModal extends Component { > } > { getFieldDecorator('nid', { diff --git a/web/src/pages/Monitor/Collect/CollectForm/LOGForm.tsx b/web/src/pages/Monitor/Collect/CollectForm/LOGForm.tsx index f0807469..ce88a497 100644 --- a/web/src/pages/Monitor/Collect/CollectForm/LOGForm.tsx +++ b/web/src/pages/Monitor/Collect/CollectForm/LOGForm.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import _ from 'lodash'; import { Button, Form, Select, Input, Modal, message, Icon, Tooltip, Row, Col, TreeSelect } from 'antd'; @@ -47,8 +48,8 @@ function getPureName(name: string) { return name; } -class CollectForm extends Component { - constructor(props: Props) { +class CollectForm extends Component { + constructor(props: Props & WrappedComponentProps) { super(props); const { params } = this.props; this.state = { @@ -98,7 +99,7 @@ class CollectForm extends Component { tags, }); } else { - message.error('tags 上限三个'); + message.error(this.props.intl.formatMessage({ id: 'collect.log.msg.tag.maximum' })); } } @@ -136,9 +137,9 @@ class CollectForm extends Component { }); if (pattern === '') { - message.error('匹配正则不能为空'); + message.error(this.props.intl.formatMessage({ id: 'collect.log.msg.pattern.empty' })); } else if (log === '') { - message.error('log不能为空'); + message.error(this.props.intl.formatMessage({ id: 'collect.log.msg.log.empty' })); } else { this.setState({ logChecked: true, logCheckLoading: true }); request(`${api.collect}/check`, { @@ -181,7 +182,7 @@ class CollectForm extends Component { const dynamicLogReg = /\$\{[^{]+\}/; const dynamicLogRegMatch = filePath.match(dynamicLogReg); if (dynamicLogRegMatch && dynamicLogRegMatch.length && _.some(dynamicLogRegMatch, n => _.includes(n, '/'))) { - message.error('动态日志 ${}中不能包含/'); + message.error('/ cannot be included in ${}'); return; } // tags 数据转换成接口需要的格式,以及验证是否包含括号 @@ -190,15 +191,15 @@ class CollectForm extends Component { if (tags.length) { const TagValidateStatus = _.every(tags, (o) => { if (o.name === '' || o.value === '') { - message.error('tagName、tagValue 值不能为空'); + message.error('tagName or tagValue is required'); return false; } if (_.includes(reservedKws, o.name)) { - message.error('tagName 不能包含 host、trigger、include 这些是odin系统保留关键字'); + message.error('Can not include the host trigger include these are the reserved keywords for the Odin'); return false; } if (!bracketsReg.test(o.value)) { - message.error('tagValue 必须包含括号'); + message.error('tagValue must include parentheses'); return false; } return true; @@ -217,7 +218,7 @@ class CollectForm extends Component { const { params = {} } = this.props; if (params.action === 'add') { if (!this.state.logChecked) { - message.error('添加采集配置的时候,请验证配置'); + message.error('Verify the configuration when adding the collection configuration'); return; } } @@ -257,13 +258,13 @@ class CollectForm extends Component { } > { getFieldDecorator('nid', { initialValue: initialValues.nid, rules: [ - { required: true, message: '不能为空' }, + { required: true }, ], })( { ) } - + }> { style={{ width: params.action === 'add' || initialValues.name.indexOf('log.') === 0 ? 500 : 500 }} /> - + }> - + }> { overlayClassName="largeTooltip" title={
- 日志末尾自带时间格式,例如 {'/path/access.log.${%Y%m%d%H}'}
- {'${}中不能包含/'} + {'/path/access.log.${%Y%m%d%H}'}
+
} > - 动态日志 +
- + }>
{ rules: [ { required: true, - message: '不能为空', }, ], })} @@ -378,25 +373,25 @@ class CollectForm extends Component {
- 时间格式必须和日志中的格式一样, 否则无法采集到数据。
- 如日志中出现多段符合时间正则的, 只使用第一个匹配结果。 +
+
- + }> 秒 + { - 请填写正则表达式
- 如计算方式选择了耗时: 必须包含括号( )
- 例如 cost=(\d+) , 则取\d+的部分(默认以第一个括号为准) +
+
+ } > - 匹配正则 +
} > @@ -420,13 +415,11 @@ class CollectForm extends Component { rules: [ { required: true, - message: '不能为空', }, ], })} size="default" style={{ width: 500 }} - placeholder="耗时计算:正则( )中的数值会用于计算曲线值;流量计数:每匹配到该正则,曲线值+1" />
@@ -451,7 +444,7 @@ class CollectForm extends Component {
{ this.changeTag(e, index, 'value'); @@ -474,25 +467,25 @@ class CollectForm extends Component { size="default" onClick={this.addTag} > - 新增tag +
-

tagName填写说明

-
1. 不允许使用host、trigger、include
-
2. 不允许包含如下4个特殊字符= , : @
-

tagValue填写说明

-
1. 必须包含括号。括号中的正则内容被用作tagValue的取值,必须可枚举。
-
2. 不允许包含如下4个特殊字符= , : @
+

+
+
+

+
+
- + } required={this.state.logCheckVisible}> { this.state.logCheckVisible ?
{ @@ -502,12 +495,12 @@ class CollectForm extends Component { }} /> - 请输入一行待监控的完整日志,包括时间。 + - 正确匹配:
输出正则匹配结果完整式及子项,输出tag正则匹配结果完整式及子项,以及时间匹配结果 -
错误匹配: -
输出错误信息 +
+
+
} > @@ -520,7 +513,7 @@ class CollectForm extends Component { onClick={this.checkLog} loading={this.state.logCheckLoading} > - 验证 + : @@ -533,11 +526,11 @@ class CollectForm extends Component { }); }} > - 我的配置是否有问题? + }
- + }> { /> - + - 验证结果: + Result: { this.state.logCheckedResultsSuccess ? - 成功 : - 失败 + success : + error } } @@ -577,7 +570,7 @@ class CollectForm extends Component { size="large" onClick={this.closeLogCheckedResults} > - 关闭 + close , ]} > @@ -608,4 +601,4 @@ class CollectForm extends Component { } } -export default Form.create()(CollectForm); +export default Form.create()(injectIntl(CollectForm)); diff --git a/web/src/pages/Monitor/Collect/CollectForm/PORTForm.tsx b/web/src/pages/Monitor/Collect/CollectForm/PORTForm.tsx index 5a81e12b..1149f228 100644 --- a/web/src/pages/Monitor/Collect/CollectForm/PORTForm.tsx +++ b/web/src/pages/Monitor/Collect/CollectForm/PORTForm.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import _ from 'lodash'; import { Button, Form, Select, Input, InputNumber, TreeSelect } from 'antd'; @@ -25,7 +26,7 @@ const defaultFormData = { step: 10, }; -class CollectForm extends Component { +class CollectForm extends Component { state = { submitLoading: false, }; @@ -69,19 +70,19 @@ class CollectForm extends Component {
} > proc.port.listen } > { getFieldDecorator('nid', { initialValue: initialValues.nid, rules: [ - { required: true, message: '不能为空' }, + { required: true }, ], })( { ) } - + }> @@ -120,29 +120,29 @@ class CollectForm extends Component { {...getFieldProps('service', { initialValue: service, rules: [ - { required: true, message: '不能为空!' }, - { pattern: /^[a-zA-Z0-9-]+$/, message: '只能允许填写英文、数字、中划线!' }, + { required: true }, + { pattern: /^[a-zA-Z0-9-]+$/, message: this.props.intl.formatMessage({ id: 'collect.port.pattern.msg' }) }, ], })} size="default" style={{ width: 500 }} - placeholder="全局唯一的进程英文名" + // placeholder="全局唯一的进程英文名" /> - + } required> - + }> { {...getFieldProps('timeout', { initialValue: initialValues.timeout, rules: [ - { required: true, message: '不能为空' }, + { required: true }, ], })} - /> 秒 + /> - + }> 秒 + - + }> { /> - + @@ -194,4 +194,4 @@ class CollectForm extends Component { } } -export default Form.create()(CollectForm); +export default Form.create()(injectIntl(CollectForm)); diff --git a/web/src/pages/Monitor/Collect/CollectForm/PROCForm.tsx b/web/src/pages/Monitor/Collect/CollectForm/PROCForm.tsx index a928d396..03473a5c 100644 --- a/web/src/pages/Monitor/Collect/CollectForm/PROCForm.tsx +++ b/web/src/pages/Monitor/Collect/CollectForm/PROCForm.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import _ from 'lodash'; import { Button, Form, Select, Input, TreeSelect } from 'antd'; @@ -25,7 +26,7 @@ const defaultFormData = { step: 10, }; -class CollectForm extends Component { +class CollectForm extends Component { state = { submitLoading: false, }; @@ -70,20 +71,20 @@ class CollectForm extends Component {
} > proc.num } required > { getFieldDecorator('nid', { initialValue: initialValues.nid, rules: [ - { required: true, message: '不能为空' }, + { required: true }, ], })( { ) } - + }> @@ -122,34 +122,34 @@ class CollectForm extends Component { {...getFieldProps('service', { initialValue: service, rules: [ - { required: true, message: '不能为空!' }, - { pattern: /^[a-zA-Z0-9-]+$/, message: '只能允许填写英文、数字、中划线!' }, + { required: true }, + { pattern: /^[a-zA-Z0-9-]+$/, message: this.props.intl.formatMessage({ id: 'collect.proc.service.pattern.msg' }) }, ], })} size="default" style={{ width: 500 }} - placeholder="全局唯一的进程英文名" + // placeholder="全局唯一的进程英文名" /> - + } required> : } required > @@ -157,31 +157,31 @@ class CollectForm extends Component { {...getFieldProps('target', { initialValue: initialValues.target, rules: [ - { required: true, message: '不能为空' }, - { pattern: /^[^\u4e00-\u9fa5]+$/, message: '不能包含中文!' }, + { required: true }, + { pattern: /^[^\u4e00-\u9fa5]+$/, message: this.props.intl.formatMessage({ id: 'collect.proc.type.input.pattern.msg' }) }, ], })} size="default" style={{ width: 500 }} /> - + }> 秒 + - + }> { /> - + @@ -205,4 +205,4 @@ class CollectForm extends Component { } } -export default Form.create()(CollectForm); +export default Form.create()(injectIntl(CollectForm)); diff --git a/web/src/pages/Monitor/Collect/CollectFormMain.tsx b/web/src/pages/Monitor/Collect/CollectFormMain.tsx index 49836977..74ab668b 100644 --- a/web/src/pages/Monitor/Collect/CollectFormMain.tsx +++ b/web/src/pages/Monitor/Collect/CollectFormMain.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps } from 'react-intl'; import { withRouter, RouteComponentProps } from 'react-router-dom'; import { Spin, message } from 'antd'; import PropTypes from 'prop-types'; @@ -9,14 +10,14 @@ import request from '@common/request'; import api from '@common/api'; import CollectForm from './CollectForm'; -class CollectFormMain extends Component { +class CollectFormMain extends Component { static contextTypes = { getSelectedNode: PropTypes.func, }; selectedNodeId: number | undefined = undefined; state = { loading: false, - data: {}, + data: {} as any, selectedTreeNode: {}, treeData: [], }; @@ -53,7 +54,7 @@ class CollectFormMain extends Component { } handleSubmit = (values: any) => { - const { action, type } = this.props.match.params; + const { action, type } = this.props.match.params as any; let reqBody; if (action === 'add' || action === 'clone') { @@ -75,7 +76,7 @@ class CollectFormMain extends Component { method: action === 'modify' ? 'PUT' : 'POST', body: JSON.stringify(reqBody), }).then(() => { - message.success('提交成功!'); + message.success(this.props.intl.formatMessage({ id: 'msg.submit.success' })); this.props.history.push({ pathname: '/monitor/collect', }); @@ -83,7 +84,7 @@ class CollectFormMain extends Component { } render() { - const { action, type } = this.props.match.params; + const { action, type } = this.props.match.params as any; const { treeData, data, loading } = this.state; const ActiveForm = CollectForm[type]; if (action === 'add') { @@ -103,4 +104,4 @@ class CollectFormMain extends Component { } } -export default CreateIncludeNsTree(withRouter(CollectFormMain)); +export default CreateIncludeNsTree(withRouter(injectIntl(CollectFormMain))); diff --git a/web/src/pages/Monitor/Collect/config.tsx b/web/src/pages/Monitor/Collect/config.tsx index db70c7c7..527f819d 100644 --- a/web/src/pages/Monitor/Collect/config.tsx +++ b/web/src/pages/Monitor/Collect/config.tsx @@ -1,4 +1,4 @@ -export const typeMap = { +export const typeMap: any = { log: '日志', port: '端口', proc: '进程', diff --git a/web/src/pages/Monitor/Collect/index.tsx b/web/src/pages/Monitor/Collect/index.tsx index 14020465..379d7974 100644 --- a/web/src/pages/Monitor/Collect/index.tsx +++ b/web/src/pages/Monitor/Collect/index.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; import { Row, Col, Input, Divider, Dropdown, Button, Icon, Menu, Select, Popconfirm, Modal, Table, message } from 'antd'; @@ -10,7 +11,7 @@ import api from '@common/api'; import { typeMap } from './config'; import BatchCloneToNidModal from './BatchCloneToNidModal'; -class Collect extends Component { +class Collect extends Component { static contextTypes = { getNodes: PropTypes.func, getSelectedNode: PropTypes.func, @@ -18,7 +19,7 @@ class Collect extends Component { selectedNodeId: number | undefined = undefined; state = { loading: false, - data: [], + data: [] as any[], collectType: undefined, searchValue: '', selectedRowKeys: [], @@ -65,7 +66,7 @@ class Collect extends Component { ids: [record.id], }]), }).then(() => { - message.success('删除成功!'); + message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' })); this.fetchData(); }); } @@ -73,8 +74,8 @@ class Collect extends Component { handleBatchDelete = () => { const { selectedRows } = this.state; Modal.confirm({ - title: '批量删除', - content: '确定要删除所选的策略吗?', + title: this.props.intl.formatMessage({ id: 'table.delete.batch' }), + content: this.props.intl.formatMessage({ id: 'table.delete.there.sure' }), onOk: () => { const typeGroup = _.groupBy(selectedRows, 'collect_type'); const reqBody = _.map(typeGroup, (value, key) => { @@ -87,7 +88,7 @@ class Collect extends Component { method: 'DELETE', body: JSON.stringify(reqBody), }).then(() => { - message.success('批量删除成功!'); + message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' })); this.fetchData(); }); }, @@ -101,7 +102,7 @@ class Collect extends Component { BatchCloneToNidModal({ treeNodes, onOk: (nid: number) => { - const reqBody = _.map(selectedRows, (item) => { + const reqBody = _.map(selectedRows, (item: any) => { const pureItem = _.pickBy(item, (v, k) => { return !_.includes(['id', 'creator', 'created', 'last_updator', 'last_updated', 'tags'], k); }); @@ -117,7 +118,7 @@ class Collect extends Component { method: 'POST', body: JSON.stringify(reqBody), }).then(() => { - message.success('批量克隆到节点成功!'); + message.success(this.props.intl.formatMessage({ id: 'clone.to.other.node.success' })); this.fetchData(); }); }, @@ -128,12 +129,12 @@ class Collect extends Component { const { searchValue, collectType } = this.state; let { data } = this.state; if (searchValue) { - data = _.filter(data, (item) => { + data = _.filter(data, (item: any) => { return item.name.indexOf(searchValue) > -1; }); } if (collectType) { - data = _.filter(data, (item) => { + data = _.filter(data, (item: any) => { return item.collect_type === collectType; }); } @@ -152,7 +153,7 @@ class Collect extends Component { allowClear style={{ width: 100, marginRight: 8 }} className="mr10" - placeholder="类型" + placeholder={this.props.intl.formatMessage({ id: 'collect.common.type' })} value={this.state.collectType} onChange={(value: string) => { this.setState({ collectType: value }); @@ -160,14 +161,13 @@ class Collect extends Component { > { _.map(typeMap, (value, key) => { - return {value}; + return ; }) }
@@ -178,7 +178,7 @@ class Collect extends Component { _.map(typeMap, (value, key) => { return ( - {value} + ); }) @@ -187,29 +187,33 @@ class Collect extends Component { } > - + - + } >
record.id + record.collect_type} + rowKey={(record: any) => record.id + record.collect_type} rowSelection={{ selectedRowKeys: this.state.selectedRowKeys, onChange: (selectedRowKeys, selectedRows) => { @@ -222,37 +226,41 @@ class Collect extends Component { dataSource={data} columns= {[ { - title: '名称', + title: , dataIndex: 'name', }, { - title: '类型', + title: , dataIndex: 'collect_type', render: (text) => { - return typeMap[text]; + return ; }, }, { - title: '创建者', + title: , dataIndex: 'creator', }, { - title: '修改时间', + title: , dataIndex: 'last_updated', render: (text) => { return moment(text).format('YYYY-MM-DD HH:mm:ss'); }, }, { - title: '操作', - render: (text, record) => { + title: , + render: (_text, record: any) => { return ( - 修改 + + + - 克隆 + + + } onConfirm={() => { this.handleDelete(record); }} > - 删除 + ); @@ -265,4 +273,4 @@ class Collect extends Component { } } -export default CreateIncludeNsTree(Collect, { visible: true }); +export default CreateIncludeNsTree(injectIntl(Collect), { visible: true }); diff --git a/web/src/pages/Monitor/Dashboard/Graphs.tsx b/web/src/pages/Monitor/Dashboard/Graphs.tsx index 5da0a88f..325624a0 100644 --- a/web/src/pages/Monitor/Dashboard/Graphs.tsx +++ b/web/src/pages/Monitor/Dashboard/Graphs.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Row, Col, Icon, Dropdown, Menu } from 'antd'; import _ from 'lodash'; import Graph, { GraphConfig, Info } from '@cpts/Graph'; @@ -63,7 +64,7 @@ export default class Graphs extends Component { onChange={onChange} extraRender={(graph: GraphData) => { return [ - + { , - + { - this.graphConfigForm.showModal('update', '保存', o); + this.graphConfigForm.showModal('update', , o); }} /> , - + { this.props.onChange('delete', o.id); }} /> , - + - { this.handleSubscribeGraph(o); }}>订阅图表 + { this.handleSubscribeGraph(o); }}> - { this.handleShareGraph(o); }}>分享图表 + { this.handleShareGraph(o); }}> }> @@ -109,12 +110,12 @@ export default class Graphs extends Component {
{ - this.graphConfigForm.showModal('push', '看图'); + this.graphConfigForm.showModal('push', ); }} style={{ height: 350, cursor: 'pointer' }} >
- 查看 +
diff --git a/web/src/pages/Monitor/Dashboard/HostSelect.tsx b/web/src/pages/Monitor/Dashboard/HostSelect.tsx index e0b44a2d..3e74c228 100644 --- a/web/src/pages/Monitor/Dashboard/HostSelect.tsx +++ b/web/src/pages/Monitor/Dashboard/HostSelect.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Switch, Popover, Input, Button, Card, Spin } from 'antd'; import _ from 'lodash'; import Multipicker from '@cpts/Multipicker'; @@ -92,7 +93,7 @@ export default class HostSelect extends Component { const { dynamicSwitch, reloadBtnVisible } = this.state; return ( - + } className={`${prefixCls}-card`}> { { dynamicSwitch ? - { this.handleDynamicSelect('=all'); }}>全选 + { this.handleDynamicSelect('=all'); }}> { if (e.keyCode === 13) { this.handleDynamicSelect('=+', e.target.value); @@ -120,9 +121,8 @@ export default class HostSelect extends Component { /> } - title="包含" > - 包含 + { content={
{ if (e.keyCode === 13) { this.handleDynamicSelect('=-', e.target.value); @@ -139,20 +139,19 @@ export default class HostSelect extends Component { />
} - title="排除" > - 排除 +
:
- 动态值 +
} { reloadBtnVisible ?
- +
: null }
diff --git a/web/src/pages/Monitor/Dashboard/MetricSelect.tsx b/web/src/pages/Monitor/Dashboard/MetricSelect.tsx index 07e1e1de..f696e277 100644 --- a/web/src/pages/Monitor/Dashboard/MetricSelect.tsx +++ b/web/src/pages/Monitor/Dashboard/MetricSelect.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import { Card, Input, Tabs, Tooltip, Spin } from 'antd'; import _ from 'lodash'; import moment from 'moment'; @@ -51,7 +52,7 @@ function getSelectedMetricsLen(metric: string, graphs: GraphData[]) { return null; } -export default class MetricSelect extends Component { +class MetricSelect extends Component { static defaultProps = { nid: undefined, hosts: [], @@ -152,18 +153,18 @@ export default class MetricSelect extends Component { key={`${metricTabKey}_${metric}`} placement="right" visible={this.state.metricTipVisible[`${metricTabKey}_${metric}`]} - title={() => { - const currentMetricMeta = getCurrentMetricMeta(metric); - if (currentMetricMeta) { - return ( -
-

含义:{currentMetricMeta.meaning}

-

单位:{currentMetricMeta.unit}

-
- ); - } - return ''; - }} + // title={() => { + // const currentMetricMeta = getCurrentMetricMeta(metric); + // if (currentMetricMeta) { + // return ( + //
+ //

含义:{currentMetricMeta.meaning}

+ //

单位:{currentMetricMeta.unit}

+ //
+ // ); + // } + // return ''; + // }} onVisibleChange={(visible) => { const key = `${metricTabKey}_${metric}`; const currentMetricMeta = getCurrentMetricMeta(metric); @@ -186,7 +187,7 @@ export default class MetricSelect extends Component { }) } : -
暂无数据
+
No data
} ); @@ -209,14 +210,15 @@ export default class MetricSelect extends Component { const newMetricMap = this.dynamicMetricMaps(); const tabPanes = _.map(newMetricMap, (val) => { + const tabName = this.props.intl.locale == 'zh' ? val.alias : val.key; return ( - + { this.renderMetricList(newMetrics, val.key) } ); }); tabPanes.unshift( - + } key="ALL"> { this.renderMetricList(newMetrics, 'ALL') } , ); @@ -239,10 +241,10 @@ export default class MetricSelect extends Component { className={`${prefixCls}-card`} title={ - 指标列表 + @@ -254,3 +256,5 @@ export default class MetricSelect extends Component { ); } } + +export default injectIntl(MetricSelect); diff --git a/web/src/pages/Monitor/Dashboard/SubscribeModal.tsx b/web/src/pages/Monitor/Dashboard/SubscribeModal.tsx index 0e35c8f6..1e156c76 100644 --- a/web/src/pages/Monitor/Dashboard/SubscribeModal.tsx +++ b/web/src/pages/Monitor/Dashboard/SubscribeModal.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import { Modal, Form, TreeSelect, Select, message } from 'antd'; import { FormProps } from 'antd/lib/form'; import _ from 'lodash'; @@ -27,9 +28,9 @@ interface State { const FormItem = Form.Item; const { Option } = Select; -class SubscribeModal extends Component { - static defaultProps = { - title: '订阅到大盘', +class SubscribeModal extends Component { + static defaultProps: any = { + title: '', visible: true, onOk: _.noop, onCancel: _.noop, @@ -95,7 +96,7 @@ class SubscribeModal extends Component { }); }), ); - message.success('图表订阅成功!'); + message.success(this.props.intl.formatMessage({ id: 'graph.subscribe.success' })); this.props.onOk(); this.props.destroy(); } catch (e) { @@ -121,15 +122,15 @@ class SubscribeModal extends Component { onOk={this.handleOk} onCancel={this.handleCancel} bodyStyle={{ padding: 14 }} - okText="订阅" + okText={} >
{ e.preventDefault(); this.handleOk(); }}> - + }> {getFieldDecorator('nid', { - rules: [{ required: true, message: '请选择所属节点!' }], + rules: [{ required: true }], })( { , )} - + }> {getFieldDecorator('scrrenId', { - rules: [{ required: true, message: '请选择所属大盘!' }], + rules: [{ required: true }], })( , )} - + }> {getFieldDecorator('subclassId', { - rules: [{ required: true, message: '请选择所属分类!' }], + rules: [{ required: true }], })(
{ dataSource={item.points} columns={[ { - title: '时间', + title: , dataIndex: 'timestamp', width: 200, render(text) { return {moment.unix(text).format('YYYY-MM-DD HH:mm:ss')}; }, }, { - title: '数值', + title: , dataIndex: 'value', }, ]} @@ -279,4 +280,4 @@ class Detail extends Component { } } -export default CreateIncludeNsTree(Detail as any); +export default CreateIncludeNsTree(injectIntl(Detail)); diff --git a/web/src/pages/Monitor/History/List.tsx b/web/src/pages/Monitor/History/List.tsx index be8fe901..9dfc409d 100644 --- a/web/src/pages/Monitor/History/List.tsx +++ b/web/src/pages/Monitor/History/List.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import { Row, Col, Select, Input, DatePicker, Tag, Divider, message, Popconfirm, Badge, Button } from 'antd'; import { ColumnProps } from 'antd/lib/table'; @@ -33,14 +34,14 @@ const nPrefixCls = `${prefixCls}-history`; const { Option } = Select; const { Search } = Input; -export default class index extends Component { +class index extends Component { static defaultProps = { nodepath: undefined, nid: undefined, }; fetchTable: any; otherParamsKey: string[]; - constructor(props: Props) { + constructor(props: Props & WrappedComponentProps) { super(props); const now = moment(); if (props.type === 'alert') { @@ -138,7 +139,7 @@ export default class index extends Component { getColumns() { const columns: ColumnProps[] = [ { - title: '发生时间', + title: , dataIndex: 'etime', fixed: 'left', width: 100, @@ -146,12 +147,12 @@ export default class index extends Component { return moment.unix(text).format('YYYY-MM-DD HH:mm:ss'); }, }, { - title: '策略名称', + title: , dataIndex: 'sname', width: 100, fixed: 'left', }, { - title: '级别', + title: , dataIndex: 'priority', width: 50, render: (text) => { @@ -169,7 +170,7 @@ export default class index extends Component { title: 'tags', dataIndex: 'tags', }, { - title: '通知结果', + title: , dataIndex: 'status', fixed: 'right', width: 70, @@ -177,9 +178,10 @@ export default class index extends Component { return _.join(text, ', '); }, }, { - title: '操作', + title: , fixed: 'right', - width: this.props.type === 'alert' ? 165 : 90, + // width: this.props.type === 'alert' ? 100 : 90, + width: this.props.intl.locale === 'zh' ? 100 : 130, render: (text, record) => { return ( @@ -189,18 +191,18 @@ export default class index extends Component { }} target="_blank" > - 详情 + { this.props.type === 'alert' ? - this.handleDelete(record.id)}> - 忽略 + } onConfirm={() => this.handleDelete(record.id)}> + - this.handleClaim(record.id)}> - 认领 + } onConfirm={() => this.handleClaim(record.id)}> + : null } @@ -212,7 +214,7 @@ export default class index extends Component { }} target="_blank" > - 屏蔽 + ); @@ -221,7 +223,7 @@ export default class index extends Component { ]; if (this.props.type === 'alert') { columns.splice(5, 0, { - title: '认领人', + title: , dataIndex: 'claimants', width: 50, fixed: 'right', @@ -232,7 +234,7 @@ export default class index extends Component { } if (this.props.type === 'all') { columns.splice(3, 0, { - title: '状态', + title: , dataIndex: 'event_type', width: 70, render: (text) => { @@ -240,7 +242,7 @@ export default class index extends Component { return ( - {eventTypeObj.label} + ); }, @@ -276,7 +278,7 @@ export default class index extends Component { > { _.map(timeOptions, (option) => { - return ; + return ; }) } @@ -317,7 +319,7 @@ export default class index extends Component { this.props.type === 'all' ? : null } , )} diff --git a/web/src/pages/Monitor/Screen/ModifyModal.tsx b/web/src/pages/Monitor/Screen/ModifyModal.tsx index 8b2b9f6e..f67f5a90 100644 --- a/web/src/pages/Monitor/Screen/ModifyModal.tsx +++ b/web/src/pages/Monitor/Screen/ModifyModal.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Modal, Form, Input } from 'antd'; import { FormProps } from 'antd/lib/form'; import _ from 'lodash'; @@ -52,10 +53,10 @@ class ModifyModal extends Component { e.preventDefault(); this.handleOk(); }}> - + }> {getFieldDecorator('name', { initialValue: this.props.name, - rules: [{ required: true, message: '请填写大盘名称!' }], + rules: [{ required: true }], })( , )} diff --git a/web/src/pages/Monitor/Screen/ScreenDetail/AddModal.tsx b/web/src/pages/Monitor/Screen/ScreenDetail/AddModal.tsx index 8639287a..7fa29950 100644 --- a/web/src/pages/Monitor/Screen/ScreenDetail/AddModal.tsx +++ b/web/src/pages/Monitor/Screen/ScreenDetail/AddModal.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Modal, Form, Input } from 'antd'; import { FormProps } from 'antd/lib/form'; import _ from 'lodash'; @@ -51,9 +52,9 @@ class AddModal extends Component { e.preventDefault(); this.handleOk(); }}> - + }> {getFieldDecorator('name', { - rules: [{ required: true, message: '请填写分类名称!' }], + rules: [{ required: true }], })( , )} diff --git a/web/src/pages/Monitor/Screen/ScreenDetail/BatchMoveSubclass.tsx b/web/src/pages/Monitor/Screen/ScreenDetail/BatchMoveSubclass.tsx index 01330407..7f4e5aae 100644 --- a/web/src/pages/Monitor/Screen/ScreenDetail/BatchMoveSubclass.tsx +++ b/web/src/pages/Monitor/Screen/ScreenDetail/BatchMoveSubclass.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Modal, Form, TreeSelect, Select } from 'antd'; import { FormProps } from 'antd/lib/form'; import _ from 'lodash'; @@ -22,7 +23,7 @@ const { Option } = Select; class BatchMoveSubclass extends Component { static defaultProps = { - title: '批量移动分类', + title: '', visible: true, onOk: _.noop, onCancel: _.noop, @@ -58,7 +59,7 @@ class BatchMoveSubclass extends Component { return ( } visible={visible} onOk={this.handleOk} onCancel={this.handleCancel} @@ -67,9 +68,9 @@ class BatchMoveSubclass extends Component { e.preventDefault(); this.handleOk(); }}> - + }> {getFieldDecorator('subclasses', { - rules: [{ required: true, message: '请选择分类!' }], + rules: [{ required: true }], })( , )} - + }> {getFieldDecorator('nid', { - rules: [{ required: true, message: '请选择节点!' }], + rules: [{ required: true }], onChange: this.handleSelectedTreeNodeIdChange, })( { , )} - + }> {getFieldDecorator('screenId', { - rules: [{ required: true, message: '请选择大盘!' }], + rules: [{ required: true }], })( , )} diff --git a/web/src/pages/Monitor/Screen/ScreenDetail/RenderGraph.tsx b/web/src/pages/Monitor/Screen/ScreenDetail/RenderGraph.tsx index 3bd248e4..d1477046 100644 --- a/web/src/pages/Monitor/Screen/ScreenDetail/RenderGraph.tsx +++ b/web/src/pages/Monitor/Screen/ScreenDetail/RenderGraph.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Popconfirm, Menu, Col } from 'antd'; import { SortableElement } from 'react-sortable-hoc'; import _ from 'lodash'; @@ -57,14 +58,14 @@ class RenderGraph extends Component { }} extraMoreList={[ - { this.handleShareGraph(data.configs); }}>分享图表 + { this.handleShareGraph(data.configs); }}> , - { this.handleCloneGraph(data.configs); }}>克隆图表 + { this.handleCloneGraph(data.configs); }}> , - { this.props.onDelChart(data.id); }}> - 删除图表 + } onConfirm={() => { this.props.onDelChart(data.id); }}> + , ]} diff --git a/web/src/pages/Monitor/Screen/ScreenDetail/index.tsx b/web/src/pages/Monitor/Screen/ScreenDetail/index.tsx index 40afe72d..013b6aee 100644 --- a/web/src/pages/Monitor/Screen/ScreenDetail/index.tsx +++ b/web/src/pages/Monitor/Screen/ScreenDetail/index.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import { Button, Card, Divider, Popconfirm, message, Row, Col, Select, Checkbox } from 'antd'; import { FormProps } from 'antd/lib/form'; import moment from 'moment'; @@ -37,7 +38,7 @@ function updateTime(nowMoment: moment.Moment, graphConfig: any) { const COUNTDOWN = 9; // 0 ~ 9 -class ScreenDetail extends Component { +class ScreenDetail extends Component { timer: NodeJS.Timeout | undefined = undefined; state = { subclassLoading: false, @@ -398,30 +399,30 @@ class ScreenDetail extends Component { { if (this.graphConfigForm) { this.currentSubclassId = subclassObj.id; - this.graphConfigForm.showModal('push', '新增'); + this.graphConfigForm.showModal('push', this.props.intl.formatMessage({ id: 'table.create' })); } }}> - 新增图表 + - this.handleModSubclass(subclassObj)}>修改 + this.handleModSubclass(subclassObj)}> - this.handleDelSubclass(subclassObj.id)}> - 删除 + } onConfirm={() => this.handleDelSubclass(subclassObj.id)}> + this.handleMoveSubclass('up', idx)} > - 上移 + this.handleMoveSubclass('down', idx)} > - 下移 + } @@ -481,7 +482,7 @@ class ScreenDetail extends Component { }} onCloneGraph={(configs: any) => { this.currentSubclassId = subclassObj.id; - this.graphConfigForm.showModal('push', '克隆图表', { + this.graphConfigForm.showModal('push', this.props.intl.formatMessage({ id: 'table.create' }), { ...configs, }); }} @@ -502,12 +503,12 @@ class ScreenDetail extends Component {
- - + + - 时间: + { @@ -566,7 +567,7 @@ class ScreenDetail extends Component { }); }} > - 自动刷新 { this.state.autoRefresh ? `(${this.state.countdown})` : '' } + { this.state.autoRefresh ? `(${this.state.countdown})` : '' } @@ -600,4 +601,4 @@ class ScreenDetail extends Component { } } -export default CreateIncludeNsTree(ScreenDetail); +export default CreateIncludeNsTree(injectIntl(ScreenDetail)); diff --git a/web/src/pages/Monitor/Screen/index.tsx b/web/src/pages/Monitor/Screen/index.tsx index 331e6951..b9da6450 100644 --- a/web/src/pages/Monitor/Screen/index.tsx +++ b/web/src/pages/Monitor/Screen/index.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage, WrappedComponentProps, injectIntl } from 'react-intl'; import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; import { Button, Input, Divider, Popconfirm, Table, message } from 'antd'; @@ -89,7 +90,7 @@ const DragableBodyRow = DropTarget( )(BodyRow), ); -class Screen extends Component { +class Screen extends Component { static contextTypes = { getSelectedNode: PropTypes.func, }; @@ -137,7 +138,8 @@ class Screen extends Component { handleAdd = () => { AddModal({ - title: '新增大盘', + language: this.props.intl.locale, + title: this.props.intl.formatMessage({ id: 'table.create' }), onOk: (values: any) => { request(`${api.node}/${this.selectedNodeId}/screen`, { method: 'POST', @@ -155,8 +157,9 @@ class Screen extends Component { handleModify = (record: any) => { ModifyModal({ + language: this.props.intl.locale, name: record.name, - title: '修改大盘', + title: this.props.intl.formatMessage({ id: 'table.modify' }), onOk: (values: any) => { request(`${api.screen}/${record.id}`, { method: 'PUT', @@ -165,7 +168,7 @@ class Screen extends Component { node_id: record.node_id, }), }).then(() => { - message.success('修改大盘成功!'); + message.success(this.props.intl.formatMessage({ id: 'msg.modify.success' })); this.fetchData(); }); }, @@ -176,7 +179,7 @@ class Screen extends Component { request(`${api.screen}/${id}`, { method: 'DELETE', }).then(() => { - message.success('删除大盘成功!'); + message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' })); this.fetchData(); }); } @@ -193,7 +196,7 @@ class Screen extends Component { }, }), () => { - const reqBody = _.map(this.state.data, (item, i) => { + const reqBody = _.map(this.state.data, (item: any, i) => { return { id: item.id, weight: i, @@ -203,7 +206,7 @@ class Screen extends Component { method: 'PUT', body: JSON.stringify(reqBody), }).then(() => { - message.success('大盘排序成功!'); + message.success(this.props.intl.formatMessage({ id: 'msg.sort.success' })); }); }, ); @@ -212,7 +215,7 @@ class Screen extends Component { filterData() { const { data, search } = this.state; if (search) { - return _.filter(data, (item) => { + return _.filter(data, (item: any) => { return item.name.indexOf(search) > -1; }); } @@ -226,10 +229,10 @@ class Screen extends Component { return (
- + { this.setState({ search: e.target.value }); @@ -251,25 +254,25 @@ class Screen extends Component { })} columns={[ { - title: '名称', + title: , dataIndex: 'name', render: (text, record) => { return {text}; }, }, { - title: '创建人', + title: , width: 200, dataIndex: 'last_updator', }, { - title: '操作', + title: , width: 200, - render: (text, record) => { + render: (text, record: any) => { return ( - this.handleModify(record)}>修改 + this.handleModify(record)}> - this.handleDel(record.id)}> - 删除 + } onConfirm={() => this.handleDel(record.id)}> + ); @@ -282,4 +285,4 @@ class Screen extends Component { } } -export default CreateIncludeNsTree(DragDropContext(HTML5Backend)(Screen), { visible: true }); +export default CreateIncludeNsTree(DragDropContext(HTML5Backend)(injectIntl(Screen)), { visible: true }); diff --git a/web/src/pages/Monitor/Silence/Add.tsx b/web/src/pages/Monitor/Silence/Add.tsx index 92f38f77..b14e6bbd 100644 --- a/web/src/pages/Monitor/Silence/Add.tsx +++ b/web/src/pages/Monitor/Silence/Add.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl'; import { Button, Row, Col, message } from 'antd'; import _ from 'lodash'; import moment from 'moment'; @@ -9,7 +10,7 @@ import api from '@common/api'; import CustomForm from './CustomForm'; import { normalizReqData } from './utils'; -class Add extends Component { +class Add extends Component { customForm: any; state = { nid: undefined, @@ -55,12 +56,12 @@ class Add extends Component { method: 'POST', body: JSON.stringify(reqData), }).then(() => { - message.success('新增屏蔽成功!'); + message.success(this.props.intl.formatMessage({ id: 'msg.create.success' })); history.push({ pathname: '/monitor/silence', }); }).catch(() => { - message.error('新增屏蔽失败!'); + // message.error('新增屏蔽失败!'); }).finally(() => { this.setState({ submitLoading: false }); }); @@ -79,13 +80,15 @@ class Add extends Component { initialValues={{ btime: now.clone().unix(), etime: now.clone().add(1, 'hours').unix(), - cause: '快速屏蔽', + cause: this.props.intl.formatMessage({ id: 'silence.cause.default' }), ...initialValues, }} />
- + @@ -93,4 +96,4 @@ class Add extends Component { } } -export default CreateIncludeNsTree(Add); +export default CreateIncludeNsTree(injectIntl(Add)); diff --git a/web/src/pages/Monitor/Silence/CustomForm.tsx b/web/src/pages/Monitor/Silence/CustomForm.tsx index 1ce81241..9acafa41 100644 --- a/web/src/pages/Monitor/Silence/CustomForm.tsx +++ b/web/src/pages/Monitor/Silence/CustomForm.tsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Button, Form, Input, DatePicker } from 'antd'; import { FormProps } from 'antd/lib/form'; import moment from 'moment'; @@ -88,7 +89,7 @@ class CustomForm extends Component { key={o.value} type={o.value === timeSpan ? 'primary' : undefined} > - {o.label} + )) } @@ -105,12 +106,12 @@ class CustomForm extends Component { } > {getFieldDecorator('metric', { initialValue: initialValues.metric, rules: [ - { required: true, message: '不能为空' }, + { required: true }, ], })( , @@ -118,12 +119,12 @@ class CustomForm extends Component { } > {getFieldDecorator('endpoints', { initialValue: _.isArray(initialValues.endpoints) ? _.join(initialValues.endpoints, '\n') : initialValues.endpoints, rules: [ - { required: true, message: '不能为空' }, + { required: true }, ], })(