diff --git a/.eslintrc.js b/.eslintrc.js index 4594b11a..497386ba 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,4 @@ module.exports = { extends: [require.resolve('@umijs/fabric/dist/eslint')], + rules: { 'import/no-extraneous-dependencies': 0 }, }; diff --git a/docs/demo/single.tsx b/docs/demo/single.tsx index a40a00a8..3e18d781 100644 --- a/docs/demo/single.tsx +++ b/docs/demo/single.tsx @@ -1,7 +1,13 @@ import React, { useRef, useState } from 'react'; import { Button, Drawer, Icon, Tag } from 'antd'; // eslint-disable-next-line import/no-unresolved -import ProTable, { ProColumns, TableDropdown, ActionType } from '@ant-design/pro-table'; +import ProTable, { + ProColumns, + TableDropdown, + IntlProvider, + enUSIntl, + ActionType, +} from '@ant-design/pro-table'; // eslint-disable-next-line import/no-extraneous-dependencies import request from 'umi-request'; @@ -162,47 +168,49 @@ export default () => { 重置 - - columns={columns} - actionRef={actionRef} - request={async (params = {}) => { - const data = await request( - 'https://api.github.com/repos/ant-design/ant-design-pro/issues', - { - params: { - ...params, - page: params.current, - per_page: params.pageSize, + + + columns={columns} + actionRef={actionRef} + request={async (params = {}) => { + const data = await request( + 'https://api.github.com/repos/ant-design/ant-design-pro/issues', + { + params: { + ...params, + page: params.current, + per_page: params.pageSize, + }, }, - }, - ); - const totalObj = await request( - 'https://api.github.com/repos/ant-design/ant-design-pro/issues?per_page=1', - { - params, - }, - ); - return { - data, - page: params.current, - success: true, - total: ((totalObj[0] || { number: 0 }).number - 56) as number, - }; - }} - rowKey="id" - pagination={{ - showSizeChanger: true, - }} - dateFormatter="string" - headerTitle="基础 Table" - params={{ state: 'all' }} - toolBarRender={() => [ - , - ]} - /> + ); + const totalObj = await request( + 'https://api.github.com/repos/ant-design/ant-design-pro/issues?per_page=1', + { + params, + }, + ); + return { + data, + page: params.current, + success: true, + total: ((totalObj[0] || { number: 0 }).number - 56) as number, + }; + }} + rowKey="id" + pagination={{ + showSizeChanger: true, + }} + dateFormatter="string" + headerTitle="基础 Table" + params={{ state: 'all' }} + toolBarRender={() => [ + , + ]} + /> + ); }; diff --git a/src/Form/index.tsx b/src/Form/index.tsx index de1efcd6..1b553483 100644 --- a/src/Form/index.tsx +++ b/src/Form/index.tsx @@ -6,6 +6,7 @@ import RcResizeObserver from 'rc-resize-observer'; import { FormComponentProps } from 'antd/lib/form'; import { ConfigConsumer, ConfigConsumerProps } from 'antd/lib/config-provider'; import { parsingValueEnumToArray, useDeepCompareEffect, useMedia } from '../component/util'; +import { useIntl, IntlType } from '../component/intlContext'; import Container from '../container'; import { ProColumns } from '../index'; import './index.less'; @@ -50,6 +51,7 @@ const FromInputRender: React.FC<{ value?: any; onChange?: (value: any) => void; }> = React.forwardRef(({ item, ...rest }, ref: any) => { + const intl = useIntl(); /** * 自定义 render */ @@ -60,7 +62,12 @@ const FromInputRender: React.FC<{ const { valueEnum } = item; if (valueEnum) { return ( - {parsingValueEnumToArray(valueEnum).map(({ value, text }) => ( {text} @@ -69,13 +76,19 @@ const FromInputRender: React.FC<{ ); } - return ; + return ( + + ); } if (item.valueType === 'date') { return ( (value ? value.replace(/\$\s?|(,*)/g, '') : '')} - placeholder="请输入" + placeholder={intl.getMessage('tableFrom.selectPlaceholder', '请选择')} precision={2} style={{ width: '100%', @@ -166,11 +179,26 @@ const genValue = (value: any, dateFormatter?: string | boolean, proColumnsMap?: return tmpValue; }; -const getDefaultSearch = (search?: boolean | SearchConfig): Required => { +const getDefaultSearch = ( + search: boolean | SearchConfig | undefined, + intl: IntlType, +): Required => { + const config = { + collapseRender: (collapsed: boolean) => { + if (collapsed) { + return intl.getMessage('tableFrom.collapsed', '展开'); + } + return intl.getMessage('tableFrom.expand', '收起'); + }, + searchText: intl.getMessage('tableFrom.search', defaultSearch.searchText), + resetText: intl.getMessage('tableFrom.reset', defaultSearch.resetText), + span: defaultColConfig, + }; + if (search === undefined || search === true) { - return defaultSearch; + return config; } - return { ...defaultSearch, ...search } as Required; + return { ...config, ...search } as Required; }; const getSpanConfig = ( @@ -193,7 +221,8 @@ const FormSearch = ({ dateFormatter = 'string', search: propsSearch, }: FormItem) => { - const searchConfig = getDefaultSearch(propsSearch); + const intl = useIntl(); + const searchConfig = getDefaultSearch(propsSearch, intl); const { span, searchText, resetText, collapseRender } = searchConfig; const counter = Container.useContainer(); diff --git a/src/Table.tsx b/src/Table.tsx index 6945c2f3..f935876f 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -6,6 +6,8 @@ import classNames from 'classnames'; import useMergeValue from 'use-merge-value'; import moment from 'moment'; import { ColumnProps, PaginationConfig, TableProps, TableRowSelection } from 'antd/es/table'; +import { ConfigConsumer, ConfigConsumerProps } from 'antd/lib/config-provider'; +import { IntlProvider, IntlConsumer } from './component/intlContext'; import useFetchData, { UseFetchDataAction, RequestData } from './useFetchData'; import Container, { ColumnsMapItem } from './container'; import IndexColumn from './component/indexColumn'; @@ -443,7 +445,11 @@ const genColumnList = ( * 更快 更好 更方便 * @param props */ -const ProTable = (props: ProTableProps) => { +const ProTable = ( + props: ProTableProps & { + defaultClassName: string; + }, +) => { const { request, className: propsClassName, @@ -465,6 +471,7 @@ const ProTable = (props: ProTableProps) => { rowSelection: propsRowSelection = false, beforeSearchSubmit = (searchParams: any) => searchParams, tableAlertRender, + defaultClassName, ...reset } = props; @@ -629,7 +636,7 @@ const ProTable = (props: ProTableProps) => { return ; } - const className = classNames('ant-pro-table', propsClassName); + const className = classNames(defaultClassName, propsClassName); return (
@@ -711,7 +718,17 @@ const ProTable = (props: ProTableProps) => { */ const ProviderWarp = (props: ProTableProps) => ( - + + {({ getPrefixCls }: ConfigConsumerProps) => ( + + {value => ( + + + + )} + + )} + ); diff --git a/src/component/columnSetting/index.tsx b/src/component/columnSetting/index.tsx index 38439d50..0f853a76 100644 --- a/src/component/columnSetting/index.tsx +++ b/src/component/columnSetting/index.tsx @@ -7,6 +7,7 @@ import Backend from 'react-dnd-html5-backend'; import Container, { ColumnsMapItem } from '../../container'; import { ProColumns } from '../../Table'; import DnDItem from './DndItem'; +import { useIntl } from '../intlContext'; import './index.less'; import { useDeepCompareEffect } from '../util'; @@ -52,6 +53,7 @@ const CheckboxListItem: React.FC<{ fixed?: boolean | 'left' | 'right'; setColumnsMap: (map: { [key: string]: ColumnsMapItem }) => void; }> = ({ columnKey, className, columnsMap, title, setColumnsMap, fixed }) => { + const intl = useIntl(); const config = columnsMap[columnKey || 'null'] || { show: true }; return ( @@ -71,20 +73,30 @@ const CheckboxListItem: React.FC<{ {title} - + - + @@ -159,7 +171,7 @@ const GroupCheckboxList: React.FC<{ const rightList: ProColumns[] = []; const leftList: ProColumns[] = []; const list: ProColumns[] = []; - + const intl = useIntl(); localColumns.forEach(item => { const { fixed } = item; if (fixed === 'left') { @@ -176,15 +188,23 @@ const GroupCheckboxList: React.FC<{ const showLeft = leftList && leftList.length > 0; return (
- + {/* 如果没有任何固定,不需要显示title */} - +
); }; @@ -217,6 +237,9 @@ const ColumnSetting = (props: ColumnSettingProps) => { const selectKeys = Object.values(columnsMap).filter(value => !value || value.show !== false); const indeterminate = selectKeys.length > 0 && selectKeys.length !== localColumns.length; + + const intl = useIntl(); + return ( {({ getPrefixCls }: ConfigConsumerProps) => { @@ -245,7 +268,7 @@ const ColumnSetting = (props: ColumnSettingProps) => { } }} > - 列展示 + {intl.getMessage('tableToolBar.columnDisplay', '列展示')} { @@ -253,7 +276,7 @@ const ColumnSetting = (props: ColumnSettingProps) => { setColumns(initialColumns.current || []); }} > - 重置 + {intl.getMessage('tableToolBar.reset', '重置')}
} @@ -262,7 +285,7 @@ const ColumnSetting = (props: ColumnSettingProps) => { content={} > ((document.getElementById('ant-design-pro-table') || document.body) as any) as HTMLElement diff --git a/src/component/intlContext/index.tsx b/src/component/intlContext/index.tsx new file mode 100644 index 00000000..fe67b6de --- /dev/null +++ b/src/component/intlContext/index.tsx @@ -0,0 +1,53 @@ +import React, { useContext } from 'react'; +import zhCN from '../../locale/zh_CN'; +import enUS from '../../locale/en_US'; + +export interface IntlType { + locale: string; + getMessage: (id: string, defaultMessage: string) => string; +} + +function get(source: object, path: string, defaultValue?: string): string | undefined { + // a[3].b -> a.3.b + const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.'); + let result = source; + let message = defaultValue; + // eslint-disable-next-line no-restricted-syntax + for (const p of paths) { + message = Object(result)[p]; + result = Object(result)[p]; + if (message === undefined) { + return defaultValue; + } + } + return message; +} + +/** + * 创建一个操作函数 + * @param locale + * @param localeMap + */ +const createIntl = (locale: string, localeMap: { [key: string]: any }): IntlType => ({ + getMessage: (id: string, defaultMessage: string) => + get(localeMap, id, defaultMessage) || defaultMessage, + locale, +}); + +const zhCNIntl = createIntl('zh_CN', zhCN); +const enUSIntl = createIntl('en_US', enUS); + +export { enUSIntl, zhCNIntl }; + +const IntlContext = React.createContext(zhCNIntl); + +const { Consumer: IntlConsumer, Provider: IntlProvider } = IntlContext; + +export { IntlConsumer, IntlProvider, createIntl }; + +export function useIntl(): IntlType { + const intl = useContext(IntlContext); + return intl; +} + +export default IntlContext; diff --git a/src/component/toolBar/FullscreenIcon.tsx b/src/component/toolBar/FullscreenIcon.tsx index 86326127..1914248e 100644 --- a/src/component/toolBar/FullscreenIcon.tsx +++ b/src/component/toolBar/FullscreenIcon.tsx @@ -1,8 +1,10 @@ import React, { useEffect, useState } from 'react'; import { FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons'; import { Tooltip } from 'antd'; +import { useIntl } from '../intlContext'; const FullScreenIcon = () => { + const intl = useIntl(); const [fullscreen, setFullscreen] = useState(false); useEffect(() => { document.onfullscreenchange = () => { @@ -11,7 +13,7 @@ const FullScreenIcon = () => { }, []); return fullscreen ? ( ((document.getElementById('ant-design-pro-table') || document.body) as any) as HTMLElement } @@ -20,7 +22,7 @@ const FullScreenIcon = () => { ) : ( ((document.getElementById('ant-design-pro-table') || document.body) as any) as HTMLElement } diff --git a/src/component/toolBar/index.tsx b/src/component/toolBar/index.tsx index fe2aa4b3..549741a7 100644 --- a/src/component/toolBar/index.tsx +++ b/src/component/toolBar/index.tsx @@ -3,7 +3,7 @@ import { ReloadOutlined, SettingOutlined } from '@ant-design/icons'; import { Divider, Tooltip } from 'antd'; import { ConfigConsumer, ConfigConsumerProps } from 'antd/lib/config-provider/context'; import ColumnSetting from '../columnSetting'; - +import { useIntl, IntlType } from '../intlContext'; import { UseFetchDataAction, RequestData } from '../../useFetchData'; import './index.less'; @@ -33,20 +33,20 @@ export interface ToolBarProps { className?: string; } -const buttonText = { +const getButtonText = (intl: IntlType) => ({ fullScreen: { - text: '全屏', + text: intl.getMessage('tableToolBar.fullScreen', '全屏'), icon: , }, reload: { - text: '刷新', + text: intl.getMessage('tableToolBar.reload', '刷新'), icon: , }, setting: { - text: '列设置', + text: intl.getMessage('tableToolBar.columnSetting', '列设置'), icon: , }, -}; +}); /** * 渲染默认的 工具栏 @@ -60,6 +60,7 @@ const renderDefaultOption = ( fullScreen: OptionsType; reload: OptionsType; setting: OptionsType; + intl: IntlType; }, ) => options && @@ -87,7 +88,7 @@ const renderDefaultOption = ( ); } - const optionItem = buttonText[key]; + const optionItem = getButtonText(defaultOptions.intl)[key]; if (optionItem) { return ( ({ selectedRows, className, }: ToolBarProps) => { + const intl = useIntl(); const optionDom = renderDefaultOption(options, `${className}-item-icon`, { fullScreen: () => action.fullScreen && action.fullScreen(), reload: () => action.reload(), setting: true, + intl, }) || []; // 操作列表 const actions = toolBarRender ? toolBarRender(action, { selectedRowKeys, selectedRows }) : []; diff --git a/src/index.tsx b/src/index.tsx index 35ab4ef0..d103a291 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,6 +3,7 @@ import IndexColumn from './component/indexColumn'; import { RequestData } from './useFetchData'; import TableDropdown from './component/dropdown'; import TableStatus from './component/status'; +import { IntlProvider, IntlConsumer, IntlType, zhCNIntl, enUSIntl } from './component/intlContext'; import Search from './Form'; export { @@ -15,6 +16,11 @@ export { TableDropdown, TableStatus, Search, + IntlProvider, + IntlConsumer, + IntlType, + zhCNIntl, + enUSIntl, }; export default ProTable; diff --git a/src/locale/en_US.tsx b/src/locale/en_US.tsx new file mode 100644 index 00000000..410bdeb2 --- /dev/null +++ b/src/locale/en_US.tsx @@ -0,0 +1,24 @@ +export default { + tableFrom: { + search: 'Query', + reset: 'Reset', + collapsed: 'Expand', + expand: 'Collapse', + inputPlaceholder: 'Please enter', + selectPlaceholder: 'Please select', + }, + tableToolBar: { + leftPin: 'Pin to left', + rightPin: 'Pin to right', + noPin: 'Unpinned', + leftFixedTitle: 'Fixed the left', + rightFixedTitle: 'Fixed the right', + noFixedTitle: 'Not Fixed', + reset: 'Reset', + columnDisplay: 'Column Display', + columnSetting: 'Settings', + fullScreen: 'Full Screen', + exitFullScreen: 'Exit Full Screen', + reload: 'Refresh', + }, +}; diff --git a/src/locale/zh_CN.tsx b/src/locale/zh_CN.tsx new file mode 100644 index 00000000..49222fe6 --- /dev/null +++ b/src/locale/zh_CN.tsx @@ -0,0 +1,24 @@ +export default { + tableFrom: { + search: '查询', + reset: '重置', + collapsed: '展开', + expand: '收起', + inputPlaceholder: '请输入', + selectPlaceholder: '请选择', + }, + tableToolBar: { + leftPin: '固定到左边', + rightPin: '固定到右边', + noPin: '取消固定', + leftFixedTitle: '固定在左侧', + rightFixedTitle: '固定在右侧', + noFixedTitle: '不固定', + reset: '重置', + columnDisplay: '列展示', + columnSetting: '列设置', + fullScreen: '全屏', + exitFullScreen: '退出全屏', + reload: '刷新', + }, +};