fix: 部分UI在英文设置下未国际化

This commit is contained in:
digua
2026-02-21 14:23:18 +08:00
parent bc6c385c39
commit fe0a2ed010
12 changed files with 144 additions and 61 deletions

View File

@@ -78,7 +78,7 @@ const monthNames = computed(() => [
const typeChartData = computed<EChartPieData>(() => { const typeChartData = computed<EChartPieData>(() => {
const sorted = [...messageTypes.value].sort((a, b) => b.count - a.count) const sorted = [...messageTypes.value].sort((a, b) => b.count - a.count)
return { return {
labels: sorted.map((item) => getMessageTypeName(item.type)), labels: sorted.map((item) => getMessageTypeName(item.type, t)),
values: sorted.map((item) => item.count), values: sorted.map((item) => item.count),
} }
}) })
@@ -89,7 +89,7 @@ const typeSummary = computed(() => {
const sorted = [...messageTypes.value].sort((a, b) => b.count - a.count) const sorted = [...messageTypes.value].sort((a, b) => b.count - a.count)
return sorted.map((item) => ({ return sorted.map((item) => ({
name: getMessageTypeName(item.type), name: getMessageTypeName(item.type, t),
count: item.count, count: item.count,
percentage: total > 0 ? Math.round((item.count / total) * 100) : 0, percentage: total > 0 ? Math.round((item.count / total) * 100) : 0,
})) }))

View File

@@ -25,32 +25,42 @@ export enum MessageType {
OTHER = 99, OTHER = 99,
} }
/** 消息类型名称映射 */ /** 消息类型 i18n key 映射 */
const MESSAGE_TYPE_NAMES: Record<number, string> = { const MESSAGE_TYPE_KEYS: Record<number, string> = {
[MessageType.TEXT]: '文字', // 基础消息类型
[MessageType.IMAGE]: '图片', [MessageType.TEXT]: 'text',
[MessageType.VOICE]: '语音', [MessageType.IMAGE]: 'image',
[MessageType.VIDEO]: '视频', [MessageType.VOICE]: 'voice',
[MessageType.FILE]: '文件', [MessageType.VIDEO]: 'video',
[MessageType.EMOJI]: '表情', [MessageType.FILE]: 'file',
[MessageType.LINK]: '链接', [MessageType.EMOJI]: 'emoji',
[MessageType.LOCATION]: '位置', [MessageType.LINK]: 'link',
[MessageType.RED_PACKET]: '红包', [MessageType.LOCATION]: 'location',
[MessageType.TRANSFER]: '转账', // 交互消息类型
[MessageType.POKE]: '拍一拍', [MessageType.RED_PACKET]: 'redPacket',
[MessageType.CALL]: '通话', [MessageType.TRANSFER]: 'transfer',
[MessageType.SHARE]: '分享', [MessageType.POKE]: 'poke',
[MessageType.REPLY]: '回复', [MessageType.CALL]: 'call',
[MessageType.FORWARD]: '转发', [MessageType.SHARE]: 'share',
[MessageType.CONTACT]: '名片', [MessageType.REPLY]: 'reply',
[MessageType.SYSTEM]: '系统', [MessageType.FORWARD]: 'forward',
[MessageType.RECALL]: '撤回', [MessageType.CONTACT]: 'contact',
[MessageType.OTHER]: '其他', // 系统消息类型
[MessageType.SYSTEM]: 'system',
[MessageType.RECALL]: 'recall',
// 其他
[MessageType.OTHER]: 'other',
} }
/** 获取消息类型名称 */ /**
export function getMessageTypeName(type: MessageType | number): string { * 获取消息类型名称
return MESSAGE_TYPE_NAMES[type] || '未知' * @param type 消息类型
* @param t 可选的 i18n t 函数,传入时使用 common.messageType.* 键
*/
export function getMessageTypeName(type: MessageType | number, t?: (key: string) => string): string {
const key = MESSAGE_TYPE_KEYS[type]
if (t && key) return t(`common.messageType.${key}`)
return t ? t('common.messageType.unknown') : '未知'
} }
/** 小时活跃度 */ /** 小时活跃度 */

View File

@@ -3,6 +3,7 @@
* ECharts 日历热力图组件GitHub 贡献图风格) * ECharts 日历热力图组件GitHub 贡献图风格)
*/ */
import { computed, ref, watch, onMounted, onUnmounted } from 'vue' import { computed, ref, watch, onMounted, onUnmounted } from 'vue'
import { useI18n } from 'vue-i18n'
import * as echarts from 'echarts/core' import * as echarts from 'echarts/core'
import { HeatmapChart } from 'echarts/charts' import { HeatmapChart } from 'echarts/charts'
import { CalendarComponent, TooltipComponent, VisualMapComponent } from 'echarts/components' import { CalendarComponent, TooltipComponent, VisualMapComponent } from 'echarts/components'
@@ -30,6 +31,7 @@ const props = withDefaults(defineProps<Props>(), {
height: 180, height: 180,
}) })
const { t, locale } = useI18n()
const isDark = useDark() const isDark = useDark()
const chartRef = ref<HTMLElement | null>(null) const chartRef = ref<HTMLElement | null>(null)
let chartInstance: echarts.ECharts | null = null let chartInstance: echarts.ECharts | null = null
@@ -70,7 +72,7 @@ const option = computed<ECOption>(() => ({
formatter: (params: any) => { formatter: (params: any) => {
const date = params.data[0] const date = params.data[0]
const value = params.data[1] const value = params.data[1]
return `${date}<br/>消息: ${value}` return `${date}<br/>${t('views.message.calendarTooltipMessages')}: ${value}`
}, },
}, },
visualMap: { visualMap: {
@@ -111,13 +113,35 @@ const option = computed<ECOption>(() => ({
show: true, show: true,
color: isDark.value ? '#9ca3af' : '#6b7280', color: isDark.value ? '#9ca3af' : '#6b7280',
fontSize: 10, fontSize: 10,
nameMap: [
t('common.month.jan'),
t('common.month.feb'),
t('common.month.mar'),
t('common.month.apr'),
t('common.month.may'),
t('common.month.jun'),
t('common.month.jul'),
t('common.month.aug'),
t('common.month.sep'),
t('common.month.oct'),
t('common.month.nov'),
t('common.month.dec'),
],
}, },
dayLabel: { dayLabel: {
show: true, show: true,
firstDay: 1, // 从周一开始 firstDay: 1, // 从周一开始
color: isDark.value ? '#6b7280' : '#9ca3af', color: isDark.value ? '#6b7280' : '#9ca3af',
fontSize: 10, fontSize: 10,
nameMap: ['日', '一', '二', '三', '四', '五', '六'], nameMap: [
t('common.weekday.sun'),
t('common.weekday.mon'),
t('common.weekday.tue'),
t('common.weekday.wed'),
t('common.weekday.thu'),
t('common.weekday.fri'),
t('common.weekday.sat'),
],
}, },
splitLine: { splitLine: {
show: false, show: false,
@@ -153,8 +177,8 @@ function handleResize() {
chartInstance?.resize() chartInstance?.resize()
} }
// 监听数据主题变化 // 监听数据主题、语言变化
watch([() => props.data, isDark], () => { watch([() => props.data, isDark, locale], () => {
updateChart() updateChart()
}) })

View File

@@ -40,6 +40,28 @@
"members": "members", "members": "members",
"days": "days" "days": "days"
}, },
"messageType": {
"text": "Text",
"image": "Image",
"voice": "Voice",
"video": "Video",
"file": "File",
"emoji": "Emoji",
"link": "Link",
"location": "Location",
"redPacket": "Red Packet",
"transfer": "Transfer",
"poke": "Poke",
"call": "Call",
"share": "Share",
"reply": "Reply",
"forward": "Forward",
"contact": "Contact",
"system": "System",
"recall": "Recalled",
"other": "Other",
"unknown": "Unknown"
},
"weekday": { "weekday": {
"mon": "Mon", "mon": "Mon",
"tue": "Tue", "tue": "Tue",

View File

@@ -37,6 +37,7 @@
"heatmapHint": "Shows chat time patterns", "heatmapHint": "Shows chat time patterns",
"calendarHeatmap": "Message Calendar", "calendarHeatmap": "Message Calendar",
"calendarHint": "Daily message distribution", "calendarHint": "Daily message distribution",
"calendarTooltipMessages": "Messages",
"lengthDetailTitle": "Short Messages (1-25 chars)", "lengthDetailTitle": "Short Messages (1-25 chars)",
"lengthDetailHint": "Per character", "lengthDetailHint": "Per character",
"lengthGroupedTitle": "Length Range Distribution", "lengthGroupedTitle": "Length Range Distribution",

View File

@@ -40,6 +40,28 @@
"members": "个成员", "members": "个成员",
"days": "天" "days": "天"
}, },
"messageType": {
"text": "文字",
"image": "图片",
"voice": "语音",
"video": "视频",
"file": "文件",
"emoji": "表情",
"link": "链接",
"location": "位置",
"redPacket": "红包",
"transfer": "转账",
"poke": "拍一拍",
"call": "通话",
"share": "分享",
"reply": "回复",
"forward": "转发",
"contact": "名片",
"system": "系统",
"recall": "撤回",
"other": "其他",
"unknown": "未知"
},
"weekday": { "weekday": {
"mon": "周一", "mon": "周一",
"tue": "周二", "tue": "周二",

View File

@@ -37,6 +37,7 @@
"heatmapHint": "展示聊天时间规律", "heatmapHint": "展示聊天时间规律",
"calendarHeatmap": "消息日历", "calendarHeatmap": "消息日历",
"calendarHint": "每日消息分布", "calendarHint": "每日消息分布",
"calendarTooltipMessages": "消息",
"lengthDetailTitle": "短消息分布 (1-25字)", "lengthDetailTitle": "短消息分布 (1-25字)",
"lengthDetailHint": "逐字统计", "lengthDetailHint": "逐字统计",
"lengthGroupedTitle": "长度区间分布", "lengthGroupedTitle": "长度区间分布",

View File

@@ -56,8 +56,8 @@ const { dailyChartData } = useDailyTrend(props.dailyActivity)
// 消息类型图表数据 // 消息类型图表数据
const typeChartData = computed<EChartPieData>(() => { const typeChartData = computed<EChartPieData>(() => {
return { return {
labels: props.messageTypes.map((t) => getMessageTypeName(t.type)), labels: props.messageTypes.map((item) => getMessageTypeName(item.type, t)),
values: props.messageTypes.map((t) => t.count), values: props.messageTypes.map((item) => item.count),
} }
}) })

View File

@@ -208,7 +208,7 @@ onMounted(() => {
icon="i-heroicons-plus-circle" icon="i-heroicons-plus-circle"
@click="showIncrementalImportModal = true" @click="showIncrementalImportModal = true"
> >
{{ t('analysis.incrementalImport', '增量导入') }} {{ t('analysis.tooltip.incrementalImport') }}
</UButton> </UButton>
<UButton <UButton
color="primary" color="primary"
@@ -217,7 +217,7 @@ onMounted(() => {
icon="i-heroicons-chat-bubble-bottom-center-text" icon="i-heroicons-chat-bubble-bottom-center-text"
@click="openChatRecordViewer" @click="openChatRecordViewer"
> >
{{ t('analysis.chatViewer', '聊天记录查看器') }} {{ t('analysis.tooltip.chatViewer') }}
</UButton> </UButton>
<UTooltip :text="t('analysis.tooltip.sessionIndex')"> <UTooltip :text="t('analysis.tooltip.sessionIndex')">
<UButton <UButton

View File

@@ -54,8 +54,8 @@ const { dailyChartData } = useDailyTrend(props.dailyActivity)
// 消息类型图表数据 // 消息类型图表数据
const typeChartData = computed<EChartPieData>(() => { const typeChartData = computed<EChartPieData>(() => {
return { return {
labels: props.messageTypes.map((t) => getMessageTypeName(t.type)), labels: props.messageTypes.map((item) => getMessageTypeName(item.type, t)),
values: props.messageTypes.map((t) => t.count), values: props.messageTypes.map((item) => item.count),
} }
}) })

View File

@@ -220,7 +220,7 @@ onMounted(() => {
icon="i-heroicons-plus-circle" icon="i-heroicons-plus-circle"
@click="showIncrementalImportModal = true" @click="showIncrementalImportModal = true"
> >
{{ t('analysis.incrementalImport', '增量导入') }} {{ t('analysis.tooltip.incrementalImport') }}
</UButton> </UButton>
<UButton <UButton
color="primary" color="primary"
@@ -229,7 +229,7 @@ onMounted(() => {
icon="i-heroicons-chat-bubble-bottom-center-text" icon="i-heroicons-chat-bubble-bottom-center-text"
@click="openChatRecordViewer" @click="openChatRecordViewer"
> >
{{ t('analysis.chatViewer', '聊天记录查看器') }} {{ t('analysis.tooltip.chatViewer') }}
</UButton> </UButton>
<UTooltip :text="t('analysis.tooltip.sessionIndex')"> <UTooltip :text="t('analysis.tooltip.sessionIndex')">
<UButton <UButton

View File

@@ -44,40 +44,43 @@ export enum MessageType {
} }
/** /**
* 消息类型名称映射 * 消息类型 i18n key 映射
*/ */
export const MESSAGE_TYPE_NAMES: Record<number, string> = { const MESSAGE_TYPE_KEYS: Record<number, string> = {
// 基础消息类型 // 基础消息类型
[MessageType.TEXT]: '文字', [MessageType.TEXT]: 'text',
[MessageType.IMAGE]: '图片', [MessageType.IMAGE]: 'image',
[MessageType.VOICE]: '语音', [MessageType.VOICE]: 'voice',
[MessageType.VIDEO]: '视频', [MessageType.VIDEO]: 'video',
[MessageType.FILE]: '文件', [MessageType.FILE]: 'file',
[MessageType.EMOJI]: '表情', [MessageType.EMOJI]: 'emoji',
[MessageType.LINK]: '链接', [MessageType.LINK]: 'link',
[MessageType.LOCATION]: '位置', [MessageType.LOCATION]: 'location',
// 交互消息类型 // 交互消息类型
[MessageType.RED_PACKET]: '红包', [MessageType.RED_PACKET]: 'redPacket',
[MessageType.TRANSFER]: '转账', [MessageType.TRANSFER]: 'transfer',
[MessageType.POKE]: '拍一拍', [MessageType.POKE]: 'poke',
[MessageType.CALL]: '通话', [MessageType.CALL]: 'call',
[MessageType.SHARE]: '分享', [MessageType.SHARE]: 'share',
[MessageType.REPLY]: '回复', [MessageType.REPLY]: 'reply',
[MessageType.FORWARD]: '转发', [MessageType.FORWARD]: 'forward',
[MessageType.CONTACT]: '名片', [MessageType.CONTACT]: 'contact',
// 系统消息类型 // 系统消息类型
[MessageType.SYSTEM]: '系统', [MessageType.SYSTEM]: 'system',
[MessageType.RECALL]: '撤回', [MessageType.RECALL]: 'recall',
// 其他 // 其他
[MessageType.OTHER]: '其他', [MessageType.OTHER]: 'other',
} }
/** /**
* 获取消息类型名称 * 获取消息类型名称
* @param type 消息类型 * @param type 消息类型
* @param t 可选的 i18n t 函数,传入时使用 common.messageType.* 键
*/ */
export function getMessageTypeName(type: MessageType | number): string { export function getMessageTypeName(type: MessageType | number, t?: (key: string) => string): string {
return MESSAGE_TYPE_NAMES[type] || '未知' const key = MESSAGE_TYPE_KEYS[type]
if (t && key) return t(`common.messageType.${key}`)
return t ? t('common.messageType.unknown') : '未知'
} }
/** /**