还有部分 form 的文字没提换

This commit is contained in:
2betop 2020-06-03 14:51:52 +08:00
parent 6c3e358c9b
commit 738b751186
10 changed files with 180 additions and 77 deletions

View File

@ -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}
/>
))}
</div>
@ -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<
<Icon icon="close" className="icon" />
</a>
) : null}
{title ? <div className={cx('Toast-title')}>{title}</div> : null}
{title ? (
<div className={cx('Toast-title')}>{__(title)}</div>
) : null}
<div className={cx('Toast-body')}>
{allowHtml ? <Html html={body} /> : body}
</div>

View File

@ -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 (
<ScopedRootRenderer

View File

@ -148,5 +148,53 @@ register('en', {
'请拖动左边的按钮进行排序': 'Please drag the button on the left to sort',
'排序': 'Sort',
'正序': 'Asc',
'降序': 'Desc'
'降序': 'Desc',
'返回数据格式不正确payload.data 没有数据':
'The return data format is incorrect, nothing is in `payload.data`',
'获取失败': 'Fetch failed',
'返回数据格式不正确payload.data.items 必须是数组':
'The return data format is incorrect, payload.data.items Must be an array',
'验证错误': 'Validate failed',
'表单验证失败,请仔细检查': 'Form validation failed, please check carefully',
'验证失败': 'Validate failed',
'当前值不唯一': 'Current value is not unique',
'加载选项失败,原因:{{reason}}':
'Failed to load options because: {{reason}}',
'获取失败,请重试': 'Fetch failed, please try again',
'请仔细检查表单规则,部分表单项没通过验证':
'Please check the form rules carefully. Some form items fail to pass the verification',
'Email 格式不正确': 'Email format is incorrect',
'这是必填项': 'This is required',
'Url 格式不正确': 'Incorrect URL format',
'请输入整型数字': 'Please enter an integer number',
'请输入字母': 'Please enter letters',
'请输入数字': 'Please enter a number',
'请输入字母或者数字': 'Please enter letters or numbers',
'请输入浮点型数值': 'Please enter a floating point value',
'只能输入字母、数字、`-` 和 `_`.':
'You can only enter letters, numbers, `-` and`_` .',
'格式不正确, 请输入符合规则为 `${1|raw}` 的内容。':
'The format is not correct. Please enter the content with the rule `${1| raw}`.',
'请输入更多的内容,至少输入 $1 个字符。':
'Please enter more, at least $1 characters.',
'请控制内容长度, 不要输入 $1 个字符以上':
'Please control the content length, do not enter more than $1 characters',
'当前输入值超出最大值 $1请检查':
'The current input value exceeds the maximum value of $1, please check',
'请输入小于 $1 的值': 'Please enter a value less than $1',
'当前输入值低于最小值 $1请检查':
'The current input value is lower than the minimum value of $1, please check',
'请输入大于 $1 的值': 'Please enter a value greater than $1',
'请检查 Json 格式。': 'Please check the JSON format.',
'请输入长度为 $1 的内容':
'Please enter make sure the length of contents is $1',
'请不要全输入空白字符': 'Please do not enter all blank characters',
'输入的数据与 $1 值不一致':
'The entered data is inconsistent with the value of $1',
'输入的数据与 $1 不一致': 'The entered data is inconsistent with $1',
'请输入合法的手机号码': 'Please enter a valid mobile phone number',
'请输入合法的电话号码': 'Please enter a valid phone number',
'请输入合法的邮编地址': 'Please enter a legal postal address',
'请输入合法的身份证号': 'Please enter a valid ID number',
'系统错误': 'System Error'
});

View File

@ -196,7 +196,7 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
if (!json.ok) {
self.updateMessage(
json.msg || options.errorMessage || '获取失败',
json.msg || options.errorMessage || self.__('获取失败'),
true
);
(getRoot(self) as IRendererStore).notify(
@ -211,7 +211,9 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
);
} else {
if (!json.data) {
throw new Error('返回数据格式不正确payload.data 没有数据');
throw new Error(
self.__('返回数据格式不正确payload.data 没有数据')
);
}
self.updatedAt = Date.now();
@ -246,7 +248,7 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
if (!Array.isArray(items)) {
throw new Error(
'返回数据格式不正确payload.data.items 必须是数组'
self.__('返回数据格式不正确payload.data.items 必须是数组')
);
} else {
// 确保成员是对象。
@ -382,7 +384,7 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
if (!json.ok) {
self.updateMessage(
json.msg || options.errorMessage || '保存失败',
json.msg || options.errorMessage || self.__('保存失败'),
true
);
(getRoot(self) as IRendererStore).notify(

View File

@ -256,7 +256,9 @@ export const FormStore = ServiceStore.named('FormStore')
});
self.updateMessage(
json.msg || (options && options.errorMessage) || '验证错误',
json.msg ||
(options && options.errorMessage) ||
self.__('验证错误'),
true
);
} else {
@ -328,9 +330,9 @@ export const FormStore = ServiceStore.named('FormStore')
if (!valid) {
(getRoot(self) as IRendererStore).notify(
'error',
failedMessage || '表单验证失败,请仔细检查'
failedMessage || self.__('表单验证失败,请仔细检查')
);
throw new Error('验证失败');
throw new Error(self.__('验证失败'));
}
if (fn) {

View File

@ -4,7 +4,8 @@ import {
SnapshotIn,
flow,
getRoot,
hasParent
hasParent,
isAlive
} from 'mobx-state-tree';
import {IFormStore} from './form';
import {str2rules, validate as doValidate} from '../utils/validations';
@ -27,6 +28,7 @@ import {normalizeOptions, optionValueCompare} from '../components/Select';
import find from 'lodash/find';
import {SimpleMap} from '../utils/SimpleMap';
import memoize from 'lodash/memoize';
import {TranslateFn} from '../locale';
interface IOption {
value?: string | number | null;
@ -199,6 +201,14 @@ export const FormItemStore = types
});
return selectedOptions;
},
get __(): TranslateFn {
return isAlive(self) &&
getRoot(self) &&
(getRoot(self) as IRendererStore).storeType === 'RendererStore'
? (getRoot(self) as IRendererStore).__
: (str: string) => 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',

View File

@ -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) {

View File

@ -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 => ({

View File

@ -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(

View File

@ -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<string> {
const errors: Array<string> = [];
@ -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<string> {
const splitValidations = function (str: string): Array<string> {
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) {