diff --git a/src/locales/en-US/apikeys.ts b/src/locales/en-US/apikeys.ts
index 97e96696..d213cf4a 100644
--- a/src/locales/en-US/apikeys.ts
+++ b/src/locales/en-US/apikeys.ts
@@ -12,5 +12,8 @@ export default {
'apikeys.form.expiration.1month': '1 month',
'apikeys.form.expiration.6months': '6 months',
'apikeys.form.expiration.never': 'No expiration',
- 'apikeys.table.bindModels': 'Allowed Models'
+ 'apikeys.table.bindModels': 'Model Access',
+ 'apikeys.models.all': 'All models',
+ 'apikeys.models.selected': 'Selected models',
+ 'apikeys.models.noModelsFound': 'No models found'
};
diff --git a/src/locales/en-US/models.ts b/src/locales/en-US/models.ts
index 728bed19..2b0767b1 100644
--- a/src/locales/en-US/models.ts
+++ b/src/locales/en-US/models.ts
@@ -170,5 +170,16 @@ export default {
'models.form.enableSpeculativeDecoding': 'Enable Speculative Decoding',
'models.form.check.clusterUnavailable': 'Current cluster is unavailable',
'models.form.check.otherClustersAvailable':
- 'Available clusters: {clusters}. Please switch cluster.'
+ 'Available clusters: {clusters}. Please switch cluster.',
+ 'models.button.accessSettings': 'Access Settings',
+ 'models.table.accessScope': 'Access Scope',
+ 'models.table.accessScope.all': 'All users',
+ 'models.table.accessScope.selected': 'Selected users',
+ 'models.table.userSelection': 'User Selection',
+ 'models.table.filterByName': 'Filter by username',
+ 'models.table.admin': 'Admin',
+ 'models.table.noselected': 'No users selected',
+ 'models.table.users.all': 'All Users',
+ 'models.table.users.selected': 'Selected Users',
+ 'models.table.nouserFound': 'No users found'
};
diff --git a/src/locales/ja-JP/apikeys.ts b/src/locales/ja-JP/apikeys.ts
index 8627e6bb..d8da8e34 100644
--- a/src/locales/ja-JP/apikeys.ts
+++ b/src/locales/ja-JP/apikeys.ts
@@ -12,5 +12,15 @@ export default {
'apikeys.form.expiration.1month': '1ヶ月',
'apikeys.form.expiration.6months': '6ヶ月',
'apikeys.form.expiration.never': '無期限',
- 'apikeys.table.bindModels': '許可されたモデル'
+ 'apikeys.table.bindModels': 'Model Access',
+ 'apikeys.models.all': 'All models',
+ 'apikeys.models.selected': 'Selected models',
+ 'apikeys.models.noModelsFound': 'No models found'
};
+
+// ========== To-Do: Translate Keys (Remove After Translation) ==========
+// 1. 'apikeys.table.bindModels': 'Model Access',
+// 2. 'apikeys.models.all': 'All models',
+// 3. 'apikeys.models.selected': 'Selected models',
+// 4. 'apikeys.models.noModelsFound': 'No models found'
+// ========== End of To-Do List ==========
diff --git a/src/locales/ja-JP/models.ts b/src/locales/ja-JP/models.ts
index 2d6dba78..ca8c72b6 100644
--- a/src/locales/ja-JP/models.ts
+++ b/src/locales/ja-JP/models.ts
@@ -167,7 +167,18 @@ export default {
'models.form.enableSpeculativeDecoding': '推測デコーディングを有効にする',
'models.form.check.clusterUnavailable': 'Current cluster is unavailable',
'models.form.check.otherClustersAvailable':
- 'Available clusters: {clusters}. Please switch cluster.'
+ 'Available clusters: {clusters}. Please switch cluster.',
+ 'models.button.accessSettings': 'Access Settings',
+ 'models.table.accessScope': 'Access Scope',
+ 'models.table.accessScope.all': 'All users',
+ 'models.table.accessScope.selected': 'Selected users',
+ 'models.table.userSelection': 'User Selection',
+ 'models.table.filterByName': 'Filter by username',
+ 'models.table.admin': 'Admin',
+ 'models.table.noselected': 'No users selected',
+ 'models.table.users.all': 'All Users',
+ 'models.table.users.selected': 'Selected Users',
+ 'models.table.nouserFound': 'No users found'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -175,5 +186,19 @@ export default {
// 2. 'models.ollama.deprecated.notice': `The Ollama model source has been deprecated as of v0.6.1. For more information, see the related GitHub issue.`
// 3. 'models.backend.mindie.310p':'Ascend 310P only supports FP16, so you need to set --dtype=float16.',
// 4. 'models.form.check.clusterUnavailable': 'Current cluster is unavailable',
-// 5. 'models.form.check.otherClustersAvailable': 'Available clusters: {clusters}. Please switch cluster.'
+// 5. 'models.form.check.otherClustersAvailable': 'Available clusters: {clusters}. Please switch cluster.',
+// 6. 'models.button.accessSettings': 'Access Settings',
+// 7. 'models.table.accessScope': 'Access Scope',
+// 8. 'models.table.accessScope.all': 'All users',
+// 9. 'models.table.accessScope.selected': 'Selected users',
+// 10. 'models.table.userSelection': 'User Selection',
+// 11. 'models.table.filterByName': 'Filter by username',
+// 12. 'models.table.admin': 'Admin',
+// 13. 'models.table.noselected': 'No users selected'
+// 14. 'models.table.uses.all': 'All users',
+// 15. 'models.table.uses.selected': 'Selected users',
+// 16. 'models.table.nouserFound': 'No users found',
+// 17. 'models.table.users.all': 'All Users',
+// 18. 'models.table.users.selected': 'Selected Users',
+// 19. 'models.table.nouserFound': 'No users found'
// ========== End of To-Do List ==========
diff --git a/src/locales/ru-RU/apikeys.ts b/src/locales/ru-RU/apikeys.ts
index b384f2b6..a76aae2d 100644
--- a/src/locales/ru-RU/apikeys.ts
+++ b/src/locales/ru-RU/apikeys.ts
@@ -12,5 +12,15 @@ export default {
'apikeys.form.expiration.1month': '1 месяц',
'apikeys.form.expiration.6months': '6 месяцев',
'apikeys.form.expiration.never': 'Без срока действия',
- 'apikeys.table.bindModels': 'Разрешенные модели'
+ 'apikeys.table.bindModels': 'Доступ к моделям',
+ 'apikeys.models.all': 'All models',
+ 'apikeys.models.selected': 'Selected models',
+ 'apikeys.models.noModelsFound': 'No models found'
};
+
+// ========== To-Do: Translate Keys (Remove After Translation) ==========
+// 1. 'apikeys.table.bindModels': 'Model Access',
+// 2. 'apikeys.models.all': 'All models',
+// 3. 'apikeys.models.selected': 'Selected models',
+// 4. 'apikeys.models.noModelsFound': 'No models found'
+// ========== End of To-Do List ==========
diff --git a/src/locales/ru-RU/models.ts b/src/locales/ru-RU/models.ts
index 778e779b..9a07cc69 100644
--- a/src/locales/ru-RU/models.ts
+++ b/src/locales/ru-RU/models.ts
@@ -166,12 +166,34 @@ export default {
'models.form.gpuCount': 'GPU на реплику',
'models.form.gpuType': 'Тип GPU',
'models.form.optimizeLongPrompt': 'Оптимизировать длинные промпты',
- 'models.form.enableSpeculativeDecoding': 'Включить спекулятивное декодирование',
+ 'models.form.enableSpeculativeDecoding':
+ 'Включить спекулятивное декодирование',
'models.form.check.clusterUnavailable': 'Текущий кластер недоступен',
'models.form.check.otherClustersAvailable':
- 'Доступные кластеры: {clusters}. Пожалуйста, переключитесь на другой кластер.'
+ 'Доступные кластеры: {clusters}. Пожалуйста, переключитесь на другой кластер.',
+ 'models.button.accessSettings': 'Access Settings',
+ 'models.table.accessScope': 'Access Scope',
+ 'models.table.accessScope.all': 'All users',
+ 'models.table.accessScope.selected': 'Selected users',
+ 'models.table.userSelection': 'User Selection',
+ 'models.table.filterByName': 'Filter by username',
+ 'models.table.admin': 'Admin',
+ 'models.table.noselected': 'No users selected',
+ 'models.table.users.all': 'All users',
+ 'models.table.users.selected': 'Selected users',
+ 'models.table.nouserFound': 'No users found'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
-
+// 1. 'models.button.accessSettings': 'Access Settings',
+// 2. 'models.table.accessScope': 'Access Scope',
+// 3. 'models.table.accessScope.all': 'All users',
+// 4. 'models.table.accessScope.selected': 'Selected users',
+// 5. 'models.table.userSelection': 'User Selection',
+// 6. 'models.table.filterByName': 'Filter by username',
+// 7. 'models.table.admin': 'Admin',
+// 8. 'models.table.noselected': 'No users selected',
+// 9. 'models.table.users.all': 'All users',
+// 10. 'models.table.users.selected': 'Selected users',
+// 11. 'models.table.nouserFound': 'No users found'
// ========== End of To-Do List ==========
diff --git a/src/locales/zh-CN/apikeys.ts b/src/locales/zh-CN/apikeys.ts
index d5fcee61..185af90c 100644
--- a/src/locales/zh-CN/apikeys.ts
+++ b/src/locales/zh-CN/apikeys.ts
@@ -11,5 +11,8 @@ export default {
'apikeys.form.expiration.1month': '1个月',
'apikeys.form.expiration.6months': '6个月',
'apikeys.form.expiration.never': '永不过期',
- 'apikeys.table.bindModels': '绑定模型'
+ 'apikeys.table.bindModels': '模型访问',
+ 'apikeys.models.all': '所有模型',
+ 'apikeys.models.selected': '指定模型',
+ 'apikeys.models.noModelsFound': '未找到模型'
};
diff --git a/src/locales/zh-CN/models.ts b/src/locales/zh-CN/models.ts
index 778a5b24..73919256 100644
--- a/src/locales/zh-CN/models.ts
+++ b/src/locales/zh-CN/models.ts
@@ -160,5 +160,16 @@ export default {
'models.form.enableSpeculativeDecoding': '启用推测解码',
'models.form.check.clusterUnavailable': '当前集群不可用',
'models.form.check.otherClustersAvailable':
- '可用的集群有: {clusters}。请切换集群。'
+ '可用的集群有: {clusters}。请切换集群。',
+ 'models.button.accessSettings': '访问设置',
+ 'models.table.accessScope': '访问范围',
+ 'models.table.accessScope.all': '所有用户',
+ 'models.table.accessScope.selected': '指定用户',
+ 'models.table.userSelection': '用户选择',
+ 'models.table.filterByName': '按用户名筛选',
+ 'models.table.admin': '管理员',
+ 'models.table.noselected': '未选择用户',
+ 'models.table.users.all': '所有用户',
+ 'models.table.users.selected': '已选用户',
+ 'models.table.nouserFound': '未找到用户'
};
diff --git a/src/pages/_components/select-panel/index.tsx b/src/pages/_components/select-panel/index.tsx
index bafc8a5a..2dbb21b1 100644
--- a/src/pages/_components/select-panel/index.tsx
+++ b/src/pages/_components/select-panel/index.tsx
@@ -1,4 +1,5 @@
import { SearchOutlined } from '@ant-design/icons';
+import { useIntl } from '@umijs/max';
import { Button, Checkbox, Empty, Input } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
@@ -34,6 +35,7 @@ interface SelectPanelProps {
leftWidth?: number;
options: Array<{ key: string; title: string }>;
selectedKeys: string[];
+ notFoundContent?: React.ReactNode;
onSelectChange: (selectedKeys: string[]) => void;
}
@@ -43,8 +45,10 @@ const SelectPanel: React.FC = ({
options,
selectedKeys,
searchPlaceholder,
+ notFoundContent,
onSelectChange
}) => {
+ const intl = useIntl();
const [indeterminate, setIndeterminate] = React.useState(false);
const [checkAll, setCheckAll] = React.useState(false);
const [searchText, setSearchText] = useState('');
@@ -162,7 +166,12 @@ const SelectPanel: React.FC = ({
indeterminate={indeterminate}
onChange={handleCheckAllChange}
>
- {selectedKeys.length} selected
+
+ {intl.formatMessage(
+ { id: 'common.select.count' },
+ { count: selectedKeys.length }
+ )}
+
= ({
}
size="small"
allowClear
+ status={'null' as any}
placeholder={searchPlaceholder}
style={{
width: 300,
@@ -192,7 +202,7 @@ const SelectPanel: React.FC = ({
) : (
)}
diff --git a/src/pages/_components/transfer.tsx b/src/pages/_components/transfer.tsx
index d762325f..2c531dfd 100644
--- a/src/pages/_components/transfer.tsx
+++ b/src/pages/_components/transfer.tsx
@@ -1,4 +1,5 @@
import { MoreOutlined } from '@ant-design/icons';
+import { useIntl } from '@umijs/max';
import { Transfer, TransferProps } from 'antd';
import styled from 'styled-components';
@@ -72,6 +73,8 @@ interface TransferInnerProps extends TransferProps {
}
const TransferInner: React.FC = (props) => {
+ const intl = useIntl();
+
const renderAllLabels = (info: {
selectedCount: number;
totalCount: number;
@@ -79,7 +82,10 @@ const TransferInner: React.FC = (props) => {
if (info.selectedCount) {
return (
- {info.selectedCount} selected
+ {intl.formatMessage(
+ { id: 'common.select.count' },
+ { count: info.selectedCount }
+ )}
);
}
diff --git a/src/pages/api-keys/components/add-apikey-modal/allow-models.tsx b/src/pages/api-keys/components/add-apikey-modal/allow-models.tsx
index 4de2b13b..78668879 100644
--- a/src/pages/api-keys/components/add-apikey-modal/allow-models.tsx
+++ b/src/pages/api-keys/components/add-apikey-modal/allow-models.tsx
@@ -1,7 +1,9 @@
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
+import useAppUtils from '@/hooks/use-app-utils';
import SelectPanel from '@/pages/_components/select-panel';
import { queryModelsList } from '@/pages/llmodels/apis';
+import { useIntl } from '@umijs/max';
import { Divider, Form, Radio } from 'antd';
import { useEffect, useState } from 'react';
import styled from 'styled-components';
@@ -18,6 +20,8 @@ const AllowModelsForm: React.FC<{
currentData?: Partial | null;
action: PageActionType;
}> = ({ currentData, action }) => {
+ const intl = useIntl();
+ const { getRuleMessage } = useAppUtils();
const form = Form.useFormInstance();
const allowedModelNames = Form.useWatch(
'allowed_model_names',
@@ -57,7 +61,7 @@ const AllowModelsForm: React.FC<{
return (
-
+
-
+
{
form.setFieldsValue({ allowed_model_names: selectedKeys });
}}
diff --git a/src/pages/api-keys/hooks/use-keys-columns.tsx b/src/pages/api-keys/hooks/use-keys-columns.tsx
index 39953f4a..f02c1bf1 100644
--- a/src/pages/api-keys/hooks/use-keys-columns.tsx
+++ b/src/pages/api-keys/hooks/use-keys-columns.tsx
@@ -68,7 +68,11 @@ const useModelsColumns = ({
showTitle: false
},
render: (text: string[], record: ListItem) => (
- {text?.join(', ')}
+
+ {text?.length
+ ? text?.join(', ')
+ : intl.formatMessage({ id: 'common.select.option' })}
+
)
},
{
diff --git a/src/pages/llmodels/components/access-control-modal/form.tsx b/src/pages/llmodels/components/access-control-modal/form.tsx
index 4220e46b..06dc0b56 100644
--- a/src/pages/llmodels/components/access-control-modal/form.tsx
+++ b/src/pages/llmodels/components/access-control-modal/form.tsx
@@ -1,5 +1,6 @@
import TransferInner from '@/pages/_components/transfer';
import { queryUsersList } from '@/pages/users/apis';
+import { useIntl } from '@umijs/max';
import { Empty, Form, Radio } from 'antd';
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import styled from 'styled-components';
@@ -22,6 +23,7 @@ interface AccessControlFormProps {
const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
const { currentData, onFinish } = props;
+ const intl = useIntl();
const [form] = Form.useForm();
const setPublic = Form.useWatch('set_public', form);
const [targetKeys, setTargetKeys] = useState([]);
@@ -42,7 +44,6 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
key: item.id,
is_admin: item.is_admin
}));
- console.log('options', options);
setTotalPages(res.pagination.totalPage);
setUserList(options);
} catch (error) {
@@ -56,7 +57,6 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
removeKeys: TransferKey[]
) => {
setTargetKeys(nextTargetKeys);
- console.log('nextTargetKeys', nextTargetKeys);
const users = nextTargetKeys.map((key) => ({ id: key }));
form.setFieldsValue({ users });
};
@@ -108,41 +108,62 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
set_public: true
}}
>
-
+
name="set_public" noStyle>
{!setPublic && (
<>
-
+
name="users">
,
]
}}
showSearch={{
- placeholder: 'Filter by username'
+ placeholder: intl.formatMessage({
+ id: 'common.filter.name'
+ })
}}
filterOption={(inputValue, item) =>
item.title.toLowerCase().includes(inputValue.toLowerCase())
@@ -151,7 +172,9 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
{item.title}
- {item.is_admin ? '(Admin)' : ''}
+ {item.is_admin
+ ? `(${intl.formatMessage({ id: 'models.table.admin' })})`
+ : ''}
)}
diff --git a/src/pages/llmodels/components/table-list.tsx b/src/pages/llmodels/components/table-list.tsx
index 88d3105c..d8110662 100644
--- a/src/pages/llmodels/components/table-list.tsx
+++ b/src/pages/llmodels/components/table-list.tsx
@@ -467,7 +467,7 @@ const Models: React.FC = ({
if (val === 'accessControl') {
setOpenAccessControlModal({
- title: 'Access Settings',
+ title: intl.formatMessage({ id: 'models.button.accessSettings' }),
action: PageAction.EDIT,
currentData: row,
open: true
diff --git a/src/pages/llmodels/config/button-actions.ts b/src/pages/llmodels/config/button-actions.ts
index b30a5f2d..a3a3df62 100644
--- a/src/pages/llmodels/config/button-actions.ts
+++ b/src/pages/llmodels/config/button-actions.ts
@@ -62,7 +62,7 @@ export const ActionList: ActionItem[] = [
icon: icons.ApiOutlined
},
{
- label: 'Access Settings',
+ label: 'models.button.accessSettings',
key: 'accessControl',
icon: icons.Private
},