feat: Integrate i18n support and enhance UI text localization

- Added internationalization (i18n) support across various components, enabling dynamic language switching and improved user experience.
- Updated multiple components to utilize translation functions for labels, buttons, and messages, ensuring consistent language display.
- Enhanced the user interface by refining text elements in the ChannelsTable, LogsTable, and various settings pages, improving clarity and accessibility.
- Adjusted CSS styles for better responsiveness and layout consistency across different screen sizes.
This commit is contained in:
CalciumIon
2024-12-13 19:03:14 +08:00
parent cd21aa1c56
commit 221d7b5c99
42 changed files with 3192 additions and 1828 deletions

View File

@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
API,
copy,
@@ -40,8 +41,8 @@ function renderTimestamp(timestamp) {
}
const MODE_OPTIONS = [
{ key: 'all', text: '全部用户', value: 'all' },
{ key: 'self', text: '当前用户', value: 'self' },
{ key: 'all', text: 'all', value: 'all' },
{ key: 'self', text: 'current user', value: 'self' },
];
const colors = [
@@ -62,123 +63,92 @@ const colors = [
'yellow',
];
function renderType(type) {
switch (type) {
case 1:
const LogsTable = () => {
const { t } = useTranslation();
function renderType(type) {
switch (type) {
case 1:
return <Tag color='cyan' size='large'>{t('充值')}</Tag>;
case 2:
return <Tag color='lime' size='large'>{t('消费')}</Tag>;
case 3:
return <Tag color='orange' size='large'>{t('管理')}</Tag>;
case 4:
return <Tag color='purple' size='large'>{t('系统')}</Tag>;
default:
return <Tag color='black' size='large'>{t('未知')}</Tag>;
}
}
function renderIsStream(bool) {
if (bool) {
return <Tag color='blue' size='large'>{t('流')}</Tag>;
} else {
return <Tag color='purple' size='large'>{t('非流')}</Tag>;
}
}
function renderUseTime(type) {
const time = parseInt(type);
if (time < 101) {
return (
<Tag color='cyan' size='large'>
<Tag color='green' size='large'>
{' '}
充值{' '}
{time} s{' '}
</Tag>
);
case 2:
return (
<Tag color='lime' size='large'>
{' '}
消费{' '}
</Tag>
);
case 3:
} else if (time < 300) {
return (
<Tag color='orange' size='large'>
{' '}
管理{' '}
{time} s{' '}
</Tag>
);
case 4:
} else {
return (
<Tag color='purple' size='large'>
<Tag color='red' size='large'>
{' '}
系统{' '}
{time} s{' '}
</Tag>
);
default:
}
}
function renderFirstUseTime(type) {
let time = parseFloat(type) / 1000.0;
time = time.toFixed(1);
if (time < 3) {
return (
<Tag color='black' size='large'>
<Tag color='green' size='large'>
{' '}
未知{' '}
{time} s{' '}
</Tag>
);
}
}
} else if (time < 10) {
return (
<Tag color='orange' size='large'>
{' '}
{time} s{' '}
</Tag>
);
} else {
return (
<Tag color='red' size='large'>
{' '}
{time} s{' '}
</Tag>
);
}
}
function renderIsStream(bool) {
if (bool) {
return (
<Tag color='blue' size='large'>
</Tag>
);
} else {
return (
<Tag color='purple' size='large'>
非流
</Tag>
);
}
}
function renderUseTime(type) {
const time = parseInt(type);
if (time < 101) {
return (
<Tag color='green' size='large'>
{' '}
{time} s{' '}
</Tag>
);
} else if (time < 300) {
return (
<Tag color='orange' size='large'>
{' '}
{time} s{' '}
</Tag>
);
} else {
return (
<Tag color='red' size='large'>
{' '}
{time} s{' '}
</Tag>
);
}
}
function renderFirstUseTime(type) {
let time = parseFloat(type) / 1000.0;
time = time.toFixed(1);
if (time < 3) {
return (
<Tag color='green' size='large'>
{' '}
{time} s{' '}
</Tag>
);
} else if (time < 10) {
return (
<Tag color='orange' size='large'>
{' '}
{time} s{' '}
</Tag>
);
} else {
return (
<Tag color='red' size='large'>
{' '}
{time} s{' '}
</Tag>
);
}
}
const LogsTable = () => {
const columns = [
{
title: '时间',
title: t('时间'),
dataIndex: 'timestamp2string',
},
{
title: '渠道',
title: t('渠道'),
dataIndex: 'channel',
className: isAdmin() ? 'tableShow' : 'tableHiddle',
render: (text, record, index) => {
@@ -204,7 +174,7 @@ const LogsTable = () => {
},
},
{
title: '用户',
title: t('用户'),
dataIndex: 'username',
className: isAdmin() ? 'tableShow' : 'tableHiddle',
render: (text, record, index) => {
@@ -226,7 +196,7 @@ const LogsTable = () => {
},
},
{
title: '令牌',
title: t('令牌'),
dataIndex: 'token_name',
render: (text, record, index) => {
return record.type === 0 || record.type === 2 ? (
@@ -239,7 +209,7 @@ const LogsTable = () => {
}}
>
{' '}
{text}{' '}
{t(text)}{' '}
</Tag>
</div>
) : (
@@ -248,14 +218,14 @@ const LogsTable = () => {
},
},
{
title: '类型',
title: t('类型'),
dataIndex: 'type',
render: (text, record, index) => {
return <>{renderType(text)}</>;
},
},
{
title: '模型',
title: t('模型'),
dataIndex: 'model_name',
render: (text, record, index) => {
return record.type === 0 || record.type === 2 ? (
@@ -277,7 +247,7 @@ const LogsTable = () => {
},
},
{
title: '用时/首字',
title: t('用时/首字'),
dataIndex: 'use_time',
render: (text, record, index) => {
if (record.is_stream) {
@@ -304,7 +274,7 @@ const LogsTable = () => {
},
},
{
title: '提示',
title: t('提示'),
dataIndex: 'prompt_tokens',
render: (text, record, index) => {
return record.type === 0 || record.type === 2 ? (
@@ -315,7 +285,7 @@ const LogsTable = () => {
},
},
{
title: '补全',
title: t('补全'),
dataIndex: 'completion_tokens',
render: (text, record, index) => {
return parseInt(text) > 0 &&
@@ -327,7 +297,7 @@ const LogsTable = () => {
},
},
{
title: '花费',
title: t('花费'),
dataIndex: 'quota',
render: (text, record, index) => {
return record.type === 0 || record.type === 2 ? (
@@ -338,11 +308,11 @@ const LogsTable = () => {
},
},
{
title: '重试',
title: t('重试'),
dataIndex: 'retry',
className: isAdmin() ? 'tableShow' : 'tableHiddle',
render: (text, record, index) => {
let content = '渠道' + record.channel;
let content = t('渠道') + `${record.channel}`;
if (record.other !== '') {
let other = JSON.parse(record.other);
if (other === null) {
@@ -357,7 +327,7 @@ const LogsTable = () => {
// channel id array
let useChannel = other.admin_info.use_channel;
let useChannelStr = useChannel.join('->');
content = `渠道${useChannelStr}`;
content = t('渠道') + `${useChannelStr}`;
}
}
}
@@ -365,7 +335,7 @@ const LogsTable = () => {
},
},
{
title: '详情',
title: t('详情'),
dataIndex: 'content',
render: (text, record, index) => {
let other = getLogOther(record.other);
@@ -493,13 +463,13 @@ const LogsTable = () => {
const { success, message, data } = res.data;
if (success) {
Modal.info({
title: '用户信息',
title: t('用户信息'),
content: (
<div style={{ padding: 12 }}>
<p>用户名: {data.username}</p>
<p>余额: {renderQuota(data.quota)}</p>
<p>已用额度{renderQuota(data.used_quota)}</p>
<p>请求次数{renderNumber(data.request_count)}</p>
<p>{t('用户名')}: {data.username}</p>
<p>{t('余额')}: {renderQuota(data.quota)}</p>
<p>{t('已用额度')}{renderQuota(data.used_quota)}</p>
<p>{t('请求次数')}{renderNumber(data.request_count)}</p>
</div>
),
centered: true,
@@ -537,26 +507,26 @@ const LogsTable = () => {
}
if (other?.ws || other?.audio) {
expandDataLocal.push({
key: '语音输入',
key: t('语音输入'),
value: other.audio_input,
});
expandDataLocal.push({
key: '语音输出',
key: t('语音输出'),
value: other.audio_output,
});
expandDataLocal.push({
key: '文字输入',
key: t('文字输入'),
value: other.text_input,
});
expandDataLocal.push({
key: '文字输出',
key: t('文字输出'),
value: other.text_output,
});
}
expandDataLocal.push({
key: '日志详情',
key: t('日志详情'),
value: logs[i].content,
})
});
if (logs[i].type === 2) {
let content = '';
if (other?.ws || other?.audio) {
@@ -583,7 +553,7 @@ const LogsTable = () => {
);
}
expandDataLocal.push({
key: '计费过程',
key: t('计费过程'),
value: content,
});
}
@@ -676,7 +646,7 @@ const LogsTable = () => {
<Spin spinning={loadingStat}>
<Space>
<Tag color='green' size='large' style={{ padding: 15 }}>
总消耗额度: {renderQuota(stat.quota)}
{t('总消耗额度')}: {renderQuota(stat.quota)}
</Tag>
<Tag color='blue' size='large' style={{ padding: 15 }}>
RPM: {stat.rpm}
@@ -691,25 +661,25 @@ const LogsTable = () => {
<>
<Form.Input
field='token_name'
label='令牌名称'
label={t('令牌名称')}
style={{ width: 176 }}
value={token_name}
placeholder={'可选值'}
placeholder={t('可选值')}
name='token_name'
onChange={(value) => handleInputChange(value, 'token_name')}
/>
<Form.Input
field='model_name'
label='模型名称'
label={t('模型名称')}
style={{ width: 176 }}
value={model_name}
placeholder='可选值'
placeholder={t('可选值')}
name='model_name'
onChange={(value) => handleInputChange(value, 'model_name')}
/>
<Form.DatePicker
field='start_timestamp'
label='起始时间'
label={t('起始时间')}
style={{ width: 272 }}
initValue={start_timestamp}
value={start_timestamp}
@@ -720,7 +690,7 @@ const LogsTable = () => {
<Form.DatePicker
field='end_timestamp'
fluid
label='结束时间'
label={t('结束时间')}
style={{ width: 272 }}
initValue={end_timestamp}
value={end_timestamp}
@@ -732,26 +702,26 @@ const LogsTable = () => {
<>
<Form.Input
field='channel'
label='渠道 ID'
label={t('渠道 ID')}
style={{ width: 176 }}
value={channel}
placeholder='可选值'
placeholder={t('可选值')}
name='channel'
onChange={(value) => handleInputChange(value, 'channel')}
/>
<Form.Input
field='username'
label='用户名称'
label={t('用户名称')}
style={{ width: 176 }}
value={username}
placeholder={'可选值'}
placeholder={t('可选值')}
name='username'
onChange={(value) => handleInputChange(value, 'username')}
/>
</>
)}
<Button
label='查询'
label={t('查询')}
type='primary'
htmlType='submit'
className='btn-margin-right'
@@ -759,7 +729,7 @@ const LogsTable = () => {
loading={loading}
style={{ marginTop: 24 }}
>
查询
{t('查询')}
</Button>
<Form.Section></Form.Section>
</>
@@ -773,11 +743,11 @@ const LogsTable = () => {
loadLogs(0, pageSize, parseInt(value));
}}
>
<Select.Option value='0'>全部</Select.Option>
<Select.Option value='1'>充值</Select.Option>
<Select.Option value='2'>消费</Select.Option>
<Select.Option value='3'>管理</Select.Option>
<Select.Option value='4'>系统</Select.Option>
<Select.Option value='0'>{t('全部')}</Select.Option>
<Select.Option value='1'>{t('充值')}</Select.Option>
<Select.Option value='2'>{t('消费')}</Select.Option>
<Select.Option value='3'>{t('管理')}</Select.Option>
<Select.Option value='4'>{t('系统')}</Select.Option>
</Select>
</div>
<Table