@fe-free/core 4.0.4 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@ import { useDebounce } from 'ahooks';
2
2
  import { Input } from 'antd';
3
3
  import classNames from 'classnames';
4
4
  import { useCallback, useEffect, useMemo, useState } from 'react';
5
+ import { useTranslation } from 'react-i18next';
5
6
  import type { CRUDProps } from '../crud';
6
7
  import { CRUD } from '../crud';
7
8
  import './style.scss';
@@ -15,15 +16,26 @@ interface CRUDOfListProps<
15
16
  }
16
17
 
17
18
  function useTips(props) {
19
+ const { t } = useTranslation();
18
20
  useEffect(() => {
19
21
  const count = props.tableProps.columns?.filter((column) => column.search).length;
20
22
  if (!count) {
21
- console.warn('CRUDOfList 的 columns 中至少有一个 search 为 true 的列');
23
+ console.warn(
24
+ t(
25
+ 'core.crudOfList.warnAtLeastOneSearch',
26
+ 'CRUDOfList 的 columns 中至少有一个 search 为 true 的列',
27
+ ),
28
+ );
22
29
  }
23
30
  if (count > 1) {
24
- console.warn('CRUDOfList 的 columns 中只能有一个 search 为 true 的列');
31
+ console.warn(
32
+ t(
33
+ 'core.crudOfList.warnOnlyOneSearch',
34
+ 'CRUDOfList 的 columns 中只能有一个 search 为 true 的列',
35
+ ),
36
+ );
25
37
  }
26
- }, []);
38
+ }, [t]);
27
39
  }
28
40
 
29
41
  function SearchRender(props: {
@@ -31,9 +43,10 @@ function SearchRender(props: {
31
43
  value?: string;
32
44
  onChange: (value: string) => void;
33
45
  }) {
46
+ const { t } = useTranslation();
34
47
  return (
35
48
  <Input
36
- placeholder={props.placeholder ?? '输入搜索'}
49
+ placeholder={props.placeholder ?? t('@fe-free/core.crudOfList.searchPlaceholder', '输入搜索')}
37
50
  allowClear
38
51
  value={props.value}
39
52
  onChange={(e) => props.onChange(e.target.value)}
@@ -1,5 +1,6 @@
1
1
  import classNames from 'classnames';
2
2
  import { useMemo } from 'react';
3
+ import { useTranslation } from 'react-i18next';
3
4
  import type { CRUDProps } from '../crud';
4
5
  import { CRUD } from '../crud';
5
6
  import './style.scss';
@@ -17,6 +18,7 @@ function CRUDOfPure<
17
18
  DataSource extends Record<string, any> = any,
18
19
  Key extends string | number = string,
19
20
  >(props: CRUDOfPureProps<DataSource, Key>) {
21
+ const { t } = useTranslation();
20
22
  const newColumns = props.tableProps.columns?.map((column) => {
21
23
  if (column.search) {
22
24
  return {
@@ -30,8 +32,12 @@ function CRUDOfPure<
30
32
  fieldProps: {
31
33
  placeholder:
32
34
  column.valueType === 'select' || column.valueEnum
33
- ? `请选择${column.title}`
34
- : `请输入${column.title}`,
35
+ ? t('@fe-free/core.crudOfPure.selectPlaceholder', '请选择{title}', {
36
+ title: column.title,
37
+ })
38
+ : t('@fe-free/core.crudOfPure.inputPlaceholder', '请输入{title}', {
39
+ title: column.title,
40
+ }),
35
41
  ...column.fieldProps,
36
42
  },
37
43
  };
@@ -1,6 +1,7 @@
1
1
  import { ArrowsAltOutlined } from '@fe-free/icons';
2
2
  import { Button, Modal, Select } from 'antd';
3
3
  import { useMemo, useState } from 'react';
4
+ import { useTranslation } from 'react-i18next';
4
5
  import { Editor } from '../editor';
5
6
  import { PageLayout } from '../page_layout';
6
7
 
@@ -19,6 +20,7 @@ const options = [
19
20
  ];
20
21
 
21
22
  function DataViewer({ data, title, enableMaximize }: DataViewerProps) {
23
+ const { t } = useTranslation();
22
24
  const [maximize, setMaximize] = useState(false);
23
25
  const [language, setLanguage] = useState<DataViewerLanguage>(
24
26
  options[0].value as DataViewerLanguage,
@@ -64,7 +66,13 @@ function DataViewer({ data, title, enableMaximize }: DataViewerProps) {
64
66
  </div>
65
67
  </PageLayout>
66
68
  {maximize && (
67
- <Modal title="查看" open width={'80vw'} onCancel={() => setMaximize(false)} footer={null}>
69
+ <Modal
70
+ title={t('@fe-free/core.dataViewer.view', '查看')}
71
+ open
72
+ width={'80vw'}
73
+ onCancel={() => setMaximize(false)}
74
+ footer={null}
75
+ >
68
76
  <div className="h-[80vh]">
69
77
  <Editor
70
78
  value={value}
@@ -3,6 +3,7 @@ import { ProForm } from '@ant-design/pro-components';
3
3
  import { Input, InputNumber, Switch } from 'antd';
4
4
 
5
5
  import { uniq, uniqBy } from 'lodash-es';
6
+ import { useTranslation } from 'react-i18next';
6
7
  import { ProFormListHelper } from './form_list_helper';
7
8
 
8
9
  interface ListTextProps {
@@ -108,6 +109,7 @@ function ListBoolean(props: ListBooleanProps) {
108
109
 
109
110
  function ProFormListText(props: ProFormItemProps<ListTextProps>) {
110
111
  const { fieldProps, ...rest } = props;
112
+ const { t } = useTranslation();
111
113
 
112
114
  return (
113
115
  <ProForm.Item
@@ -121,19 +123,19 @@ function ProFormListText(props: ProFormItemProps<ListTextProps>) {
121
123
  if (value) {
122
124
  if (fieldProps?.isValueLabel) {
123
125
  if (value?.some((item) => item.value === undefined || item.value === '')) {
124
- return Promise.reject('存在空选项');
126
+ return Promise.reject(t('@fe-free/core.formList.emptyOption', '存在空选项'));
125
127
  }
126
128
  // 不能有重复的 value
127
129
  if (uniqBy(value, 'value').length !== value.length) {
128
- return Promise.reject('不能有重复');
130
+ return Promise.reject(t('@fe-free/core.formList.duplicateValue', '不能有重复'));
129
131
  }
130
132
  } else {
131
133
  if (value?.some((item) => item === undefined || item === '')) {
132
- return Promise.reject('存在空选项');
134
+ return Promise.reject(t('@fe-free/core.formList.emptyOption', '存在空选项'));
133
135
  }
134
136
  // 不能有重复的 value
135
137
  if (uniq(value).length !== value.length) {
136
- return Promise.reject('不能有重复');
138
+ return Promise.reject(t('@fe-free/core.formList.duplicateValue', '不能有重复'));
137
139
  }
138
140
  }
139
141
  }
@@ -150,6 +152,7 @@ function ProFormListText(props: ProFormItemProps<ListTextProps>) {
150
152
 
151
153
  function ProFormListNumber(props: ProFormItemProps<ListNumberProps>) {
152
154
  const { fieldProps, ...rest } = props;
155
+ const { t } = useTranslation();
153
156
 
154
157
  return (
155
158
  <ProForm.Item
@@ -163,19 +166,19 @@ function ProFormListNumber(props: ProFormItemProps<ListNumberProps>) {
163
166
  if (value) {
164
167
  if (fieldProps?.isValueLabel) {
165
168
  if (value?.some((item) => item.value === undefined || item.value === null)) {
166
- return Promise.reject('存在空选项');
169
+ return Promise.reject(t('@fe-free/core.formList.emptyOption', '存在空选项'));
167
170
  }
168
171
  // 不能有重复的 value
169
172
  if (uniqBy(value, 'value').length !== value.length) {
170
- return Promise.reject('不能有重复');
173
+ return Promise.reject(t('@fe-free/core.formList.duplicateValue', '不能有重复'));
171
174
  }
172
175
  } else {
173
176
  if (value?.some((item) => item === undefined || item === null)) {
174
- return Promise.reject('存在空选项');
177
+ return Promise.reject(t('@fe-free/core.formList.emptyOption', '存在空选项'));
175
178
  }
176
179
  // 不能有重复的 value
177
180
  if (uniq(value).length !== value.length) {
178
- return Promise.reject('不能有重复');
181
+ return Promise.reject(t('@fe-free/core.formList.duplicateValue', '不能有重复'));
179
182
  }
180
183
  }
181
184
  }
@@ -1,6 +1,7 @@
1
1
  import { DeleteOutlined, PlusOutlined } from '@fe-free/icons';
2
2
  import { Button } from 'antd';
3
3
  import classNames from 'classnames';
4
+ import { useTranslation } from 'react-i18next';
4
5
 
5
6
  interface ProFormListHelperProps<T> {
6
7
  value?: T[];
@@ -27,6 +28,7 @@ interface ProFormListHelperProps<T> {
27
28
 
28
29
  const emptyArr = [];
29
30
  function ProFormListHelper<T = any>(props: ProFormListHelperProps<T>) {
31
+ const { t } = useTranslation();
30
32
  const options = props.value || emptyArr;
31
33
 
32
34
  return (
@@ -85,7 +87,7 @@ function ProFormListHelper<T = any>(props: ProFormListHelperProps<T>) {
85
87
  props.onChange?.(newOptions);
86
88
  }}
87
89
  >
88
- {props.addText || '添加'}
90
+ {props.addText || t('@fe-free/core.formList.add', '添加')}
89
91
  </Button>
90
92
  </div>
91
93
  )}
@@ -2,6 +2,7 @@ import { ModalForm } from '@ant-design/pro-components';
2
2
  import { DeleteOutlined, EditOutlined, PlusOutlined } from '@fe-free/icons';
3
3
  import { Button } from 'antd';
4
4
  import React from 'react';
5
+ import { useTranslation } from 'react-i18next';
5
6
 
6
7
  const emptyArr = [];
7
8
 
@@ -34,6 +35,7 @@ function Edit<T>(props: {
34
35
  editForm?: any;
35
36
  disabledSubmitter?: boolean;
36
37
  }) {
38
+ const { t } = useTranslation();
37
39
  const handleFinish = async (newValues) => {
38
40
  props.onChange(newValues as T);
39
41
 
@@ -42,7 +44,11 @@ function Edit<T>(props: {
42
44
 
43
45
  return (
44
46
  <ModalForm
45
- title={props.values ? '编辑' : '添加'}
47
+ title={
48
+ props.values
49
+ ? t('@fe-free/core.formList.edit', '编辑')
50
+ : t('@fe-free/core.formList.add', '添加')
51
+ }
46
52
  trigger={props.children}
47
53
  onFinish={handleFinish}
48
54
  formRef={props?.editForm}
@@ -119,7 +125,7 @@ function ProFormListModalHelper<T = any>(props: ProFormListModalHelperProps<T>)
119
125
  >
120
126
  {props.addTrigger || (
121
127
  <Button size="small" icon={<PlusOutlined />}>
122
- 添加
128
+ {t('@fe-free/core.formList.add', '添加')}
123
129
  </Button>
124
130
  )}
125
131
  </Edit>
package/src/i18n.tsx CHANGED
@@ -33,6 +33,8 @@ function initI18n({ enTranslation }) {
33
33
  const cacheLng = localStorage.getItem('i18nextLng') || EnumLanguage.ZH_CN;
34
34
  const lng = listLanguage.find((item) => item.value === cacheLng) ? cacheLng : EnumLanguage.ZH_CN;
35
35
 
36
+ console.log('initI18n', 'cacheLng', cacheLng, 'lng', lng);
37
+
36
38
  i18n
37
39
  .use(LanguageDetector)
38
40
  .use(initReactI18next)
@@ -60,4 +62,7 @@ function I18nProvider({ children }: { children: React.ReactNode }) {
60
62
  return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
61
63
  }
62
64
 
65
+ // @ts-ignore
66
+ window._i18n = i18n;
67
+
63
68
  export { EnumLanguage, I18nProvider, initI18n, listLanguage, valueEnumLanguage };
@@ -2,6 +2,7 @@ import { Spin } from 'antd';
2
2
  import classNames from 'classnames';
3
3
  import type { ReactNode } from 'react';
4
4
  import { useImperativeHandle, useRef, useState } from 'react';
5
+ import { useTranslation } from 'react-i18next';
5
6
  import stringify from 'safe-stable-stringify';
6
7
  import { useGlobalInfiniteScroll } from '../ahooks/use_global_infinite_scroll';
7
8
 
@@ -34,6 +35,7 @@ const InfiniteListBase = <D, P>({
34
35
  gridClassName,
35
36
  className,
36
37
  }: InfiniteListProps<D, P>) => {
38
+ const { t } = useTranslation();
37
39
  const ref = useRef<HTMLDivElement>(null);
38
40
 
39
41
  const { data, loading, loadingMore, noMore, mutate, reload } = useGlobalInfiniteScroll(
@@ -103,8 +105,16 @@ const InfiniteListBase = <D, P>({
103
105
  </div>
104
106
  )}
105
107
  <div className="flex w-full items-center justify-center">
106
- {noMore && <div className="my-5 text-center text-03">没有更多数据</div>}
107
- {loadingMore && <div className="my-5 text-center text-03">加载更多数据中...</div>}
108
+ {noMore && (
109
+ <div className="my-5 text-center text-03">
110
+ {t('@fe-free/core.infiniteList.noMoreData', '没有更多数据')}
111
+ </div>
112
+ )}
113
+ {loadingMore && (
114
+ <div className="my-5 text-center text-03">
115
+ {t('@fe-free/core.infiniteList.loadingMore', '加载更多数据中...')}
116
+ </div>
117
+ )}
108
118
  </div>
109
119
  </div>
110
120
  );
@@ -0,0 +1,87 @@
1
+ {
2
+ "@fe-free/core": {
3
+ "app": {
4
+ "mainScriptNotFound": "Could not find [data-name=\"mainScript\"], update reminder is disabled",
5
+ "newVersionFound": "New version found",
6
+ "refresh": "Refresh",
7
+ "refreshPrompt": "Please refresh the page in time to update to avoid affecting usage",
8
+ "updateLater": "Update later"
9
+ },
10
+ "crud": {
11
+ "batchActionConfirm": "Are you sure you want to execute {action}?",
12
+ "batchDelete": "Batch delete",
13
+ "cancel": "Cancel",
14
+ "clearSelection": "Clear selection",
15
+ "confirm": "Confirm",
16
+ "create": "Create",
17
+ "createSuccess": "Created successfully",
18
+ "delete": "Delete",
19
+ "deleteConfirm": "Are you sure you want to delete \"{name}\"?",
20
+ "deleteSuccess": "Deleted successfully",
21
+ "deleteWarning": "This action cannot be undone, please proceed with caution",
22
+ "operate": "Actions",
23
+ "read": "View",
24
+ "requestDeleteByRecordRequired": "requestDeleteByRecord is required",
25
+ "selectedItems": "{num} items selected",
26
+ "update": "Edit",
27
+ "updateSuccess": "Updated successfully",
28
+ "warnCreateDetailForm": "detailForm is required when actions include create",
29
+ "warnReadDetailForm": "detailForm is required when actions include read",
30
+ "warnUpdateDetailForm": "detailForm is required when actions include update"
31
+ },
32
+ "crudOfList": {
33
+ "searchPlaceholder": "Enter search"
34
+ },
35
+ "crudOfPure": {
36
+ "inputPlaceholder": "Please enter {title}",
37
+ "selectPlaceholder": "Please select {title}"
38
+ },
39
+ "dataViewer": {
40
+ "view": "View"
41
+ },
42
+ "fileTree": {
43
+ "create": "Create",
44
+ "createSubDirectory": "Create subdirectory",
45
+ "delete": "Delete",
46
+ "directoryName": "Directory name",
47
+ "update": "Edit"
48
+ },
49
+ "formList": {
50
+ "add": "Add",
51
+ "duplicateValue": "Duplicate values are not allowed",
52
+ "edit": "Edit",
53
+ "emptyOption": "Empty option exists"
54
+ },
55
+ "infiniteList": {
56
+ "loadingMore": "Loading more data...",
57
+ "noMoreData": "No more data"
58
+ },
59
+ "record": {
60
+ "inputPlaceholder": "Please enter"
61
+ },
62
+ "upload": {
63
+ "delete": "Delete",
64
+ "dragUpload": "Click or drag files to this area to upload",
65
+ "fileCount": "File count ({success}/{total})",
66
+ "localUpload": "Local upload",
67
+ "maxFilesWarning": "Only {num} files can be uploaded at most, excess files will be ignored.",
68
+ "pleaseSelect": "Please select"
69
+ },
70
+ "valueTypeMap": {
71
+ "view": "View"
72
+ }
73
+ },
74
+ "core": {
75
+ "crud": {
76
+ "warnBatchDeleteRequestDeleteByRecords": "requestDeleteByRecords is required when actions include batch_delete",
77
+ "warnCreateRequestCreateByValues": "requestCreateByValues is required when actions include create",
78
+ "warnDeleteProps": "deleteProps and requestDeleteByRecord are required when actions include delete",
79
+ "warnReadRequestGetByRecord": "requestGetByRecord is required when actions include read",
80
+ "warnUpdateRequest": "requestGetByRecord and requestUpdateByValues are required when actions include update"
81
+ },
82
+ "crudOfList": {
83
+ "warnAtLeastOneSearch": "At least one column with search set to true is required in CRUDOfList columns",
84
+ "warnOnlyOneSearch": "Only one column with search set to true is allowed in CRUDOfList columns"
85
+ }
86
+ }
87
+ }
@@ -0,0 +1,87 @@
1
+ {
2
+ "@fe-free/core": {
3
+ "app": {
4
+ "mainScriptNotFound": "没找到 [data-name=\"mainScript\"],不启用更新提醒",
5
+ "newVersionFound": "发现新版本",
6
+ "refresh": "刷新",
7
+ "refreshPrompt": "请及时刷新页面更新,以避免影响使用",
8
+ "updateLater": "稍后更新"
9
+ },
10
+ "crud": {
11
+ "batchActionConfirm": "确定要执行 {action} 吗?",
12
+ "batchDelete": "批量删除",
13
+ "cancel": "取消",
14
+ "clearSelection": "取消选择",
15
+ "confirm": "确定",
16
+ "create": "新建",
17
+ "createSuccess": "新建成功",
18
+ "delete": "删除",
19
+ "deleteConfirm": "确认删除 \"{name}\" 吗?",
20
+ "deleteSuccess": "删除成功",
21
+ "deleteWarning": "删除后不可恢复,请谨慎操作",
22
+ "operate": "操作",
23
+ "read": "查看",
24
+ "requestDeleteByRecordRequired": "没有传 requestDeleteByRecord",
25
+ "selectedItems": "已选 {num} 项",
26
+ "update": "编辑",
27
+ "updateSuccess": "更新成功",
28
+ "warnCreateDetailForm": "actions 包含 create 时,需要传递 detailForm",
29
+ "warnReadDetailForm": "actions 包含 read 时,需要传递 detailForm",
30
+ "warnUpdateDetailForm": "actions 包含 update 时,需要传递 detailForm"
31
+ },
32
+ "crudOfList": {
33
+ "searchPlaceholder": "输入搜索"
34
+ },
35
+ "crudOfPure": {
36
+ "inputPlaceholder": "请输入{title}",
37
+ "selectPlaceholder": "请选择{title}"
38
+ },
39
+ "dataViewer": {
40
+ "view": "查看"
41
+ },
42
+ "fileTree": {
43
+ "create": "新建",
44
+ "createSubDirectory": "新建子目录",
45
+ "delete": "删除",
46
+ "directoryName": "目录名称",
47
+ "update": "编辑"
48
+ },
49
+ "formList": {
50
+ "add": "添加",
51
+ "duplicateValue": "不能有重复",
52
+ "edit": "编辑",
53
+ "emptyOption": "存在空选项"
54
+ },
55
+ "infiniteList": {
56
+ "loadingMore": "加载更多数据中...",
57
+ "noMoreData": "没有更多数据"
58
+ },
59
+ "record": {
60
+ "inputPlaceholder": "请输入"
61
+ },
62
+ "upload": {
63
+ "delete": "删除",
64
+ "dragUpload": "点击或拖拽到此区域进行上传",
65
+ "fileCount": "文件数量 ({success}/{total})",
66
+ "localUpload": "本地上传",
67
+ "maxFilesWarning": "最多只能上传 {num} 个文件,超出部分会忽略。",
68
+ "pleaseSelect": "请选择"
69
+ },
70
+ "valueTypeMap": {
71
+ "view": "查看"
72
+ }
73
+ },
74
+ "core": {
75
+ "crud": {
76
+ "warnBatchDeleteRequestDeleteByRecords": "actions 包含 batch_delete 时,需要传递 requestDeleteByRecords",
77
+ "warnCreateRequestCreateByValues": "actions 包含 create 时,需要传递 requestCreateByValues",
78
+ "warnDeleteProps": "actions 包含 delete 时,需要传递 deleteProps 和 requestDeleteByRecord",
79
+ "warnReadRequestGetByRecord": "actions 包含 read 时,需要传递 requestGetByRecord",
80
+ "warnUpdateRequest": "actions 包含 update 时,需要传递 requestGetByRecord 和 requestUpdateByValues"
81
+ },
82
+ "crudOfList": {
83
+ "warnAtLeastOneSearch": "CRUDOfList 的 columns 中至少有一个 search 为 true 的列",
84
+ "warnOnlyOneSearch": "CRUDOfList 的 columns 中只能有一个 search 为 true 的列"
85
+ }
86
+ }
87
+ }
@@ -1,6 +1,7 @@
1
1
  import { Divider, Input } from 'antd';
2
2
  import classNames from 'classnames';
3
3
  import { useCallback, useMemo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
4
5
  import { ProFormListHelper } from '../form';
5
6
 
6
7
  function Item({
@@ -12,6 +13,7 @@ function Item({
12
13
  label?: string;
13
14
  onChange: (value: string) => void;
14
15
  }) {
16
+ const { t } = useTranslation();
15
17
  return (
16
18
  <div className="flex flex-col gap-2">
17
19
  <div className="flex items-center gap-1">
@@ -20,7 +22,7 @@ function Item({
20
22
  </div>
21
23
  <Input
22
24
  value={value}
23
- placeholder={'请输入'}
25
+ placeholder={t('@fe-free/core.record.inputPlaceholder', '请输入')}
24
26
  onChange={(e) => {
25
27
  onChange(e.target.value);
26
28
  }}
@@ -4,6 +4,7 @@ import { Dropdown } from 'antd';
4
4
  import type { DataNode } from 'antd/es/tree';
5
5
  import classNames from 'classnames';
6
6
  import { useCallback, useMemo } from 'react';
7
+ import { useTranslation } from 'react-i18next';
7
8
  import { OperateDelete } from '../crud/crud_delete';
8
9
  import { FileCard } from '../file';
9
10
  import type { TreeProps } from './tree';
@@ -46,13 +47,14 @@ function Detail<D extends DataNode>({
46
47
  requestUpdateByValues?: FileTreeProps<D>['requestUpdateByValues'];
47
48
  trigger: React.ReactElement;
48
49
  }) {
50
+ const { t } = useTranslation();
49
51
  const title = useMemo(() => {
50
52
  if (action === 'create') {
51
- return '新建';
53
+ return t('@fe-free/core.fileTree.create', '新建');
52
54
  }
53
55
 
54
- return '编辑';
55
- }, [action]);
56
+ return t('@fe-free/core.fileTree.update', '编辑');
57
+ }, [action, t]);
56
58
 
57
59
  return (
58
60
  <ModalForm
@@ -83,7 +85,12 @@ function Detail<D extends DataNode>({
83
85
  labelCol={{ span: 6 }}
84
86
  >
85
87
  <ProFormText name="key" hidden />
86
- <ProFormText name="title" label="目录名称" required rules={[{ required: true }]} />
88
+ <ProFormText
89
+ name="title"
90
+ label={t('@fe-free/core.fileTree.directoryName', '目录名称')}
91
+ required
92
+ rules={[{ required: true }]}
93
+ />
87
94
  </ModalForm>
88
95
  );
89
96
  }
@@ -98,6 +105,7 @@ function More({
98
105
  updateProps,
99
106
  deleteProps,
100
107
  }) {
108
+ const { t } = useTranslation();
101
109
  const isCreateDisabled = createProps?.operateIsDisabled?.(nodeData);
102
110
  const isCreateHidden = createProps?.operateIsHidden?.(nodeData);
103
111
  const isUpdateDisabled = updateProps?.operateIsDisabled?.(nodeData);
@@ -109,13 +117,15 @@ function More({
109
117
  actions?.includes('create') &&
110
118
  !isCreateHidden && {
111
119
  label: isCreateDisabled ? (
112
- <div className="cursor-not-allowed text-03">新建子目录</div>
120
+ <div className="cursor-not-allowed text-03">
121
+ {t('@fe-free/core.fileTree.createSubDirectory', '新建子目录')}
122
+ </div>
113
123
  ) : (
114
124
  <Detail
115
125
  action="create"
116
126
  nodeData={{ key: nodeData.key }}
117
127
  requestCreateByValues={(values) => requestCreateByValues?.({ ...values })}
118
- trigger={<div>新建子目录</div>}
128
+ trigger={<div>{t('@fe-free/core.fileTree.createSubDirectory', '新建子目录')}</div>}
119
129
  />
120
130
  ),
121
131
  key: 'create',
@@ -123,13 +133,15 @@ function More({
123
133
  actions?.includes('update') &&
124
134
  !isUpdateHidden && {
125
135
  label: isUpdateDisabled ? (
126
- <div className="cursor-not-allowed text-03">编辑</div>
136
+ <div className="cursor-not-allowed text-03">
137
+ {t('@fe-free/core.fileTree.update', '编辑')}
138
+ </div>
127
139
  ) : (
128
140
  <Detail
129
141
  action="update"
130
142
  nodeData={nodeData}
131
143
  requestUpdateByValues={(values) => requestUpdateByValues?.({ ...values })}
132
- trigger={<div>编辑</div>}
144
+ trigger={<div>{t('@fe-free/core.fileTree.update', '编辑')}</div>}
133
145
  />
134
146
  ),
135
147
  key: 'update',
@@ -137,11 +149,13 @@ function More({
137
149
  actions?.includes('delete') &&
138
150
  !isDeleteHidden && {
139
151
  label: isDeleteDisabled ? (
140
- <div className="cursor-not-allowed text-03">删除</div>
152
+ <div className="cursor-not-allowed text-03">
153
+ {t('@fe-free/core.fileTree.delete', '删除')}
154
+ </div>
141
155
  ) : (
142
156
  <OperateDelete
143
157
  name={nodeData.title}
144
- operateText="删除"
158
+ operateText={t('@fe-free/core.fileTree.delete', '删除')}
145
159
  onDelete={() => requestDeleteByRecord?.({ key: nodeData.key })}
146
160
  />
147
161
  ),