feat: add i18n for stats command

This commit is contained in:
pomelo-nwu
2025-11-20 14:03:56 +08:00
parent 406e6b5e1f
commit 450c09b4b8
5 changed files with 93 additions and 27 deletions

View File

@@ -879,6 +879,36 @@ export default {
'of input tokens were served from the cache, reducing costs.',
'Tip: For a full token breakdown, run `/stats model`.':
'Tip: For a full token breakdown, run `/stats model`.',
'Model Stats For Nerds': 'Model Stats For Nerds',
'Tool Stats For Nerds': 'Tool Stats For Nerds',
Metric: 'Metric',
API: 'API',
Requests: 'Requests',
Errors: 'Errors',
'Avg Latency': 'Avg Latency',
Tokens: 'Tokens',
Total: 'Total',
Prompt: 'Prompt',
Cached: 'Cached',
Thoughts: 'Thoughts',
Tool: 'Tool',
Output: 'Output',
'No API calls have been made in this session.':
'No API calls have been made in this session.',
'Tool Name': 'Tool Name',
Calls: 'Calls',
'Success Rate': 'Success Rate',
'Avg Duration': 'Avg Duration',
'User Decision Summary': 'User Decision Summary',
'Total Reviewed Suggestions:': 'Total Reviewed Suggestions:',
' » Accepted:': ' » Accepted:',
' » Rejected:': ' » Rejected:',
' » Modified:': ' » Modified:',
' Overall Agreement Rate:': ' Overall Agreement Rate:',
'No tool calls have been made in this session.':
'No tool calls have been made in this session.',
'Session start time is unavailable, cannot calculate stats.':
'Session start time is unavailable, cannot calculate stats.',
// ============================================================================
// Loading Phrases

View File

@@ -832,6 +832,36 @@ export default {
'的输入令牌来自缓存,降低了成本',
'Tip: For a full token breakdown, run `/stats model`.':
'提示:要查看完整的令牌明细,请运行 `/stats model`',
'Model Stats For Nerds': '模型统计(技术细节)',
'Tool Stats For Nerds': '工具统计(技术细节)',
Metric: '指标',
API: 'API',
Requests: '请求数',
Errors: '错误数',
'Avg Latency': '平均延迟',
Tokens: '令牌',
Total: '总计',
Prompt: '提示',
Cached: '缓存',
Thoughts: '思考',
Tool: '工具',
Output: '输出',
'No API calls have been made in this session.':
'本次会话中未进行任何 API 调用',
'Tool Name': '工具名称',
Calls: '调用次数',
'Success Rate': '成功率',
'Avg Duration': '平均耗时',
'User Decision Summary': '用户决策摘要',
'Total Reviewed Suggestions:': '已审核建议总数:',
' » Accepted:': ' » 已接受:',
' » Rejected:': ' » 已拒绝:',
' » Modified:': ' » 已修改:',
' Overall Agreement Rate:': ' 总体同意率:',
'No tool calls have been made in this session.':
'本次会话中未进行任何工具调用',
'Session start time is unavailable, cannot calculate stats.':
'会话开始时间不可用,无法计算统计信息',
// ============================================================================
// Loading Phrases

View File

@@ -28,7 +28,7 @@ export const statsCommand: SlashCommand = {
context.ui.addItem(
{
type: MessageType.ERROR,
text: 'Session start time is unavailable, cannot calculate stats.',
text: t('Session start time is unavailable, cannot calculate stats.'),
},
Date.now(),
);

View File

@@ -15,6 +15,7 @@ import {
} from '../utils/computeStats.js';
import type { ModelMetrics } from '../contexts/SessionContext.js';
import { useSessionStats } from '../contexts/SessionContext.js';
import { t } from '../../i18n/index.js';
const METRIC_COL_WIDTH = 28;
const MODEL_COL_WIDTH = 22;
@@ -65,7 +66,7 @@ export const ModelStatsDisplay: React.FC = () => {
paddingX={2}
>
<Text color={theme.text.primary}>
No API calls have been made in this session.
{t('No API calls have been made in this session.')}
</Text>
</Box>
);
@@ -94,7 +95,7 @@ export const ModelStatsDisplay: React.FC = () => {
paddingX={2}
>
<Text bold color={theme.text.accent}>
Model Stats For Nerds
{t('Model Stats For Nerds')}
</Text>
<Box height={1} />
@@ -102,7 +103,7 @@ export const ModelStatsDisplay: React.FC = () => {
<Box>
<Box width={METRIC_COL_WIDTH}>
<Text bold color={theme.text.primary}>
Metric
{t('Metric')}
</Text>
</Box>
{modelNames.map((name) => (
@@ -125,13 +126,13 @@ export const ModelStatsDisplay: React.FC = () => {
/>
{/* API Section */}
<StatRow title="API" values={[]} isSection />
<StatRow title={t('API')} values={[]} isSection />
<StatRow
title="Requests"
title={t('Requests')}
values={getModelValues((m) => m.api.totalRequests.toLocaleString())}
/>
<StatRow
title="Errors"
title={t('Errors')}
values={getModelValues((m) => {
const errorRate = calculateErrorRate(m);
return (
@@ -146,7 +147,7 @@ export const ModelStatsDisplay: React.FC = () => {
})}
/>
<StatRow
title="Avg Latency"
title={t('Avg Latency')}
values={getModelValues((m) => {
const avgLatency = calculateAverageLatency(m);
return formatDuration(avgLatency);
@@ -156,9 +157,9 @@ export const ModelStatsDisplay: React.FC = () => {
<Box height={1} />
{/* Tokens Section */}
<StatRow title="Tokens" values={[]} isSection />
<StatRow title={t('Tokens')} values={[]} isSection />
<StatRow
title="Total"
title={t('Total')}
values={getModelValues((m) => (
<Text color={theme.status.warning}>
{m.tokens.total.toLocaleString()}
@@ -166,13 +167,13 @@ export const ModelStatsDisplay: React.FC = () => {
))}
/>
<StatRow
title="Prompt"
title={t('Prompt')}
isSubtle
values={getModelValues((m) => m.tokens.prompt.toLocaleString())}
/>
{hasCached && (
<StatRow
title="Cached"
title={t('Cached')}
isSubtle
values={getModelValues((m) => {
const cacheHitRate = calculateCacheHitRate(m);
@@ -186,20 +187,20 @@ export const ModelStatsDisplay: React.FC = () => {
)}
{hasThoughts && (
<StatRow
title="Thoughts"
title={t('Thoughts')}
isSubtle
values={getModelValues((m) => m.tokens.thoughts.toLocaleString())}
/>
)}
{hasTool && (
<StatRow
title="Tool"
title={t('Tool')}
isSubtle
values={getModelValues((m) => m.tokens.tool.toLocaleString())}
/>
)}
<StatRow
title="Output"
title={t('Output')}
isSubtle
values={getModelValues((m) => m.tokens.candidates.toLocaleString())}
/>

View File

@@ -17,6 +17,7 @@ import {
} from '../utils/displayUtils.js';
import { useSessionStats } from '../contexts/SessionContext.js';
import type { ToolCallStats } from '@qwen-code/qwen-code-core';
import { t } from '../../i18n/index.js';
const TOOL_NAME_COL_WIDTH = 25;
const CALLS_COL_WIDTH = 8;
@@ -68,7 +69,7 @@ export const ToolStatsDisplay: React.FC = () => {
paddingX={2}
>
<Text color={theme.text.primary}>
No tool calls have been made in this session.
{t('No tool calls have been made in this session.')}
</Text>
</Box>
);
@@ -103,7 +104,7 @@ export const ToolStatsDisplay: React.FC = () => {
width={70}
>
<Text bold color={theme.text.accent}>
Tool Stats For Nerds
{t('Tool Stats For Nerds')}
</Text>
<Box height={1} />
@@ -111,22 +112,22 @@ export const ToolStatsDisplay: React.FC = () => {
<Box>
<Box width={TOOL_NAME_COL_WIDTH}>
<Text bold color={theme.text.primary}>
Tool Name
{t('Tool Name')}
</Text>
</Box>
<Box width={CALLS_COL_WIDTH} justifyContent="flex-end">
<Text bold color={theme.text.primary}>
Calls
{t('Calls')}
</Text>
</Box>
<Box width={SUCCESS_RATE_COL_WIDTH} justifyContent="flex-end">
<Text bold color={theme.text.primary}>
Success Rate
{t('Success Rate')}
</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
<Text bold color={theme.text.primary}>
Avg Duration
{t('Avg Duration')}
</Text>
</Box>
</Box>
@@ -151,13 +152,15 @@ export const ToolStatsDisplay: React.FC = () => {
{/* User Decision Summary */}
<Text bold color={theme.text.primary}>
User Decision Summary
{t('User Decision Summary')}
</Text>
<Box>
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
<Text color={theme.text.link}>Total Reviewed Suggestions:</Text>
<Text color={theme.text.link}>
{t('Total Reviewed Suggestions:')}
</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
<Text color={theme.text.primary}>{totalReviewed}</Text>
@@ -167,7 +170,7 @@ export const ToolStatsDisplay: React.FC = () => {
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
<Text color={theme.text.primary}> » Accepted:</Text>
<Text color={theme.text.primary}>{t(' » Accepted:')}</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
<Text color={theme.status.success}>{totalDecisions.accept}</Text>
@@ -177,7 +180,7 @@ export const ToolStatsDisplay: React.FC = () => {
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
<Text color={theme.text.primary}> » Rejected:</Text>
<Text color={theme.text.primary}>{t(' » Rejected:')}</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
<Text color={theme.status.error}>{totalDecisions.reject}</Text>
@@ -187,7 +190,7 @@ export const ToolStatsDisplay: React.FC = () => {
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
<Text color={theme.text.primary}> » Modified:</Text>
<Text color={theme.text.primary}>{t(' » Modified:')}</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
<Text color={theme.status.warning}>{totalDecisions.modify}</Text>
@@ -209,7 +212,9 @@ export const ToolStatsDisplay: React.FC = () => {
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
<Text color={theme.text.primary}> Overall Agreement Rate:</Text>
<Text color={theme.text.primary}>
{t(' Overall Agreement Rate:')}
</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
<Text bold color={totalReviewed > 0 ? agreementColor : undefined}>