From 0d95ee7757c731d8f34ad4b61a24da2ac014ee11 Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Mon, 1 Jun 2020 20:02:36 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E5=B9=B2=E6=8E=89=20eslint=20=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderers/Form/Repeat.tsx | 1 - src/renderers/Video.tsx | 1 - src/utils/resize-sensor.ts | 13 ++++++------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/renderers/Form/Repeat.tsx b/src/renderers/Form/Repeat.tsx index 626877064..fcef034cc 100644 --- a/src/renderers/Form/Repeat.tsx +++ b/src/renderers/Form/Repeat.tsx @@ -4,7 +4,6 @@ * * 不建议用,以后可能会删除。可以直接用组合出来,不需要新建一个组件。 */ -/* eslint fecs-indent: [0, "space", 2, 2] */ import React from 'react'; import cx from 'classnames'; diff --git a/src/renderers/Video.tsx b/src/renderers/Video.tsx index 51174c14e..900a26303 100644 --- a/src/renderers/Video.tsx +++ b/src/renderers/Video.tsx @@ -2,7 +2,6 @@ * @file video * @author fex */ -/* eslint fecs-indent: [0, "space", 2, 2] */ import React from 'react'; diff --git a/src/utils/resize-sensor.ts b/src/utils/resize-sensor.ts index 2404b6cea..472bee2a7 100644 --- a/src/utils/resize-sensor.ts +++ b/src/utils/resize-sensor.ts @@ -2,7 +2,6 @@ * @file resize-sensor.js. * @author fex */ -/* eslint-disable */ class EventQueue { q: Array = []; @@ -70,7 +69,7 @@ function attachResizeEvent(element: HTMLElement, resized: Function) { let lastWidth: number, lastHeight: number; - const reset = function() { + const reset = function () { expandChild.style.width = expand.offsetWidth + 10 + 'px'; expandChild.style.height = expand.offsetHeight + 10 + 'px'; expand.scrollLeft = expand.scrollWidth; @@ -83,13 +82,13 @@ function attachResizeEvent(element: HTMLElement, resized: Function) { reset(); - let changed = function() { + let changed = function () { if ((element as any).resizedAttached) { (element as any).resizedAttached.call(); } }; - let addEvent = function(el: HTMLElement, name: string, cb: Function) { + let addEvent = function (el: HTMLElement, name: string, cb: Function) { if ((el as any).attachEvent) { (el as any).attachEvent('on' + name, cb); } else { @@ -97,7 +96,7 @@ function attachResizeEvent(element: HTMLElement, resized: Function) { } }; - let onScroll = function(e: Event) { + let onScroll = function (e: Event) { if ( element.offsetWidth != lastWidth || element.offsetHeight != lastHeight @@ -132,7 +131,7 @@ export function resizeSensor( once: boolean = false ) { if (once) { - attachResizeEvent(element, function(this: any) { + attachResizeEvent(element, function (this: any) { callback.apply(this, arguments); detach(element); }); @@ -142,7 +141,7 @@ export function resizeSensor( attachResizeEvent(element, callback); let detached = false; - return function() { + return function () { if (detached) return; detached = true; detach(element); From af3f40021f7ce285843ec5b3a7a499512ee1ac59 Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Mon, 1 Jun 2020 20:54:41 +0800 Subject: [PATCH 02/10] i18n draft --- src/locale.tsx | 108 ++++++++++++++++++++++++++++++++++++++++++++ src/locale/en_UK.ts | 0 2 files changed, 108 insertions(+) create mode 100644 src/locale.tsx create mode 100644 src/locale/en_UK.ts diff --git a/src/locale.tsx b/src/locale.tsx new file mode 100644 index 000000000..f6a3aa752 --- /dev/null +++ b/src/locale.tsx @@ -0,0 +1,108 @@ +// 主题管理 +import cx from 'classnames'; +import React from 'react'; +import hoistNonReactStatic from 'hoist-non-react-statics'; +import {ExtractProps, Omit} from './types'; + +type translateFn = (str: string, ...args: any[]) => string; + +interface LocaleConfig { + [propsName: string]: string; +} + +let defaultLocale: string = ''; + +const locales: { + [propName: string]: LocaleConfig; +} = {}; + +export function register(name: string, config: LocaleConfig) { + locales[name] = config; +} + +const fns: { + [propName: string]: translateFn; +} = {}; + +// todo 支持参数 +function format(str: string, ...args: any[]) { + return str; +} + +export function makeTranslator(locale?: string): translateFn { + if (locale && fns[locale]) { + return fns[locale]; + } + + const fn = (str: string, ...args: any[]) => { + if (!str || typeof str !== 'string') { + return str; + } + + const dict = locales[locale!] || locales[defaultLocale]; + return format(dict[str] || str, ...args); + }; + + locale && (fns[locale] = fn); + return fn; +} + +export function setDefaultLocale(loacle: string) { + defaultLocale = loacle; +} + +export interface LocaleProps { + locale: string; + translate: translateFn; +} + +export const LocaleContext = React.createContext('locale'); + +export function localeable< + T extends React.ComponentType> +>(ComposedComponent: T) { + type ComposedProps = JSX.LibraryManagedAttributes>; + type Props = Omit & { + locale?: string; + translate: (str: string, ...args: any[]) => string; + }; + + const result = hoistNonReactStatic( + class extends React.Component { + static displayName = `I18N(${ + ComposedComponent.displayName || ComposedComponent.name + })`; + static contextType = LocaleContext; + static ComposedComponent = ComposedComponent; + + render() { + const locale: string = + this.props.locale || this.context || defaultLocale; + const translate = makeTranslator(locale); + const injectedProps: { + locale: string; + translate: translateFn; + } = { + locale, + translate + }; + + return ( + + + + ); + } + }, + ComposedComponent + ); + + return result as typeof result & { + ComposedComponent: T; + }; +} diff --git a/src/locale/en_UK.ts b/src/locale/en_UK.ts new file mode 100644 index 000000000..e69de29bb From 95bc3e802967566715beff7c1cd95269d1920850 Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Tue, 2 Jun 2020 10:56:16 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Table=20=E7=9A=84=20?= =?UTF-8?q?footable=20=E5=B1=95=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderers/Table.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderers/Table.tsx b/src/renderers/Table.tsx index a39d50249..a5009a2b9 100644 --- a/src/renderers/Table.tsx +++ b/src/renderers/Table.tsx @@ -1767,7 +1767,7 @@ export default class Table extends React.Component { ? filter(rowClassNameExpr, item.data) : rowClassName )} - columns={columns} + columns={store.footableColumns} renderCell={this.renderCell} render={render} onAction={onAction} From 654bafc127d90d3c1cf88bb10019dc79fdd8f0cf Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Tue, 2 Jun 2020 11:02:43 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E5=85=88=E5=88=87=E6=88=90=20typescript@?= =?UTF-8?q?3.8.x?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 ++- package.json | 6 +++--- publish.sh | 2 +- src/components/AssociatedCheckboxes.tsx | 6 +++--- src/components/ListRadios.tsx | 2 +- src/components/TreeRadios.tsx | 2 +- types/uncontrollable/index.d.ts | 11 +++++++---- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f89ed5f1d..6a30c1d58 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "editor.formatOnSave": true + "editor.formatOnSave": true, + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/package.json b/package.json index 5a549dfcc..2077e2222 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "@types/classnames": "^2.2.3", "@types/dom-helpers": "^3.4.1", "@types/history": "^4.6.0", - "@types/hoist-non-react-statics": "^3.0.1", + "@types/hoist-non-react-statics": "^3.3.1", "@types/jest": "^24.0.11", "@types/jquery": "^3.3.1", "@types/lodash": "^4.14.76", @@ -89,7 +89,7 @@ "@types/pretty-bytes": "^4.0.0", "@types/prop-types": "^15.5.2", "@types/qs": "^6.5.1", - "@types/react": "^16.8.1", + "@types/react": "^16.9.35", "@types/react-addons-update": "^0.14.19", "@types/react-color": "^2.13.3", "@types/react-cropper": "^0.10.1", @@ -139,7 +139,7 @@ "react-testing-library": "6.0.4", "strip-json-comments": "^2.0.1", "ts-jest": "^24.0.0", - "typescript": "^3.9.2" + "typescript": "^3.8.3" }, "jest": { "testEnvironment": "jsdom", diff --git a/publish.sh b/publish.sh index c8f1bdcfc..7e641f4a6 100644 --- a/publish.sh +++ b/publish.sh @@ -11,7 +11,7 @@ rm -rf lib/node_modules rm -rf sdk && fis3 release publish-sdk -c # 生成 .d.ts 文件 -tsc --allowJs --declaration +./node_modules/.bin/tsc --allowJs --declaration cd output diff --git a/src/components/AssociatedCheckboxes.tsx b/src/components/AssociatedCheckboxes.tsx index cfb524efd..279de9a60 100644 --- a/src/components/AssociatedCheckboxes.tsx +++ b/src/components/AssociatedCheckboxes.tsx @@ -58,7 +58,7 @@ export class AssociatedCheckboxes extends Checkboxes< const selectdOption = ListRadios.resolveSelected( leftValue, options, - option => option.ref + (option: Option) => option.ref ); if (selectdOption && onDeferLoad && selectdOption.defer) { @@ -80,7 +80,7 @@ export class AssociatedCheckboxes extends Checkboxes< const selectdOption = ListRadios.resolveSelected( value, options, - option => option.ref + (option: Option) => option.ref ); if (selectdOption && onDeferLoad && selectdOption.defer) { @@ -111,7 +111,7 @@ export class AssociatedCheckboxes extends Checkboxes< const selectdOption = ListRadios.resolveSelected( this.state.leftValue, options, - option => option.ref + (option: Option) => option.ref ); return ( diff --git a/src/components/ListRadios.tsx b/src/components/ListRadios.tsx index 58efd6bd2..74377c4a0 100644 --- a/src/components/ListRadios.tsx +++ b/src/components/ListRadios.tsx @@ -24,7 +24,7 @@ export interface ListRadiosProps extends ThemeProps { export class ListRadios< T extends ListRadiosProps = ListRadiosProps, - S = any + S = {} > extends React.Component { selected: Option | undefined | null; diff --git a/src/components/TreeRadios.tsx b/src/components/TreeRadios.tsx index 3e0190a65..c7803aa47 100644 --- a/src/components/TreeRadios.tsx +++ b/src/components/TreeRadios.tsx @@ -8,7 +8,7 @@ import Spinner from './Spinner'; import {ListRadiosProps, ListRadios} from './ListRadios'; export interface TreeRadiosProps extends ListRadiosProps { - expand?: 'all' | 'first' | 'root' | 'none'; + expand: 'all' | 'first' | 'root' | 'none'; } export interface TreeRadiosState { diff --git a/types/uncontrollable/index.d.ts b/types/uncontrollable/index.d.ts index fb57b7abc..ee4b35a9d 100644 --- a/types/uncontrollable/index.d.ts +++ b/types/uncontrollable/index.d.ts @@ -1,7 +1,10 @@ declare module 'uncontrollable' { - function uncontrollable, P extends { - [propName:string]: any - }>(arg:T, config:P):T; + function uncontrollable< + T extends Raect.ComponentType, + P extends { + [propName: string]: any; + } + >(arg: T, config: P): T; - export = uncontrollable; + export = uncontrollable; } From f46a1362b98e7f57e1389057c0037ec6846e5d45 Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Tue, 2 Jun 2020 20:41:51 +0800 Subject: [PATCH 05/10] =?UTF-8?q?Locale=20=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/components/App.jsx | 40 ++++++- examples/components/SchemaRender.jsx | 5 +- src/components/Alert.tsx | 24 ++-- src/components/AssociatedCheckboxes.tsx | 18 +-- src/components/ChainedCheckboxes.tsx | 13 +- src/components/Checkboxes.tsx | 15 ++- src/components/ColorPicker.tsx | 18 +-- src/components/DatePicker.tsx | 84 +++++++------ src/components/DateRangePicker.tsx | 42 +++---- src/components/ImageGallery.tsx | 12 +- src/components/ListCheckboxes.tsx | 14 ++- src/components/ListMenu.tsx | 9 +- src/components/ListRadios.tsx | 14 ++- src/components/LocationPicker.tsx | 22 ++-- src/components/Modal.tsx | 65 +++++----- src/components/ResultBox.tsx | 18 ++- src/components/ResultList.tsx | 10 +- src/components/SearchBox.tsx | 18 +-- src/components/Select.tsx | 31 ++--- src/components/TableCheckboxes.tsx | 14 ++- src/components/TabsTransfer.tsx | 10 +- src/components/Tinymce.tsx | 7 +- src/components/Transfer.tsx | 32 +++-- src/components/Tree.tsx | 32 ++--- src/components/TreeCheckboxes.tsx | 16 ++- src/components/TreeRadios.tsx | 5 +- src/components/calendar/DaysView.tsx | 20 +++- src/components/calendar/MonthsView.tsx | 13 +- src/components/calendar/YearsView.tsx | 10 +- src/factory.tsx | 91 ++++++++------ src/locale.tsx | 62 ++++++---- src/locale/en.ts | 153 ++++++++++++++++++++++++ src/locale/en_UK.ts | 0 src/renderers/Action.tsx | 1 - src/renderers/CRUD.tsx | 39 +++--- src/renderers/Cards.tsx | 19 ++- src/renderers/Copyable.tsx | 5 +- src/renderers/Date.tsx | 5 +- src/renderers/Dialog.tsx | 17 +-- src/renderers/Drawer.tsx | 6 +- src/renderers/Form/Checkboxes.tsx | 7 +- src/renderers/Form/City.tsx | 5 +- src/renderers/Form/Combo.tsx | 86 +++++++------ src/renderers/Form/Date.tsx | 2 + src/renderers/Form/File.tsx | 74 +++++++----- src/renderers/Form/IconPicker.tsx | 5 +- src/renderers/Form/Image.tsx | 114 ++++++++++-------- src/renderers/Form/Matrix.tsx | 4 +- src/renderers/Form/NestedSelect.tsx | 5 +- src/renderers/Form/Options.tsx | 23 ++-- src/renderers/Form/Picker.tsx | 9 +- src/renderers/Form/Radios.tsx | 5 +- src/renderers/Form/Repeat.tsx | 14 ++- src/renderers/Form/RichText.tsx | 20 +++- src/renderers/Form/SubForm.tsx | 20 ++-- src/renderers/Form/Table.tsx | 81 ++++++++----- src/renderers/Form/Tag.tsx | 9 +- src/renderers/Form/Text.tsx | 5 +- src/renderers/Form/Tree.tsx | 5 +- src/renderers/Form/TreeSelect.tsx | 12 +- src/renderers/Form/index.tsx | 28 +++-- src/renderers/Image.tsx | 14 +-- src/renderers/Link.tsx | 5 +- src/renderers/List.tsx | 19 ++- src/renderers/Nav.tsx | 4 +- src/renderers/PopOver.tsx | 4 +- src/renderers/QuickEdit.tsx | 6 +- src/renderers/Service.tsx | 6 +- src/renderers/Table.tsx | 50 +++++--- src/renderers/Wizard.tsx | 11 +- src/theme.tsx | 18 +-- src/types.ts | 12 +- 72 files changed, 1087 insertions(+), 624 deletions(-) create mode 100644 src/locale/en.ts delete mode 100644 src/locale/en_UK.ts diff --git a/examples/components/App.jsx b/examples/components/App.jsx index d98c9bc75..fada1e56d 100644 --- a/examples/components/App.jsx +++ b/examples/components/App.jsx @@ -4,6 +4,7 @@ import Layout from '../../src/components/Layout'; import AsideNav from '../../src/components/AsideNav'; import {AlertComponent, ToastComponent} from '../../src/components/index'; import {mapTree} from '../../src/utils/helper'; +import '../../src/locale/en'; import { Router, Route, @@ -560,6 +561,18 @@ const themes = [ } ]; +const locales = [ + { + label: '默认', + value: 'zh-cn' + }, + + { + label: 'English', + value: 'en' + } +]; + @withRouter export class App extends React.PureComponent { state = { @@ -568,7 +581,8 @@ export class App extends React.PureComponent { headerVisible: true, themeIndex: 0, themes: themes, - theme: themes[localStorage.getItem('themeIndex') || 0] + theme: themes[localStorage.getItem('themeIndex') || 0], + locale: localStorage.getItem('locale') || '' }; constructor(props) { @@ -767,10 +781,27 @@ export class App extends React.PureComponent { +
+ 语言: + { + - - + + {React.cloneElement(this.props.children, { ...this.props.children.props, setAsideFolded: this.setAsideFolded, setHeaderVisible: this.setHeaderVisible, theme: theme.value, - classPrefix: theme.ns + classPrefix: theme.ns, + locale: this.state.locale })} ); diff --git a/examples/components/SchemaRender.jsx b/examples/components/SchemaRender.jsx index e7e0a39c5..5509f1b2a 100644 --- a/examples/components/SchemaRender.jsx +++ b/examples/components/SchemaRender.jsx @@ -161,13 +161,14 @@ export default function (schema) { } renderSchema() { - const {router, location, theme} = this.props; + const {router, location, theme, locale} = this.props; return render( schema, { location, - theme + theme, + locale }, this.env ); diff --git a/src/components/Alert.tsx b/src/components/Alert.tsx index 958efd428..3b4ba396d 100644 --- a/src/components/Alert.tsx +++ b/src/components/Alert.tsx @@ -7,18 +7,16 @@ import React from 'react'; import {render} from 'react-dom'; import Modal from './Modal'; import Button from './Button'; -import {ClassNamesFn, themeable} from '../theme'; +import {ClassNamesFn, themeable, ThemeProps} from '../theme'; +import {LocaleProps, localeable} from '../locale'; -export interface AlertProps { +export interface AlertProps extends ThemeProps, LocaleProps { container?: any; confirmText?: string; cancelText?: string; title?: string; confirmBtnLevel?: string; alertBtnLevel?: string; - classPrefix: string; - classnames: ClassNamesFn; - theme?: string; } export interface AlertState { @@ -37,7 +35,7 @@ export class Alert extends React.Component { const container = document.body; const div = document.createElement('div'); container.appendChild(div); - render(, div); + render(, div); } return Alert.instance; @@ -150,6 +148,8 @@ export class Alert extends React.Component { classnames: cx, classPrefix } = this.props; + const __ = this.props.translate; + return ( { ref={this.modalRef} >
-
{this.state.title || title}
+
+ {__(this.state.title || title)} +
{this.state.confirm ? ( - + ) : null}
@@ -189,5 +191,5 @@ export const confirm: ( confirmText?: string ) => Promise = (content, title, confirmText) => Alert.getInstance().confirm(content, title, confirmText); -export const ThemedAlert = themeable(Alert); -export default ThemedAlert; +export const FinnalAlert = themeable(localeable(Alert)); +export default FinnalAlert; diff --git a/src/components/AssociatedCheckboxes.tsx b/src/components/AssociatedCheckboxes.tsx index 279de9a60..3bec02551 100644 --- a/src/components/AssociatedCheckboxes.tsx +++ b/src/components/AssociatedCheckboxes.tsx @@ -19,6 +19,7 @@ import ChainedCheckboxes from './ChainedCheckboxes'; import Spinner from './Spinner'; import TreeRadios from './TreeRadios'; import {Icon} from './icons'; +import {localeable} from '../locale'; export interface AssociatedCheckboxesProps extends CheckboxesProps { leftOptions: Options; @@ -113,6 +114,7 @@ export class AssociatedCheckboxes extends Checkboxes< options, (option: Option) => option.ref ); + const __ = this.props.translate; return (
@@ -155,9 +157,9 @@ export class AssociatedCheckboxes extends Checkboxes<
{selectdOption.loading ? ( -

加载中

+

{__('加载中')}

) : ( -

点击刷新重新加载

+

{__('点击刷新重新加载')}

)}
) : rightMode === 'table' ? ( @@ -193,12 +195,12 @@ export class AssociatedCheckboxes extends Checkboxes< ) ) : (
- 配置错误,选项无法与左侧选项对应 + {__('配置错误,选项无法与左侧选项对应')}
) ) : (
- 请先选择左侧数据 + {__('请先选择左侧数据')}
)}
@@ -208,7 +210,9 @@ export class AssociatedCheckboxes extends Checkboxes< } export default themeable( - uncontrollable(AssociatedCheckboxes, { - value: 'onChange' - }) + localeable( + uncontrollable(AssociatedCheckboxes, { + value: 'onChange' + }) + ) ); diff --git a/src/components/ChainedCheckboxes.tsx b/src/components/ChainedCheckboxes.tsx index 1a75915f0..04080d2f1 100644 --- a/src/components/ChainedCheckboxes.tsx +++ b/src/components/ChainedCheckboxes.tsx @@ -10,6 +10,7 @@ import {Option} from './Select'; import {getTreeDepth} from '../utils/helper'; import times from 'lodash/times'; import Spinner from './Spinner'; +import {localeable} from '../locale'; export interface ChainedCheckboxesProps extends CheckboxesProps { defaultSelectedIndex?: string; @@ -188,13 +189,15 @@ export class ChainedCheckboxes extends Checkboxes< ); } + const __ = this.props.translate; + return (
{body && body.length ? ( body ) : (
- {placeholder} + {__(placeholder)}
)}
@@ -203,7 +206,9 @@ export class ChainedCheckboxes extends Checkboxes< } export default themeable( - uncontrollable(ChainedCheckboxes, { - value: 'onChange' - }) + localeable( + uncontrollable(ChainedCheckboxes, { + value: 'onChange' + }) + ) ); diff --git a/src/components/Checkboxes.tsx b/src/components/Checkboxes.tsx index 41b46ebab..538d48753 100644 --- a/src/components/Checkboxes.tsx +++ b/src/components/Checkboxes.tsx @@ -13,9 +13,10 @@ import {Option, value2array, Options} from './Select'; import find from 'lodash/find'; import {autobind, findTree} from '../utils/helper'; import isEqual from 'lodash/isEqual'; +import {LocaleProps, localeable} from '../locale'; // import isPlainObject from 'lodash/isPlainObject'; -export interface CheckboxesProps extends ThemeProps { +export interface CheckboxesProps extends ThemeProps, LocaleProps { options: Options; className?: string; placeholder?: string; @@ -115,6 +116,8 @@ export class Checkboxes< itemRender } = this.props; + const __ = this.props.translate; + let valueArray = Checkboxes.value2array(value, options, option2value); let body: Array = []; @@ -142,14 +145,16 @@ export class Checkboxes< inline ? 'Checkboxes--inline' : '' )} > - {body && body.length ? body :
{placeholder}
} + {body && body.length ? body :
{__(placeholder)}
} ); } } export default themeable( - uncontrollable(Checkboxes, { - value: 'onChange' - }) + localeable( + uncontrollable(Checkboxes, { + value: 'onChange' + }) + ) ); diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index 5528db2f9..b36c31da4 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -12,10 +12,11 @@ import {Icon} from './icons'; import Overlay from './Overlay'; import uncontrollable from 'uncontrollable'; import PopOver from './PopOver'; -import {ClassNamesFn, themeable} from '../theme'; +import {ClassNamesFn, themeable, ThemeProps} from '../theme'; import {autobind} from '../utils/helper'; +import {localeable, LocaleProps} from '../locale'; -export interface ColorProps { +export interface ColorProps extends LocaleProps, ThemeProps { placeholder?: string; format: string; // closeOnSelect:boolean; @@ -25,8 +26,6 @@ export interface ColorProps { popOverContainer?: any; placement?: string; value: any; - classPrefix: string; - classnames: ClassNamesFn; onChange: (value: any) => void; presetColors?: string[]; resetValue?: string; @@ -219,6 +218,7 @@ export class ColorControl extends React.PureComponent< allowCustomColor } = this.props; + const __ = this.props.translate; const isOpened = this.state.isOpened; const isFocused = this.state.isFocused; @@ -240,7 +240,7 @@ export class ColorControl extends React.PureComponent< size={10} className={cx('ColorPicker-input')} value={this.state.inputValue || ''} - placeholder={placeholder} + placeholder={__(placeholder)} disabled={disabled} onChange={this.handleInputChange} onFocus={this.handleFocus} @@ -300,7 +300,9 @@ export class ColorControl extends React.PureComponent< } export default themeable( - uncontrollable(ColorControl, { - value: 'onChange' - }) + localeable( + uncontrollable(ColorControl, { + value: 'onChange' + }) + ) ); diff --git a/src/components/DatePicker.tsx b/src/components/DatePicker.tsx index 16e4531d7..c133cb11d 100644 --- a/src/components/DatePicker.tsx +++ b/src/components/DatePicker.tsx @@ -11,10 +11,11 @@ import 'moment/locale/zh-cn'; import {Icon} from './icons'; import PopOver from './PopOver'; import Overlay from './Overlay'; -import {ClassNamesFn, themeable} from '../theme'; +import {ClassNamesFn, themeable, ThemeProps} from '../theme'; import {PlainObject} from '../types'; import Calendar from './calendar/Calendar'; import 'react-datetime/css/react-datetime.css'; +import {localeable, LocaleProps, TranslateFn} from '../locale'; const availableShortcuts: {[propName: string]: any} = { now: { @@ -97,9 +98,9 @@ const availableShortcuts: {[propName: string]: any} = { const advancedShortcuts = [ { regexp: /^(\d+)hoursago$/, - resolve: (_: string, hours: string) => { + resolve: (_: string, hours: string, __: TranslateFn) => { return { - label: `${hours}小时前`, + label: __('${hours}小时前', {hours}), date: (now: moment.Moment) => { return now.subtract(hours, 'hours'); } @@ -108,9 +109,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)hourslater$/, - resolve: (_: string, hours: string) => { + resolve: (_: string, hours: string, __: TranslateFn) => { return { - label: `${hours}小时后`, + label: __('${hours}小时后', {hours}), date: (now: moment.Moment) => { return now.add(hours, 'hours'); } @@ -119,9 +120,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)daysago$/, - resolve: (_: string, days: string) => { + resolve: (_: string, days: string, __: TranslateFn) => { return { - label: `${days}天前`, + label: __('${days}天前', {days}), date: (now: moment.Moment) => { return now.subtract(days, 'days'); } @@ -130,9 +131,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)dayslater$/, - resolve: (_: string, days: string) => { + resolve: (_: string, days: string, __: TranslateFn) => { return { - label: `${days}天后`, + label: __('${days}天后', {days}), date: (now: moment.Moment) => { return now.add(days, 'days'); } @@ -141,9 +142,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)weeksago$/, - resolve: (_: string, weeks: string) => { + resolve: (_: string, weeks: string, __: TranslateFn) => { return { - label: `${weeks}周前`, + label: __('${weeks}周前', {weeks}), date: (now: moment.Moment) => { return now.subtract(weeks, 'weeks'); } @@ -152,9 +153,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)weekslater$/, - resolve: (_: string, weeks: string) => { + resolve: (_: string, weeks: string, __: TranslateFn) => { return { - label: `${weeks}周后`, + label: __('${weeks}周后', {weeks}), date: (now: moment.Moment) => { return now.add(weeks, 'weeks'); } @@ -163,9 +164,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)monthsago$/, - resolve: (_: string, months: string) => { + resolve: (_: string, months: string, __: TranslateFn) => { return { - label: `${months}月前`, + label: __('${months}月前', {months}), date: (now: moment.Moment) => { return now.subtract(months, 'months'); } @@ -174,9 +175,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)monthslater$/, - resolve: (_: string, months: string) => { + resolve: (_: string, months: string, __: TranslateFn) => { return { - label: `${months}月后`, + label: __('${months}月后', {months}), date: (now: moment.Moment) => { return now.add(months, 'months'); } @@ -185,9 +186,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)quartersago$/, - resolve: (_: string, quarters: string) => { + resolve: (_: string, quarters: string, __: TranslateFn) => { return { - label: `${quarters}季度前`, + label: __('${quarters}季度前', {quarters}), date: (now: moment.Moment) => { return now.subtract(quarters, 'quarters'); } @@ -196,9 +197,9 @@ const advancedShortcuts = [ }, { regexp: /^(\d+)quarterslater$/, - resolve: (_: string, quarters: string) => { + resolve: (_: string, quarters: string, __: TranslateFn) => { return { - label: `${quarters}季度后`, + label: __('${quarters}季度后', {quarters}), date: (now: moment.Moment) => { return now.add(quarters, 'quarters'); } @@ -226,17 +227,15 @@ export type ShortCuts = | ShortCutDate | ShortCutDateRange; -export interface DateProps { +export interface DateProps extends LocaleProps, ThemeProps { viewMode: 'years' | 'months' | 'days' | 'time'; className?: string; - classPrefix: string; - classnames: ClassNamesFn; placeholder?: string; inputFormat?: string; timeFormat?: string; format?: string; timeConstrainst?: object; - closeOnSelect?: boolean; + closeOnSelect: boolean; disabled?: boolean; minDate?: moment.Moment; maxDate?: moment.Moment; @@ -247,7 +246,14 @@ export interface DateProps { value: any; shortcuts: string | Array; overlayPlacement: string; - [propName: string]: any; + minTime?: moment.Moment; + maxTime?: moment.Moment; + dateFormat?: string; + timeConstraints?: any; + popOverContainer?: any; + + // 下面那个千万不要写,写了就会导致 keyof DateProps 得到的结果是 string | number; + // [propName: string]: any; } export interface DatePickerState { @@ -257,11 +263,8 @@ export interface DatePickerState { } export class DatePicker extends React.Component { - static defaultProps: Pick< - DateProps, - 'viewMode' | 'shortcuts' | 'closeOnSelect' | 'overlayPlacement' - > = { - viewMode: 'days', + static defaultProps = { + viewMode: 'days' as 'years' | 'months' | 'days' | 'time', shortcuts: '', closeOnSelect: true, overlayPlacement: 'auto' @@ -429,12 +432,14 @@ export class DatePicker extends React.Component { return availableShortcuts[key]; } + const __ = this.props.locale; + for (let i = 0, len = advancedShortcuts.length; i < len; i++) { let item = advancedShortcuts[i]; const m = item.regexp.exec(key); if (m) { - return item.resolve.apply(item, m); + return item.resolve.apply(item, m, __); } } @@ -452,6 +457,8 @@ export class DatePicker extends React.Component { } else { shortcutArr = shortcuts; } + + const __ = this.props.translate; return (