diff --git a/packages/chart-message/MessageView.vue b/packages/chart-message/MessageView.vue index 674468b..e4c3dad 100644 --- a/packages/chart-message/MessageView.vue +++ b/packages/chart-message/MessageView.vue @@ -78,7 +78,7 @@ const monthNames = computed(() => [ const typeChartData = computed(() => { const sorted = [...messageTypes.value].sort((a, b) => b.count - a.count) return { - labels: sorted.map((item) => getMessageTypeName(item.type)), + labels: sorted.map((item) => getMessageTypeName(item.type, t)), values: sorted.map((item) => item.count), } }) @@ -89,7 +89,7 @@ const typeSummary = computed(() => { const sorted = [...messageTypes.value].sort((a, b) => b.count - a.count) return sorted.map((item) => ({ - name: getMessageTypeName(item.type), + name: getMessageTypeName(item.type, t), count: item.count, percentage: total > 0 ? Math.round((item.count / total) * 100) : 0, })) diff --git a/packages/chart-message/types.ts b/packages/chart-message/types.ts index 2fd6266..31db461 100644 --- a/packages/chart-message/types.ts +++ b/packages/chart-message/types.ts @@ -25,32 +25,42 @@ export enum MessageType { OTHER = 99, } -/** 消息类型名称映射 */ -const MESSAGE_TYPE_NAMES: Record = { - [MessageType.TEXT]: '文字', - [MessageType.IMAGE]: '图片', - [MessageType.VOICE]: '语音', - [MessageType.VIDEO]: '视频', - [MessageType.FILE]: '文件', - [MessageType.EMOJI]: '表情', - [MessageType.LINK]: '链接', - [MessageType.LOCATION]: '位置', - [MessageType.RED_PACKET]: '红包', - [MessageType.TRANSFER]: '转账', - [MessageType.POKE]: '拍一拍', - [MessageType.CALL]: '通话', - [MessageType.SHARE]: '分享', - [MessageType.REPLY]: '回复', - [MessageType.FORWARD]: '转发', - [MessageType.CONTACT]: '名片', - [MessageType.SYSTEM]: '系统', - [MessageType.RECALL]: '撤回', - [MessageType.OTHER]: '其他', +/** 消息类型 i18n key 映射 */ +const MESSAGE_TYPE_KEYS: Record = { + // 基础消息类型 + [MessageType.TEXT]: 'text', + [MessageType.IMAGE]: 'image', + [MessageType.VOICE]: 'voice', + [MessageType.VIDEO]: 'video', + [MessageType.FILE]: 'file', + [MessageType.EMOJI]: 'emoji', + [MessageType.LINK]: 'link', + [MessageType.LOCATION]: 'location', + // 交互消息类型 + [MessageType.RED_PACKET]: 'redPacket', + [MessageType.TRANSFER]: 'transfer', + [MessageType.POKE]: 'poke', + [MessageType.CALL]: 'call', + [MessageType.SHARE]: 'share', + [MessageType.REPLY]: 'reply', + [MessageType.FORWARD]: 'forward', + [MessageType.CONTACT]: 'contact', + // 系统消息类型 + [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') : '未知' } /** 小时活跃度 */ diff --git a/src/components/charts/EChartCalendar.vue b/src/components/charts/EChartCalendar.vue index e3852be..d112b38 100644 --- a/src/components/charts/EChartCalendar.vue +++ b/src/components/charts/EChartCalendar.vue @@ -3,6 +3,7 @@ * ECharts 日历热力图组件(GitHub 贡献图风格) */ import { computed, ref, watch, onMounted, onUnmounted } from 'vue' +import { useI18n } from 'vue-i18n' import * as echarts from 'echarts/core' import { HeatmapChart } from 'echarts/charts' import { CalendarComponent, TooltipComponent, VisualMapComponent } from 'echarts/components' @@ -30,6 +31,7 @@ const props = withDefaults(defineProps(), { height: 180, }) +const { t, locale } = useI18n() const isDark = useDark() const chartRef = ref(null) let chartInstance: echarts.ECharts | null = null @@ -70,7 +72,7 @@ const option = computed(() => ({ formatter: (params: any) => { const date = params.data[0] const value = params.data[1] - return `${date}
消息: ${value}` + return `${date}
${t('views.message.calendarTooltipMessages')}: ${value}` }, }, visualMap: { @@ -111,13 +113,35 @@ const option = computed(() => ({ show: true, color: isDark.value ? '#9ca3af' : '#6b7280', 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: { show: true, firstDay: 1, // 从周一开始 color: isDark.value ? '#6b7280' : '#9ca3af', 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: { show: false, @@ -153,8 +177,8 @@ function handleResize() { chartInstance?.resize() } -// 监听数据和主题变化 -watch([() => props.data, isDark], () => { +// 监听数据、主题、语言变化 +watch([() => props.data, isDark, locale], () => { updateChart() }) diff --git a/src/i18n/locales/en-US/common.json b/src/i18n/locales/en-US/common.json index 95efb24..92888c3 100644 --- a/src/i18n/locales/en-US/common.json +++ b/src/i18n/locales/en-US/common.json @@ -40,6 +40,28 @@ "members": "members", "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": { "mon": "Mon", "tue": "Tue", diff --git a/src/i18n/locales/en-US/views.json b/src/i18n/locales/en-US/views.json index 384a85c..fb5ffde 100644 --- a/src/i18n/locales/en-US/views.json +++ b/src/i18n/locales/en-US/views.json @@ -37,6 +37,7 @@ "heatmapHint": "Shows chat time patterns", "calendarHeatmap": "Message Calendar", "calendarHint": "Daily message distribution", + "calendarTooltipMessages": "Messages", "lengthDetailTitle": "Short Messages (1-25 chars)", "lengthDetailHint": "Per character", "lengthGroupedTitle": "Length Range Distribution", diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 059df9a..c585fea 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -40,6 +40,28 @@ "members": "个成员", "days": "天" }, + "messageType": { + "text": "文字", + "image": "图片", + "voice": "语音", + "video": "视频", + "file": "文件", + "emoji": "表情", + "link": "链接", + "location": "位置", + "redPacket": "红包", + "transfer": "转账", + "poke": "拍一拍", + "call": "通话", + "share": "分享", + "reply": "回复", + "forward": "转发", + "contact": "名片", + "system": "系统", + "recall": "撤回", + "other": "其他", + "unknown": "未知" + }, "weekday": { "mon": "周一", "tue": "周二", diff --git a/src/i18n/locales/zh-CN/views.json b/src/i18n/locales/zh-CN/views.json index 8e8ae66..9ca8511 100644 --- a/src/i18n/locales/zh-CN/views.json +++ b/src/i18n/locales/zh-CN/views.json @@ -37,6 +37,7 @@ "heatmapHint": "展示聊天时间规律", "calendarHeatmap": "消息日历", "calendarHint": "每日消息分布", + "calendarTooltipMessages": "消息", "lengthDetailTitle": "短消息分布 (1-25字)", "lengthDetailHint": "逐字统计", "lengthGroupedTitle": "长度区间分布", diff --git a/src/pages/group-chat/components/OverviewTab.vue b/src/pages/group-chat/components/OverviewTab.vue index a192909..4a59aeb 100644 --- a/src/pages/group-chat/components/OverviewTab.vue +++ b/src/pages/group-chat/components/OverviewTab.vue @@ -56,8 +56,8 @@ const { dailyChartData } = useDailyTrend(props.dailyActivity) // 消息类型图表数据 const typeChartData = computed(() => { return { - labels: props.messageTypes.map((t) => getMessageTypeName(t.type)), - values: props.messageTypes.map((t) => t.count), + labels: props.messageTypes.map((item) => getMessageTypeName(item.type, t)), + values: props.messageTypes.map((item) => item.count), } }) diff --git a/src/pages/group-chat/index.vue b/src/pages/group-chat/index.vue index e582bdf..79bf00f 100644 --- a/src/pages/group-chat/index.vue +++ b/src/pages/group-chat/index.vue @@ -208,7 +208,7 @@ onMounted(() => { icon="i-heroicons-plus-circle" @click="showIncrementalImportModal = true" > - {{ t('analysis.incrementalImport', '增量导入') }} + {{ t('analysis.tooltip.incrementalImport') }} { icon="i-heroicons-chat-bubble-bottom-center-text" @click="openChatRecordViewer" > - {{ t('analysis.chatViewer', '聊天记录查看器') }} + {{ t('analysis.tooltip.chatViewer') }} (() => { return { - labels: props.messageTypes.map((t) => getMessageTypeName(t.type)), - values: props.messageTypes.map((t) => t.count), + labels: props.messageTypes.map((item) => getMessageTypeName(item.type, t)), + values: props.messageTypes.map((item) => item.count), } }) diff --git a/src/pages/private-chat/index.vue b/src/pages/private-chat/index.vue index f41b84a..3baa84f 100644 --- a/src/pages/private-chat/index.vue +++ b/src/pages/private-chat/index.vue @@ -220,7 +220,7 @@ onMounted(() => { icon="i-heroicons-plus-circle" @click="showIncrementalImportModal = true" > - {{ t('analysis.incrementalImport', '增量导入') }} + {{ t('analysis.tooltip.incrementalImport') }} { icon="i-heroicons-chat-bubble-bottom-center-text" @click="openChatRecordViewer" > - {{ t('analysis.chatViewer', '聊天记录查看器') }} + {{ t('analysis.tooltip.chatViewer') }} = { +const MESSAGE_TYPE_KEYS: Record = { // 基础消息类型 - [MessageType.TEXT]: '文字', - [MessageType.IMAGE]: '图片', - [MessageType.VOICE]: '语音', - [MessageType.VIDEO]: '视频', - [MessageType.FILE]: '文件', - [MessageType.EMOJI]: '表情', - [MessageType.LINK]: '链接', - [MessageType.LOCATION]: '位置', + [MessageType.TEXT]: 'text', + [MessageType.IMAGE]: 'image', + [MessageType.VOICE]: 'voice', + [MessageType.VIDEO]: 'video', + [MessageType.FILE]: 'file', + [MessageType.EMOJI]: 'emoji', + [MessageType.LINK]: 'link', + [MessageType.LOCATION]: 'location', // 交互消息类型 - [MessageType.RED_PACKET]: '红包', - [MessageType.TRANSFER]: '转账', - [MessageType.POKE]: '拍一拍', - [MessageType.CALL]: '通话', - [MessageType.SHARE]: '分享', - [MessageType.REPLY]: '回复', - [MessageType.FORWARD]: '转发', - [MessageType.CONTACT]: '名片', + [MessageType.RED_PACKET]: 'redPacket', + [MessageType.TRANSFER]: 'transfer', + [MessageType.POKE]: 'poke', + [MessageType.CALL]: 'call', + [MessageType.SHARE]: 'share', + [MessageType.REPLY]: 'reply', + [MessageType.FORWARD]: 'forward', + [MessageType.CONTACT]: 'contact', // 系统消息类型 - [MessageType.SYSTEM]: '系统', - [MessageType.RECALL]: '撤回', + [MessageType.SYSTEM]: 'system', + [MessageType.RECALL]: 'recall', // 其他 - [MessageType.OTHER]: '其他', + [MessageType.OTHER]: 'other', } /** * 获取消息类型名称 * @param type 消息类型 + * @param t 可选的 i18n t 函数,传入时使用 common.messageType.* 键 */ -export function getMessageTypeName(type: MessageType | number): string { - return MESSAGE_TYPE_NAMES[type] || '未知' +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') : '未知' } /**