feat: i18n support

This commit is contained in:
JustSong 2025-02-01 23:48:05 +08:00
parent 958f2f4ea8
commit ee3ed65356
5 changed files with 151 additions and 45 deletions

View File

@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/songquanpeng/one-api/common" "github.com/songquanpeng/one-api/common"
"github.com/songquanpeng/one-api/common/config" "github.com/songquanpeng/one-api/common/config"
) )
@ -71,7 +72,7 @@ func memoryRateLimiter(c *gin.Context, maxRequestNum int, duration int64, mark s
} }
func rateLimitFactory(maxRequestNum int, duration int64, mark string) func(c *gin.Context) { func rateLimitFactory(maxRequestNum int, duration int64, mark string) func(c *gin.Context) {
if maxRequestNum == 0 { if maxRequestNum == 0 || config.DebugEnabled {
return func(c *gin.Context) { return func(c *gin.Context) {
c.Next() c.Next()
} }

View File

@ -305,6 +305,7 @@
} }
}, },
"user": { "user": {
"title": "User Management",
"edit": { "edit": {
"title": "Update User Information", "title": "Update User Information",
"username": "Username", "username": "Username",
@ -337,6 +338,50 @@
}, },
"messages": { "messages": {
"create_success": "User account created successfully!" "create_success": "User account created successfully!"
},
"search": "Search users...",
"table": {
"id": "ID",
"username": "Username",
"group": "Group",
"quota": "Quota",
"role_text": "Role",
"status_text": "Status",
"actions": "Actions",
"remaining_quota": "Remaining Quota",
"used_quota": "Used Quota",
"request_count": "Request Count",
"role_types": {
"normal": "Normal User",
"admin": "Admin",
"super_admin": "Super Admin",
"unknown": "Unknown Role"
},
"status_types": {
"activated": "Activated",
"banned": "Banned",
"unknown": "Unknown Status"
},
"sort": {
"default": "Default Order",
"by_quota": "Sort by Remaining Quota",
"by_used_quota": "Sort by Used Quota",
"by_request_count": "Sort by Request Count"
},
"sort_by": "Sort By"
},
"buttons": {
"add": "Add New User",
"delete": "Delete",
"delete_user": "Delete User",
"enable": "Enable",
"disable": "Disable",
"edit": "Edit",
"promote": "Promote",
"demote": "Demote"
},
"messages": {
"operation_success": "Operation completed successfully!"
} }
} }
} }

View File

@ -305,6 +305,7 @@
} }
}, },
"user": { "user": {
"title": "用户管理",
"edit": { "edit": {
"title": "更新用户信息", "title": "更新用户信息",
"username": "用户名", "username": "用户名",
@ -337,6 +338,50 @@
}, },
"messages": { "messages": {
"create_success": "用户账户创建成功!" "create_success": "用户账户创建成功!"
},
"search": "搜索用户...",
"table": {
"id": "ID",
"username": "用户名",
"group": "分组",
"quota": "额度",
"role_text": "角色",
"status_text": "状态",
"actions": "操作",
"remaining_quota": "剩余额度",
"used_quota": "已用额度",
"request_count": "请求次数",
"role_types": {
"normal": "普通用户",
"admin": "管理员",
"super_admin": "超级管理员",
"unknown": "未知身份"
},
"status_types": {
"activated": "已激活",
"banned": "已封禁",
"unknown": "未知状态"
},
"sort": {
"default": "默认排序",
"by_quota": "按剩余额度排序",
"by_used_quota": "按已用额度排序",
"by_request_count": "按请求次数排序"
},
"sort_by": "排序方式"
},
"buttons": {
"add": "添加新的用户",
"delete": "删除",
"delete_user": "删除用户",
"enable": "启用",
"disable": "禁用",
"edit": "编辑",
"promote": "提升",
"demote": "降级"
},
"messages": {
"operation_success": "操作成功完成!"
} }
} }
} }

View File

@ -20,16 +20,18 @@ import {
renderText, renderText,
} from '../helpers/render'; } from '../helpers/render';
function renderRole(role) { function renderRole(role, t) {
switch (role) { switch (role) {
case 1: case 1:
return <Label>普通用户</Label>; return <Label>{t('user.table.role_types.normal')}</Label>;
case 10: case 10:
return <Label color='yellow'>管理员</Label>; return <Label color='yellow'>{t('user.table.role_types.admin')}</Label>;
case 100: case 100:
return <Label color='orange'>超级管理员</Label>; return (
<Label color='orange'>{t('user.table.role_types.super_admin')}</Label>
);
default: default:
return <Label color='red'>未知身份</Label>; return <Label color='red'>{t('user.table.role_types.unknown')}</Label>;
} }
} }
@ -85,7 +87,7 @@ const UsersTable = () => {
}); });
const { success, message } = res.data; const { success, message } = res.data;
if (success) { if (success) {
showSuccess('操作成功完成!'); showSuccess(t('user.messages.operation_success'));
let user = res.data.data; let user = res.data.data;
let newUsers = [...users]; let newUsers = [...users];
let realIdx = (activePage - 1) * ITEMS_PER_PAGE + idx; let realIdx = (activePage - 1) * ITEMS_PER_PAGE + idx;
@ -105,17 +107,17 @@ const UsersTable = () => {
const renderStatus = (status) => { const renderStatus = (status) => {
switch (status) { switch (status) {
case 1: case 1:
return <Label basic>已激活</Label>; return <Label basic>{t('user.table.status_types.activated')}</Label>;
case 2: case 2:
return ( return (
<Label basic color='red'> <Label basic color='red'>
已封禁 {t('user.table.status_types.banned')}
</Label> </Label>
); );
default: default:
return ( return (
<Label basic color='grey'> <Label basic color='grey'>
未知状态 {t('user.table.status_types.unknown')}
</Label> </Label>
); );
} }
@ -177,7 +179,7 @@ const UsersTable = () => {
icon='search' icon='search'
fluid fluid
iconPosition='left' iconPosition='left'
placeholder='搜索用户的 ID用户名显示名称以及邮箱地址 ...' placeholder={t('user.search')}
value={searchKeyword} value={searchKeyword}
loading={searching} loading={searching}
onChange={handleKeywordChange} onChange={handleKeywordChange}
@ -193,7 +195,7 @@ const UsersTable = () => {
sortUser('id'); sortUser('id');
}} }}
> >
ID {t('user.table.id')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@ -201,7 +203,7 @@ const UsersTable = () => {
sortUser('username'); sortUser('username');
}} }}
> >
用户名 {t('user.table.username')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@ -209,7 +211,7 @@ const UsersTable = () => {
sortUser('group'); sortUser('group');
}} }}
> >
分组 {t('user.table.group')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@ -217,7 +219,7 @@ const UsersTable = () => {
sortUser('quota'); sortUser('quota');
}} }}
> >
统计信息 {t('user.table.quota')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@ -225,7 +227,7 @@ const UsersTable = () => {
sortUser('role'); sortUser('role');
}} }}
> >
用户角色 {t('user.table.role_text')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@ -233,9 +235,9 @@ const UsersTable = () => {
sortUser('status'); sortUser('status');
}} }}
> >
状态 {t('user.table.status_text')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell>操作</Table.HeaderCell> <Table.HeaderCell>{t('user.table.actions')}</Table.HeaderCell>
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>
@ -267,23 +269,25 @@ const UsersTable = () => {
{/*</Table.Cell>*/} {/*</Table.Cell>*/}
<Table.Cell> <Table.Cell>
<Popup <Popup
content='剩余额度' content={t('user.table.remaining_quota')}
trigger={<Label basic>{renderQuota(user.quota, t)}</Label>} trigger={
<Label basic>{renderQuota(user.quota, t)}</Label>
}
/> />
<Popup <Popup
content='已用额度' content={t('user.table.used_quota')}
trigger={ trigger={
<Label basic>{renderQuota(user.used_quota, t)}</Label> <Label basic>{renderQuota(user.used_quota, t)}</Label>
} }
/> />
<Popup <Popup
content='请求次数' content={t('user.table.request_count')}
trigger={ trigger={
<Label basic>{renderNumber(user.request_count)}</Label> <Label basic>{renderNumber(user.request_count)}</Label>
} }
/> />
</Table.Cell> </Table.Cell>
<Table.Cell>{renderRole(user.role)}</Table.Cell> <Table.Cell>{renderRole(user.role, t)}</Table.Cell>
<Table.Cell>{renderStatus(user.status)}</Table.Cell> <Table.Cell>{renderStatus(user.status)}</Table.Cell>
<Table.Cell> <Table.Cell>
<div> <div>
@ -295,7 +299,7 @@ const UsersTable = () => {
}} }}
disabled={user.role === 100} disabled={user.role === 100}
> >
提升 {t('user.buttons.promote')}
</Button> </Button>
<Button <Button
size={'small'} size={'small'}
@ -305,7 +309,7 @@ const UsersTable = () => {
}} }}
disabled={user.role === 100} disabled={user.role === 100}
> >
降级 {t('user.buttons.demote')}
</Button> </Button>
<Popup <Popup
trigger={ trigger={
@ -314,7 +318,7 @@ const UsersTable = () => {
negative negative
disabled={user.role === 100} disabled={user.role === 100}
> >
删除 {t('user.buttons.delete')}
</Button> </Button>
} }
on='click' on='click'
@ -327,7 +331,7 @@ const UsersTable = () => {
manageUser(user.username, 'delete', idx); manageUser(user.username, 'delete', idx);
}} }}
> >
删除用户 {user.username} {t('user.buttons.delete_user')} {user.username}
</Button> </Button>
</Popup> </Popup>
<Button <Button
@ -341,14 +345,16 @@ const UsersTable = () => {
}} }}
disabled={user.role === 100} disabled={user.role === 100}
> >
{user.status === 1 ? '禁用' : '启用'} {user.status === 1
? t('user.buttons.disable')
: t('user.buttons.enable')}
</Button> </Button>
<Button <Button
size={'small'} size={'small'}
as={Link} as={Link}
to={'/user/edit/' + user.id} to={'/user/edit/' + user.id}
> >
编辑 {t('user.buttons.edit')}
</Button> </Button>
</div> </div>
</Table.Cell> </Table.Cell>
@ -361,22 +367,26 @@ const UsersTable = () => {
<Table.Row> <Table.Row>
<Table.HeaderCell colSpan='7'> <Table.HeaderCell colSpan='7'>
<Button size='small' as={Link} to='/user/add' loading={loading}> <Button size='small' as={Link} to='/user/add' loading={loading}>
添加新的用户 {t('user.buttons.add')}
</Button> </Button>
<Dropdown <Dropdown
placeholder='排序方式' placeholder={t('user.table.sort_by')}
selection selection
options={[ options={[
{ key: '', text: '默认排序', value: '' }, { key: '', text: t('user.table.sort.default'), value: '' },
{ key: 'quota', text: '按剩余额度排序', value: 'quota' }, {
key: 'quota',
text: t('user.table.sort.by_quota'),
value: 'quota',
},
{ {
key: 'used_quota', key: 'used_quota',
text: '按已用额度排序', text: t('user.table.sort.by_used_quota'),
value: 'used_quota', value: 'used_quota',
}, },
{ {
key: 'request_count', key: 'request_count',
text: '按请求次数排序', text: t('user.table.sort.by_request_count'),
value: 'request_count', value: 'request_count',
}, },
]} ]}

View File

@ -1,16 +1,21 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next';
import { Card } from 'semantic-ui-react'; import { Card } from 'semantic-ui-react';
import UsersTable from '../../components/UsersTable'; import UsersTable from '../../components/UsersTable';
const User = () => ( const User = () => {
const { t } = useTranslation();
return (
<div className='dashboard-container'> <div className='dashboard-container'>
<Card fluid className='chart-card'> <Card fluid className='chart-card'>
<Card.Content> <Card.Content>
<Card.Header className='header'>用户管理</Card.Header> <Card.Header className='header'>{t('user.title')}</Card.Header>
<UsersTable /> <UsersTable />
</Card.Content> </Card.Content>
</Card> </Card>
</div> </div>
); );
};
export default User; export default User;