From 9ef7d439d245c1fd9f0526ba6390b0154b52c463 Mon Sep 17 00:00:00 2001 From: Supra4E8C Date: Fri, 13 Feb 2026 15:24:00 +0800 Subject: [PATCH] fix(usage): update chart labels when locale changes --- src/components/usage/CostTrendChart.tsx | 21 ++++---- src/components/usage/TokenBreakdownChart.tsx | 53 ++++++++++---------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/components/usage/CostTrendChart.tsx b/src/components/usage/CostTrendChart.tsx index d77f04e..92adbdc 100644 --- a/src/components/usage/CostTrendChart.tsx +++ b/src/components/usage/CostTrendChart.tsx @@ -8,7 +8,7 @@ import { buildHourlyCostSeries, buildDailyCostSeries, formatUsd, - type ModelPrice, + type ModelPrice } from '@/utils/usage'; import { buildChartOptions, getHourChartMinWidth } from '@/utils/usage/chartConfig'; import type { UsagePayload } from './hooks/useUsageData'; @@ -43,7 +43,7 @@ export function CostTrendChart({ isDark, isMobile, modelPrices, - hourWindowHours, + hourWindowHours }: CostTrendChartProps) { const { t } = useTranslation(); const [period, setPeriod] = useState<'hour' | 'day'>('hour'); @@ -70,9 +70,9 @@ export function CostTrendChart({ pointBackgroundColor: COST_COLOR, pointBorderColor: COST_COLOR, fill: true, - tension: 0.35, - }, - ], + tension: 0.35 + } + ] }; const baseOptions = buildChartOptions({ period, labels: series.labels, isDark, isMobile }); @@ -84,15 +84,14 @@ export function CostTrendChart({ ...baseOptions.scales?.y, ticks: { ...(baseOptions.scales?.y && 'ticks' in baseOptions.scales.y ? baseOptions.scales.y.ticks : {}), - callback: (value: string | number) => formatUsd(Number(value)), - }, - }, - }, + callback: (value: string | number) => formatUsd(Number(value)) + } + } + } }; return { chartData: data, chartOptions: options, hasData: series.hasData }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [usage, period, isDark, isMobile, modelPrices, hasPrices, hourWindowHours]); + }, [usage, period, isDark, isMobile, modelPrices, hasPrices, hourWindowHours, t]); return ( = { - input: { border: '#3b82f6', bg: 'rgba(59, 130, 246, 0.25)' }, - output: { border: '#22c55e', bg: 'rgba(34, 197, 94, 0.25)' }, - cached: { border: '#f59e0b', bg: 'rgba(245, 158, 11, 0.25)' }, - reasoning: { border: '#8b5cf6', bg: 'rgba(139, 92, 246, 0.25)' }, + input: { border: '#3b82f6', bg: 'rgba(59, 130, 246, 0.25)' }, + output: { border: '#22c55e', bg: 'rgba(34, 197, 94, 0.25)' }, + cached: { border: '#f59e0b', bg: 'rgba(245, 158, 11, 0.25)' }, + reasoning: { border: '#8b5cf6', bg: 'rgba(139, 92, 246, 0.25)' } }; const CATEGORIES: TokenCategory[] = ['input', 'output', 'cached', 'reasoning']; @@ -34,56 +34,55 @@ export function TokenBreakdownChart({ loading, isDark, isMobile, - hourWindowHours, + hourWindowHours }: TokenBreakdownChartProps) { const { t } = useTranslation(); const [period, setPeriod] = useState<'hour' | 'day'>('hour'); - const CATEGORY_LABELS: Record = { - input: t('usage_stats.input_tokens'), - output: t('usage_stats.output_tokens'), - cached: t('usage_stats.cached_tokens'), - reasoning: t('usage_stats.reasoning_tokens'), - }; - const { chartData, chartOptions } = useMemo(() => { const series = period === 'hour' ? buildHourlyTokenBreakdown(usage, hourWindowHours) : buildDailyTokenBreakdown(usage); + const categoryLabels: Record = { + input: t('usage_stats.input_tokens'), + output: t('usage_stats.output_tokens'), + cached: t('usage_stats.cached_tokens'), + reasoning: t('usage_stats.reasoning_tokens') + }; const data = { labels: series.labels, datasets: CATEGORIES.map((cat) => ({ - label: CATEGORY_LABELS[cat], + label: categoryLabels[cat], data: series.dataByCategory[cat], borderColor: TOKEN_COLORS[cat].border, backgroundColor: TOKEN_COLORS[cat].bg, pointBackgroundColor: TOKEN_COLORS[cat].border, pointBorderColor: TOKEN_COLORS[cat].border, fill: true, - tension: 0.35, - })), + tension: 0.35 + })) }; + const baseOptions = buildChartOptions({ period, labels: series.labels, isDark, isMobile }); const options = { - ...buildChartOptions({ period, labels: series.labels, isDark, isMobile }), + ...baseOptions, scales: { - ...buildChartOptions({ period, labels: series.labels, isDark, isMobile }).scales, + ...baseOptions.scales, y: { - ...buildChartOptions({ period, labels: series.labels, isDark, isMobile }).scales?.y, - stacked: true, + ...baseOptions.scales?.y, + stacked: true }, x: { - ...buildChartOptions({ period, labels: series.labels, isDark, isMobile }).scales?.x, - stacked: true, - }, - }, + ...baseOptions.scales?.x, + stacked: true + } + } }; - return { chartData: data, chartOptions: options, hasData: series.hasData }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [usage, period, isDark, isMobile, hourWindowHours]); + return { chartData: data, chartOptions: options }; + }, [usage, period, isDark, isMobile, hourWindowHours, t]); return (