From f4ac5e2a6e68d5cf0c0e7caba46a7d9236d2973d Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Tue, 2 Jun 2020 20:41:51 +0800 Subject: [PATCH] =?UTF-8?q?Locale=20=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/components/App.jsx | 40 ++++++- examples/components/SchemaRender.jsx | 5 +- src/components/Alert.tsx | 24 ++-- src/components/AssociatedCheckboxes.tsx | 18 +-- src/components/ChainedCheckboxes.tsx | 13 +- src/components/Checkboxes.tsx | 15 ++- src/components/ColorPicker.tsx | 18 +-- src/components/DatePicker.tsx | 84 +++++++------ src/components/DateRangePicker.tsx | 42 +++---- src/components/ImageGallery.tsx | 12 +- src/components/ListCheckboxes.tsx | 14 ++- src/components/ListMenu.tsx | 9 +- src/components/ListRadios.tsx | 14 ++- src/components/LocationPicker.tsx | 22 ++-- src/components/Modal.tsx | 65 +++++----- src/components/ResultBox.tsx | 18 ++- src/components/ResultList.tsx | 10 +- src/components/SearchBox.tsx | 18 +-- src/components/Select.tsx | 31 ++--- src/components/TableCheckboxes.tsx | 14 ++- src/components/TabsTransfer.tsx | 10 +- src/components/Tinymce.tsx | 7 +- src/components/Transfer.tsx | 32 +++-- src/components/Tree.tsx | 32 ++--- src/components/TreeCheckboxes.tsx | 16 ++- src/components/TreeRadios.tsx | 5 +- src/components/calendar/DaysView.tsx | 20 +++- src/components/calendar/MonthsView.tsx | 13 +- src/components/calendar/YearsView.tsx | 10 +- src/factory.tsx | 91 ++++++++------ src/locale.tsx | 62 ++++++---- src/locale/en.ts | 153 ++++++++++++++++++++++++ src/locale/en_UK.ts | 0 src/renderers/Action.tsx | 1 - src/renderers/CRUD.tsx | 39 +++--- src/renderers/Cards.tsx | 19 ++- src/renderers/Copyable.tsx | 5 +- src/renderers/Date.tsx | 5 +- src/renderers/Dialog.tsx | 17 +-- src/renderers/Drawer.tsx | 6 +- src/renderers/Form/Checkboxes.tsx | 7 +- src/renderers/Form/City.tsx | 5 +- src/renderers/Form/Combo.tsx | 86 +++++++------ src/renderers/Form/Date.tsx | 2 + src/renderers/Form/File.tsx | 74 +++++++----- src/renderers/Form/IconPicker.tsx | 5 +- src/renderers/Form/Image.tsx | 114 ++++++++++-------- src/renderers/Form/Matrix.tsx | 4 +- src/renderers/Form/NestedSelect.tsx | 5 +- src/renderers/Form/Options.tsx | 23 ++-- src/renderers/Form/Picker.tsx | 9 +- src/renderers/Form/Radios.tsx | 5 +- src/renderers/Form/Repeat.tsx | 14 ++- src/renderers/Form/RichText.tsx | 20 +++- src/renderers/Form/SubForm.tsx | 20 ++-- src/renderers/Form/Table.tsx | 81 ++++++++----- src/renderers/Form/Tag.tsx | 9 +- src/renderers/Form/Text.tsx | 5 +- src/renderers/Form/Tree.tsx | 5 +- src/renderers/Form/TreeSelect.tsx | 12 +- src/renderers/Form/index.tsx | 28 +++-- src/renderers/Image.tsx | 14 +-- src/renderers/Link.tsx | 5 +- src/renderers/List.tsx | 19 ++- src/renderers/Nav.tsx | 4 +- src/renderers/PopOver.tsx | 4 +- src/renderers/QuickEdit.tsx | 6 +- src/renderers/Service.tsx | 6 +- src/renderers/Table.tsx | 50 +++++--- src/renderers/Wizard.tsx | 11 +- src/theme.tsx | 18 +-- src/types.ts | 12 +- 72 files changed, 1087 insertions(+), 624 deletions(-) create mode 100644 src/locale/en.ts delete mode 100644 src/locale/en_UK.ts diff --git a/examples/components/App.jsx b/examples/components/App.jsx index d98c9bc75..fada1e56d 100644 --- a/examples/components/App.jsx +++ b/examples/components/App.jsx @@ -4,6 +4,7 @@ import Layout from '../../src/components/Layout'; import AsideNav from '../../src/components/AsideNav'; import {AlertComponent, ToastComponent} from '../../src/components/index'; import {mapTree} from '../../src/utils/helper'; +import '../../src/locale/en'; import { Router, Route, @@ -560,6 +561,18 @@ const themes = [ } ]; +const locales = [ + { + label: '默认', + value: 'zh-cn' + }, + + { + label: 'English', + value: 'en' + } +]; + @withRouter export class App extends React.PureComponent { state = { @@ -568,7 +581,8 @@ export class App extends React.PureComponent { headerVisible: true, themeIndex: 0, themes: themes, - theme: themes[localStorage.getItem('themeIndex') || 0] + theme: themes[localStorage.getItem('themeIndex') || 0], + locale: localStorage.getItem('locale') || '' }; constructor(props) { @@ -767,10 +781,27 @@ export class App extends React.PureComponent { +
+ 语言: + { + - - + + {React.cloneElement(this.props.children, { ...this.props.children.props, setAsideFolded: this.setAsideFolded, setHeaderVisible: this.setHeaderVisible, theme: theme.value, - classPrefix: theme.ns + classPrefix: theme.ns, + locale: this.state.locale })} ); diff --git a/examples/components/SchemaRender.jsx b/examples/components/SchemaRender.jsx index e7e0a39c5..5509f1b2a 100644 --- a/examples/components/SchemaRender.jsx +++ b/examples/components/SchemaRender.jsx @@ -161,13 +161,14 @@ export default function (schema) { } renderSchema() { - const {router, location, theme} = this.props; + const {router, location, theme, locale} = this.props; return render( schema, { location, - theme + theme, + locale }, this.env ); diff --git a/src/components/Alert.tsx b/src/components/Alert.tsx index 958efd428..3b4ba396d 100644 --- a/src/components/Alert.tsx +++ b/src/components/Alert.tsx @@ -7,18 +7,16 @@ import React from 'react'; import {render} from 'react-dom'; import Modal from './Modal'; import Button from './Button'; -import {ClassNamesFn, themeable} from '../theme'; +import {ClassNamesFn, themeable, ThemeProps} from '../theme'; +import {LocaleProps, localeable} from '../locale'; -export interface AlertProps { +export interface AlertProps extends ThemeProps, LocaleProps { container?: any; confirmText?: string; cancelText?: string; title?: string; confirmBtnLevel?: string; alertBtnLevel?: string; - classPrefix: string; - classnames: ClassNamesFn; - theme?: string; } export interface AlertState { @@ -37,7 +35,7 @@ export class Alert extends React.Component { const container = document.body; const div = document.createElement('div'); container.appendChild(div); - render(, div); + render(, div); } return Alert.instance; @@ -150,6 +148,8 @@ export class Alert extends React.Component { classnames: cx, classPrefix } = this.props; + const __ = this.props.translate; + return ( { ref={this.modalRef} >
-
{this.state.title || title}
+
+ {__(this.state.title || title)} +
{this.state.confirm ? ( - + ) : null}
@@ -189,5 +191,5 @@ export const confirm: ( confirmText?: string ) => Promise = (content, title, confirmText) => Alert.getInstance().confirm(content, title, confirmText); -export const ThemedAlert = themeable(Alert); -export default ThemedAlert; +export const FinnalAlert = themeable(localeable(Alert)); +export default FinnalAlert; diff --git a/src/components/AssociatedCheckboxes.tsx b/src/components/AssociatedCheckboxes.tsx index 279de9a60..3bec02551 100644 --- a/src/components/AssociatedCheckboxes.tsx +++ b/src/components/AssociatedCheckboxes.tsx @@ -19,6 +19,7 @@ import ChainedCheckboxes from './ChainedCheckboxes'; import Spinner from './Spinner'; import TreeRadios from './TreeRadios'; import {Icon} from './icons'; +import {localeable} from '../locale'; export interface AssociatedCheckboxesProps extends CheckboxesProps { leftOptions: Options; @@ -113,6 +114,7 @@ export class AssociatedCheckboxes extends Checkboxes< options, (option: Option) => option.ref ); + const __ = this.props.translate; return (
@@ -155,9 +157,9 @@ export class AssociatedCheckboxes extends Checkboxes<
{selectdOption.loading ? ( -

加载中

+

{__('加载中')}

) : ( -

点击刷新重新加载

+

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

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