From 2218e3310ed8dd293e8674d516cf37c1daa3c08e Mon Sep 17 00:00:00 2001 From: Nezumi-2711 Date: Wed, 22 Jul 2026 15:20:26 +0700 Subject: [PATCH] feat(i18n): localize QQ markdown reports to Vietnamese Translate QQ Official Markdown report labels, headings, dashboard text, date display, and logs to Vietnamese. Update localization assertions while preserving report logic. --- .../reporting/qq_official_markdown.py | 47 ++++++++++--------- tests/test_avatar_only_reporting.py | 42 ++++++++--------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/infrastructure/reporting/qq_official_markdown.py b/src/infrastructure/reporting/qq_official_markdown.py index 28ba4c2..e61bdcc 100644 --- a/src/infrastructure/reporting/qq_official_markdown.py +++ b/src/infrastructure/reporting/qq_official_markdown.py @@ -62,19 +62,22 @@ class QQOfficialMarkdownReportGenerator: for hour, count in enumerate(hourly_counts) ] metrics = [ - {"value": self.format_metric(stats.message_count), "label": "消息"}, - {"value": self.format_metric(stats.participant_count), "label": "参与"}, - {"value": self.format_metric(stats.total_characters), "label": "字符"}, - {"value": self.format_metric(stats.emoji_count), "label": "表情"}, + {"value": self.format_metric(stats.message_count), "label": "Tin nhắn"}, + { + "value": self.format_metric(stats.participant_count), + "label": "Tham gia", + }, + {"value": self.format_metric(stats.total_characters), "label": "Ký tự"}, + {"value": self.format_metric(stats.emoji_count), "label": "Biểu cảm"}, { "value": self.format_peak_period(stats.most_active_period), - "label": "高峰", + "label": "Cao điểm", }, ] html_content = self.html_templates.render_platform_template( "qq_official", "summary_dashboard.html", - report_title="群聊日常分析", + report_title="Phân tích nhóm", report_date=datetime.now().strftime("%Y.%m.%d"), metrics=metrics, chart_data=chart_data, @@ -99,7 +102,7 @@ class QQOfficialMarkdownReportGenerator: url = str(result or "").strip() if url.startswith(("http://", "https://")): return url - logger.warning("[QQOfficial] T2I 概览图未返回可公开访问的 URL") + logger.warning("[QQOfficial] Ảnh tổng quan T2I không trả về URL công khai") return None try: @@ -108,7 +111,7 @@ class QQOfficialMarkdownReportGenerator: async with self.render_semaphore: return await render() except Exception as exc: - logger.warning("[QQOfficial] T2I 群聊概览图生成失败: %s", exc) + logger.warning("[QQOfficial] Không thể tạo ảnh tổng quan T2I: %s", exc) return None def _generate_markdown_report( @@ -120,20 +123,20 @@ class QQOfficialMarkdownReportGenerator: if summary_dashboard_url: lines = [ - f"![群聊分析概览 #800px #360px]({summary_dashboard_url})", + f"![Tổng quan phân tích nhóm #800px #360px]({summary_dashboard_url})", "", ] else: lines = [ - "# 🎯 群聊日常分析报告", - f"📅 {datetime.now().strftime('%Y年%m月%d日')}", + "# 🎯 Báo cáo phân tích nhóm hôm nay", + f"📅 {datetime.now().strftime('%d/%m/%Y')}", "", - "## 📊 基础统计", - f"- **消息总数**:{stats.message_count}", - f"- **参与人数**:{stats.participant_count}", - f"- **总字符数**:{stats.total_characters}", - f"- **表情数量**:{stats.emoji_count}", - f"- **最活跃时段**:{stats.most_active_period}", + "## 📊 Thống kê cơ bản", + f"- **Tổng tin nhắn**: {stats.message_count}", + f"- **Người tham gia**: {stats.participant_count}", + f"- **Tổng ký tự**: {stats.total_characters}", + f"- **Biểu cảm**: {stats.emoji_count}", + f"- **Khung giờ sôi nổi nhất**: {stats.most_active_period}", "", ] activity_chart = self.build_activity_chart(stats) @@ -141,7 +144,7 @@ class QQOfficialMarkdownReportGenerator: lines.extend(activity_chart) lines.append("") - lines.append("## 💬 热门话题") + lines.append("## 💬 Chủ đề nổi bật") max_topics = self.config_manager.get_max_topics() for index, topic in enumerate(topics[:max_topics], 1): topic_name = self.render_identity_text(topic.topic, analysis_result) @@ -149,13 +152,13 @@ class QQOfficialMarkdownReportGenerator: contributor_ids = list(getattr(topic, "contributor_ids", []) or []) mentions = self.mentions(contributor_ids) if mentions: - lines.append(f"**参与者**:{mentions}") + lines.append(f"**Người tham gia**: {mentions}") detail = self.render_identity_text(topic.detail, analysis_result) if detail: lines.append(detail) lines.append("") - lines.append("## 🏆 群友称号") + lines.append("## 🏆 Danh hiệu thành viên") max_user_titles = self.config_manager.get_max_user_titles() for title in user_titles[:max_user_titles]: mention = self.mention(getattr(title, "user_id", "")) @@ -168,7 +171,7 @@ class QQOfficialMarkdownReportGenerator: lines.append(f" > {reason}") lines.append("") - lines.append("## 💬 群圣经") + lines.append("## 💬 Câu nói vàng") max_golden_quotes = self.config_manager.get_max_golden_quotes() for index, golden_quote in enumerate( stats.golden_quotes[:max_golden_quotes], 1 @@ -216,7 +219,7 @@ class QQOfficialMarkdownReportGenerator: return [] effective_width = max(1, int(bar_width)) - lines = ["## ⏰ 活跃时间分布"] + lines = ["## ⏰ Phân bố thời gian hoạt động"] for hour, count in enumerate(hourly_counts): if count > 0: blocks = max( diff --git a/tests/test_avatar_only_reporting.py b/tests/test_avatar_only_reporting.py index 0253040..d9f9363 100644 --- a/tests/test_avatar_only_reporting.py +++ b/tests/test_avatar_only_reporting.py @@ -171,8 +171,8 @@ def test_qq_official_markdown_uses_mentions_for_all_identity_sections(): without_mentions = report.replace(f"<@{openid}>", "") assert openid not in without_mentions assert nickname not in without_mentions - assert "## 💬 热门话题" in report - assert "**参与者**" in report + assert "## 💬 Chủ đề nổi bật" in report + assert "**Người tham gia**" in report assert "**龙王**" in report assert f"- **1. <@{openid}> 说了一句话** — <@{openid}>" in report assert f" > <@{openid}> 的发言很精彩" in report @@ -284,14 +284,14 @@ def test_qq_official_markdown_renders_simple_hourly_bar_chart(): report = generate_qq_markdown(generator, analysis_result) - assert "## ⏰ 活跃时间分布" in report + assert "## ⏰ Phân bố thời gian hoạt động" in report assert "- 00:00 — 0" in report assert "- 01:00 ███ 2" in report assert "- 02:00 ██████ 5" in report assert "- 03:00 ████████████ 10" in report - chart_section = report.split("## ⏰ 活跃时间分布", 1)[1].split("## 💬 热门话题", 1)[ - 0 - ] + chart_section = report.split("## ⏰ Phân bố thời gian hoạt động", 1)[1].split( + "## 💬 Chủ đề nổi bật", 1 + )[0] assert sum(1 for line in chart_section.splitlines() if line.startswith("- ")) == 24 @@ -315,7 +315,7 @@ def test_qq_official_markdown_omits_empty_hourly_bar_chart(): report = generate_qq_markdown(generator, analysis_result) - assert "## ⏰ 活跃时间分布" not in report + assert "## ⏰ Phân bố thời gian hoạt động" not in report def test_qq_official_t2i_summary_dashboard_replaces_text_summary(): @@ -351,12 +351,12 @@ def test_qq_official_t2i_summary_dashboard_replaces_text_summary(): assert len(render_calls) == 1 template, data, return_url, options = render_calls[0] - assert "群聊日常分析" in template - assert "消息" in template - assert "参与" in template - assert "字符" in template - assert "表情" in template - assert "高峰" in template + assert "Phân tích nhóm" in template + assert "Tin nhắn" in template + assert "Tham gia" in template + assert "Ký tự" in template + assert "Biểu cảm" in template + assert "Cao điểm" in template assert ">10<" in template assert ">2<" in template assert ">50<" in template @@ -385,18 +385,18 @@ def test_qq_official_t2i_summary_dashboard_replaces_text_summary(): assert options["omit_background"] is True assert options["clip"] == {"x": 0, "y": 0, "width": 800, "height": 360} assert "https://t2i.example/chart.png" in markdown_report - assert "# 🎯 群聊日常分析报告" not in markdown_report + assert "# 🎯 Báo cáo phân tích nhóm hôm nay" not in markdown_report assert "📅" not in markdown_report - assert "## 📊 基础统计" not in markdown_report - assert "消息总数" not in markdown_report - assert "## ⏰ 活跃时间分布" not in markdown_report + assert "## 📊 Thống kê cơ bản" not in markdown_report + assert "Tổng tin nhắn" not in markdown_report + assert "## ⏰ Phân bố thời gian hoạt động" not in markdown_report assert "████" not in markdown_report assert "https://t2i.example/chart.png" not in fallback_report - assert "# 🎯 群聊日常分析报告" in fallback_report + assert "# 🎯 Báo cáo phân tích nhóm hôm nay" in fallback_report assert "📅" in fallback_report - assert "## 📊 基础统计" in fallback_report - assert "消息总数" in fallback_report - assert "## ⏰ 活跃时间分布" in fallback_report + assert "## 📊 Thống kê cơ bản" in fallback_report + assert "Tổng tin nhắn" in fallback_report + assert "## ⏰ Phân bố thời gian hoạt động" in fallback_report assert "████" in fallback_report