feat: i18n support

This commit is contained in:
JustSong
2025-02-01 23:58:55 +08:00
parent b7f008cd72
commit e183e3b9b0
4 changed files with 364 additions and 302 deletions

View File

@@ -292,16 +292,43 @@
}, },
"log": { "log": {
"title": "Operation Log", "title": "Operation Log",
"search": "Search logs...",
"usage_details": "Usage Details", "usage_details": "Usage Details",
"total_quota": "Total Quota Used", "total_quota": "Total Quota Used",
"click_to_view": "Click to View", "click_to_view": "Click to View",
"type": {
"select": "Select Log Type",
"all": "All",
"topup": "Top Up",
"usage": "Usage",
"admin": "Admin",
"system": "System",
"test": "Test"
},
"table": { "table": {
"id": "ID", "time": "Time",
"username": "Username", "channel": "Channel",
"type": "Type", "type": "Type",
"content": "Content", "model": "Model",
"amount": "Amount", "username": "Username",
"time": "Time" "token_name": "Token Name",
"token_name_placeholder": "Optional",
"model_name": "Model Name",
"model_name_placeholder": "Optional",
"start_time": "Start Time",
"end_time": "End Time",
"channel_id": "Channel ID",
"channel_id_placeholder": "Optional",
"username_placeholder": "Optional",
"prompt_tokens": "Prompt Tokens",
"completion_tokens": "Completion Tokens",
"quota": "Quota",
"detail": "Detail"
},
"buttons": {
"query": "Action",
"submit": "Query",
"refresh": "Refresh"
} }
}, },
"user": { "user": {

View File

@@ -292,16 +292,43 @@
}, },
"log": { "log": {
"title": "操作日志", "title": "操作日志",
"search": "搜索日志...",
"usage_details": "使用明细", "usage_details": "使用明细",
"total_quota": "总消耗额度", "total_quota": "总消耗额度",
"click_to_view": "点击查看", "click_to_view": "点击查看",
"type": {
"select": "选择明细分类",
"all": "全部",
"topup": "充值",
"usage": "消费",
"admin": "管理",
"system": "系统",
"test": "测试"
},
"table": { "table": {
"id": "ID", "time": "时间",
"username": "用户名", "channel": "渠道",
"type": "类型", "type": "类型",
"content": "内容", "model": "模型",
"amount": "数量", "username": "用户名",
"time": "时间" "token_name": "令牌名称",
"token_name_placeholder": "可选值",
"model_name": "模型名称",
"model_name_placeholder": "可选值",
"start_time": "起始时间",
"end_time": "结束时间",
"channel_id": "渠道 ID",
"channel_id_placeholder": "可选值",
"username_placeholder": "可选值",
"prompt_tokens": "提示词消耗",
"completion_tokens": "补全消耗",
"quota": "额度",
"detail": "详情"
},
"buttons": {
"query": "操作",
"submit": "查询",
"refresh": "刷新"
} }
}, },
"user": { "user": {

View File

@@ -8,6 +8,7 @@ import {
Segment, Segment,
Select, Select,
Table, Table,
Popup,
} from 'semantic-ui-react'; } from 'semantic-ui-react';
import { import {
API, API,
@@ -46,15 +47,6 @@ const MODE_OPTIONS = [
{ key: 'self', text: '当前用户', value: 'self' }, { key: 'self', text: '当前用户', value: 'self' },
]; ];
const LOG_OPTIONS = [
{ key: '0', text: '全部', value: 0 },
{ key: '1', text: '充值', value: 1 },
{ key: '2', text: '消费', value: 2 },
{ key: '3', text: '管理', value: 3 },
{ key: '4', text: '系统', value: 4 },
{ key: '5', text: '测试', value: 5 },
];
function renderType(type) { function renderType(type) {
switch (type) { switch (type) {
case 1: case 1:
@@ -170,6 +162,15 @@ const LogsTable = () => {
token: 0, token: 0,
}); });
const LOG_OPTIONS = [
{ key: '0', text: t('log.type.all'), value: 0 },
{ key: '1', text: t('log.type.topup'), value: 1 },
{ key: '2', text: t('log.type.usage'), value: 2 },
{ key: '3', text: t('log.type.admin'), value: 3 },
{ key: '4', text: t('log.type.system'), value: 4 },
{ key: '5', text: t('log.type.test'), value: 5 },
];
const handleInputChange = (e, { name, value }) => { const handleInputChange = (e, { name, value }) => {
setInputs((inputs) => ({ ...inputs, [name]: value })); setInputs((inputs) => ({ ...inputs, [name]: value }));
}; };
@@ -308,7 +309,6 @@ const LogsTable = () => {
}; };
return ( return (
<>
<> <>
<Header as='h3'> <Header as='h3'>
{t('log.usage_details')}{t('log.total_quota')} {t('log.usage_details')}{t('log.total_quota')}
@@ -327,25 +327,25 @@ const LogsTable = () => {
<Form.Group> <Form.Group>
<Form.Input <Form.Input
fluid fluid
label={'令牌名称'} label={t('log.table.token_name')}
width={3} width={3}
value={token_name} value={token_name}
placeholder={'可选值'} placeholder={t('log.table.token_name_placeholder')}
name='token_name' name='token_name'
onChange={handleInputChange} onChange={handleInputChange}
/> />
<Form.Input <Form.Input
fluid fluid
label='模型名称' label={t('log.table.model_name')}
width={3} width={3}
value={model_name} value={model_name}
placeholder='可选值' placeholder={t('log.table.model_name_placeholder')}
name='model_name' name='model_name'
onChange={handleInputChange} onChange={handleInputChange}
/> />
<Form.Input <Form.Input
fluid fluid
label='起始时间' label={t('log.table.start_time')}
width={4} width={4}
value={start_timestamp} value={start_timestamp}
type='datetime-local' type='datetime-local'
@@ -354,15 +354,20 @@ const LogsTable = () => {
/> />
<Form.Input <Form.Input
fluid fluid
label='结束时间' label={t('log.table.end_time')}
width={4} width={4}
value={end_timestamp} value={end_timestamp}
type='datetime-local' type='datetime-local'
name='end_timestamp' name='end_timestamp'
onChange={handleInputChange} onChange={handleInputChange}
/> />
<Form.Button fluid label='操作' width={2} onClick={refresh}> <Form.Button
查询 fluid
label={t('log.buttons.query')}
width={2}
onClick={refresh}
>
{t('log.buttons.submit')}
</Form.Button> </Form.Button>
</Form.Group> </Form.Group>
{isAdminUser && ( {isAdminUser && (
@@ -370,25 +375,31 @@ const LogsTable = () => {
<Form.Group> <Form.Group>
<Form.Input <Form.Input
fluid fluid
label={'渠道 ID'} label={t('log.table.channel_id')}
width={3} width={3}
value={channel} value={channel}
placeholder='可选值' placeholder={t('log.table.channel_id_placeholder')}
name='channel' name='channel'
onChange={handleInputChange} onChange={handleInputChange}
/> />
<Form.Input <Form.Input
fluid fluid
label={'用户名称'} label={t('log.table.username')}
width={3} width={3}
value={username} value={username}
placeholder={'可选值'} placeholder={t('log.table.username_placeholder')}
name='username' name='username'
onChange={handleInputChange} onChange={handleInputChange}
/> />
</Form.Group> </Form.Group>
</> </>
)} )}
<Form.Input
icon='search'
placeholder={t('log.search')}
value={searchKeyword}
onChange={(e, { value }) => setSearchKeyword(value)}
/>
</Form> </Form>
<Table basic={'very'} compact size='small'> <Table basic={'very'} compact size='small'>
<Table.Header> <Table.Header>
@@ -400,7 +411,7 @@ const LogsTable = () => {
}} }}
width={3} width={3}
> >
时间 {t('log.table.time')}
</Table.HeaderCell> </Table.HeaderCell>
{isAdminUser && ( {isAdminUser && (
<Table.HeaderCell <Table.HeaderCell
@@ -410,7 +421,7 @@ const LogsTable = () => {
}} }}
width={1} width={1}
> >
渠道 {t('log.table.channel')}
</Table.HeaderCell> </Table.HeaderCell>
)} )}
<Table.HeaderCell <Table.HeaderCell
@@ -420,7 +431,7 @@ const LogsTable = () => {
}} }}
width={1} width={1}
> >
类型 {t('log.table.type')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@@ -429,7 +440,7 @@ const LogsTable = () => {
}} }}
width={2} width={2}
> >
模型 {t('log.table.model')}
</Table.HeaderCell> </Table.HeaderCell>
{showUserTokenQuota() && ( {showUserTokenQuota() && (
<> <>
@@ -439,9 +450,9 @@ const LogsTable = () => {
onClick={() => { onClick={() => {
sortLog('username'); sortLog('username');
}} }}
width={1} width={2}
> >
用户 {t('log.table.username')}
</Table.HeaderCell> </Table.HeaderCell>
)} )}
<Table.HeaderCell <Table.HeaderCell
@@ -449,9 +460,9 @@ const LogsTable = () => {
onClick={() => { onClick={() => {
sortLog('token_name'); sortLog('token_name');
}} }}
width={1} width={2}
> >
令牌 {t('log.table.token_name')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@@ -460,7 +471,7 @@ const LogsTable = () => {
}} }}
width={1} width={1}
> >
提示 {t('log.table.prompt_tokens')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@@ -469,7 +480,7 @@ const LogsTable = () => {
}} }}
width={1} width={1}
> >
补全 {t('log.table.completion_tokens')}
</Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@@ -478,19 +489,11 @@ const LogsTable = () => {
}} }}
width={1} width={1}
> >
额度 {t('log.table.quota')}
</Table.HeaderCell> </Table.HeaderCell>
</> </>
)} )}
<Table.HeaderCell <Table.HeaderCell>{t('log.table.detail')}</Table.HeaderCell>
style={{ cursor: 'pointer' }}
onClick={() => {
sortLog('content');
}}
width={isAdminUser ? 4 : 6}
>
详情
</Table.HeaderCell>
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>
@@ -544,9 +547,7 @@ const LogsTable = () => {
</Table.Cell> </Table.Cell>
)} )}
<Table.Cell> <Table.Cell>
{log.token_name {log.token_name ? renderColorLabel(log.token_name) : ''}
? renderColorLabel(log.token_name)
: ''}
</Table.Cell> </Table.Cell>
<Table.Cell> <Table.Cell>
@@ -571,7 +572,7 @@ const LogsTable = () => {
<Table.Row> <Table.Row>
<Table.HeaderCell colSpan={'10'}> <Table.HeaderCell colSpan={'10'}>
<Select <Select
placeholder='选择明细分类' placeholder={t('log.type.select')}
options={LOG_OPTIONS} options={LOG_OPTIONS}
style={{ marginRight: '8px' }} style={{ marginRight: '8px' }}
name='logType' name='logType'
@@ -581,7 +582,7 @@ const LogsTable = () => {
}} }}
/> />
<Button size='small' onClick={refresh} loading={loading}> <Button size='small' onClick={refresh} loading={loading}>
刷新 {t('log.buttons.refresh')}
</Button> </Button>
<Pagination <Pagination
floated='right' floated='right'
@@ -599,7 +600,6 @@ const LogsTable = () => {
</Table.Footer> </Table.Footer>
</Table> </Table>
</> </>
</>
); );
}; };

View File

@@ -86,7 +86,7 @@ const Dashboard = () => {
setSummaryData({ setSummaryData({
todayRequests: 0, todayRequests: 0,
todayQuota: 0, todayQuota: 0,
todayTokens: 0 todayTokens: 0,
}); });
return; return;
} }
@@ -224,9 +224,11 @@ const Dashboard = () => {
}} }}
formatter={(value) => [ formatter={(value) => [
value, value,
t('dashboard.charts.requests.tooltip') t('dashboard.charts.requests.tooltip'),
]} ]}
labelFormatter={(label) => `${t('dashboard.tooltip.date')}: ${label}`} labelFormatter={(label) =>
`${t('dashboard.tooltip.date')}: ${label}`
}
/> />
<Line <Line
type='monotone' type='monotone'
@@ -277,9 +279,11 @@ const Dashboard = () => {
}} }}
formatter={(value) => [ formatter={(value) => [
value, value,
t('dashboard.charts.quota.tooltip') t('dashboard.charts.quota.tooltip'),
]} ]}
labelFormatter={(label) => `${t('dashboard.tooltip.date')}: ${label}`} labelFormatter={(label) =>
`${t('dashboard.tooltip.date')}: ${label}`
}
/> />
<Line <Line
type='monotone' type='monotone'
@@ -328,9 +332,11 @@ const Dashboard = () => {
}} }}
formatter={(value) => [ formatter={(value) => [
value, value,
t('dashboard.charts.tokens.tooltip') t('dashboard.charts.tokens.tooltip'),
]} ]}
labelFormatter={(label) => `${t('dashboard.tooltip.date')}: ${label}`} labelFormatter={(label) =>
`${t('dashboard.tooltip.date')}: ${label}`
}
/> />
<Line <Line
type='monotone' type='monotone'
@@ -378,7 +384,9 @@ const Dashboard = () => {
borderRadius: '4px', borderRadius: '4px',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)', boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
}} }}
labelFormatter={(label) => `${t('dashboard.tooltip.date')}: ${label}`} labelFormatter={(label) =>
`${t('dashboard.tooltip.date')}: ${label}`
}
/> />
<Legend <Legend
wrapperStyle={{ wrapperStyle={{