From 738b751186376848d57a6c5e4079f348d7274b27 Mon Sep 17 00:00:00 2001
From: 2betop <2betop.cn@gmail.com>
Date: Wed, 3 Jun 2020 14:51:52 +0800
Subject: [PATCH] =?UTF-8?q?=E8=BF=98=E6=9C=89=E9=83=A8=E5=88=86=20form=20?=
=?UTF-8?q?=E7=9A=84=E6=96=87=E5=AD=97=E6=B2=A1=E6=8F=90=E6=8D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/Toast.tsx | 26 ++++++----
src/factory.tsx | 10 ++--
src/locale/en.ts | 50 +++++++++++++++++++-
src/store/crud.ts | 10 ++--
src/store/form.ts | 8 ++--
src/store/formItem.ts | 28 ++++++++---
src/store/iRenderer.ts | 12 ++++-
src/store/index.ts | 5 ++
src/store/service.ts | 8 +++-
src/utils/validations.ts | 100 ++++++++++++++++++++-------------------
10 files changed, 180 insertions(+), 77 deletions(-)
diff --git a/src/components/Toast.tsx b/src/components/Toast.tsx
index 0eaa362b..d2a447cd 100644
--- a/src/components/Toast.tsx
+++ b/src/components/Toast.tsx
@@ -14,8 +14,9 @@ import React from 'react';
import cx from 'classnames';
import Html from './Html';
import {uuid, autobind, noop} from '../utils/helper';
-import {ClassNamesFn, themeable, classnames} from '../theme';
+import {ClassNamesFn, themeable, classnames, ThemeProps} from '../theme';
import {Icon} from './icons';
+import {LocaleProps, localeable, TranslateFn} from '../locale';
interface Config {
closeButton?: boolean;
@@ -43,7 +44,7 @@ const show = (
toastRef[method](content, title || '', {...conf});
};
-interface ToastComponentProps {
+interface ToastComponentProps extends ThemeProps, LocaleProps {
position:
| 'top-right'
| 'top-center'
@@ -53,8 +54,6 @@ interface ToastComponentProps {
| 'bottom-right';
closeButton: boolean;
timeout: number;
- classPrefix: string;
- classnames: ClassNamesFn;
className?: string;
}
@@ -146,7 +145,13 @@ export class ToastComponent extends React.Component<
return null;
}
- const {classnames: cx, className, timeout, position} = this.props;
+ const {
+ classnames: cx,
+ className,
+ timeout,
+ position,
+ translate
+ } = this.props;
const items = this.state.items;
return (
@@ -168,6 +173,7 @@ export class ToastComponent extends React.Component<
timeout={item.timeout ?? timeout}
closeButton={item.closeButton}
onDismiss={this.handleDismissed.bind(this, index)}
+ translate={translate}
/>
))}
@@ -175,7 +181,7 @@ export class ToastComponent extends React.Component<
}
}
-export default themeable(ToastComponent);
+export default themeable(localeable(ToastComponent));
interface ToastMessageProps {
title?: string;
@@ -192,6 +198,7 @@ interface ToastMessageProps {
| 'bottom-right';
onDismiss?: () => void;
classnames: ClassNamesFn;
+ translate: TranslateFn;
allowHtml: boolean;
}
@@ -265,7 +272,8 @@ export class ToastMessage extends React.Component<
title,
body,
allowHtml,
- level
+ level,
+ translate: __
} = this.props;
return (
@@ -290,7 +298,9 @@ export class ToastMessage extends React.Component<
) : null}
- {title ?
{title}
: null}
+ {title ? (
+ {__(title)}
+ ) : null}
{allowHtml ?
: body}
diff --git a/src/factory.tsx b/src/factory.tsx
index 51b5b674..58b0374c 100644
--- a/src/factory.tsx
+++ b/src/factory.tsx
@@ -956,6 +956,8 @@ export function render(
...options
};
+ const locale = props.locale || getDefaultLocale();
+ const translate = props.translate || makeTranslator(locale);
let store =
stores[options.session || 'global'] ||
(stores[options.session || 'global'] = RendererStore.create(
@@ -967,7 +969,9 @@ export function render(
: defaultOptions.fetcher,
confirm: options.confirm
? promisify(options.confirm)
- : defaultOptions.confirm
+ : defaultOptions.confirm,
+ locale,
+ translate
}
));
@@ -975,8 +979,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);
+ env.translate = translate;
+ env.locale = locale;
return (
str;
}
};
})
@@ -303,7 +313,13 @@ export const FormItemStore = types
}
addError(
- doValidate(self.value, self.form.data, self.rules, self.messages)
+ doValidate(
+ self.value,
+ self.form.data,
+ self.rules,
+ self.messages,
+ self.__
+ )
);
self.validated = true;
@@ -320,7 +336,7 @@ export const FormItemStore = types
item => item !== self && self.value && item.value === self.value
)
) {
- addError(`当前值不唯一`);
+ addError(self.__('`当前值不唯一`'));
}
}
@@ -398,9 +414,9 @@ export const FormItemStore = types
if (!json.ok) {
setErrorFlag !== false &&
setError(
- `加载选项失败,原因:${
- json.msg || (config && config.errorMessage)
- }`
+ self.__('加载选项失败,原因:{{reason}}', {
+ reason: json.msg || (config && config.errorMessage)
+ })
);
(getRoot(self) as IRendererStore).notify(
'error',
diff --git a/src/store/iRenderer.ts b/src/store/iRenderer.ts
index b0796de6..bbfd03fd 100644
--- a/src/store/iRenderer.ts
+++ b/src/store/iRenderer.ts
@@ -3,6 +3,7 @@ import {extendObject, createObject} from '../utils/helper';
import {IRendererStore} from './index';
import {dataMapping} from '../utils/tpl-builtin';
import {SimpleMap} from '../utils/SimpleMap';
+import {TranslateFn} from '../locale';
export const iRendererStore = types
.model('iRendererStore', {
@@ -25,7 +26,6 @@ export const iRendererStore = types
})
.views(self => {
return {
- // todo 不能自己引用自己
get parentStore(): any {
return isAlive(self) &&
self.parentId &&
@@ -33,6 +33,14 @@ export const iRendererStore = types
(getRoot(self) as IRendererStore).storeType === 'RendererStore'
? (getRoot(self) as IRendererStore).stores.get(self.parentId)
: null;
+ },
+
+ get __(): TranslateFn {
+ return isAlive(self) &&
+ getRoot(self) &&
+ (getRoot(self) as IRendererStore).storeType === 'RendererStore'
+ ? (getRoot(self) as IRendererStore).__
+ : (str: string) => str;
}
};
})
@@ -62,7 +70,7 @@ export const iRendererStore = types
self.data = self.pristine;
},
- updateData(data: object = {}, tag?: object, replace?:boolean) {
+ updateData(data: object = {}, tag?: object, replace?: boolean) {
const prev = self.data;
let newData;
if (tag) {
diff --git a/src/store/index.ts b/src/store/index.ts
index 957e2d2e..2b10d285 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -8,6 +8,7 @@ import {CRUDStore} from './crud';
import {TableStore} from './table';
import {ListStore} from './list';
import {ModalStore} from './modal';
+import {TranslateFn} from '../locale';
setLivelynessChecking(
process.env.NODE_ENV === 'production' ? 'ignore' : 'error'
@@ -56,6 +57,10 @@ export const RendererStore = types
get isCancel(): (value: any) => boolean {
return getEnv(self).isCancel;
+ },
+
+ get __(): TranslateFn {
+ return getEnv(self).translate;
}
}))
.views(self => ({
diff --git a/src/store/service.ts b/src/store/service.ts
index 3169e71d..9e03815e 100644
--- a/src/store/service.ts
+++ b/src/store/service.ts
@@ -278,7 +278,9 @@ export const ServiceStore = iRendererStore
if (!json.ok) {
updateMessage(
- json.msg || (options && options.errorMessage) || '保存失败',
+ json.msg ||
+ (options && options.errorMessage) ||
+ self.__('保存失败'),
true
);
throw new ServerError(self.msg, json);
@@ -370,7 +372,9 @@ export const ServiceStore = iRendererStore
if (!json.ok) {
updateMessage(
- json.msg || (options && options.errorMessage) || '获取失败,请重试',
+ json.msg ||
+ (options && options.errorMessage) ||
+ self.__('获取失败,请重试'),
true
);
(getRoot(self) as IRendererStore).notify(
diff --git a/src/utils/validations.ts b/src/utils/validations.ts
index a2e8bd47..afc6ecb5 100644
--- a/src/utils/validations.ts
+++ b/src/utils/validations.ts
@@ -26,7 +26,7 @@ export interface ValidateFn {
export const validations: {
[propsName: string]: ValidateFn;
} = {
- isRequired: function(values, value: any) {
+ isRequired: function (values, value: any) {
return (
value !== undefined &&
value !== '' &&
@@ -34,113 +34,113 @@ export const validations: {
(!Array.isArray(value) || !!value.length)
);
},
- isExisty: function(values, value) {
+ isExisty: function (values, value) {
return isExisty(value);
},
- matchRegexp: function(values, value, regexp) {
+ matchRegexp: function (values, value, regexp) {
return !isExisty(value) || isEmpty(value) || makeRegexp(regexp).test(value);
},
- isUndefined: function(values, value) {
+ isUndefined: function (values, value) {
return value === undefined;
},
- isEmptyString: function(values, value) {
+ isEmptyString: function (values, value) {
return isEmpty(value);
},
- isEmail: function(values, value) {
+ isEmail: function (values, value) {
return validations.matchRegexp(
values,
value,
/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i
);
},
- isUrl: function(values, value) {
+ isUrl: function (values, value) {
return validations.matchRegexp(
values,
value,
/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i
);
},
- isTrue: function(values, value) {
+ isTrue: function (values, value) {
return value === true;
},
- isFalse: function(values, value) {
+ isFalse: function (values, value) {
return value === false;
},
- isNumeric: function(values, value) {
+ isNumeric: function (values, value) {
if (typeof value === 'number') {
return true;
}
return validations.matchRegexp(values, value, /^[-+]?(?:\d*[.])?\d+$/);
},
- isAlpha: function(values, value) {
+ isAlpha: function (values, value) {
return validations.matchRegexp(values, value, /^[A-Z]+$/i);
},
- isAlphanumeric: function(values, value) {
+ isAlphanumeric: function (values, value) {
return validations.matchRegexp(values, value, /^[0-9A-Z]+$/i);
},
- isInt: function(values, value) {
+ isInt: function (values, value) {
return validations.matchRegexp(values, value, /^(?:[-+]?(?:0|[1-9]\d*))$/);
},
- isFloat: function(values, value) {
+ isFloat: function (values, value) {
return validations.matchRegexp(
values,
value,
/^(?:[-+]?(?:\d+))?(?:\.\d*)?(?:[eE][\+\-]?(?:\d+))?$/
);
},
- isWords: function(values, value) {
+ isWords: function (values, value) {
return validations.matchRegexp(values, value, /^[A-Z\s]+$/i);
},
- isSpecialWords: function(values, value) {
+ isSpecialWords: function (values, value) {
return validations.matchRegexp(values, value, /^[A-Z\s\u00C0-\u017F]+$/i);
},
- isLength: function(values, value, length) {
+ isLength: function (values, value, length) {
return !isExisty(value) || isEmpty(value) || value.length === length;
},
- equals: function(values, value, eql) {
+ equals: function (values, value, eql) {
return !isExisty(value) || isEmpty(value) || value == eql;
},
- equalsField: function(values, value, field) {
+ equalsField: function (values, value, field) {
return value == values[field];
},
- maxLength: function(values, value, length) {
+ maxLength: function (values, value, length) {
return !isExisty(value) || value.length <= length;
},
- minLength: function(values, value, length) {
+ minLength: function (values, value, length) {
return !isExisty(value) || isEmpty(value) || value.length >= length;
},
- isUrlPath: function(values, value, regexp) {
+ isUrlPath: function (values, value, regexp) {
return !isExisty(value) || isEmpty(value) || /^[a-z0-9_\\-]+$/i.test(value);
},
- maximum: function(values, value, maximum) {
+ maximum: function (values, value, maximum) {
return (
!isExisty(value) ||
isEmpty(value) ||
(parseFloat(value) || 0) <= (parseFloat(maximum) || 0)
);
},
- lt: function(values, value, maximum) {
+ lt: function (values, value, maximum) {
return (
!isExisty(value) ||
isEmpty(value) ||
(parseFloat(value) || 0) < (parseFloat(maximum) || 0)
);
},
- minimum: function(values, value, minimum) {
+ minimum: function (values, value, minimum) {
return (
!isExisty(value) ||
isEmpty(value) ||
(parseFloat(value) || 0) >= (parseFloat(minimum) || 0)
);
},
- gt: function(values, value, minimum) {
+ gt: function (values, value, minimum) {
return (
!isExisty(value) ||
isEmpty(value) ||
(parseFloat(value) || 0) > (parseFloat(minimum) || 0)
);
},
- isJson: function(values, value, minimum) {
+ isJson: function (values, value, minimum) {
if (isExisty(value) && !isEmpty(value)) {
try {
JSON.parse(value);
@@ -150,24 +150,24 @@ export const validations: {
}
return true;
},
- isPhoneNumber: function(values, value) {
+ isPhoneNumber: function (values, value) {
return (
!isExisty(value) || isEmpty(value) || /^[1]([3-9])[0-9]{9}$/.test(value)
);
},
- isTelNumber: function(values, value) {
+ isTelNumber: function (values, value) {
return (
!isExisty(value) ||
isEmpty(value) ||
/^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/.test(value)
);
},
- isZipcode: function(values, value) {
+ isZipcode: function (values, value) {
return (
!isExisty(value) || isEmpty(value) || /^[1-9]{1}(\d+){5}$/.test(value)
);
},
- isId: function(values, value) {
+ isId: function (values, value) {
return (
!isExisty(value) ||
isEmpty(value) ||
@@ -176,34 +176,34 @@ export const validations: {
)
);
},
- notEmptyString: function(values, value) {
+ notEmptyString: function (values, value) {
return !isExisty(value) || !(String(value) && String(value).trim() === '');
},
- matchRegexp1: function(values, value, regexp) {
+ matchRegexp1: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
},
- matchRegexp2: function(values, value, regexp) {
+ matchRegexp2: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
},
- matchRegexp3: function(values, value, regexp) {
+ matchRegexp3: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
},
- matchRegexp4: function(values, value, regexp) {
+ matchRegexp4: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
},
- matchRegexp5: function(values, value, regexp) {
+ matchRegexp5: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
},
- matchRegexp6: function(values, value, regexp) {
+ matchRegexp6: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
},
- matchRegexp7: function(values, value, regexp) {
+ matchRegexp7: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
},
- matchRegexp8: function(values, value, regexp) {
+ matchRegexp8: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
},
- matchRegexp9: function(values, value, regexp) {
+ matchRegexp9: function (values, value, regexp) {
return validations.matchRegexp(values, value, regexp);
}
};
@@ -252,7 +252,8 @@ export function validate(
value: any,
values: {[propName: string]: any},
rules: {[propName: string]: any},
- messages?: {[propName: string]: string}
+ messages?: {[propName: string]: string},
+ __ = (str: string) => str
): Array {
const errors: Array = [];
@@ -275,9 +276,12 @@ export function validate(
)
) {
errors.push(
- filter((messages && messages[ruleName]) || validateMessages[ruleName], {
- ...[''].concat(rules[ruleName])
- })
+ filter(
+ __((messages && messages[ruleName]) || validateMessages[ruleName]),
+ {
+ ...[''].concat(rules[ruleName])
+ }
+ )
);
}
});
@@ -285,7 +289,7 @@ export function validate(
return errors;
}
-const splitValidations = function(str: string): Array {
+const splitValidations = function (str: string): Array {
let i = 0;
const placeholder: {[propName: string]: string} = {};
@@ -303,7 +307,7 @@ export function str2rules(
): {[propName: string]: any} {
if (typeof validations === 'string') {
return validations
- ? splitValidations(validations).reduce(function(
+ ? splitValidations(validations).reduce(function (
validations: {[propName: string]: any},
validation
) {
@@ -318,7 +322,7 @@ export function str2rules(
: validation
.substring(idx + 1)
.split(',')
- .map(function(arg) {
+ .map(function (arg) {
try {
return JSON.parse(arg);
} catch (e) {