mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:48:55 +08:00
Locale 支持
This commit is contained in:
parent
ae4fb3afbf
commit
f4ac5e2a6e
@ -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 {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="hidden-xs p-t-sm pull-right m-l-sm">
|
||||
语言:
|
||||
{
|
||||
<Select
|
||||
clearable={false}
|
||||
theme={this.state.theme.value}
|
||||
value={this.state.locale || 'zh-cn'}
|
||||
options={locales}
|
||||
onChange={locale => {
|
||||
this.setState({locale: locale.value});
|
||||
localStorage.setItem('locale', locale.value);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="hidden-xs p-t-sm pull-right">
|
||||
主题:
|
||||
{
|
||||
<Select
|
||||
clearable={false}
|
||||
theme={this.state.theme.value}
|
||||
value={this.state.theme}
|
||||
options={this.state.themes}
|
||||
@ -802,14 +833,15 @@ export class App extends React.PureComponent {
|
||||
folded={this.state.asideFolded}
|
||||
aside={this.renderAside()}
|
||||
>
|
||||
<ToastComponent theme={theme.value} />
|
||||
<AlertComponent theme={theme.value} />
|
||||
<ToastComponent theme={theme.value} locale={this.state.locale} />
|
||||
<AlertComponent theme={theme.value} locale={this.state.locale} />
|
||||
{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
|
||||
})}
|
||||
</Layout>
|
||||
);
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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<AlertProps, AlertState> {
|
||||
const container = document.body;
|
||||
const div = document.createElement('div');
|
||||
container.appendChild(div);
|
||||
render(<ThemedAlert />, div);
|
||||
render(<FinnalAlert />, div);
|
||||
}
|
||||
|
||||
return Alert.instance;
|
||||
@ -150,6 +148,8 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
||||
classnames: cx,
|
||||
classPrefix
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
show={this.state.show}
|
||||
@ -158,20 +158,22 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
||||
ref={this.modalRef}
|
||||
>
|
||||
<div className={cx('Modal-header')}>
|
||||
<div className={cx('Modal-title')}>{this.state.title || title}</div>
|
||||
<div className={cx('Modal-title')}>
|
||||
{__(this.state.title || title)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={cx('Modal-body')}>
|
||||
<div ref={this.bodyRef} />
|
||||
</div>
|
||||
<div className={cx('Modal-footer')}>
|
||||
{this.state.confirm ? (
|
||||
<Button onClick={this.handleCancel}>{cancelText}</Button>
|
||||
<Button onClick={this.handleCancel}>{__(cancelText)}</Button>
|
||||
) : null}
|
||||
<Button
|
||||
level={this.state.confirm ? confirmBtnLevel : alertBtnLevel}
|
||||
onClick={this.handleConfirm}
|
||||
>
|
||||
{this.state.confirmText || confirmText}
|
||||
{__(this.state.confirmText || confirmText)}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
@ -189,5 +191,5 @@ export const confirm: (
|
||||
confirmText?: string
|
||||
) => Promise<any> = (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;
|
||||
|
@ -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 (
|
||||
<div className={cx('AssociatedCheckboxes', className)}>
|
||||
@ -155,9 +157,9 @@ export class AssociatedCheckboxes extends Checkboxes<
|
||||
</div>
|
||||
|
||||
{selectdOption.loading ? (
|
||||
<p>加载中</p>
|
||||
<p>{__('加载中')}</p>
|
||||
) : (
|
||||
<p>点击刷新重新加载</p>
|
||||
<p>{__('点击刷新重新加载')}</p>
|
||||
)}
|
||||
</div>
|
||||
) : rightMode === 'table' ? (
|
||||
@ -193,12 +195,12 @@ export class AssociatedCheckboxes extends Checkboxes<
|
||||
)
|
||||
) : (
|
||||
<div className={cx('AssociatedCheckboxes-box')}>
|
||||
配置错误,选项无法与左侧选项对应
|
||||
{__('配置错误,选项无法与左侧选项对应')}
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<div className={cx('AssociatedCheckboxes-box')}>
|
||||
请先选择左侧数据
|
||||
{__('请先选择左侧数据')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -208,7 +210,9 @@ export class AssociatedCheckboxes extends Checkboxes<
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(AssociatedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(AssociatedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -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 (
|
||||
<div className={cx('ChainedCheckboxes', className)}>
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('ChainedCheckboxes-placeholder')}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -203,7 +206,9 @@ export class ChainedCheckboxes extends Checkboxes<
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(ChainedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ChainedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -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<React.ReactNode> = [];
|
||||
|
||||
@ -142,14 +145,16 @@ export class Checkboxes<
|
||||
inline ? 'Checkboxes--inline' : ''
|
||||
)}
|
||||
>
|
||||
{body && body.length ? body : <div>{placeholder}</div>}
|
||||
{body && body.length ? body : <div>{__(placeholder)}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Checkboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(Checkboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -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'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -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<ShortCuts>;
|
||||
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<DateProps, DatePickerState> {
|
||||
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<DateProps, DatePickerState> {
|
||||
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<DateProps, DatePickerState> {
|
||||
} else {
|
||||
shortcutArr = shortcuts;
|
||||
}
|
||||
|
||||
const __ = this.props.translate;
|
||||
return (
|
||||
<ul className={`${ns}DatePicker-shortcuts`}>
|
||||
{shortcutArr.map(item => {
|
||||
@ -474,7 +481,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
onClick={() => this.selectRannge(shortcut)}
|
||||
key={shortcut.key || shortcut.label}
|
||||
>
|
||||
<a>{shortcut.label}</a>
|
||||
<a>{__(shortcut.label)}</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
@ -498,9 +505,11 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
clearable,
|
||||
shortcuts,
|
||||
utc,
|
||||
overlayPlacement
|
||||
overlayPlacement,
|
||||
locale
|
||||
} = this.props;
|
||||
|
||||
const __ = this.props.translate;
|
||||
const isOpened = this.state.isOpened;
|
||||
let date: moment.Moment | undefined = this.state.value;
|
||||
|
||||
@ -526,7 +535,9 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
{date.format(inputFormat)}
|
||||
</span>
|
||||
) : (
|
||||
<span className={`${ns}DatePicker-placeholder`}>{placeholder}</span>
|
||||
<span className={`${ns}DatePicker-placeholder`}>
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{clearable && !disabled && value ? (
|
||||
@ -565,6 +576,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
timeConstraints={timeConstraints}
|
||||
input={false}
|
||||
onClose={this.close}
|
||||
locale={locale}
|
||||
// utc={utc}
|
||||
/>
|
||||
</PopOver>
|
||||
@ -575,4 +587,4 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(DatePicker);
|
||||
export default themeable(localeable(DatePicker));
|
||||
|
@ -13,14 +13,13 @@ import Overlay from './Overlay';
|
||||
import {ShortCuts, ShortCutDateRange} from './DatePicker';
|
||||
import Calendar from './calendar/Calendar';
|
||||
import PopOver from './PopOver';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {PlainObject} from '../types';
|
||||
import {noop} from '../utils/helper';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface DateRangePickerProps {
|
||||
export interface DateRangePickerProps extends ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
placeholder?: string;
|
||||
theme?: any;
|
||||
format: string;
|
||||
@ -39,7 +38,10 @@ export interface DateRangePickerProps {
|
||||
disabled?: boolean;
|
||||
closeOnSelect?: boolean;
|
||||
overlayPlacement: string;
|
||||
[propName: string]: any;
|
||||
timeFormat?: string;
|
||||
resetValue?: any;
|
||||
popOverContainer?: any;
|
||||
dateFormat?: string;
|
||||
}
|
||||
|
||||
export interface DateRangePickerState {
|
||||
@ -106,10 +108,7 @@ const availableRanges: {[propName: string]: any} = {
|
||||
return now.startOf('week').add(-1, 'weeks');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now
|
||||
.startOf('week')
|
||||
.add(-1, 'days')
|
||||
.endOf('day');
|
||||
return now.startOf('week').add(-1, 'days').endOf('day');
|
||||
}
|
||||
},
|
||||
|
||||
@ -129,10 +128,7 @@ const availableRanges: {[propName: string]: any} = {
|
||||
return now.startOf('month').add(-1, 'month');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now
|
||||
.startOf('month')
|
||||
.add(-1, 'day')
|
||||
.endOf('day');
|
||||
return now.startOf('month').add(-1, 'day').endOf('day');
|
||||
}
|
||||
},
|
||||
|
||||
@ -142,10 +138,7 @@ const availableRanges: {[propName: string]: any} = {
|
||||
return now.startOf('quarter').add(-1, 'quarter');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now
|
||||
.startOf('quarter')
|
||||
.add(-1, 'day')
|
||||
.endOf('day');
|
||||
return now.startOf('quarter').add(-1, 'day').endOf('day');
|
||||
}
|
||||
},
|
||||
|
||||
@ -416,6 +409,8 @@ export class DateRangePicker extends React.Component<
|
||||
} else {
|
||||
rangeArr = ranges;
|
||||
}
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<ul className={`${ns}DateRangePicker-rangers`}>
|
||||
{rangeArr.map(item => {
|
||||
@ -442,7 +437,7 @@ export class DateRangePicker extends React.Component<
|
||||
onClick={() => this.selectRannge(range)}
|
||||
key={range.key || range.label}
|
||||
>
|
||||
<a>{range.label}</a>
|
||||
<a>{__(range.label)}</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
@ -551,6 +546,7 @@ export class DateRangePicker extends React.Component<
|
||||
const arr = [];
|
||||
startViewValue && arr.push(startViewValue);
|
||||
endViewValue && arr.push(endViewValue);
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -571,11 +567,11 @@ export class DateRangePicker extends React.Component<
|
||||
>
|
||||
{arr.length ? (
|
||||
<span className={`${ns}DateRangePicker-value`}>
|
||||
{arr.join(' 至 ')}
|
||||
{arr.join(__(' 至 '))}
|
||||
</span>
|
||||
) : (
|
||||
<span className={`${ns}DateRangePicker-placeholder`}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@ -646,10 +642,10 @@ export class DateRangePicker extends React.Component<
|
||||
})}
|
||||
onClick={this.confirm}
|
||||
>
|
||||
确认
|
||||
{__('确认')}
|
||||
</a>
|
||||
<a className="rdtBtn rdtBtnCancel" onClick={this.close}>
|
||||
取消
|
||||
{__('取消')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -661,4 +657,4 @@ export class DateRangePicker extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(DateRangePicker);
|
||||
export default themeable(localeable(DateRangePicker));
|
||||
|
@ -1,12 +1,11 @@
|
||||
import React from 'react';
|
||||
import {themeable, ClassNamesFn} from '../theme';
|
||||
import {themeable, ClassNamesFn, ThemeProps} from '../theme';
|
||||
import {autobind} from '../utils/helper';
|
||||
import Modal from './Modal';
|
||||
import {Icon} from './icons';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ImageGalleryProps {
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
export interface ImageGalleryProps extends ThemeProps, LocaleProps {
|
||||
children: React.ReactNode;
|
||||
modalContainer?: () => HTMLElement;
|
||||
}
|
||||
@ -87,6 +86,7 @@ export class ImageGallery extends React.Component<
|
||||
render() {
|
||||
const {children, classnames: cx, modalContainer} = this.props;
|
||||
const {index, items} = this.state;
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -103,7 +103,7 @@ export class ImageGallery extends React.Component<
|
||||
container={modalContainer}
|
||||
>
|
||||
<a
|
||||
data-tooltip="关闭"
|
||||
data-tooltip={__('关闭')}
|
||||
data-position="left"
|
||||
className={cx('ImageGallery-close')}
|
||||
onClick={this.close}
|
||||
@ -176,4 +176,4 @@ export class ImageGallery extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(ImageGallery);
|
||||
export default themeable(localeable(ImageGallery));
|
||||
|
@ -4,6 +4,7 @@ import React from 'react';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import Checkbox from './Checkbox';
|
||||
import {Option} from './Select';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export class ListCheckboxes extends Checkboxes {
|
||||
valueArray: Array<Option>;
|
||||
@ -72,6 +73,7 @@ export class ListCheckboxes extends Checkboxes {
|
||||
classnames: cx,
|
||||
option2value
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
@ -85,7 +87,9 @@ export class ListCheckboxes extends Checkboxes {
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('ListCheckboxes-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('ListCheckboxes-placeholder')}>
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@ -93,7 +97,9 @@ export class ListCheckboxes extends Checkboxes {
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(ListCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ListCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -1,8 +1,9 @@
|
||||
import {ThemeProps, themeable} from '../theme';
|
||||
import React from 'react';
|
||||
import {Options, Option} from './Select';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ListMenuProps extends ThemeProps {
|
||||
export interface ListMenuProps extends ThemeProps, LocaleProps {
|
||||
options: Options;
|
||||
disabled?: boolean;
|
||||
selectedOptions?: Options;
|
||||
@ -85,6 +86,8 @@ export class ListMenu extends React.Component<ListMenuProps> {
|
||||
|
||||
render() {
|
||||
const {classnames: cx, options, placeholder, prefix, children} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div className={cx('ListMenu')}>
|
||||
{prefix}
|
||||
@ -98,7 +101,7 @@ export class ListMenu extends React.Component<ListMenuProps> {
|
||||
}
|
||||
).items
|
||||
) : (
|
||||
<span className={cx('ListMenu-placeholder')}>{placeholder}</span>
|
||||
<span className={cx('ListMenu-placeholder')}>{__(placeholder)}</span>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
@ -106,4 +109,4 @@ export class ListMenu extends React.Component<ListMenuProps> {
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(ListMenu);
|
||||
export default themeable(localeable(ListMenu));
|
||||
|
@ -6,8 +6,9 @@ import Checkbox from './Checkbox';
|
||||
import {Option, Options} from './Select';
|
||||
import {findTree, autobind} from '../utils/helper';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ListRadiosProps extends ThemeProps {
|
||||
export interface ListRadiosProps extends ThemeProps, LocaleProps {
|
||||
options: Options;
|
||||
className?: string;
|
||||
placeholder: string;
|
||||
@ -120,6 +121,7 @@ export class ListRadios<
|
||||
classnames: cx,
|
||||
option2value
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
this.selected = ListRadios.resolveSelected(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
@ -133,7 +135,7 @@ export class ListRadios<
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('ListRadios-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('ListRadios-placeholder')}>{__(placeholder)}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@ -141,9 +143,11 @@ export class ListRadios<
|
||||
}
|
||||
|
||||
const themedListRadios = themeable(
|
||||
uncontrollable(ListRadios, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ListRadios, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
themedListRadios.resolveSelected = ListRadios.resolveSelected;
|
||||
|
@ -1,13 +1,14 @@
|
||||
import React from 'react';
|
||||
import {themeable, ClassNamesFn} from '../theme';
|
||||
import {themeable, ClassNamesFn, ThemeProps} from '../theme';
|
||||
import Overlay from './Overlay';
|
||||
import PopOver from './PopOver';
|
||||
import {Icon} from './icons';
|
||||
import {autobind} from '../utils/helper';
|
||||
import Alert2 from './Alert2';
|
||||
import BaiduMapPicker from './BaiduMapPicker';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface LocationProps {
|
||||
export interface LocationProps extends ThemeProps, LocaleProps {
|
||||
vendor: 'baidu' | 'gaode' | 'tenxun';
|
||||
placeholder: string;
|
||||
clearable: boolean;
|
||||
@ -21,8 +22,6 @@ export interface LocationProps {
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
onChange: (value: any) => void;
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
popOverContainer?: any;
|
||||
}
|
||||
|
||||
@ -137,6 +136,7 @@ export class LocationPicker extends React.Component<
|
||||
vendor,
|
||||
ak
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
const {isFocused, isOpened} = this.state;
|
||||
|
||||
return (
|
||||
@ -161,7 +161,7 @@ export class LocationPicker extends React.Component<
|
||||
<span className={cx('LocationPicker-value')}>{value.address}</span>
|
||||
) : (
|
||||
<span className={cx('LocationPicker-placeholder')}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@ -189,8 +189,14 @@ export class LocationPicker extends React.Component<
|
||||
style={{width: this.getTarget()?.offsetWidth}}
|
||||
>
|
||||
{vendor === 'baidu' ? (
|
||||
<BaiduMapPicker ak={ak} value={value} onChange={this.handleChange} />
|
||||
) : (<Alert2>{vendor} 地图控件不支持</Alert2>)}
|
||||
<BaiduMapPicker
|
||||
ak={ak}
|
||||
value={value}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
) : (
|
||||
<Alert2>{__('$0 地图控件不支持', vendor)}</Alert2>
|
||||
)}
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
</div>
|
||||
@ -198,5 +204,5 @@ export class LocationPicker extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
const ThemedCity = themeable(LocationPicker);
|
||||
const ThemedCity = themeable(localeable(LocationPicker));
|
||||
export default ThemedCity;
|
||||
|
@ -14,8 +14,9 @@ import {Portal} from 'react-overlays';
|
||||
import {current, addModal, removeModal} from './ModalManager';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {Icon} from './icons';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ModalProps extends ThemeProps {
|
||||
export interface ModalProps extends ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
contentClassName?: string;
|
||||
size?: any;
|
||||
@ -44,33 +45,37 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
||||
};
|
||||
|
||||
static Header = themeable(
|
||||
({
|
||||
classnames: cx,
|
||||
className,
|
||||
showCloseButton,
|
||||
onClose,
|
||||
children,
|
||||
classPrefix,
|
||||
...rest
|
||||
}: ThemeProps & {
|
||||
className?: string;
|
||||
showCloseButton?: boolean;
|
||||
onClose?: () => void;
|
||||
children?: React.ReactNode;
|
||||
} & React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div {...rest} className={cx('Modal-header', className)}>
|
||||
{showCloseButton !== false ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-position="left"
|
||||
onClick={onClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
localeable(
|
||||
({
|
||||
classnames: cx,
|
||||
className,
|
||||
showCloseButton,
|
||||
onClose,
|
||||
children,
|
||||
classPrefix,
|
||||
translate: __,
|
||||
...rest
|
||||
}: ThemeProps &
|
||||
LocaleProps & {
|
||||
className?: string;
|
||||
showCloseButton?: boolean;
|
||||
onClose?: () => void;
|
||||
children?: React.ReactNode;
|
||||
} & React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div {...rest} className={cx('Modal-header', className)}>
|
||||
{showCloseButton !== false ? (
|
||||
<a
|
||||
data-tooltip={__('关闭弹窗')}
|
||||
data-position="left"
|
||||
onClick={onClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@ -216,9 +221,9 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
||||
}
|
||||
}
|
||||
|
||||
const themedModal = themeable(Modal);
|
||||
const FinalModal = themeable(localeable(Modal));
|
||||
|
||||
export default themedModal as typeof themedModal & {
|
||||
export default FinalModal as typeof FinalModal & {
|
||||
Header: typeof Modal.Header;
|
||||
Title: typeof Modal.Title;
|
||||
Body: typeof Modal.Body;
|
||||
|
@ -5,10 +5,12 @@ import uncontrollable from 'uncontrollable';
|
||||
import {Icon} from './icons';
|
||||
import Input from './Input';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ResultBoxProps
|
||||
extends ThemeProps,
|
||||
Omit<InputBoxProps, 'result' | 'prefix' | 'onChange'> {
|
||||
LocaleProps,
|
||||
Omit<InputBoxProps, 'result' | 'prefix' | 'onChange' | 'translate'> {
|
||||
onChange?: (value: string) => void;
|
||||
onResultClick?: (e: React.MouseEvent<HTMLElement>) => void;
|
||||
result?: Array<any>;
|
||||
@ -96,6 +98,8 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
onResultChange,
|
||||
onChange,
|
||||
onResultClick,
|
||||
translate: __,
|
||||
locale,
|
||||
...rest
|
||||
} = this.props;
|
||||
const isFocused = this.state.isFocused;
|
||||
@ -124,7 +128,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
))
|
||||
) : allowInput ? null : (
|
||||
<span className={cx('ResultBox-placeholder')}>
|
||||
{placeholder || '无'}
|
||||
{__(placeholder || '无')}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@ -163,8 +167,10 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(ResultBox, {
|
||||
value: 'onChange',
|
||||
result: 'onResultChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ResultBox, {
|
||||
value: 'onChange',
|
||||
result: 'onResultChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -8,8 +8,9 @@ import {Icon} from './icons';
|
||||
import {autobind, guid} from '../utils/helper';
|
||||
import Sortable from 'sortablejs';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ResultListProps extends ThemeProps {
|
||||
export interface ResultListProps extends ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
value?: Array<Option>;
|
||||
onChange?: (value: Array<Option>) => void;
|
||||
@ -123,7 +124,8 @@ export class ResultList extends React.Component<ResultListProps> {
|
||||
disabled,
|
||||
title,
|
||||
itemClassName,
|
||||
sortable
|
||||
sortable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -163,11 +165,11 @@ export class ResultList extends React.Component<ResultListProps> {
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className={cx('Selections-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('Selections-placeholder')}>{__(placeholder)}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(ResultList);
|
||||
export default themeable(localeable(ResultList));
|
||||
|
@ -3,8 +3,9 @@ import {ThemeProps, themeable} from '../theme';
|
||||
import {Icon} from './icons';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface SearchBoxProps extends ThemeProps {
|
||||
export interface SearchBoxProps extends ThemeProps, LocaleProps {
|
||||
name?: string;
|
||||
onChange?: (text: string) => void;
|
||||
placeholder?: string;
|
||||
@ -47,7 +48,8 @@ export class SearchBox extends React.Component<SearchBoxProps> {
|
||||
active,
|
||||
name,
|
||||
onChange,
|
||||
placeholder
|
||||
placeholder,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -56,7 +58,7 @@ export class SearchBox extends React.Component<SearchBoxProps> {
|
||||
name={name}
|
||||
onChange={this.handleChange}
|
||||
value={value || ''}
|
||||
placeholder={placeholder || '输入关键字'}
|
||||
placeholder={__(placeholder || '输入关键字')}
|
||||
ref={this.inputRef}
|
||||
/>
|
||||
|
||||
@ -75,8 +77,10 @@ export class SearchBox extends React.Component<SearchBoxProps> {
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(SearchBox, {
|
||||
active: 'onActiveChange',
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(SearchBox, {
|
||||
active: 'onActiveChange',
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -19,10 +19,11 @@ import isPlainObject from 'lodash/isPlainObject';
|
||||
import union from 'lodash/union';
|
||||
import {highlight} from '../renderers/Form/Options';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import Checkbox from './Checkbox';
|
||||
import Input from './Input';
|
||||
import {Api} from '../types';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface Option {
|
||||
label?: string;
|
||||
@ -273,9 +274,7 @@ export function normalizeOptions(
|
||||
|
||||
const DownshiftChangeTypes = Downshift.stateChangeTypes;
|
||||
|
||||
interface SelectProps extends OptionProps {
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
interface SelectProps extends OptionProps, ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
creatable: boolean;
|
||||
createBtnLabel: string;
|
||||
@ -629,7 +628,8 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
placeholder,
|
||||
classPrefix: ns,
|
||||
labelField,
|
||||
disabled
|
||||
disabled,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const selection = this.state.selection;
|
||||
@ -638,7 +638,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
if (!selection.length) {
|
||||
return (
|
||||
<div key="placeholder" className={`${ns}Select-placeholder`}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -693,7 +693,8 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
searchPromptText,
|
||||
editable,
|
||||
removable,
|
||||
overlayPlacement
|
||||
overlayPlacement,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const {selection} = this.state;
|
||||
|
||||
@ -732,7 +733,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
onFocus: this.onFocus,
|
||||
onBlur: this.onBlur,
|
||||
disabled: disabled,
|
||||
placeholder: searchPromptText,
|
||||
placeholder: __(searchPromptText),
|
||||
onChange: this.handleInputChange,
|
||||
ref: this.inputRef
|
||||
})}
|
||||
@ -747,7 +748,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
partial={checkedPartial && !checkedAll}
|
||||
onChange={this.toggleCheckAll}
|
||||
>
|
||||
{checkAllLabel}
|
||||
{__(checkAllLabel)}
|
||||
</Checkbox>
|
||||
</div>
|
||||
) : null}
|
||||
@ -830,13 +831,13 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className={cx('Select-noResult')}>{noResultsText}</div>
|
||||
<div className={cx('Select-noResult')}>{__(noResultsText)}</div>
|
||||
)}
|
||||
|
||||
{creatable && !disabled ? (
|
||||
<a className={cx('Select-addBtn')} onClick={this.handleAddClick}>
|
||||
<Icon icon="plus" className="icon" />
|
||||
{createBtnLabel}
|
||||
{__(createBtnLabel)}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
@ -942,7 +943,9 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Select, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(Select, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -5,6 +5,7 @@ import uncontrollable from 'uncontrollable';
|
||||
import Checkbox from './Checkbox';
|
||||
import {Option} from './Select';
|
||||
import {resolveVariable} from '../utils/tpl-builtin';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface TableCheckboxesProps extends CheckboxesProps {
|
||||
columns: Array<{
|
||||
@ -94,7 +95,8 @@ export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
||||
classnames: cx,
|
||||
cellRender,
|
||||
value,
|
||||
option2value
|
||||
option2value,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const columns = this.getColumns();
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
@ -123,7 +125,7 @@ export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
||||
})
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={columns.length}>{placeholder}</td>
|
||||
<td colSpan={columns.length}>{__(placeholder)}</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
@ -187,7 +189,9 @@ export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(TableCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(TableCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -10,6 +10,7 @@ import {Options, Option} from './Select';
|
||||
import Transfer, {TransferProps} from './Transfer';
|
||||
import {themeable} from '../theme';
|
||||
import AssociatedCheckboxes from './AssociatedCheckboxes';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface TabsTransferProps
|
||||
extends Omit<
|
||||
@ -101,13 +102,14 @@ export class TabsTransfer extends React.Component<TabsTransferProps> {
|
||||
onSearch: searchable,
|
||||
option2value,
|
||||
onDeferLoad,
|
||||
cellRender
|
||||
cellRender,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (!Array.isArray(options) || !options.length) {
|
||||
return (
|
||||
<div className={cx('TabsTransfer-placeholder')}>
|
||||
{placeholder || '暂无可选项'}
|
||||
{__(placeholder || '暂无选项')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -128,7 +130,7 @@ export class TabsTransfer extends React.Component<TabsTransferProps> {
|
||||
>
|
||||
{searchResult !== null
|
||||
? [
|
||||
<Tab title="搜索结果" key={0} eventKey={0}>
|
||||
<Tab title={__('搜索结果')} key={0} eventKey={0}>
|
||||
{this.renderSearchResult(searchResult)}
|
||||
</Tab>
|
||||
]
|
||||
@ -210,4 +212,4 @@ export class TabsTransfer extends React.Component<TabsTransferProps> {
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(TabsTransfer);
|
||||
export default themeable(localeable(TabsTransfer));
|
||||
|
@ -35,8 +35,9 @@ import 'tinymce/plugins/template';
|
||||
import 'tinymce/plugins/nonbreaking';
|
||||
import 'tinymce/plugins/emoticons';
|
||||
import 'tinymce/plugins/emoticons/js/emojis';
|
||||
import {LocaleProps} from '../locale';
|
||||
|
||||
interface TinymceEditorProps {
|
||||
interface TinymceEditorProps extends LocaleProps {
|
||||
model: string;
|
||||
onModelChange?: (value: string) => void;
|
||||
onFocus?: () => void;
|
||||
@ -58,12 +59,14 @@ export default class TinymceEditor extends React.Component<TinymceEditorProps> {
|
||||
elementRef: React.RefObject<HTMLTextAreaElement> = React.createRef();
|
||||
|
||||
componentDidMount() {
|
||||
const locale = this.props.locale;
|
||||
|
||||
this.config = {
|
||||
inline: false,
|
||||
skin: false,
|
||||
content_css: false,
|
||||
height: 400,
|
||||
language: 'zh_CN',
|
||||
language: !locale || locale === 'zh-cn' ? 'zh_CN' : '',
|
||||
plugins: [
|
||||
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker',
|
||||
'searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking',
|
||||
|
@ -13,8 +13,12 @@ import {Icon} from './icons';
|
||||
import debounce from 'lodash/debounce';
|
||||
import ChainedCheckboxes from './ChainedCheckboxes';
|
||||
import AssociatedCheckboxes from './AssociatedCheckboxes';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface TransferProps extends ThemeProps, CheckboxesProps {
|
||||
export interface TransferProps
|
||||
extends ThemeProps,
|
||||
LocaleProps,
|
||||
CheckboxesProps {
|
||||
inline?: boolean;
|
||||
statistics?: boolean;
|
||||
showArrow?: boolean;
|
||||
@ -185,7 +189,8 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
onSearch,
|
||||
disabled,
|
||||
options,
|
||||
statistics
|
||||
statistics,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (selectRender) {
|
||||
@ -206,7 +211,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
)}
|
||||
>
|
||||
<span>
|
||||
{selectTitle}
|
||||
{__(selectTitle)}
|
||||
{statistics !== false ? (
|
||||
<span>
|
||||
({this.valueArray.length}/{this.availableOptions.length})
|
||||
@ -221,7 +226,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
disabled || !options.length ? 'is-disabled' : ''
|
||||
)}
|
||||
>
|
||||
全选
|
||||
{__('全选')}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
@ -231,7 +236,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
<InputBox
|
||||
value={this.state.inputValue}
|
||||
onChange={this.handleSearch}
|
||||
placeholder="请输入关键字"
|
||||
placeholder={__('请输入关键字')}
|
||||
clearable={false}
|
||||
>
|
||||
{this.state.searchResult !== null ? (
|
||||
@ -393,7 +398,8 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
option2value,
|
||||
disabled,
|
||||
statistics,
|
||||
showArrow
|
||||
showArrow,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
@ -419,7 +425,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
<div className={cx('Transfer-result')}>
|
||||
<div className={cx('Transfer-title')}>
|
||||
<span>
|
||||
{resultTitle}
|
||||
{__(resultTitle)}
|
||||
{statistics !== false ? (
|
||||
<span>
|
||||
({this.valueArray.length}/{this.availableOptions.length})
|
||||
@ -433,7 +439,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
disabled || !this.valueArray.length ? 'is-disabled' : ''
|
||||
)}
|
||||
>
|
||||
清空
|
||||
{__('清空')}
|
||||
</a>
|
||||
</div>
|
||||
<ResultList
|
||||
@ -441,7 +447,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
sortable={sortable}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder="请先选择左侧数据"
|
||||
placeholder={__('请先选择左侧数据')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -450,7 +456,9 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Transfer, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(Transfer, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -14,15 +14,13 @@ import {
|
||||
createObject
|
||||
} from '../utils/helper';
|
||||
import {Option, Options, value2array} from './Select';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {highlight} from '../renderers/Form/Options';
|
||||
import {Icon} from './icons';
|
||||
import Checkbox from './Checkbox';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
interface TreeSelectorProps {
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
|
||||
interface TreeSelectorProps extends ThemeProps, LocaleProps {
|
||||
highlightTxt?: string;
|
||||
|
||||
showIcon?: boolean;
|
||||
@ -421,7 +419,7 @@ export class TreeSelector extends React.Component<
|
||||
}
|
||||
|
||||
renderInput(prfix: JSX.Element | null = null) {
|
||||
const {classnames: cx} = this.props;
|
||||
const {classnames: cx, translate: __} = this.props;
|
||||
const {inputValue} = this.state;
|
||||
|
||||
return (
|
||||
@ -431,12 +429,12 @@ export class TreeSelector extends React.Component<
|
||||
<input
|
||||
onChange={this.handleInputChange}
|
||||
value={inputValue}
|
||||
placeholder="请输入"
|
||||
placeholder={__('请输入')}
|
||||
/>
|
||||
<a data-tooltip="取消" onClick={this.handleCancel}>
|
||||
<a data-tooltip={__('取消')} onClick={this.handleCancel}>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
<a data-tooltip="确认" onClick={this.handleConfirm}>
|
||||
<a data-tooltip={__('确认')} onClick={this.handleConfirm}>
|
||||
<Icon icon="check" className="icon" />
|
||||
</a>
|
||||
</div>
|
||||
@ -473,7 +471,8 @@ export class TreeSelector extends React.Component<
|
||||
removable,
|
||||
createTip,
|
||||
editTip,
|
||||
removeTip
|
||||
removeTip,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const {
|
||||
unfolded,
|
||||
@ -611,7 +610,7 @@ export class TreeSelector extends React.Component<
|
||||
{creatable && hasAbility(item, 'creatable') ? (
|
||||
<a
|
||||
onClick={this.handleAdd.bind(this, item)}
|
||||
data-tooltip={createTip}
|
||||
data-tooltip={__(createTip)}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="plus" className="icon" />
|
||||
@ -621,7 +620,7 @@ export class TreeSelector extends React.Component<
|
||||
{removable && hasAbility(item, 'removable') ? (
|
||||
<a
|
||||
onClick={this.handleRemove.bind(this, item)}
|
||||
data-tooltip={removeTip}
|
||||
data-tooltip={__(removeTip)}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="minus" className="icon" />
|
||||
@ -631,7 +630,7 @@ export class TreeSelector extends React.Component<
|
||||
{editable && hasAbility(item, 'editable') ? (
|
||||
<a
|
||||
onClick={this.handleEdit.bind(this, item)}
|
||||
data-tooltip={editTip}
|
||||
data-tooltip={__(editTip)}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="pencil" className="icon" />
|
||||
@ -689,7 +688,8 @@ export class TreeSelector extends React.Component<
|
||||
creatable,
|
||||
rootCreatable,
|
||||
rootCreateTip,
|
||||
disabled
|
||||
disabled,
|
||||
translate: __
|
||||
} = this.props;
|
||||
let options = this.props.options;
|
||||
const {value, isAdding, addingParent, isEditing, inputValue} = this.state;
|
||||
@ -705,7 +705,7 @@ export class TreeSelector extends React.Component<
|
||||
onClick={this.handleAdd.bind(this, null)}
|
||||
>
|
||||
<Icon icon="plus" className="icon" />
|
||||
<span>{rootCreateTip}</span>
|
||||
<span>{__(rootCreateTip)}</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@ -772,4 +772,4 @@ export class TreeSelector extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(TreeSelector);
|
||||
export default themeable(localeable(TreeSelector));
|
||||
|
@ -6,6 +6,7 @@ import Checkbox from './Checkbox';
|
||||
import {Option} from './Select';
|
||||
import {autobind, eachTree, everyTree} from '../utils/helper';
|
||||
import Spinner from './Spinner';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface TreeCheckboxesProps extends CheckboxesProps {
|
||||
expand?: 'all' | 'first' | 'root' | 'none';
|
||||
@ -257,7 +258,8 @@ export class TreeCheckboxes extends Checkboxes<
|
||||
className,
|
||||
placeholder,
|
||||
classnames: cx,
|
||||
option2value
|
||||
option2value,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
@ -272,7 +274,9 @@ export class TreeCheckboxes extends Checkboxes<
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('TreeCheckboxes-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('TreeCheckboxes-placeholder')}>
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@ -280,7 +284,9 @@ export class TreeCheckboxes extends Checkboxes<
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(TreeCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(TreeCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -168,7 +168,8 @@ export class TreeRadios extends ListRadios<TreeRadiosProps, TreeRadiosState> {
|
||||
className,
|
||||
placeholder,
|
||||
classnames: cx,
|
||||
option2value
|
||||
option2value,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.selected = ListRadios.resolveSelected(value, options, option2value);
|
||||
@ -183,7 +184,7 @@ export class TreeRadios extends ListRadios<TreeRadiosProps, TreeRadiosState> {
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('TreeRadios-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('TreeRadios-placeholder')}>{__(placeholder)}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -2,8 +2,9 @@ import moment from 'moment';
|
||||
// @ts-ignore
|
||||
import DaysView from 'react-datetime/src/DaysView';
|
||||
import React from 'react';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
|
||||
interface CustomDaysViewProps {
|
||||
interface CustomDaysViewProps extends LocaleProps {
|
||||
classPrefix?: string;
|
||||
prevIcon?: string;
|
||||
nextIcon?: string;
|
||||
@ -36,7 +37,7 @@ interface CustomDaysViewProps {
|
||||
handleClickOutside: () => void;
|
||||
}
|
||||
|
||||
export default class CustomDaysView extends DaysView {
|
||||
export class CustomDaysView extends DaysView {
|
||||
props: CustomDaysViewProps;
|
||||
getDaysOfWeek: (locale: any) => any;
|
||||
renderDays: () => JSX.Element;
|
||||
@ -160,6 +161,8 @@ export default class CustomDaysView extends DaysView {
|
||||
return null;
|
||||
}
|
||||
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<tfoot key="tf">
|
||||
<tr>
|
||||
@ -168,10 +171,10 @@ export default class CustomDaysView extends DaysView {
|
||||
{this.props.requiredConfirm ? (
|
||||
<div key="button" className="rdtActions">
|
||||
<a className="rdtBtn rdtBtnConfirm" onClick={this.confirm}>
|
||||
确认
|
||||
{__('确认')}
|
||||
</a>
|
||||
<a className="rdtBtn rdtBtnCancel" onClick={this.cancel}>
|
||||
取消
|
||||
{__('取消')}
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
@ -185,6 +188,7 @@ export default class CustomDaysView extends DaysView {
|
||||
const footer = this.renderFooter();
|
||||
const date = this.props.viewDate;
|
||||
const locale = date.localeData();
|
||||
const __ = this.props.translate;
|
||||
|
||||
const tableChildren = [
|
||||
<thead key="th">
|
||||
@ -206,13 +210,13 @@ export default class CustomDaysView extends DaysView {
|
||||
|
||||
<div className="rdtCenter">
|
||||
<a className="rdtSwitch" onClick={this.props.showView('years')}>
|
||||
{date.format('YYYY年')}
|
||||
{date.format(__('YYYY年'))}
|
||||
</a>
|
||||
<a
|
||||
className="rdtSwitch"
|
||||
onClick={this.props.showView('months')}
|
||||
>
|
||||
{date.format('MM月')}
|
||||
{date.format(__('MMM'))}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -246,3 +250,7 @@ export default class CustomDaysView extends DaysView {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default localeable(
|
||||
(CustomDaysView as any) as React.ComponentClass<CustomDaysViewProps>
|
||||
);
|
||||
|
@ -2,8 +2,9 @@
|
||||
import MonthsView from 'react-datetime/src/MonthsView';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
|
||||
export default class CustomMonthsView extends MonthsView {
|
||||
export class CustomMonthsView extends MonthsView {
|
||||
props: {
|
||||
viewDate: moment.Moment;
|
||||
subtractTime: (
|
||||
@ -16,7 +17,7 @@ export default class CustomMonthsView extends MonthsView {
|
||||
type: string,
|
||||
toSelected?: moment.Moment
|
||||
) => () => void;
|
||||
};
|
||||
} & LocaleProps;
|
||||
renderMonths: () => JSX.Element;
|
||||
renderMonth = (props: any, month: number) => {
|
||||
var localMoment = this.props.viewDate;
|
||||
@ -34,6 +35,8 @@ export default class CustomMonthsView extends MonthsView {
|
||||
);
|
||||
};
|
||||
render() {
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div className="rdtMonths">
|
||||
<table>
|
||||
@ -45,7 +48,9 @@ export default class CustomMonthsView extends MonthsView {
|
||||
>
|
||||
«
|
||||
</th>
|
||||
<th className="rdtSwitch">{this.props.viewDate.year()}年</th>
|
||||
<th className="rdtSwitch">
|
||||
{this.props.viewDate.format(__('YYYY年'))}
|
||||
</th>
|
||||
<th className="rdtNext" onClick={this.props.addTime(1, 'years')}>
|
||||
»
|
||||
</th>
|
||||
@ -59,3 +64,5 @@ export default class CustomMonthsView extends MonthsView {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default localeable(CustomMonthsView as any);
|
||||
|
@ -2,8 +2,9 @@
|
||||
import YearsView from 'react-datetime/src/YearsView';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
|
||||
export default class CustomYearsView extends YearsView {
|
||||
export class CustomYearsView extends YearsView {
|
||||
props: {
|
||||
viewDate: moment.Moment;
|
||||
subtractTime: (
|
||||
@ -17,7 +18,7 @@ export default class CustomYearsView extends YearsView {
|
||||
toSelected?: moment.Moment
|
||||
) => () => void;
|
||||
showView: (view: string) => () => void;
|
||||
};
|
||||
} & LocaleProps;
|
||||
renderYears: (year: number) => JSX.Element;
|
||||
renderYear = (props: any, year: number) => {
|
||||
return (
|
||||
@ -29,6 +30,7 @@ export default class CustomYearsView extends YearsView {
|
||||
render() {
|
||||
let year = this.props.viewDate.year();
|
||||
year = year - (year % 10);
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div className="rdtYears">
|
||||
@ -42,7 +44,7 @@ export default class CustomYearsView extends YearsView {
|
||||
«
|
||||
</th>
|
||||
<th className="rdtSwitch">
|
||||
{year}年-{year + 9}年
|
||||
{__('${from}年-${to}年', {from: year, to: year + 9})}
|
||||
</th>
|
||||
<th className="rdtNext" onClick={this.props.addTime(10, 'years')}>
|
||||
»
|
||||
@ -57,3 +59,5 @@ export default class CustomYearsView extends YearsView {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default localeable(CustomYearsView as any);
|
||||
|
@ -24,7 +24,6 @@ import {
|
||||
SchemaNode,
|
||||
Schema,
|
||||
Action,
|
||||
Omit,
|
||||
RendererData
|
||||
} from './types';
|
||||
import {observer} from 'mobx-react';
|
||||
@ -34,11 +33,24 @@ import omit from 'lodash/omit';
|
||||
import difference from 'lodash/difference';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
import Scoped from './Scoped';
|
||||
import {getTheme, ThemeInstance, ClassNamesFn, ThemeContext} from './theme';
|
||||
import {
|
||||
getTheme,
|
||||
ThemeInstance,
|
||||
ClassNamesFn,
|
||||
ThemeContext,
|
||||
ThemeProps
|
||||
} from './theme';
|
||||
import find from 'lodash/find';
|
||||
import Alert from './components/Alert2';
|
||||
import {LazyComponent} from './components';
|
||||
import ImageGallery from './components/ImageGallery';
|
||||
import {
|
||||
TranslateFn,
|
||||
getDefaultLocale,
|
||||
makeTranslator,
|
||||
LocaleContext,
|
||||
LocaleProps
|
||||
} from './locale';
|
||||
|
||||
export interface TestFunc {
|
||||
(
|
||||
@ -98,11 +110,9 @@ export interface RendererEnv {
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
export interface RendererProps {
|
||||
export interface RendererProps extends ThemeProps, LocaleProps {
|
||||
render: (region: string, node: SchemaNode, props?: any) => JSX.Element;
|
||||
env: RendererEnv;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
$path: string; // 当前组件所在的层级信息
|
||||
store?: IIRendererStore;
|
||||
syncSuperStore?: boolean;
|
||||
@ -193,7 +203,7 @@ export function filterSchema(
|
||||
}
|
||||
|
||||
export function Renderer(config: RendererBasicConfig) {
|
||||
return function<T extends RendererComponent>(component: T): T {
|
||||
return function <T extends RendererComponent>(component: T): T {
|
||||
const renderer = registerRenderer({
|
||||
...config,
|
||||
component: component
|
||||
@ -215,9 +225,7 @@ export function registerRenderer(config: RendererConfig): RendererConfig {
|
||||
|
||||
if (~rendererNames.indexOf(config.name)) {
|
||||
throw new Error(
|
||||
`The renderer with name "${
|
||||
config.name
|
||||
}" has already exists, please try another name!`
|
||||
`The renderer with name "${config.name}" has already exists, please try another name!`
|
||||
);
|
||||
}
|
||||
|
||||
@ -322,6 +330,8 @@ export interface RootRendererProps {
|
||||
env: RendererEnv;
|
||||
theme: string;
|
||||
pathPrefix?: string;
|
||||
locale?: string;
|
||||
translate?: TranslateFn;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
@ -362,6 +372,8 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
||||
pathPrefix,
|
||||
location,
|
||||
data,
|
||||
locale,
|
||||
translate,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
@ -385,28 +397,32 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
||||
return (
|
||||
<RootStoreContext.Provider value={rootStore}>
|
||||
<ThemeContext.Provider value={this.props.theme || 'default'}>
|
||||
<ImageGallery modalContainer={env.getModalContainer}>
|
||||
{
|
||||
renderChild(
|
||||
pathPrefix || '',
|
||||
isPlainObject(schema)
|
||||
? {
|
||||
type: 'page',
|
||||
...(schema as Schema)
|
||||
}
|
||||
: schema,
|
||||
{
|
||||
...rest,
|
||||
resolveDefinitions: this.resolveDefinitions,
|
||||
location: location,
|
||||
data: finalData,
|
||||
env,
|
||||
classnames: theme.classnames,
|
||||
classPrefix: theme.classPrefix
|
||||
}
|
||||
) as JSX.Element
|
||||
}
|
||||
</ImageGallery>
|
||||
<LocaleContext.Provider value={this.props.locale!}>
|
||||
<ImageGallery modalContainer={env.getModalContainer}>
|
||||
{
|
||||
renderChild(
|
||||
pathPrefix || '',
|
||||
isPlainObject(schema)
|
||||
? {
|
||||
type: 'page',
|
||||
...(schema as Schema)
|
||||
}
|
||||
: schema,
|
||||
{
|
||||
...rest,
|
||||
resolveDefinitions: this.resolveDefinitions,
|
||||
location: location,
|
||||
data: finalData,
|
||||
env,
|
||||
classnames: theme.classnames,
|
||||
classPrefix: theme.classPrefix,
|
||||
locale,
|
||||
translate
|
||||
}
|
||||
) as JSX.Element
|
||||
}
|
||||
</ImageGallery>
|
||||
</LocaleContext.Provider>
|
||||
</ThemeContext.Provider>
|
||||
</RootStoreContext.Provider>
|
||||
);
|
||||
@ -634,7 +650,7 @@ export function HocStoreFactory(renderer: {
|
||||
storeType: string;
|
||||
extendsData?: boolean;
|
||||
}): any {
|
||||
return function<T extends React.ComponentType<RendererProps>>(Component: T) {
|
||||
return function <T extends React.ComponentType<RendererProps>>(Component: T) {
|
||||
type Props = Omit<
|
||||
RendererProps,
|
||||
'store' | 'data' | 'dataUpdatedAt' | 'scope'
|
||||
@ -646,8 +662,9 @@ export function HocStoreFactory(renderer: {
|
||||
|
||||
@observer
|
||||
class StoreFactory extends React.Component<Props> {
|
||||
static displayName = `WithStore(${Component.displayName ||
|
||||
Component.name})`;
|
||||
static displayName = `WithStore(${
|
||||
Component.displayName || Component.name
|
||||
})`;
|
||||
static ComposedComponent = Component;
|
||||
static contextType = RootStoreContext;
|
||||
store: IIRendererStore;
|
||||
@ -839,7 +856,7 @@ export function HocStoreFactory(renderer: {
|
||||
return (
|
||||
<Component
|
||||
{
|
||||
...rest as any /* todo */
|
||||
...(rest as any) /* todo */
|
||||
}
|
||||
{...exprProps}
|
||||
ref={this.refFn}
|
||||
@ -956,6 +973,8 @@ export function render(
|
||||
const env = getEnv(store);
|
||||
const theme = props.theme || options.theme || 'default';
|
||||
env.theme = getTheme(theme);
|
||||
const locale = props.locale || getDefaultLocale();
|
||||
const translate = props.translate || makeTranslator(locale);
|
||||
|
||||
return (
|
||||
<ScopedRootRenderer
|
||||
@ -965,6 +984,8 @@ export function render(
|
||||
rootStore={store}
|
||||
env={env}
|
||||
theme={theme}
|
||||
locale={locale}
|
||||
translate={translate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -2,15 +2,16 @@
|
||||
import cx from 'classnames';
|
||||
import React from 'react';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
import {ExtractProps, Omit} from './types';
|
||||
import {isObject} from './utils/helper';
|
||||
import {resolveVariable, resolveVariableAndFilter} from './utils/tpl-builtin';
|
||||
|
||||
type translateFn = (str: string, ...args: any[]) => string;
|
||||
export type TranslateFn<T = any> = (str: T, data?: object) => T;
|
||||
|
||||
interface LocaleConfig {
|
||||
[propsName: string]: string;
|
||||
}
|
||||
|
||||
let defaultLocale: string = '';
|
||||
let defaultLocale: string = 'zh-cn';
|
||||
|
||||
const locales: {
|
||||
[propName: string]: LocaleConfig;
|
||||
@ -21,54 +22,68 @@ export function register(name: string, config: LocaleConfig) {
|
||||
}
|
||||
|
||||
const fns: {
|
||||
[propName: string]: translateFn;
|
||||
[propName: string]: TranslateFn;
|
||||
} = {};
|
||||
|
||||
// todo 支持参数
|
||||
function format(str: string, ...args: any[]) {
|
||||
return str;
|
||||
function format(str: string, data?: object) {
|
||||
return str.replace(
|
||||
/(\\)?\$([a-z0-9_.]+?)|\$\{([\s\S]+?)\}/g,
|
||||
(_, escape, key1, key2) => {
|
||||
if (escape) {
|
||||
return _.substring(1);
|
||||
}
|
||||
|
||||
return resolveVariable(key1 || key2, data || {});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function makeTranslator(locale?: string): translateFn {
|
||||
export function makeTranslator(locale?: string): TranslateFn {
|
||||
if (locale && fns[locale]) {
|
||||
return fns[locale];
|
||||
}
|
||||
|
||||
const fn = (str: string, ...args: any[]) => {
|
||||
const fn = (str: any, ...args: any[]) => {
|
||||
if (!str || typeof str !== 'string') {
|
||||
return str;
|
||||
}
|
||||
|
||||
const dict = locales[locale!] || locales[defaultLocale];
|
||||
return format(dict[str] || str, ...args);
|
||||
return format(dict?.[str] || str, ...args);
|
||||
};
|
||||
|
||||
locale && (fns[locale] = fn);
|
||||
return fn;
|
||||
}
|
||||
|
||||
export function getDefaultLocale() {
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
export function setDefaultLocale(loacle: string) {
|
||||
defaultLocale = loacle;
|
||||
}
|
||||
|
||||
export interface LocaleProps {
|
||||
locale: string;
|
||||
translate: translateFn;
|
||||
translate: TranslateFn;
|
||||
}
|
||||
|
||||
export const LocaleContext = React.createContext('locale');
|
||||
export const LocaleContext = React.createContext('');
|
||||
|
||||
export function localeable<
|
||||
T extends React.ComponentType<LocaleProps & ExtractProps<T>>
|
||||
T extends React.ComponentType<React.ComponentProps<T> & LocaleProps>
|
||||
>(ComposedComponent: T) {
|
||||
type ComposedProps = JSX.LibraryManagedAttributes<T, ExtractProps<T>>;
|
||||
type Props = Omit<ComposedProps, keyof LocaleProps> & {
|
||||
type OuterProps = JSX.LibraryManagedAttributes<
|
||||
T,
|
||||
Omit<React.ComponentProps<T>, keyof LocaleProps>
|
||||
> & {
|
||||
locale?: string;
|
||||
translate: (str: string, ...args: any[]) => string;
|
||||
translate?: (str: string, ...args: any[]) => string;
|
||||
};
|
||||
|
||||
const result = hoistNonReactStatic(
|
||||
class extends React.Component<Props> {
|
||||
class extends React.Component<OuterProps> {
|
||||
static displayName = `I18N(${
|
||||
ComposedComponent.displayName || ComposedComponent.name
|
||||
})`;
|
||||
@ -78,21 +93,22 @@ export function localeable<
|
||||
render() {
|
||||
const locale: string =
|
||||
this.props.locale || this.context || defaultLocale;
|
||||
const translate = makeTranslator(locale);
|
||||
const translate = this.props.translate || makeTranslator(locale);
|
||||
const injectedProps: {
|
||||
locale: string;
|
||||
translate: translateFn;
|
||||
translate: TranslateFn;
|
||||
} = {
|
||||
locale,
|
||||
translate
|
||||
translate: translate!
|
||||
};
|
||||
|
||||
return (
|
||||
<LocaleContext.Provider value={locale}>
|
||||
<ComposedComponent
|
||||
{
|
||||
...(this.props as any) /* todo, 解决这个类型问题 */
|
||||
}
|
||||
{...(this.props as JSX.LibraryManagedAttributes<
|
||||
T,
|
||||
React.ComponentProps<T>
|
||||
>)}
|
||||
{...injectedProps}
|
||||
/>
|
||||
</LocaleContext.Provider>
|
||||
|
153
src/locale/en.ts
Normal file
153
src/locale/en.ts
Normal file
@ -0,0 +1,153 @@
|
||||
import {register} from '../locale';
|
||||
|
||||
register('en', {
|
||||
'确认': 'Confirm',
|
||||
'取消': 'Cancel',
|
||||
'YYYY年': 'YYYY',
|
||||
'MM月': 'MMM',
|
||||
'${from}年-${to}年': '${from} - ${to}',
|
||||
'请选择日期': 'Select Date',
|
||||
'请选择日期以及时间': 'Select Datetime',
|
||||
'请选择时间': 'Select time',
|
||||
'系统消息': 'System Info',
|
||||
'加载中': 'Loading',
|
||||
'点击刷新重新加载': 'Click to refresh',
|
||||
'请先选择左侧数据': 'Select from left first.',
|
||||
'请选择颜色': 'Select color',
|
||||
'现在': 'Now',
|
||||
'今天': 'Today',
|
||||
'昨天': 'Yesterday',
|
||||
'本周一': 'This monday',
|
||||
'本月初': 'Early this month',
|
||||
'上个月初': 'Early prev month',
|
||||
'上个季节初': 'Early this quarter',
|
||||
'明天': 'Tomorrow',
|
||||
'本周日': 'Last day of this week',
|
||||
'本月底': 'Last day of this month',
|
||||
'${hours}小时前': '${hours} hour(s) ago',
|
||||
'${hours}小时后': '${hours} hour(s) after',
|
||||
'${days}天前': '${days} day(s) ago',
|
||||
'${days}天后': '${days} day(s) after',
|
||||
'${weeks}周前': '${weeks} week(s) ago',
|
||||
'${weeks}周后': '${weeks} week(s) after',
|
||||
'${months}月前': '${months} month(s) ago',
|
||||
'${months}月后': '${months} month(s) after',
|
||||
'${quarters}季度前': '${quarters} quarter(s) ago',
|
||||
'${quarters}季度后': '${quarters} quarter(s) after',
|
||||
' 至 ': ' to ',
|
||||
'最近1天': 'Last day',
|
||||
'最近7天': 'Last week',
|
||||
'最近90天': 'Last 90 days',
|
||||
'上周': 'Prev week',
|
||||
'本月': 'This month',
|
||||
'上个月': 'Prev month',
|
||||
'上个季节': 'Prev quarter',
|
||||
'本季度': 'This quarter',
|
||||
'请选择日期范围': 'Select daterange',
|
||||
'关闭': 'Close',
|
||||
'暂无选项': 'No Options',
|
||||
'请选择位置': 'Pick location',
|
||||
'无': 'None',
|
||||
'没有数据': 'No data',
|
||||
'请先选择数据': 'Select data first',
|
||||
'请选择': 'Select',
|
||||
'全选': 'Check all',
|
||||
'搜索结果': 'Search result',
|
||||
'清空': 'Clear',
|
||||
'当前选择': 'Selected',
|
||||
'添加一级节点': 'Add root node',
|
||||
'添加孩子节点': 'Add child',
|
||||
'编辑该节点': 'Edit this node',
|
||||
'移除该节点': 'Remove this node',
|
||||
'请输入': 'Enter',
|
||||
'请输入关键字': 'Enter keywords',
|
||||
'新增选项': 'New Option',
|
||||
'请输入街道信息': 'Enter street info',
|
||||
'删除': 'Delete',
|
||||
'新增': 'New',
|
||||
'新增一条数据': 'Create a new data',
|
||||
'类型': 'Type',
|
||||
'拖拽排序': 'Drag to sort',
|
||||
'删除失败': 'Delete success',
|
||||
'确认要删除?': 'Are u sure to delete?',
|
||||
'组合表单成员数量不够,低于设定的最小${minLenth}个,请添加更多的成员。':
|
||||
'The count of members is less than ${minLenth}.',
|
||||
'组合表单成员数量超出,超出设定的最大${maxLength}个,请删除多余的成员。':
|
||||
'The count of members is more than ${maxLength}.',
|
||||
'子表单验证失败,请仔细检查': 'Validate failed, please check this sub-form.',
|
||||
'成员${index}': 'Member ${index}',
|
||||
'清空数据': 'Clear data',
|
||||
'您选择的文件 ${filename} 大小为 ${actualSize} 超出了最大为 ${maxSize} 的限制,请重新选择。':
|
||||
'The size of ${filename} ${actualSize} is great than ${maxSize}.',
|
||||
|
||||
'您添加的文件${files}不符合类型的`${accept}`的设定,请仔细检查。':
|
||||
'The files ${files} are not match `${accept}`, please retry.',
|
||||
'把文件拖到这,然后松完成添加!':
|
||||
'Drag the file here, then release to finish adding!',
|
||||
'把图片拖到这,然后松开完成添加!':
|
||||
'Drag the picture here, then release to finish adding!',
|
||||
'重新上传': 'Repick',
|
||||
'重试上传': 'Retry',
|
||||
'继续添加': 'Continue add',
|
||||
'上传文件': 'Upload file',
|
||||
'移除': 'Remove',
|
||||
'暂停上传': 'Pause uplaod',
|
||||
'开始上传': 'Start upload',
|
||||
'已成功上传{uploaded}个文件,{failed}个文件上传失败,':
|
||||
'${uploaded} files success, ${failed} failed, ',
|
||||
'失败文件': 'failed files.',
|
||||
'高度${height}px': 'height: ${height}px',
|
||||
'宽度${width}px': 'width: ${width}px',
|
||||
'尺寸(${width} x ${height})': 'size: (${width}px x ${height}px)',
|
||||
'您选择的图片不符合尺寸要求, 请上传${info}的图片':
|
||||
'The picture you selected does not meet the size requirements. Please upload the picture of ${info}',
|
||||
'您选择的图片不符合尺寸要求, 请上传不要超过${info}的图片':
|
||||
'The picture you selected does not meet the size requirements. Please upload a picture that does not exceed ${info}`.',
|
||||
'您选择的图片不符合尺寸要求, 请上传不要小于${info}的图片':
|
||||
'The picture you selected does not meet the size requirements. Please upload a picture no less than ${info}',
|
||||
'您选择的图片不符合尺寸要求, 请上传尺寸比率为 ${ratio} 的图片':
|
||||
'The picture you selected does not meet the size requirements. Please upload the picture with the size ratio of ${ration}',
|
||||
'文件上传失败请重试': 'File upload failed, please try again',
|
||||
'文件上传中': 'File uploading',
|
||||
'查看大图': 'Zoom',
|
||||
'裁剪图片': 'Crop picture',
|
||||
'当前状态支持从剪切板中粘贴图片文件。':
|
||||
'The current state supports pasting picture files from the clipboard.',
|
||||
'表单': 'Form',
|
||||
'提交': 'Submit',
|
||||
'初始化失败': 'initialization failed',
|
||||
'保存成功': 'Saved successfully',
|
||||
'保存失败': 'Save failed',
|
||||
'依赖的部分字段没有通过验证,请注意填写!':
|
||||
'Some of the dependent fields failed to pass the verification, please fill in!',
|
||||
'请输入名称': 'Please enter a name',
|
||||
'编辑${label}': 'Edit ${label}',
|
||||
'每': 'Per',
|
||||
'编辑详情': 'Detail',
|
||||
'删除当前行': 'Delete current row',
|
||||
'操作': 'Operation',
|
||||
'新增一行': 'Add a new row',
|
||||
'暂无标签': 'No tag yet',
|
||||
'新增:${label}': 'New ${label}',
|
||||
'顶级': 'Root',
|
||||
'点击复制': 'Copy',
|
||||
'${page}/${lastPage} 总共:${total} 项。':
|
||||
'${page} of ${lastPage} total: ${total}.',
|
||||
'每页显示': 'Per page',
|
||||
'加载更多': 'Load more',
|
||||
'筛选': 'Filter',
|
||||
'搜索': 'Search',
|
||||
'日期无效': 'Invalid date',
|
||||
'关闭弹窗': 'Close',
|
||||
'链接': 'Link',
|
||||
'当前有 ${modified} 条记录修改了内容, 但并没有提交。请选择:':
|
||||
'There are currently ${modified} records that have modified the contents, but they have not been submitted. Please select:',
|
||||
'放弃': 'Give up',
|
||||
'当前有 ${moved} 条记录修改了顺序, 但并没有提交。请选择:':
|
||||
'There are currently ${moved} records that have changed the order, but have not been committed. Please select:',
|
||||
'点击开始排序': 'Click to start sorting',
|
||||
'请拖动左边的按钮进行排序': 'Please drag the button on the left to sort',
|
||||
'排序': 'Sort',
|
||||
'正序': 'Asc',
|
||||
'降序': 'Desc'
|
||||
});
|
@ -40,7 +40,6 @@ const ActionProps = [
|
||||
];
|
||||
import {filterContents} from './Remark';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {Omit} from '../types';
|
||||
import {autobind} from '../utils/helper';
|
||||
|
||||
export interface ActionProps {
|
||||
|
@ -1335,16 +1335,20 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
|
||||
renderStatistics() {
|
||||
const {store, classnames: cx} = this.props;
|
||||
const {store, classnames: cx, translate: __} = this.props;
|
||||
|
||||
if (store.lastPage <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx('Crud-statistics')}>{`${
|
||||
store.page + '/' + store.lastPage
|
||||
}总共${store.total}项。`}</div>
|
||||
<div className={cx('Crud-statistics')}>
|
||||
{__('${page}/${lastPage} 总共:${total} 项。', {
|
||||
page: store.page,
|
||||
lastPage: store.lastPage,
|
||||
total: store.total
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1353,7 +1357,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
store,
|
||||
perPageAvailable,
|
||||
classnames: cx,
|
||||
classPrefix: ns
|
||||
classPrefix: ns,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const items = childProps.items;
|
||||
@ -1371,11 +1376,11 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
|
||||
return (
|
||||
<div className={cx('Crud-pageSwitch')}>
|
||||
每页显示
|
||||
{__('每页显示')}
|
||||
<Select
|
||||
classPrefix={ns}
|
||||
searchable={false}
|
||||
placeholder="请选择.."
|
||||
placeholder={__('请选择')}
|
||||
options={perPages}
|
||||
value={store.perPage + ''}
|
||||
onChange={(value: any) => this.handleChangePage(1, value.value)}
|
||||
@ -1386,7 +1391,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
|
||||
renderLoadMore() {
|
||||
const {store, classPrefix: ns, classnames: cx} = this.props;
|
||||
const {store, classPrefix: ns, classnames: cx, translate: __} = this.props;
|
||||
const {page, lastPage} = store;
|
||||
|
||||
return page < lastPage ? (
|
||||
@ -1399,7 +1404,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
size="sm"
|
||||
className="btn-primary"
|
||||
>
|
||||
加载更多
|
||||
{__('加载更多')}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
@ -1408,7 +1413,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
|
||||
renderFilterToggler() {
|
||||
const {store, classnames: cx} = this.props;
|
||||
const {store, classnames: cx, translate: __} = this.props;
|
||||
|
||||
if (!store.filterTogggable) {
|
||||
return null;
|
||||
@ -1422,7 +1427,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
})}
|
||||
>
|
||||
<i className="fa fa-sliders m-r-sm" />
|
||||
筛选
|
||||
{__('筛选')}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@ -1574,7 +1579,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
classnames: cx,
|
||||
labelField,
|
||||
labelTpl,
|
||||
primaryField
|
||||
primaryField,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (!store.selectedItems.length) {
|
||||
@ -1587,7 +1593,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
{store.selectedItems.map((item, index) => (
|
||||
<div key={index} className={cx(`Crud-value`)}>
|
||||
<span
|
||||
data-tooltip="删除"
|
||||
data-tooltip={__('删除')}
|
||||
data-position="bottom"
|
||||
className={cx('Crud-valueIcon')}
|
||||
onClick={this.unSelectItem.bind(this, item, index)}
|
||||
@ -1605,7 +1611,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
</div>
|
||||
))}
|
||||
<a onClick={this.clearSelection} className={cx('Crud-selectionClear')}>
|
||||
清空
|
||||
{__('清空')}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
@ -1633,6 +1639,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
keepItemSelectionOnPageChange,
|
||||
onAction,
|
||||
popOverContainer,
|
||||
translate: __,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
@ -1646,9 +1653,9 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
? render(
|
||||
'filter',
|
||||
{
|
||||
title: '条件过滤',
|
||||
title: __('条件过滤'),
|
||||
mode: 'inline',
|
||||
submitText: '搜索',
|
||||
submitText: __('搜索'),
|
||||
...filter,
|
||||
type: 'form',
|
||||
api: null
|
||||
|
@ -177,9 +177,9 @@ export default class Cards extends React.Component<GridProps, object> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let parent: HTMLElement | Window | null = getScrollParent(findDOMNode(
|
||||
this
|
||||
) as HTMLElement);
|
||||
let parent: HTMLElement | Window | null = getScrollParent(
|
||||
findDOMNode(this) as HTMLElement
|
||||
);
|
||||
if (!parent || parent === document.body) {
|
||||
parent = window;
|
||||
}
|
||||
@ -282,9 +282,7 @@ export default class Cards extends React.Component<GridProps, object> {
|
||||
const afixedDom = dom.querySelector(`.${ns}Cards-fixedTop`) as HTMLElement;
|
||||
|
||||
this.body.offsetWidth &&
|
||||
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${
|
||||
this.body.offsetWidth
|
||||
}px;`);
|
||||
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${this.body.offsetWidth}px;`);
|
||||
affixed ? afixedDom.classList.add('in') : afixedDom.classList.remove('in');
|
||||
// store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
|
||||
}
|
||||
@ -520,9 +518,7 @@ export default class Cards extends React.Component<GridProps, object> {
|
||||
<div className={cx('Cards-heading')}>
|
||||
{store.modified && !hideQuickSaveBtn ? (
|
||||
<span>
|
||||
{`当前有 ${
|
||||
store.modified
|
||||
} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
{`当前有 ${store.modified} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
<button
|
||||
type="button"
|
||||
className={cx('Button Button--xs Button--success m-l-sm')}
|
||||
@ -753,7 +749,8 @@ export default class Cards extends React.Component<GridProps, object> {
|
||||
masonryLayout,
|
||||
itemsClassName,
|
||||
classnames: cx,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.renderedToolbars = []; // 用来记录哪些 toolbar 已经渲染了,已经渲染了就不重复渲染了。
|
||||
@ -840,7 +837,7 @@ export default class Cards extends React.Component<GridProps, object> {
|
||||
</div>
|
||||
) : (
|
||||
<div className={cx('Cards-placeholder')}>
|
||||
{filter(placeholder, data)}
|
||||
{filter(__(placeholder), data)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
@ -38,7 +38,8 @@ export const HocCopyable = () => (Component: React.ComponentType<any>): any => {
|
||||
className,
|
||||
data,
|
||||
noHoc,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (copyable && !noHoc) {
|
||||
@ -55,7 +56,7 @@ export const HocCopyable = () => (Component: React.ComponentType<any>): any => {
|
||||
<Component {...this.props} wrapperComponent={''} noHoc />
|
||||
<i
|
||||
key="edit-btn"
|
||||
data-tooltip="点击复制"
|
||||
data-tooltip={__('点击复制')}
|
||||
className={cx('Field-copyBtn fa fa-clipboard')}
|
||||
onClick={this.handleClick.bind(this, content)}
|
||||
/>
|
||||
|
@ -55,7 +55,8 @@ export class DateField extends React.Component<DateProps, DateState> {
|
||||
placeholder,
|
||||
fromNow,
|
||||
className,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
translate: __
|
||||
} = this.props;
|
||||
let viewValue: React.ReactNode = (
|
||||
<span className="text-muted">{placeholder}</span>
|
||||
@ -77,7 +78,7 @@ export class DateField extends React.Component<DateProps, DateState> {
|
||||
}
|
||||
|
||||
viewValue = !viewValue ? (
|
||||
<span className="text-danger">日期无效</span>
|
||||
<span className="text-danger">{__('日期无效')}</span>
|
||||
) : (
|
||||
viewValue
|
||||
);
|
||||
|
@ -122,7 +122,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
||||
}
|
||||
|
||||
buildActions(): Array<Action> {
|
||||
const {actions, confirm} = this.props;
|
||||
const {actions, confirm, translate: __} = this.props;
|
||||
|
||||
if (typeof actions !== 'undefined') {
|
||||
return actions;
|
||||
@ -132,14 +132,14 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'cancel',
|
||||
label: '取消'
|
||||
label: __('取消')
|
||||
});
|
||||
|
||||
if (confirm) {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '确认',
|
||||
label: __('确认'),
|
||||
primary: true
|
||||
});
|
||||
}
|
||||
@ -380,7 +380,8 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
||||
showCloseButton,
|
||||
env,
|
||||
classnames: cx,
|
||||
classPrefix
|
||||
classPrefix,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
// console.log('Render Dialog');
|
||||
@ -408,7 +409,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
||||
<div className={cx('Modal-header', headerClassName)}>
|
||||
{showCloseButton !== false && !store.loading ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-tooltip={__('关闭弹窗')}
|
||||
data-position="left"
|
||||
onClick={this.handleSelfClose}
|
||||
className={cx('Modal-close')}
|
||||
@ -417,14 +418,14 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
||||
</a>
|
||||
) : null}
|
||||
<div className={cx('Modal-title')}>
|
||||
{filter(title, store.formData)}
|
||||
{filter(__(title), store.formData)}
|
||||
</div>
|
||||
</div>
|
||||
) : title ? (
|
||||
<div className={cx('Modal-header', headerClassName)}>
|
||||
{showCloseButton !== false && !store.loading ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-tooltip={__('关闭弹窗')}
|
||||
onClick={this.handleSelfClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
@ -437,7 +438,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
||||
</div>
|
||||
) : showCloseButton !== false && !store.loading ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-tooltip={__('关闭弹窗')}
|
||||
onClick={this.handleSelfClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
|
@ -113,7 +113,7 @@ export default class Drawer extends React.Component<DrawerProps, object> {
|
||||
}
|
||||
|
||||
buildActions(): Array<Action> {
|
||||
const {actions, confirm} = this.props;
|
||||
const {actions, confirm, translate: __} = this.props;
|
||||
|
||||
if (typeof actions !== 'undefined') {
|
||||
return actions;
|
||||
@ -123,14 +123,14 @@ export default class Drawer extends React.Component<DrawerProps, object> {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'close',
|
||||
label: '取消'
|
||||
label: __('取消')
|
||||
});
|
||||
|
||||
if (confirm) {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '确认',
|
||||
label: __('确认'),
|
||||
primary: true
|
||||
});
|
||||
}
|
||||
|
@ -165,7 +165,8 @@ export default class CheckboxesControl extends React.Component<
|
||||
labelClassName,
|
||||
creatable,
|
||||
addApi,
|
||||
createBtnLabel
|
||||
createBtnLabel,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let body: Array<React.ReactNode> = [];
|
||||
@ -217,13 +218,13 @@ export default class CheckboxesControl extends React.Component<
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<span className={`Form-placeholder`}>{placeholder}</span>
|
||||
<span className={`Form-placeholder`}>{__(placeholder)}</span>
|
||||
)}
|
||||
|
||||
{(creatable || addApi) && !disabled ? (
|
||||
<a className={cx('Checkboxes-addBtn')} onClick={this.handleAddClick}>
|
||||
<Icon icon="plus" className="icon" />
|
||||
{createBtnLabel}
|
||||
{__(createBtnLabel)}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -226,7 +226,8 @@ export class CityPicker extends React.Component<
|
||||
disabled,
|
||||
allowCity,
|
||||
allowDistrict,
|
||||
allowStreet
|
||||
allowStreet,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const {provinceCode, cityCode, districtCode, street} = this.state;
|
||||
@ -290,7 +291,7 @@ export class CityPicker extends React.Component<
|
||||
value={street}
|
||||
onChange={this.handleStreetChange}
|
||||
onBlur={this.handleStreetEnd}
|
||||
placeholder="请输入街道信息"
|
||||
placeholder={__('请输入街道信息')}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -321,7 +321,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
deleteApi,
|
||||
deleteConfirmText,
|
||||
data,
|
||||
env
|
||||
env,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (disabled) {
|
||||
@ -333,7 +334,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
|
||||
if (isEffectiveApi(deleteApi, ctx)) {
|
||||
const confirmed = await env.confirm(
|
||||
deleteConfirmText ? filter(deleteConfirmText, ctx) : '确认要删除?'
|
||||
deleteConfirmText ? filter(deleteConfirmText, ctx) : __('确认要删除?')
|
||||
);
|
||||
if (!confirmed) {
|
||||
// 如果不确认,则跳过!
|
||||
@ -343,7 +344,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
const result = await env.fetcher(deleteApi as Api, ctx);
|
||||
|
||||
if (!result.ok) {
|
||||
env.notify('error', '删除失败');
|
||||
env.notify('error', __('删除失败'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -480,25 +481,34 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
}
|
||||
|
||||
validate(): any {
|
||||
const {value, minLength, maxLength, messages, nullable} = this.props;
|
||||
const {
|
||||
value,
|
||||
minLength,
|
||||
maxLength,
|
||||
messages,
|
||||
nullable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (minLength && (!Array.isArray(value) || value.length < minLength)) {
|
||||
return (
|
||||
return __(
|
||||
(messages && messages.minLengthValidateFailed) ||
|
||||
`组合表单成员数量不够,低于设定的最小${minLength}个,请添加更多的成员。`
|
||||
'组合表单成员数量不够,低于设定的最小${minLenth}个,请添加更多的成员。',
|
||||
{minLength}
|
||||
);
|
||||
} else if (maxLength && Array.isArray(value) && value.length > maxLength) {
|
||||
return (
|
||||
return __(
|
||||
(messages && messages.maxLengthValidateFailed) ||
|
||||
`组合表单成员数量超出,超出设定的最大${maxLength}个,请删除多余的成员。`
|
||||
'组合表单成员数量超出,超出设定的最大${maxLength}个,请删除多余的成员。',
|
||||
{maxLength}
|
||||
);
|
||||
} else if (this.subForms.length && (!nullable || value)) {
|
||||
return Promise.all(this.subForms.map(item => item.validate())).then(
|
||||
values => {
|
||||
if (~values.indexOf(false)) {
|
||||
return (
|
||||
return __(
|
||||
(messages && messages.validateFailed) ||
|
||||
'子表单验证失败,请仔细检查'
|
||||
'子表单验证失败,请仔细检查'
|
||||
);
|
||||
}
|
||||
|
||||
@ -698,9 +708,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
}
|
||||
|
||||
renderPlaceholder() {
|
||||
return (
|
||||
<span className="text-muted">{this.props.placeholder || '没有数据'}</span>
|
||||
);
|
||||
const {placeholder, translate: __} = this.props;
|
||||
return <span className="text-muted">{__(placeholder || '没有数据')}</span>;
|
||||
}
|
||||
|
||||
renderTabsMode() {
|
||||
@ -725,7 +734,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
deleteIcon,
|
||||
tabsLabelTpl,
|
||||
conditions,
|
||||
changeImmediately
|
||||
changeImmediately,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let controls = this.props.controls;
|
||||
@ -762,7 +772,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
{
|
||||
type: 'dropdown-button',
|
||||
icon: addIcon,
|
||||
label: addButtonText || '新增',
|
||||
label: __(addButtonText || '新增'),
|
||||
level: 'info',
|
||||
size: 'sm',
|
||||
closeOnClick: true
|
||||
@ -781,10 +791,10 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
<a
|
||||
onClick={this.addItem}
|
||||
data-position="left"
|
||||
data-tooltip="新增一条数据"
|
||||
data-tooltip={__('新增一条数据')}
|
||||
>
|
||||
{addIcon ? <i className={cx('m-r-xs', addIcon)} /> : null}
|
||||
<span>{addButtonText || '新增'}</span>
|
||||
<span>{__(addButtonText || '新增')}</span>
|
||||
</a>
|
||||
)
|
||||
) : null}
|
||||
@ -808,7 +818,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
className={cx(
|
||||
`Combo-toolbarBtn ${!store.removable ? 'is-disabled' : ''}`
|
||||
)}
|
||||
data-tooltip="删除"
|
||||
data-tooltip={__('删除')}
|
||||
data-position="bottom"
|
||||
>
|
||||
{deleteIcon ? (
|
||||
@ -837,7 +847,11 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
|
||||
return (
|
||||
<Tab
|
||||
title={filter(tabsLabelTpl || '成员${index|plus}', data)}
|
||||
title={filter(
|
||||
tabsLabelTpl ||
|
||||
__('成员${index}', {index: (data as any).index + 1}),
|
||||
data
|
||||
)}
|
||||
key={this.keys[index] || (this.keys[index] = guid())}
|
||||
toolbar={toolbar}
|
||||
eventKey={index}
|
||||
@ -847,7 +861,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
>
|
||||
{condition && typeSwitchable !== false ? (
|
||||
<div className={cx('Combo-itemTag')}>
|
||||
<label>类型</label>
|
||||
<label>{__('类型')}</label>
|
||||
<Select
|
||||
onChange={this.handleComboTypeChange.bind(this, index)}
|
||||
options={(conditions as Array<Condition>).map(item => ({
|
||||
@ -888,7 +902,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
)
|
||||
) : (
|
||||
<Alert2 level="warning" className="m-b-none">
|
||||
数据非法,或者数据已失效,请移除
|
||||
{__('数据非法,或者数据已失效,请移除')}
|
||||
</Alert2>
|
||||
)}
|
||||
</div>
|
||||
@ -931,7 +945,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
conditions,
|
||||
lazyLoad,
|
||||
changeImmediately,
|
||||
placeholder
|
||||
placeholder,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let controls = this.props.controls;
|
||||
@ -990,7 +1005,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
!store.removable ? 'is-disabled' : ''
|
||||
}`
|
||||
)}
|
||||
data-tooltip="删除"
|
||||
data-tooltip={__('删除')}
|
||||
data-position="bottom"
|
||||
>
|
||||
{deleteIcon ? (
|
||||
@ -1029,7 +1044,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
<div className={cx('Combo-itemDrager')}>
|
||||
<a
|
||||
key="drag"
|
||||
data-tooltip="拖拽排序"
|
||||
data-tooltip={__('拖拽排序')}
|
||||
data-position="bottom"
|
||||
>
|
||||
{dragIcon ? (
|
||||
@ -1042,7 +1057,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
) : null}
|
||||
{condition && typeSwitchable !== false ? (
|
||||
<div className={cx('Combo-itemTag')}>
|
||||
<label>类型</label>
|
||||
<label>{__('类型')}</label>
|
||||
<Select
|
||||
onChange={this.handleComboTypeChange.bind(this, index)}
|
||||
options={(conditions as Array<Condition>).map(item => ({
|
||||
@ -1084,7 +1099,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
)
|
||||
) : (
|
||||
<Alert2 level="warning" className="m-b-none">
|
||||
数据非法,或者数据已失效,请移除
|
||||
{__('数据非法,或者数据已失效,请移除')}
|
||||
</Alert2>
|
||||
)}
|
||||
</div>
|
||||
@ -1107,7 +1122,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
{
|
||||
type: 'dropdown-button',
|
||||
icon: addIcon,
|
||||
label: addButtonText || '新增',
|
||||
label: __(addButtonText || '新增'),
|
||||
level: 'info',
|
||||
size: 'sm',
|
||||
closeOnClick: true
|
||||
@ -1127,18 +1142,20 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
type="button"
|
||||
onClick={this.addItem}
|
||||
className={cx(`Button Combo-addBtn`, addButtonClassName)}
|
||||
data-tooltip="新增一条数据"
|
||||
data-tooltip={__('新增一条数据')}
|
||||
>
|
||||
{addIcon ? (
|
||||
<i className={cx('Button-icon', addIcon)} />
|
||||
) : null}
|
||||
<span>{addButtonText || '新增'}</span>
|
||||
<span>{__(addButtonText || '新增')}</span>
|
||||
</button>
|
||||
)
|
||||
) : null}
|
||||
{draggable ? (
|
||||
<span className={cx(`Combo-dragableTip`)} ref={this.dragTipRef}>
|
||||
{Array.isArray(value) && value.length > 1 ? draggableTip : ''}
|
||||
{Array.isArray(value) && value.length > 1
|
||||
? __(draggableTip)
|
||||
: ''}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
@ -1159,7 +1176,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
noBorder,
|
||||
disabled,
|
||||
typeSwitchable,
|
||||
nullable
|
||||
nullable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let controls = this.props.controls;
|
||||
@ -1183,7 +1201,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
<div className={cx(`Combo-item`)}>
|
||||
{condition && typeSwitchable !== false ? (
|
||||
<div className={cx('Combo-itemTag')}>
|
||||
<label>类型</label>
|
||||
<label>{__('类型')}</label>
|
||||
<Select
|
||||
onChange={this.handleComboTypeChange.bind(this, 0)}
|
||||
options={(conditions as Array<Condition>).map(item => ({
|
||||
@ -1219,14 +1237,14 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
)
|
||||
) : (
|
||||
<Alert2 level="warning" className="m-b-none">
|
||||
数据非法,或者数据已失效,请移除
|
||||
{__('数据非法,或者数据已失效,请移除')}
|
||||
</Alert2>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{value && nullable ? (
|
||||
<a className={cx('Combo-setNullBtn')} href="#" onClick={this.setNull}>
|
||||
清空数据
|
||||
{__('清空数据')}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -101,6 +101,8 @@ export default class DateControl extends React.PureComponent<
|
||||
defaultValue,
|
||||
defaultData,
|
||||
classnames: cx,
|
||||
minDate,
|
||||
maxDate,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
|
@ -271,7 +271,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
return;
|
||||
}
|
||||
|
||||
const {maxSize, multiple, maxLength} = this.props;
|
||||
const {maxSize, multiple, maxLength, translate: __} = this.props;
|
||||
let allowed =
|
||||
multiple && maxLength
|
||||
? maxLength - this.state.files.length
|
||||
@ -282,11 +282,14 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
[].slice.call(files, 0, allowed).forEach((file: FileX) => {
|
||||
if (maxSize && file.size > maxSize) {
|
||||
this.props.env.alert(
|
||||
`您选择的文件 ${file.name} 大小为 ${ImageControl.formatFileSize(
|
||||
file.size
|
||||
)} 超出了最大为 ${ImageControl.formatFileSize(
|
||||
maxSize
|
||||
)} 的限制,请重新选择`
|
||||
__(
|
||||
'您选择的文件 ${filename} 大小为 ${actualSize} 超出了最大为 ${maxSize} 的限制,请重新选择。',
|
||||
{
|
||||
filename: file.name,
|
||||
actualSize: ImageControl.formatFileSize(file.size),
|
||||
maxSize: ImageControl.formatFileSize(maxSize)
|
||||
}
|
||||
)
|
||||
);
|
||||
file.state = 'invalid';
|
||||
} else {
|
||||
@ -320,7 +323,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
if (evt.type !== 'change' && evt.type !== 'drop') {
|
||||
return;
|
||||
}
|
||||
const {multiple, env, accept} = this.props;
|
||||
const {multiple, env, accept, translate: __} = this.props;
|
||||
|
||||
const files = rejectedFiles.map((file: any) => ({
|
||||
...file,
|
||||
@ -338,9 +341,10 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
});
|
||||
|
||||
env.alert(
|
||||
`您添加的文件${files.map(
|
||||
(item: any) => `【${item.name}】`
|
||||
)}不符合类型的\`${accept}\`设定,请仔细检查。`
|
||||
__('您添加的文件${files}不符合类型的`${accept}`的设定,请仔细检查。', {
|
||||
files: files.map((item: any) => `「${item.name}」`).join(' '),
|
||||
accept
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@ -393,6 +397,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
return;
|
||||
}
|
||||
|
||||
const __ = this.props.translate;
|
||||
const file = find(
|
||||
this.state.files,
|
||||
item => item.state === 'pending'
|
||||
@ -463,7 +468,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
if (this.resolve) {
|
||||
this.resolve(
|
||||
this.state.files.some(file => file.state === 'error')
|
||||
? '文件上传失败请重试'
|
||||
? __('文件上传失败请重试')
|
||||
: null
|
||||
);
|
||||
this.resolve = undefined;
|
||||
@ -489,7 +494,8 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
finishChunkApi,
|
||||
asBase64,
|
||||
asBlob,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (asBase64) {
|
||||
@ -545,7 +551,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
)
|
||||
.then(ret => {
|
||||
if (ret.status || !ret.data) {
|
||||
throw new Error(ret.msg || '上传失败, 请重试');
|
||||
throw new Error(ret.msg || __('上传失败, 请重试'));
|
||||
}
|
||||
|
||||
onProgress(1);
|
||||
@ -565,7 +571,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
cb(error.message || '上传失败, 请重试', file);
|
||||
cb(error.message || __('上传失败, 请重试'), file);
|
||||
});
|
||||
}
|
||||
|
||||
@ -660,6 +666,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
let startProgress = 0.2;
|
||||
let endProgress = 0.9;
|
||||
let progressArr: Array<number>;
|
||||
const __ = this.props.translate;
|
||||
|
||||
interface ObjectState {
|
||||
key: string;
|
||||
@ -692,10 +699,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
}
|
||||
);
|
||||
|
||||
self
|
||||
._send(startApi)
|
||||
.then(startChunk)
|
||||
.catch(reject);
|
||||
self._send(startApi).then(startChunk).catch(reject);
|
||||
|
||||
function startChunk(ret: Payload) {
|
||||
onProgress(startProgress);
|
||||
@ -703,7 +707,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
progressArr = tasks.map(() => 0);
|
||||
|
||||
if (!ret.data) {
|
||||
throw new Error('接口返回错误,请仔细检查');
|
||||
throw new Error(__('接口返回错误,请仔细检查'));
|
||||
}
|
||||
|
||||
state = {
|
||||
@ -713,7 +717,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
total: tasks.length
|
||||
};
|
||||
|
||||
mapLimit(tasks, 3, uploadPartFile(state, config), function(
|
||||
mapLimit(tasks, 3, uploadPartFile(state, config), function (
|
||||
err,
|
||||
results
|
||||
) {
|
||||
@ -755,10 +759,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
}
|
||||
);
|
||||
|
||||
self
|
||||
._send(endApi)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
self._send(endApi).then(resolve).catch(reject);
|
||||
}
|
||||
|
||||
function uploadPartFile(state: ObjectState, conf: Partial<FileProps>) {
|
||||
@ -853,6 +854,8 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
}
|
||||
|
||||
validate(): any {
|
||||
const __ = this.props.translate;
|
||||
|
||||
if (
|
||||
this.state.uploading ||
|
||||
this.state.files.some(item => item.state === 'pending')
|
||||
@ -862,7 +865,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
this.startUpload();
|
||||
});
|
||||
} else if (this.state.files.some(item => item.state === 'error')) {
|
||||
return '文件上传失败请重试';
|
||||
return __('文件上传失败请重试');
|
||||
}
|
||||
}
|
||||
|
||||
@ -878,6 +881,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
hideUploadButton,
|
||||
className,
|
||||
classnames: cx,
|
||||
translate: __,
|
||||
render
|
||||
} = this.props;
|
||||
let {files, uploading, error} = this.state;
|
||||
@ -921,7 +925,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
|
||||
{isDragActive ? (
|
||||
<div className={cx('FileControl-acceptTip')}>
|
||||
把文件拖到这,然后松完成添加!
|
||||
{__('把文件拖到这,然后松完成添加!')}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
@ -935,10 +939,10 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
>
|
||||
<Icon icon="upload" className="icon" />
|
||||
{!multiple && files.length
|
||||
? '重新上传'
|
||||
? __('重新上传')
|
||||
: multiple && files.length
|
||||
? '继续添加'
|
||||
: '上传文件'}
|
||||
? __('继续添加')
|
||||
: __('上传文件')}
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
@ -980,7 +984,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
) : null}
|
||||
{file.state !== 'uploading' ? (
|
||||
<a
|
||||
data-tooltip="移除"
|
||||
data-tooltip={__('移除')}
|
||||
className={cx('FileControl-clear')}
|
||||
onClick={() => this.removeFile(file, index)}
|
||||
>
|
||||
@ -1024,8 +1028,12 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
|
||||
{failed ? (
|
||||
<div className={cx('FileControl-sum')}>
|
||||
已成功上传{uploaded}个文件,{failed}个文件上传失败,
|
||||
<a onClick={this.retry}>重新上传</a>失败文件
|
||||
{__('已成功上传{uploaded}个文件,{failed}个文件上传失败,', {
|
||||
uploaded,
|
||||
failed
|
||||
})}
|
||||
<a onClick={this.retry}>{__('重试上传')}</a>
|
||||
{__('失败文件。')}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@ -1036,7 +1044,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
className={cx('FileControl-uploadBtn')}
|
||||
onClick={this.toggleUpload}
|
||||
>
|
||||
{uploading ? '暂停上传' : '开始上传'}
|
||||
{__(uploading ? '暂停上传' : '开始上传')}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -201,7 +201,8 @@ export default class IconPickerControl extends React.PureComponent<
|
||||
classnames: cx,
|
||||
name,
|
||||
value,
|
||||
noDataTip
|
||||
noDataTip,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const options = this.formatOptions();
|
||||
const vendors = this.getVendors();
|
||||
@ -311,7 +312,7 @@ export default class IconPickerControl extends React.PureComponent<
|
||||
: 'IconPickerControl-singleVendor'
|
||||
)}
|
||||
>
|
||||
{noDataTip}
|
||||
{__(noDataTip)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -15,6 +15,7 @@ import Button from '../../components/Button';
|
||||
import accepts from 'attr-accept';
|
||||
import {getNameFromUrl} from './File';
|
||||
import ImageComponent, {ImageThumbProps} from '../Image';
|
||||
import {TranslateFn} from '../../locale';
|
||||
|
||||
let preventEvent = (e: any) => e.stopPropagation();
|
||||
|
||||
@ -139,14 +140,18 @@ export default class ImageControl extends React.Component<
|
||||
: undefined;
|
||||
}
|
||||
|
||||
static sizeInfo(width?: number, height?: number): string {
|
||||
static sizeInfo(
|
||||
width: number | undefined,
|
||||
height: number | undefined,
|
||||
__: TranslateFn
|
||||
): string {
|
||||
if (!width) {
|
||||
return `高度${height}px`;
|
||||
return __('高度${height}px', {height: height});
|
||||
} else if (!height) {
|
||||
return `宽度${width}px`;
|
||||
return __('宽度${width}px', {width: width});
|
||||
}
|
||||
|
||||
return `尺寸(${width} x ${height})`;
|
||||
return __('尺寸(${width} x ${height})', {width, height});
|
||||
}
|
||||
|
||||
state: ImageState = {
|
||||
@ -268,11 +273,12 @@ export default class ImageControl extends React.Component<
|
||||
|
||||
buildCrop(props: ImageProps) {
|
||||
let crop = props.crop;
|
||||
const __ = this.props.translate;
|
||||
|
||||
if (crop && props.multiple) {
|
||||
props.env &&
|
||||
props.env.alert &&
|
||||
props.env.alert('图片多选配置和裁剪配置冲突,目前不能二者都支持!');
|
||||
props.env.alert(__('图片多选配置和裁剪配置冲突,目前不能二者都支持!'));
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -299,7 +305,7 @@ export default class ImageControl extends React.Component<
|
||||
if (evt.type !== 'change' && evt.type !== 'drop') {
|
||||
return;
|
||||
}
|
||||
const {multiple, env, accept} = this.props;
|
||||
const {multiple, env, accept, translate: __} = this.props;
|
||||
|
||||
const files = rejectedFiles.map((file: any) => ({
|
||||
...file,
|
||||
@ -317,9 +323,10 @@ export default class ImageControl extends React.Component<
|
||||
// });
|
||||
|
||||
env.alert(
|
||||
`您添加的文件${files.map(
|
||||
(item: any) => `【${item.name}】`
|
||||
)}不符合类型的\`${accept}\`设定,请仔细检查。`
|
||||
__('您添加的文件${files}不符合类型的`${accept}`的设定,请仔细检查。', {
|
||||
files: files.map((file: any) => `「${file.name}」`).join(' '),
|
||||
accept
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@ -365,6 +372,7 @@ export default class ImageControl extends React.Component<
|
||||
}
|
||||
|
||||
const env = this.props.env;
|
||||
const __ = this.props.translate;
|
||||
const file = find(this.files, item => item.state === 'pending') as FileX;
|
||||
if (file) {
|
||||
this.current = file;
|
||||
@ -405,7 +413,7 @@ export default class ImageControl extends React.Component<
|
||||
);
|
||||
}
|
||||
|
||||
env.notify('error', error || '图片上传失败,请重试');
|
||||
env.notify('error', error || __('图片上传失败,请重试'));
|
||||
} else {
|
||||
newFile = {
|
||||
...obj,
|
||||
@ -449,7 +457,7 @@ export default class ImageControl extends React.Component<
|
||||
if (this.resolve) {
|
||||
this.resolve(
|
||||
this.files.some(file => file.state === 'error')
|
||||
? '文件上传失败请重试'
|
||||
? __('文件上传失败请重试')
|
||||
: null
|
||||
);
|
||||
this.resolve = undefined;
|
||||
@ -631,7 +639,7 @@ export default class ImageControl extends React.Component<
|
||||
return;
|
||||
}
|
||||
|
||||
const {multiple, maxLength, maxSize, accept} = this.props;
|
||||
const {multiple, maxLength, maxSize, accept, translate: __} = this.props;
|
||||
let currentFiles = this.files;
|
||||
|
||||
if (!multiple && currentFiles.length) {
|
||||
@ -649,11 +657,14 @@ export default class ImageControl extends React.Component<
|
||||
[].slice.call(files, 0, allowed).forEach((file: FileX) => {
|
||||
if (maxSize && file.size > maxSize) {
|
||||
alert(
|
||||
`您选择的文件 ${file.name} 大小为 ${ImageControl.formatFileSize(
|
||||
file.size
|
||||
)} 超出了最大为 ${ImageControl.formatFileSize(
|
||||
maxSize
|
||||
)} 的限制,请重新选择`
|
||||
__(
|
||||
'您选择的文件 ${filename} 大小为 ${actualSize} 超出了最大为 ${maxSize} 的限制,请重新选择。',
|
||||
{
|
||||
filename: file.name,
|
||||
actualSize: ImageControl.formatFileSize(file.size),
|
||||
maxSize: ImageControl.formatFileSize(maxSize)
|
||||
}
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -691,7 +702,7 @@ export default class ImageControl extends React.Component<
|
||||
cb: (error: null | string, file: FileX, obj?: FileValue) => void,
|
||||
onProgress: (progress: number) => void
|
||||
) {
|
||||
const {limit} = this.props;
|
||||
const {limit, translate: __} = this.props;
|
||||
|
||||
if (!limit) {
|
||||
return this._upload(file, cb, onProgress);
|
||||
@ -707,32 +718,33 @@ export default class ImageControl extends React.Component<
|
||||
(limit.width && limit.width != width) ||
|
||||
(limit.height && limit.height != height)
|
||||
) {
|
||||
error = `您选择的图片不符合尺寸要求, 请上传${ImageControl.sizeInfo(
|
||||
limit.width,
|
||||
limit.height
|
||||
)}的图片`;
|
||||
error = __('您选择的图片不符合尺寸要求, 请上传${info}的图片', {
|
||||
info: ImageControl.sizeInfo(limit.width, limit.height, __)
|
||||
});
|
||||
} else if (
|
||||
(limit.maxWidth && limit.maxWidth < width) ||
|
||||
(limit.maxHeight && limit.maxHeight < height)
|
||||
) {
|
||||
error = `您选择的图片不符合尺寸要求, 请上传不要超过${ImageControl.sizeInfo(
|
||||
limit.maxWidth,
|
||||
limit.maxHeight
|
||||
)}的图片`;
|
||||
error = __('您选择的图片不符合尺寸要求, 请上传不要超过${info}的图片', {
|
||||
info: ImageControl.sizeInfo(limit.maxWidth, limit.maxHeight, __)
|
||||
});
|
||||
} else if (
|
||||
(limit.minWidth && limit.minWidth > width) ||
|
||||
(limit.minHeight && limit.minHeight > height)
|
||||
) {
|
||||
error = `您选择的图片不符合尺寸要求, 请上传不要小于${ImageControl.sizeInfo(
|
||||
limit.minWidth,
|
||||
limit.minHeight
|
||||
)}的图片`;
|
||||
error = __('您选择的图片不符合尺寸要求, 请上传不要小于${info}的图片', {
|
||||
info: ImageControl.sizeInfo(limit.minWidth, limit.minHeight, __)
|
||||
});
|
||||
} else if (
|
||||
limit.aspectRatio &&
|
||||
Math.abs(width / height - limit.aspectRatio) > 0.01
|
||||
) {
|
||||
error = `您选择的图片不符合尺寸要求, 请上传尺寸比率为 ${limit.aspectRatioLabel ||
|
||||
limit.aspectRatio} 的图片`;
|
||||
error = __(
|
||||
'您选择的图片不符合尺寸要求, 请上传尺寸比率为 ${ratio} 的图片',
|
||||
{
|
||||
ratio: limit.aspectRatioLabel || limit.aspectRatio
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
@ -750,10 +762,11 @@ export default class ImageControl extends React.Component<
|
||||
cb: (error: null | string, file: Blob, obj?: FileValue) => void,
|
||||
onProgress: (progress: number) => void
|
||||
) {
|
||||
const __ = this.props.translate;
|
||||
this._send(file, this.props.reciever as string, {}, onProgress)
|
||||
.then((ret: Payload) => {
|
||||
if (ret.status) {
|
||||
throw new Error(ret.msg || '上传失败, 请重试');
|
||||
throw new Error(ret.msg || __('上传失败, 请重试'));
|
||||
}
|
||||
|
||||
const obj: FileValue = {
|
||||
@ -764,7 +777,7 @@ export default class ImageControl extends React.Component<
|
||||
|
||||
cb(null, file, obj);
|
||||
})
|
||||
.catch(error => cb(error.message || '上传失败,请重试', file));
|
||||
.catch(error => cb(error.message || __('上传失败,请重试'), file));
|
||||
}
|
||||
|
||||
_send(
|
||||
@ -854,6 +867,8 @@ export default class ImageControl extends React.Component<
|
||||
}
|
||||
|
||||
validate(): any {
|
||||
const __ = this.props.translate;
|
||||
|
||||
if (this.state.locked && this.state.lockedReason) {
|
||||
return this.state.lockedReason;
|
||||
} else if (this.state.cropFile) {
|
||||
@ -870,7 +885,7 @@ export default class ImageControl extends React.Component<
|
||||
this.startUpload();
|
||||
});
|
||||
} else if (this.files.some(item => item.state === 'error')) {
|
||||
return '文件上传失败请重试';
|
||||
return __('文件上传失败请重试');
|
||||
}
|
||||
}
|
||||
|
||||
@ -887,7 +902,8 @@ export default class ImageControl extends React.Component<
|
||||
hideUploadButton,
|
||||
thumbMode,
|
||||
thumbRatio,
|
||||
reCropable
|
||||
reCropable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const {files, error, crop, uploading, cropFile} = this.state;
|
||||
@ -902,7 +918,7 @@ export default class ImageControl extends React.Component<
|
||||
<a
|
||||
className={cx('ImageControl-cropCancel')}
|
||||
onClick={this.cancelCrop}
|
||||
data-tooltip="取消"
|
||||
data-tooltip={__('取消')}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
@ -910,7 +926,7 @@ export default class ImageControl extends React.Component<
|
||||
<a
|
||||
className={cx('ImageControl-cropConfirm')}
|
||||
onClick={this.handleCrop}
|
||||
data-tooltip="确认"
|
||||
data-tooltip={__('确认')}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="check" className="icon" />
|
||||
@ -954,7 +970,7 @@ export default class ImageControl extends React.Component<
|
||||
'is-reject': isDragReject
|
||||
})}
|
||||
>
|
||||
把图片拖到这,然后松开完成添加!
|
||||
{__('把图片拖到这,然后松开完成添加!')}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
@ -974,7 +990,7 @@ export default class ImageControl extends React.Component<
|
||||
<>
|
||||
<a
|
||||
className={cx('ImageControl-itemClear')}
|
||||
data-tooltip="移除"
|
||||
data-tooltip={__('移除')}
|
||||
data-position="bottom"
|
||||
onClick={this.removeFile.bind(
|
||||
this,
|
||||
@ -993,7 +1009,7 @@ export default class ImageControl extends React.Component<
|
||||
>
|
||||
<Icon icon="retry" className="icon" />
|
||||
<p className="ImageControl-itemInfoError">
|
||||
重新上传
|
||||
{__('重新上传')}
|
||||
</p>
|
||||
</a>
|
||||
</>
|
||||
@ -1007,7 +1023,7 @@ export default class ImageControl extends React.Component<
|
||||
)}
|
||||
key="clear"
|
||||
className={cx('ImageControl-itemClear')}
|
||||
data-tooltip="移除"
|
||||
data-tooltip={__('移除')}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
@ -1015,7 +1031,7 @@ export default class ImageControl extends React.Component<
|
||||
key="info"
|
||||
className={cx('ImageControl-itemInfo')}
|
||||
>
|
||||
<p>文件上传中</p>
|
||||
<p>{__('文件上传中')}</p>
|
||||
<div className={cx('ImageControl-progress')}>
|
||||
<span
|
||||
style={{
|
||||
@ -1067,7 +1083,7 @@ export default class ImageControl extends React.Component<
|
||||
)}
|
||||
|
||||
<a
|
||||
data-tooltip="查看大图"
|
||||
data-tooltip={__('查看大图')}
|
||||
data-position="bottom"
|
||||
target="_blank"
|
||||
href={file.url || file.preview}
|
||||
@ -1084,7 +1100,7 @@ export default class ImageControl extends React.Component<
|
||||
reCropable !== false &&
|
||||
!disabled ? (
|
||||
<a
|
||||
data-tooltip="裁剪图片"
|
||||
data-tooltip={__('裁剪图片')}
|
||||
data-position="bottom"
|
||||
onClick={this.editImage.bind(this, key)}
|
||||
>
|
||||
@ -1093,7 +1109,7 @@ export default class ImageControl extends React.Component<
|
||||
) : null}
|
||||
{!disabled ? (
|
||||
<a
|
||||
data-tooltip="移除"
|
||||
data-tooltip={__('移除')}
|
||||
data-position="bottom"
|
||||
onClick={this.removeFile.bind(
|
||||
this,
|
||||
@ -1128,14 +1144,14 @@ export default class ImageControl extends React.Component<
|
||||
'is-disabled': disabled
|
||||
})}
|
||||
onClick={this.handleSelect}
|
||||
data-tooltip={placeholder}
|
||||
data-tooltip={__(placeholder)}
|
||||
data-position="right"
|
||||
>
|
||||
<Icon icon="plus" className="icon" />
|
||||
|
||||
{isFocused ? (
|
||||
<span className={cx('ImageControl-pasteTip')}>
|
||||
当前状态支持从剪切板中粘贴图片文件。
|
||||
{__('当前状态支持从剪切板中粘贴图片文件。')}
|
||||
</span>
|
||||
) : null}
|
||||
</label>
|
||||
@ -1148,7 +1164,7 @@ export default class ImageControl extends React.Component<
|
||||
disabled={!hasPending}
|
||||
onClick={this.toggleUpload}
|
||||
>
|
||||
{uploading ? '暂停上传' : '开始上传'}
|
||||
{__(uploading ? '暂停上传' : '开始上传')}
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
|
@ -131,7 +131,7 @@ export default class MatrixCheckbox extends React.Component<
|
||||
}
|
||||
|
||||
async reload() {
|
||||
const {source, data, env, onChange} = this.props;
|
||||
const {source, data, env, onChange, translate: __} = this.props;
|
||||
|
||||
if (!isEffectiveApi(source, data) || this.state.loading) {
|
||||
return;
|
||||
@ -159,7 +159,7 @@ export default class MatrixCheckbox extends React.Component<
|
||||
.fetcher(source, data)
|
||||
.then(ret => {
|
||||
if (!ret.ok) {
|
||||
throw new Error(ret.msg || '数据请求错误');
|
||||
throw new Error(ret.msg || __('数据请求错误'));
|
||||
}
|
||||
if (!this.mounted) {
|
||||
return resolve();
|
||||
|
@ -393,7 +393,8 @@ export default class NestedSelectControl extends React.Component<
|
||||
options,
|
||||
disabled,
|
||||
searchable,
|
||||
searchPromptText
|
||||
searchPromptText,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const stack = this.state.stack;
|
||||
@ -410,7 +411,7 @@ export default class NestedSelectControl extends React.Component<
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
disabled={disabled!!}
|
||||
placeholder={searchPromptText}
|
||||
placeholder={__(searchPromptText)}
|
||||
onChange={this.handleInputChange}
|
||||
ref={this.inputRef}
|
||||
/>
|
||||
|
@ -539,7 +539,8 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
valueField,
|
||||
formItem: model,
|
||||
createBtnLabel,
|
||||
env
|
||||
env,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
// 禁用或者没有配置 name
|
||||
@ -554,7 +555,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
type: 'text',
|
||||
name: labelField || 'label',
|
||||
label: false,
|
||||
placeholder: '请输入名称'
|
||||
placeholder: __('请输入名称')
|
||||
}
|
||||
];
|
||||
}
|
||||
@ -650,7 +651,8 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
source,
|
||||
data,
|
||||
formItem: model,
|
||||
optionLabel
|
||||
optionLabel,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (disabled || !model) {
|
||||
@ -663,7 +665,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
type: 'text',
|
||||
name: labelField || 'label',
|
||||
label: false,
|
||||
placeholder: '请输入名称'
|
||||
placeholder: __('请输入名称')
|
||||
}
|
||||
];
|
||||
}
|
||||
@ -673,7 +675,9 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
: await onOpenDialog(
|
||||
{
|
||||
type: 'dialog',
|
||||
title: `编辑${optionLabel || '选项'}`,
|
||||
title: __('编辑${label}', {
|
||||
label: optionLabel || '选项'
|
||||
}),
|
||||
body: {
|
||||
type: 'form',
|
||||
api: editApi,
|
||||
@ -695,7 +699,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
);
|
||||
|
||||
if (!payload.ok) {
|
||||
env.notify('error', payload.msg || '保存失败,请仔细检查');
|
||||
env.notify('error', payload.msg || __('保存失败,请仔细检查'));
|
||||
result = null;
|
||||
} else {
|
||||
result = payload.data || result;
|
||||
@ -738,7 +742,8 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
env,
|
||||
formItem: model,
|
||||
source,
|
||||
valueField
|
||||
valueField,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (disabled || !model) {
|
||||
@ -758,7 +763,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
// 通过 deleteApi 删除。
|
||||
try {
|
||||
if (!deleteApi) {
|
||||
throw new Error('请配置 deleteApi');
|
||||
throw new Error(__('请配置 deleteApi'));
|
||||
}
|
||||
|
||||
const result = await env.fetcher(deleteApi!, ctx, {
|
||||
@ -766,7 +771,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
env.notify('error', result.msg || '删除失败,请重试');
|
||||
env.notify('error', result.msg || __('删除失败,请重试'));
|
||||
} else if (source) {
|
||||
this.reload();
|
||||
} else {
|
||||
|
@ -382,7 +382,8 @@ export default class PickerControl extends React.PureComponent<
|
||||
placeholder,
|
||||
embed,
|
||||
value,
|
||||
selectedOptions
|
||||
selectedOptions,
|
||||
translate: __
|
||||
} = this.props;
|
||||
return (
|
||||
<div className={cx(`PickerControl`, className)}>
|
||||
@ -399,7 +400,9 @@ export default class PickerControl extends React.PureComponent<
|
||||
>
|
||||
<div onClick={this.handleClick} className={cx('Picker-input')}>
|
||||
{!selectedOptions.length && placeholder ? (
|
||||
<div className={cx('Picker-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('Picker-placeholder')}>
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className={cx('Picker-valueWrap')}>
|
||||
@ -427,7 +430,7 @@ export default class PickerControl extends React.PureComponent<
|
||||
{render(
|
||||
'modal',
|
||||
{
|
||||
title: '请选择',
|
||||
title: __('请选择'),
|
||||
size: size,
|
||||
type: modalMode,
|
||||
body: {
|
||||
|
@ -63,7 +63,8 @@ export default class RadiosControl extends React.Component<RadiosProps, any> {
|
||||
classPrefix,
|
||||
itemClassName,
|
||||
labelClassName,
|
||||
labelField
|
||||
labelField,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -78,7 +79,7 @@ export default class RadiosControl extends React.Component<RadiosProps, any> {
|
||||
delimiter={delimiter!}
|
||||
labelClassName={labelClassName}
|
||||
labelField={labelField}
|
||||
placeholder={placeholder}
|
||||
placeholder={__(placeholder)}
|
||||
options={options}
|
||||
columnsCount={columnsCount}
|
||||
classPrefix={classPrefix}
|
||||
|
@ -58,7 +58,13 @@ export default class RepeatControl extends React.Component<RepeatProps, any> {
|
||||
renderInput() {
|
||||
const value = this.props.value;
|
||||
const parts = value ? value.split(':') : [];
|
||||
let {options, placeholder, disabled, classPrefix: ns} = this.props;
|
||||
let {
|
||||
options,
|
||||
placeholder,
|
||||
disabled,
|
||||
classPrefix: ns,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let optionsArray: Array<Option> = [];
|
||||
|
||||
@ -68,7 +74,7 @@ export default class RepeatControl extends React.Component<RepeatProps, any> {
|
||||
}));
|
||||
|
||||
optionsArray.unshift({
|
||||
label: placeholder as string,
|
||||
label: __(placeholder as string),
|
||||
value: ''
|
||||
});
|
||||
|
||||
@ -181,7 +187,7 @@ export default class RepeatControl extends React.Component<RepeatProps, any> {
|
||||
<div className="repeat-control hbox">
|
||||
{input ? (
|
||||
<div className="col v-middle" style={{width: 30}}>
|
||||
<span>每</span>
|
||||
<span>{__('每')}</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@ -192,7 +198,7 @@ export default class RepeatControl extends React.Component<RepeatProps, any> {
|
||||
classPrefix={ns}
|
||||
className={input ? 'pull-right' : ''}
|
||||
options={optionsArray}
|
||||
placeholder={placeholder}
|
||||
placeholder={__(placeholder)}
|
||||
onChange={this.handleOptionChange}
|
||||
value={parts[0]}
|
||||
clearable={false}
|
||||
|
@ -34,7 +34,6 @@ export default class RichTextControl extends React.Component<
|
||||
videoReciever: '/api/upload/video',
|
||||
placeholder: '请输入',
|
||||
options: {
|
||||
language: 'zh_cn',
|
||||
toolbarButtonsSM: [
|
||||
'paragraphFormat',
|
||||
'quote',
|
||||
@ -156,7 +155,9 @@ export default class RichTextControl extends React.Component<
|
||||
...(props.options && props.options.events),
|
||||
'froalaEditor.focus': this.handleFocus,
|
||||
'froalaEditor.blur': this.handleBlur
|
||||
}
|
||||
},
|
||||
language:
|
||||
!this.props.locale || this.props.locale === 'zh-cn' ? 'zh_cn' : ''
|
||||
};
|
||||
|
||||
if (props.buttons) {
|
||||
@ -178,10 +179,15 @@ export default class RichTextControl extends React.Component<
|
||||
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
||||
try {
|
||||
const response = await fetcher(props.reciever, formData, {
|
||||
method: 'post',
|
||||
method: 'post'
|
||||
});
|
||||
if (response.ok) {
|
||||
ok(response.data?.link || response.data?.url || response.data?.value || (response as any).link);
|
||||
ok(
|
||||
response.data?.link ||
|
||||
response.data?.url ||
|
||||
response.data?.value ||
|
||||
(response as any).link
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
fail(e);
|
||||
@ -212,7 +218,9 @@ export default class RichTextControl extends React.Component<
|
||||
disabled,
|
||||
size,
|
||||
vendor,
|
||||
env
|
||||
env,
|
||||
locale,
|
||||
translate
|
||||
} = this.props;
|
||||
|
||||
const finnalVendor = vendor || (env.richTextToken ? 'froala' : 'tinymce');
|
||||
@ -232,6 +240,8 @@ export default class RichTextControl extends React.Component<
|
||||
onBlur={this.handleBlur}
|
||||
config={this.config}
|
||||
disabled={disabled}
|
||||
locale={locale}
|
||||
translate={translate}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -151,7 +151,8 @@ export default class SubFormControl extends React.PureComponent<
|
||||
value,
|
||||
btnLabel,
|
||||
render,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return [
|
||||
@ -169,7 +170,7 @@ export default class SubFormControl extends React.PureComponent<
|
||||
key={key}
|
||||
>
|
||||
<span
|
||||
data-tooltip="删除"
|
||||
data-tooltip={__('删除')}
|
||||
data-position="bottom"
|
||||
className={`${ns}Select-valueIcon`}
|
||||
onClick={this.removeItem.bind(this, key)}
|
||||
@ -179,7 +180,7 @@ export default class SubFormControl extends React.PureComponent<
|
||||
<span
|
||||
onClick={this.open.bind(this, key)}
|
||||
className={`${ns}SubForm-valueLabel`}
|
||||
data-tooltip="编辑详情"
|
||||
data-tooltip={__('编辑详情')}
|
||||
data-position="bottom"
|
||||
>
|
||||
{(value &&
|
||||
@ -190,7 +191,7 @@ export default class SubFormControl extends React.PureComponent<
|
||||
'label',
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: btnLabel
|
||||
tpl: __(btnLabel)
|
||||
},
|
||||
{
|
||||
data: createObject(data, value)
|
||||
@ -207,10 +208,10 @@ export default class SubFormControl extends React.PureComponent<
|
||||
onClick={this.addItem}
|
||||
className={cx(`${ns}Button ${ns}SubForm-addBtn`, addButtonClassName)}
|
||||
disabled={disabled}
|
||||
data-tooltip="新增一条数据"
|
||||
data-tooltip={__('新增一条数据')}
|
||||
>
|
||||
<i className="fa fa-plus m-r-xs" />
|
||||
<span>新增</span>
|
||||
<span>{__('新增')}</span>
|
||||
</button>
|
||||
];
|
||||
}
|
||||
@ -224,7 +225,8 @@ export default class SubFormControl extends React.PureComponent<
|
||||
labelField,
|
||||
btnLabel,
|
||||
render,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -238,7 +240,7 @@ export default class SubFormControl extends React.PureComponent<
|
||||
btnClassName
|
||||
)}
|
||||
onClick={this.open.bind(this, 0)}
|
||||
data-tooltip="编辑详情"
|
||||
data-tooltip={__('编辑详情')}
|
||||
data-position="bottom"
|
||||
>
|
||||
<span className={`${ns}SubForm-valueLabel`}>
|
||||
@ -250,7 +252,7 @@ export default class SubFormControl extends React.PureComponent<
|
||||
'label',
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: btnLabel
|
||||
tpl: __(btnLabel)
|
||||
},
|
||||
{
|
||||
data: createObject(data, value)
|
||||
|
@ -10,7 +10,7 @@ import omit from 'lodash/omit';
|
||||
import {dataMapping} from '../../utils/tpl-builtin';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import memoize from 'lodash/memoize';
|
||||
import { SimpleMap } from '../../utils/SimpleMap';
|
||||
import {SimpleMap} from '../../utils/SimpleMap';
|
||||
|
||||
export interface TableProps extends FormControlProps {
|
||||
placeholder?: string;
|
||||
@ -103,12 +103,18 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
}
|
||||
|
||||
validate(): any {
|
||||
const {value, minLength, maxLength} = this.props;
|
||||
const {value, minLength, maxLength, translate: __} = this.props;
|
||||
|
||||
if (minLength && (!Array.isArray(value) || value.length < minLength)) {
|
||||
return `组合表单成员数量不够,低于最小的设定${minLength}个,请添加更多的成员。`;
|
||||
return __(
|
||||
'组合表单成员数量不够,低于设定的最小${minLenth}个,请添加更多的成员。',
|
||||
{minLength}
|
||||
);
|
||||
} else if (maxLength && Array.isArray(value) && value.length > maxLength) {
|
||||
return `组合表单成员数量超出,超出最大的设定${maxLength}个,请删除多余的成员。`;
|
||||
return __(
|
||||
'组合表单成员数量超出,超出设定的最大${maxLength}个,请删除多余的成员。',
|
||||
{maxLength}
|
||||
);
|
||||
} else {
|
||||
const subForms: Array<any> = [];
|
||||
Object.keys(this.subForms).forEach(
|
||||
@ -118,7 +124,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
return Promise.all(subForms.map(item => item.validate())).then(
|
||||
values => {
|
||||
if (~values.indexOf(false)) {
|
||||
return '内部表单验证失败';
|
||||
return __('内部表单验证失败');
|
||||
}
|
||||
|
||||
return;
|
||||
@ -129,7 +135,15 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
}
|
||||
|
||||
doAction(action: Action, ctx: RendererData, ...rest: Array<any>) {
|
||||
const {onAction, value, valueField, env, onChange, editable} = this.props;
|
||||
const {
|
||||
onAction,
|
||||
value,
|
||||
valueField,
|
||||
env,
|
||||
onChange,
|
||||
editable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (action.actionType === 'add') {
|
||||
const rows = Array.isArray(value) ? value.concat() : [];
|
||||
@ -166,9 +180,9 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
action.actionType === 'delete'
|
||||
) {
|
||||
if (!valueField) {
|
||||
return env.alert('请配置 valueField');
|
||||
return env.alert(__('请配置 valueField'));
|
||||
} else if (!action.payload) {
|
||||
return env.alert('action 上请配置 payload, 否则不清楚要删除哪个');
|
||||
return env.alert(__('action 上请配置 payload, 否则不清楚要删除哪个'));
|
||||
}
|
||||
|
||||
const rows = Array.isArray(value) ? value.concat() : [];
|
||||
@ -226,7 +240,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
addApi,
|
||||
updateApi,
|
||||
data,
|
||||
env
|
||||
env,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
// form 是 lazyChange 的,先让他们 flush, 即把未提交的数据提交。
|
||||
@ -252,11 +267,13 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
}
|
||||
|
||||
if (remote && !remote.ok) {
|
||||
env.notify('error', remote.msg || '保存失败');
|
||||
env.notify('error', remote.msg || __('保存失败'));
|
||||
return;
|
||||
} else if (remote && remote.ok) {
|
||||
item = {
|
||||
...((isNew ? addApi : updateApi) as ApiObject).replaceData ? {} : item,
|
||||
...(((isNew ? addApi : updateApi) as ApiObject).replaceData
|
||||
? {}
|
||||
: item),
|
||||
...remote.data
|
||||
};
|
||||
}
|
||||
@ -291,7 +308,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
deleteApi,
|
||||
deleteConfirmText,
|
||||
env,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
let newValue = Array.isArray(value) ? value.concat() : [];
|
||||
const item = newValue[index];
|
||||
@ -303,7 +321,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
const ctx = createObject(data, item);
|
||||
if (isEffectiveApi(deleteApi, ctx)) {
|
||||
const confirmed = await env.confirm(
|
||||
deleteConfirmText ? filter(deleteConfirmText, ctx) : '确认要删除?'
|
||||
deleteConfirmText ? filter(deleteConfirmText, ctx) : __('确认要删除?')
|
||||
);
|
||||
if (!confirmed) {
|
||||
// 如果不确认,则跳过!
|
||||
@ -313,7 +331,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
const result = await env.fetcher(deleteApi, ctx);
|
||||
|
||||
if (!result.ok) {
|
||||
env.notify('error', '删除失败');
|
||||
env.notify('error', __('删除失败'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -339,6 +357,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
? props.columns.concat()
|
||||
: [];
|
||||
const ns = this.props.classPrefix;
|
||||
const __ = this.props.translate;
|
||||
|
||||
let btns = [];
|
||||
if (props.addable && props.showAddBtn !== false) {
|
||||
@ -350,7 +369,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="新增一行"
|
||||
tooltip={__('新增一行')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
@ -399,7 +418,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="编辑当前行"
|
||||
tooltip={__('编辑当前行')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
@ -423,7 +442,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="保存"
|
||||
tooltip={__('保存')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
@ -447,7 +466,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="取消"
|
||||
tooltip={__('取消')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
@ -481,7 +500,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="删除当前行"
|
||||
tooltip={__('删除当前行')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
@ -503,7 +522,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
type: 'operation',
|
||||
buttons: btns,
|
||||
width: 150,
|
||||
label: '操作'
|
||||
label: __('操作')
|
||||
});
|
||||
}
|
||||
|
||||
@ -576,7 +595,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
buildItems = memoize(
|
||||
(value: Array<any>, editIndex: number) => {
|
||||
return value.map((value: any, index: number) =>
|
||||
index === editIndex ? this.state.editting : value)
|
||||
index === editIndex ? this.state.editting : value
|
||||
);
|
||||
},
|
||||
(...args: Array<any>) => JSON.stringify(args)
|
||||
);
|
||||
@ -592,7 +612,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
draggable,
|
||||
addable,
|
||||
columnsTogglable,
|
||||
combineNum
|
||||
combineNum,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -601,7 +622,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
'body',
|
||||
{
|
||||
type: 'table',
|
||||
placeholder,
|
||||
placeholder: __(placeholder),
|
||||
columns: this.state.columns,
|
||||
affixHeader: false
|
||||
},
|
||||
@ -610,12 +631,14 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
saveImmediately: true,
|
||||
disabled,
|
||||
draggable: draggable && !~this.state.editIndex,
|
||||
items: this.buildItems((Array.isArray(value) && value.length
|
||||
? value
|
||||
: addable && showAddBtn !== false
|
||||
? [{__isPlaceholder: true}]
|
||||
: []
|
||||
), this.state.editIndex),
|
||||
items: this.buildItems(
|
||||
Array.isArray(value) && value.length
|
||||
? value
|
||||
: addable && showAddBtn !== false
|
||||
? [{__isPlaceholder: true}]
|
||||
: [],
|
||||
this.state.editIndex
|
||||
),
|
||||
getEntryId: this.getEntryId,
|
||||
onSave: this.handleTableSave,
|
||||
onSaveOrder: this.handleSaveTableOrder,
|
||||
|
@ -271,7 +271,8 @@ export default class TagControl extends React.PureComponent<
|
||||
popOverContainer,
|
||||
dropdown,
|
||||
options,
|
||||
optionsTip
|
||||
optionsTip,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const finnalOptions = Array.isArray(options)
|
||||
@ -300,7 +301,7 @@ export default class TagControl extends React.PureComponent<
|
||||
{...getInputProps({
|
||||
name,
|
||||
ref: this.input,
|
||||
placeholder: placeholder || '暂无标签',
|
||||
placeholder: __(placeholder || '暂无标签'),
|
||||
value: this.state.inputValue,
|
||||
onKeyDown: this.handleKeyDown,
|
||||
onFocus: this.handleFocus,
|
||||
@ -348,7 +349,9 @@ export default class TagControl extends React.PureComponent<
|
||||
// 保留原来的展现方式,不推荐
|
||||
<div className={cx('TagControl-sug')}>
|
||||
{optionsTip ? (
|
||||
<div className={cx('TagControl-sugTip')}>{optionsTip}</div>
|
||||
<div className={cx('TagControl-sugTip')}>
|
||||
{__(optionsTip)}
|
||||
</div>
|
||||
) : null}
|
||||
{options.map((item, index) => (
|
||||
<div
|
||||
|
@ -415,7 +415,8 @@ export default class TextControl extends React.PureComponent<
|
||||
labelField,
|
||||
valueField,
|
||||
multiple,
|
||||
spinnerClassName
|
||||
spinnerClassName,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -542,7 +543,7 @@ export default class TextControl extends React.PureComponent<
|
||||
>
|
||||
{option.isNew ? (
|
||||
<span>
|
||||
新增:{option.label}
|
||||
{__('新增:${label}', {label: option.label})}
|
||||
<Icon icon="enter" className="icon" />
|
||||
</span>
|
||||
) : (
|
||||
|
@ -69,7 +69,8 @@ export default class TreeControl extends React.Component<TreeProps> {
|
||||
removeTip,
|
||||
onDelete,
|
||||
rootCreatable,
|
||||
rootCreateTip
|
||||
rootCreateTip,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -84,7 +85,7 @@ export default class TreeControl extends React.Component<TreeProps> {
|
||||
joinValues={joinValues}
|
||||
extractValue={extractValue}
|
||||
delimiter={delimiter}
|
||||
placeholder={placeholder}
|
||||
placeholder={__(placeholder)}
|
||||
options={options}
|
||||
multiple={multiple}
|
||||
initiallyOpen={initiallyOpen}
|
||||
|
@ -321,7 +321,8 @@ export default class TreeSelectControl extends React.Component<
|
||||
labelField,
|
||||
disabled,
|
||||
placeholder,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if ((!multiple || !selectedOptions.length) && this.state.inputValue) {
|
||||
@ -355,7 +356,7 @@ export default class TreeSelectControl extends React.Component<
|
||||
)
|
||||
) : (
|
||||
<span key="placeholder" className={cx('TreeSelect-placeholder')}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -386,7 +387,8 @@ export default class TreeSelectControl extends React.Component<
|
||||
searchable,
|
||||
autoComplete,
|
||||
maxLength,
|
||||
minLength
|
||||
minLength,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let filtedOptions =
|
||||
@ -420,14 +422,14 @@ export default class TreeSelectControl extends React.Component<
|
||||
joinValues={joinValues}
|
||||
extractValue={extractValue}
|
||||
delimiter={delimiter}
|
||||
placeholder={optionsPlaceholder}
|
||||
placeholder={__(optionsPlaceholder)}
|
||||
options={filtedOptions}
|
||||
highlightTxt={this.state.inputValue}
|
||||
multiple={multiple}
|
||||
initiallyOpen={initiallyOpen}
|
||||
unfoldedLevel={unfoldedLevel}
|
||||
withChildren={withChildren}
|
||||
rootLabel={rootLabel}
|
||||
rootLabel={__(rootLabel)}
|
||||
rootValue={rootValue}
|
||||
showIcon={showIcon}
|
||||
showRadio={showRadio}
|
||||
|
@ -460,13 +460,13 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
}
|
||||
|
||||
submit(fn?: (values: object) => Promise<any>): Promise<any> {
|
||||
const {store, messages} = this.props;
|
||||
const {store, messages, translate: __} = this.props;
|
||||
this.flush();
|
||||
|
||||
return store.submit(
|
||||
fn,
|
||||
this.hooks['validate' || []],
|
||||
messages && messages.validateFailed
|
||||
__(messages && messages.validateFailed)
|
||||
);
|
||||
}
|
||||
|
||||
@ -563,7 +563,8 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
env,
|
||||
onChange,
|
||||
clearPersistDataAfterSubmit,
|
||||
trimValues
|
||||
trimValues,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
// 做动作之前,先把数据同步一下。
|
||||
@ -581,7 +582,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
if (Array.isArray(action.required) && action.required.length) {
|
||||
return store.validateFields(action.required).then(result => {
|
||||
if (!result) {
|
||||
env.notify('error', '依赖的部分字段没有通过验证,请注意填写!');
|
||||
env.notify('error', __('依赖的部分字段没有通过验证,请注意填写!'));
|
||||
} else {
|
||||
this.handleAction(
|
||||
e,
|
||||
@ -706,15 +707,17 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
} else if (action.actionType === 'ajax') {
|
||||
store.setCurrentAction(action);
|
||||
if (!isEffectiveApi(action.api)) {
|
||||
return env.alert(`当 actionType 为 ajax 时,请设置 api 属性`);
|
||||
return env.alert(__(`当 actionType 为 ajax 时,请设置 api 属性`));
|
||||
}
|
||||
|
||||
return store
|
||||
.saveRemote(action.api as Api, data, {
|
||||
successMessage:
|
||||
(action.messages && action.messages.success) || saveSuccess,
|
||||
errorMessage:
|
||||
successMessage: __(
|
||||
(action.messages && action.messages.success) || saveSuccess
|
||||
),
|
||||
errorMessage: __(
|
||||
(action.messages && action.messages.failed) || saveFailed
|
||||
)
|
||||
})
|
||||
.then(async response => {
|
||||
response &&
|
||||
@ -833,7 +836,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
}
|
||||
|
||||
buildActions() {
|
||||
const {actions, submitText, controls} = this.props;
|
||||
const {actions, submitText, controls, translate: __} = this.props;
|
||||
|
||||
if (
|
||||
typeof actions !== 'undefined' ||
|
||||
@ -852,7 +855,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
return [
|
||||
{
|
||||
type: 'submit',
|
||||
label: submitText,
|
||||
label: __(submitText),
|
||||
primary: true
|
||||
}
|
||||
];
|
||||
@ -1126,7 +1129,8 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
bodyClassName,
|
||||
classnames: cx,
|
||||
affixFooter,
|
||||
lazyLoad
|
||||
lazyLoad,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let body: JSX.Element = this.renderBody();
|
||||
@ -1136,7 +1140,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
'body',
|
||||
{
|
||||
type: 'panel',
|
||||
title: title
|
||||
title: __(title)
|
||||
},
|
||||
{
|
||||
className: cx(panelClassName, 'Panel--form'),
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import {filter} from '../utils/tpl';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {Icon} from '../components/icons';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ImageThumbProps {
|
||||
export interface ImageThumbProps extends LocaleProps, ThemeProps {
|
||||
src: string;
|
||||
originalSrc?: string; // 原图
|
||||
enlargeAble?: boolean;
|
||||
@ -19,8 +20,6 @@ export interface ImageThumbProps {
|
||||
caption?: string;
|
||||
thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||
thumbRatio?: '1:1' | '4:3' | '16:9';
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
onLoad?: React.EventHandler<any>;
|
||||
}
|
||||
|
||||
@ -43,7 +42,8 @@ export class ImageThumb extends React.Component<ImageThumbProps> {
|
||||
title,
|
||||
caption,
|
||||
onLoad,
|
||||
enlargeAble
|
||||
enlargeAble,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -65,7 +65,7 @@ export class ImageThumb extends React.Component<ImageThumbProps> {
|
||||
{enlargeAble ? (
|
||||
<div key="overlay" className={cx('Image-overlay')}>
|
||||
<a
|
||||
data-tooltip="查看大图"
|
||||
data-tooltip={__('查看大图')}
|
||||
data-position="bottom"
|
||||
target="_blank"
|
||||
onClick={this.handleEnlarge}
|
||||
@ -87,7 +87,7 @@ export class ImageThumb extends React.Component<ImageThumbProps> {
|
||||
);
|
||||
}
|
||||
}
|
||||
const ThemedImageThumb = themeable(ImageThumb);
|
||||
const ThemedImageThumb = themeable(localeable(ImageThumb));
|
||||
export default ThemedImageThumb;
|
||||
|
||||
export interface ImageFieldProps extends RendererProps {
|
||||
|
@ -24,7 +24,8 @@ export class LinkField extends React.Component<LinkProps, object> {
|
||||
blank,
|
||||
htmlTarget,
|
||||
data,
|
||||
render
|
||||
render,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let value = this.props.value;
|
||||
@ -36,7 +37,7 @@ export class LinkField extends React.Component<LinkProps, object> {
|
||||
target={htmlTarget || (blank ? '_blank' : '_self')}
|
||||
className={cx('Link', className)}
|
||||
>
|
||||
{body ? render('body', body) : finnalHref || value || '链接'}
|
||||
{body ? render('body', body) : finnalHref || value || __('链接')}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
@ -167,9 +167,9 @@ export default class List extends React.Component<ListProps, object> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let parent: HTMLElement | Window | null = getScrollParent(findDOMNode(
|
||||
this
|
||||
) as HTMLElement);
|
||||
let parent: HTMLElement | Window | null = getScrollParent(
|
||||
findDOMNode(this) as HTMLElement
|
||||
);
|
||||
if (!parent || parent === document.body) {
|
||||
parent = window;
|
||||
}
|
||||
@ -251,9 +251,7 @@ export default class List extends React.Component<ListProps, object> {
|
||||
const affixed = clip.top < offsetY && clip.top + clip.height - 40 > offsetY;
|
||||
|
||||
this.body.offsetWidth &&
|
||||
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${
|
||||
this.body.offsetWidth
|
||||
}px;`);
|
||||
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${this.body.offsetWidth}px;`);
|
||||
affixed ? afixedDom.classList.add('in') : afixedDom.classList.remove('in');
|
||||
// store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
|
||||
}
|
||||
@ -494,9 +492,7 @@ export default class List extends React.Component<ListProps, object> {
|
||||
<div className={cx('List-heading')}>
|
||||
{store.modified && !hideQuickSaveBtn ? (
|
||||
<span>
|
||||
{`当前有 ${
|
||||
store.modified
|
||||
} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
{`当前有 ${store.modified} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
<button
|
||||
type="button"
|
||||
className={cx('Button Button--xs Button--success m-l-sm')}
|
||||
@ -732,7 +728,8 @@ export default class List extends React.Component<ListProps, object> {
|
||||
checkOnItemClick,
|
||||
affixHeader,
|
||||
classnames: cx,
|
||||
size
|
||||
size,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.renderedToolbars = [];
|
||||
@ -791,7 +788,7 @@ export default class List extends React.Component<ListProps, object> {
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className={cx('List-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('List-placeholder')}>{__(placeholder)}</div>
|
||||
)}
|
||||
|
||||
{this.renderFooter()}
|
||||
|
@ -128,7 +128,7 @@ export class Navigation extends React.Component<
|
||||
return this.receive(query);
|
||||
}
|
||||
|
||||
const {data, env, source} = this.props;
|
||||
const {data, env, source, translate: __} = this.props;
|
||||
const finalData = values ? createObject(data, values) : data;
|
||||
|
||||
if (!isEffectiveApi(source, data)) {
|
||||
@ -144,7 +144,7 @@ export class Navigation extends React.Component<
|
||||
|
||||
if (!payload.ok) {
|
||||
this.setState({
|
||||
error: payload.msg || '获取链接错误'
|
||||
error: payload.msg || __('获取链接错误')
|
||||
});
|
||||
} else {
|
||||
const links = Array.isArray(payload.data)
|
||||
|
@ -91,7 +91,7 @@ export const HocPopOver = (config: Partial<PopOverConfig> = {}) => (
|
||||
}
|
||||
|
||||
buildSchema() {
|
||||
const {popOver, name, label} = this.props;
|
||||
const {popOver, name, label, translate: __} = this.props;
|
||||
|
||||
let schema;
|
||||
|
||||
@ -108,7 +108,7 @@ export const HocPopOver = (config: Partial<PopOverConfig> = {}) => (
|
||||
type: popOver.mode,
|
||||
actions: [
|
||||
{
|
||||
label: '关闭',
|
||||
label: __('关闭'),
|
||||
type: 'button',
|
||||
actionType: 'cancel'
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ export const HocQuickEdit = (config: Partial<QuickEditConfig> = {}) => (
|
||||
}
|
||||
|
||||
buildSchema() {
|
||||
const {quickEdit, name, label} = this.props;
|
||||
const {quickEdit, name, label, translate: __} = this.props;
|
||||
|
||||
let schema;
|
||||
|
||||
@ -372,12 +372,12 @@ export const HocQuickEdit = (config: Partial<QuickEditConfig> = {}) => (
|
||||
: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '取消',
|
||||
label: __('取消'),
|
||||
actionType: 'cancel'
|
||||
},
|
||||
|
||||
{
|
||||
label: '确认',
|
||||
label: __('确认'),
|
||||
type: 'submit',
|
||||
primary: true
|
||||
}
|
||||
|
@ -213,14 +213,14 @@ export default class Service extends React.Component<ServiceProps> {
|
||||
throwErrors: boolean = false,
|
||||
delegate?: IScopedContext
|
||||
) {
|
||||
const {onAction, store, env, api} = this.props;
|
||||
const {onAction, store, env, api, translate: __} = this.props;
|
||||
|
||||
if (api && action.actionType === 'ajax') {
|
||||
store.setCurrentAction(action);
|
||||
store
|
||||
.saveRemote(action.api as string, data, {
|
||||
successMessage: action.messages && action.messages.success,
|
||||
errorMessage: action.messages && action.messages.failed
|
||||
successMessage: __(action.messages && action.messages.success),
|
||||
errorMessage: __(action.messages && action.messages.failed)
|
||||
})
|
||||
.then(async () => {
|
||||
if (action.feedback && isVisible(action.feedback, store.data)) {
|
||||
|
@ -959,7 +959,8 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
data,
|
||||
classnames: cx,
|
||||
saveImmediately,
|
||||
headingClassName
|
||||
headingClassName,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
@ -971,14 +972,19 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
<div className={cx('Table-heading', headingClassName)} key="heading">
|
||||
{!saveImmediately && store.modified && !hideQuickSaveBtn ? (
|
||||
<span>
|
||||
{`当前有 ${store.modified} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
{__(
|
||||
'当前有 ${modified} 条记录修改了内容, 但并没有提交。请选择:',
|
||||
{
|
||||
modified: store.modified
|
||||
}
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className={cx('Button Button--xs Button--success m-l-sm')}
|
||||
onClick={this.handleSave}
|
||||
>
|
||||
<i className="fa fa-check m-r-xs" />
|
||||
提交
|
||||
{__('提交')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -986,19 +992,21 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
onClick={this.reset}
|
||||
>
|
||||
<i className="fa fa-times m-r-xs" />
|
||||
放弃
|
||||
{__('放弃')}
|
||||
</button>
|
||||
</span>
|
||||
) : store.moved ? (
|
||||
<span>
|
||||
{`当前有 ${store.moved} 条记录修改了顺序, 但并没有提交。请选择:`}
|
||||
{__('当前有 ${moved} 条记录修改了顺序, 但并没有提交。请选择:', {
|
||||
moved: store.moved
|
||||
})}
|
||||
<button
|
||||
type="button"
|
||||
className={cx('Button Button--xs Button--success m-l-sm')}
|
||||
onClick={this.handleSaveOrder}
|
||||
>
|
||||
<i className="fa fa-check m-r-xs" />
|
||||
提交
|
||||
{__('提交')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -1006,7 +1014,7 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
onClick={this.reset}
|
||||
>
|
||||
<i className="fa fa-times m-r-xs" />
|
||||
放弃
|
||||
{__('放弃')}
|
||||
</button>
|
||||
</span>
|
||||
) : title ? (
|
||||
@ -1497,7 +1505,14 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
}
|
||||
|
||||
renderDragToggler() {
|
||||
const {store, env, draggable, classPrefix: ns, dragIcon} = this.props;
|
||||
const {
|
||||
store,
|
||||
env,
|
||||
draggable,
|
||||
classPrefix: ns,
|
||||
dragIcon,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (!draggable || store.isNested) {
|
||||
return null;
|
||||
@ -1508,7 +1523,7 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
disabled={!!store.modified}
|
||||
classPrefix={ns}
|
||||
key="dragging-toggle"
|
||||
tooltip="点击开始排序"
|
||||
tooltip={__('点击开始排序')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
@ -1587,7 +1602,8 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
showHeader,
|
||||
store,
|
||||
classnames: cx,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (showHeader === false) {
|
||||
@ -1625,7 +1641,7 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
{child}
|
||||
{store.dragging ? (
|
||||
<div className={cx('Table-dragTip')} ref={this.dragTipRef}>
|
||||
请拖动左边的按钮进行排序
|
||||
{__('请拖动左边的按钮进行排序')}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
@ -2160,7 +2176,7 @@ export class HeadCellSearchDropDown extends React.Component<
|
||||
}
|
||||
|
||||
buildSchema() {
|
||||
const {searchable, sortable, name, label} = this.props;
|
||||
const {searchable, sortable, name, label, translate: __} = this.props;
|
||||
|
||||
let schema;
|
||||
|
||||
@ -2207,14 +2223,14 @@ export class HeadCellSearchDropDown extends React.Component<
|
||||
{
|
||||
type: 'button-group',
|
||||
name: 'orderDir',
|
||||
label: '排序',
|
||||
label: __('排序'),
|
||||
options: [
|
||||
{
|
||||
label: '正序',
|
||||
label: __('正序'),
|
||||
value: 'asc'
|
||||
},
|
||||
{
|
||||
label: '降序',
|
||||
label: __('降序'),
|
||||
value: 'desc'
|
||||
}
|
||||
]
|
||||
@ -2230,12 +2246,12 @@ export class HeadCellSearchDropDown extends React.Component<
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '取消',
|
||||
label: __('取消'),
|
||||
actionType: 'cancel'
|
||||
},
|
||||
|
||||
{
|
||||
label: '搜索',
|
||||
label: __('搜索'),
|
||||
type: 'submit',
|
||||
primary: true
|
||||
}
|
||||
|
@ -650,7 +650,8 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
||||
actionNextLabel,
|
||||
actionNextSaveLabel,
|
||||
actionFinishLabel,
|
||||
render
|
||||
render,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (!Array.isArray(steps)) {
|
||||
@ -698,7 +699,7 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
||||
`prev-btn`,
|
||||
{
|
||||
type: 'button',
|
||||
label: actionPrevLabel,
|
||||
label: __(actionPrevLabel),
|
||||
actionType: 'prev',
|
||||
className: actionClassName
|
||||
},
|
||||
@ -713,10 +714,10 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
||||
{
|
||||
type: 'button',
|
||||
label: !nextStep
|
||||
? actionFinishLabel
|
||||
? __(actionFinishLabel)
|
||||
: !step.api
|
||||
? actionNextLabel
|
||||
: actionNextSaveLabel,
|
||||
? __(actionNextLabel)
|
||||
: __(actionNextSaveLabel),
|
||||
actionType: 'next',
|
||||
primary: !nextStep || !!step.api,
|
||||
className: actionClassName
|
||||
|
@ -2,7 +2,6 @@
|
||||
import cx from 'classnames';
|
||||
import React from 'react';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
import {ExtractProps, Omit} from './types';
|
||||
|
||||
export type ClassValue =
|
||||
| string
|
||||
@ -117,17 +116,19 @@ export const ThemeContext = React.createContext('theme');
|
||||
export let defaultTheme: string = 'default';
|
||||
|
||||
export function themeable<
|
||||
T extends React.ComponentType<ThemeProps & ExtractProps<T>>
|
||||
T extends React.ComponentType<React.ComponentProps<T> & ThemeProps>
|
||||
>(ComposedComponent: T) {
|
||||
type ComposedProps = JSX.LibraryManagedAttributes<T, ExtractProps<T>>;
|
||||
type Props = Omit<ComposedProps, keyof ThemeProps> & {
|
||||
type OuterProps = JSX.LibraryManagedAttributes<
|
||||
T,
|
||||
Omit<React.ComponentProps<T>, keyof ThemeProps>
|
||||
> & {
|
||||
theme?: string;
|
||||
classPrefix?: string;
|
||||
classnames?: ClassNamesFn;
|
||||
};
|
||||
|
||||
const result = hoistNonReactStatic(
|
||||
class extends React.Component<Props> {
|
||||
class extends React.Component<OuterProps> {
|
||||
static displayName = `Themeable(${
|
||||
ComposedComponent.displayName || ComposedComponent.name
|
||||
})`;
|
||||
@ -150,9 +151,10 @@ export function themeable<
|
||||
return (
|
||||
<ThemeContext.Provider value={theme}>
|
||||
<ComposedComponent
|
||||
{
|
||||
...(this.props as any) /* todo, 解决这个类型问题 */
|
||||
}
|
||||
{...(this.props as JSX.LibraryManagedAttributes<
|
||||
T,
|
||||
React.ComponentProps<T>
|
||||
>)}
|
||||
{...injectedProps}
|
||||
/>
|
||||
</ThemeContext.Provider>
|
||||
|
12
src/types.ts
12
src/types.ts
@ -140,15 +140,15 @@ export interface RendererData {
|
||||
type RendererDataAlis = RendererData;
|
||||
|
||||
export type FunctionPropertyNames<T> = {
|
||||
[K in keyof T]: T[K] extends Function ? K : never
|
||||
[K in keyof T]: T[K] extends Function ? K : never;
|
||||
}[keyof T];
|
||||
|
||||
export interface JSONSchema {
|
||||
[propsName: string]: any;
|
||||
}
|
||||
|
||||
export type Omit<T, K extends keyof T & any> = Pick<T, Exclude<keyof T, K>>;
|
||||
export type Override<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
|
||||
export type ExtractProps<
|
||||
TComponentOrTProps
|
||||
> = TComponentOrTProps extends React.ComponentType<infer P> ? P : never;
|
||||
// export type Omit<T, K extends keyof T & any> = Pick<T, Exclude<keyof T, K>>;
|
||||
// export type Override<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
|
||||
// export type ExtractProps<
|
||||
// TComponentOrTProps
|
||||
// > = TComponentOrTProps extends React.ComponentType<infer P> ? P : never;
|
||||
|
Loading…
Reference in New Issue
Block a user