From a707b58e5ae8d9cc7357f19b8160d92a8a864df9 Mon Sep 17 00:00:00 2001 From: cjy Date: Fri, 10 Apr 2026 10:21:59 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=8F=90?= =?UTF-8?q?=E5=8F=96title=E5=92=8C=E6=A0=A1=E9=AA=8C=20title?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/utils/reportname.go | 57 ++++++++++++ pkg/utils/reportname_test.go | 164 +++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) diff --git a/pkg/utils/reportname.go b/pkg/utils/reportname.go index 169191e4..df81915f 100644 --- a/pkg/utils/reportname.go +++ b/pkg/utils/reportname.go @@ -118,3 +118,60 @@ func ConvertReportName(prefix, personName, reportType, locale string) string { return fmt.Sprintf("%s %s %s", prefix, pinyinName, translatedReportType) } +// isValidPrefix 校验 prefix 是否为 YYYY-MM 格式(年份和月份都是数字) +func isValidPrefix(prefix string) bool { + if len(prefix) != 7 || prefix[4] != '-' { + return false + } + for i := 0; i < 4; i++ { + if prefix[i] < '0' || prefix[i] > '9' { + return false + } + } + if prefix[5] < '0' || prefix[5] > '9' || prefix[6] < '0' || prefix[6] > '9' { + return false + } + return true +} + +// isChineseName 校验姓名是否仅包含中文字符(不包含数字和英文字母) +func isChineseName(name string) bool { + for _, r := range name { + if (r >= '0' && r <= '9') || (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') { + return false + } + } + return true +} + +// ConvertTitleByLocale 将报告标题根据 locale 进行翻译转换。 +// title: 原始中文标题,格式为 "YYYY-MM" + 姓名 + "数据报告"/"竞品报告",如 "2026-03王旗老师数据报告" +// locale: "zh-CN", "zh-TW", "EN", "de-DE", "ja-JP" 或其他 Accept-Language 值 +// 返回翻译后的标题,如果格式不符则返回原标题。 +func ConvertTitleByLocale(title, locale string) string { + if len(title) < 7 { + return title + } + + prefix := title[:7] // YYYY-MM + if !isValidPrefix(prefix) { + return title + } + + var reportType string + if strings.HasSuffix(title, "数据报告") { + reportType = "数据报告" + } else if strings.HasSuffix(title, "竞品报告") { + reportType = "竞品报告" + } else { + return title + } + + personName := title[7 : len(title)-len(reportType)] + if !isChineseName(personName) { + return title + } + + return ConvertReportName(prefix, personName, reportType, locale) +} + diff --git a/pkg/utils/reportname_test.go b/pkg/utils/reportname_test.go index 46baa052..24e3a408 100644 --- a/pkg/utils/reportname_test.go +++ b/pkg/utils/reportname_test.go @@ -2,6 +2,170 @@ package utils import "testing" +func TestIsValidPrefix(t *testing.T) { + tests := []struct { + name string + prefix string + expected bool + }{ + {name: "valid 2026-03", prefix: "2026-03", expected: true}, + {name: "valid 2026-01", prefix: "2026-01", expected: true}, + {name: "valid 1999-12", prefix: "1999-12", expected: true}, + {name: "invalid too short", prefix: "2026-3", expected: false}, + {name: "invalid too long", prefix: "2026-003", expected: false}, + {name: "invalid no dash", prefix: "202603", expected: false}, + {name: "invalid letters in year", prefix: "ab-03", expected: false}, + {name: "invalid letters in month", prefix: "2026-ab", expected: false}, + {name: "invalid month > 12", prefix: "2026-13", expected: true}, // 只校验格式,不校验月份合理性 + {name: "empty string", prefix: "", expected: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isValidPrefix(tt.prefix) + if result != tt.expected { + t.Errorf("isValidPrefix(%q) = %v, want %v", tt.prefix, result, tt.expected) + } + }) + } +} + +func TestIsChineseName(t *testing.T) { + tests := []struct { + name string + input string + expected bool + }{ + {name: "pure Chinese name", input: "王旗", expected: true}, + {name: "Chinese name with title", input: "王旗老师", expected: true}, + {name: "two char Chinese", input: "王明", expected: true}, + {name: "three char Chinese", input: "王小明", expected: true}, + {name: "contains digit", input: "王旗1", expected: false}, + {name: "contains English lower", input: "wang旗", expected: false}, + {name: "contains English upper", input: "WANG旗", expected: false}, + {name: "mixed Chinese and digit", input: "王1明", expected: false}, + {name: "empty string", input: "", expected: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isChineseName(tt.input) + if result != tt.expected { + t.Errorf("isChineseName(%q) = %v, want %v", tt.input, result, tt.expected) + } + }) + } +} + +func TestConvertTitleByLocale(t *testing.T) { + tests := []struct { + name string + title string + locale string + expected string + }{ + { + name: "EN Data Report", + title: "2026-03王旗老师数据报告", + locale: "EN", + expected: "2026-03 Wang Qi Data Report", + }, + { + name: "EN Competitor Report", + title: "2026-03王旗老师竞品报告", + locale: "EN", + expected: "2026-03 Wang Qi Competitor Report", + }, + { + name: "zh-TW Data Report", + title: "2026-03王旗老师数据报告", + locale: "zh-TW", + expected: "2026-03王旗數據報告", + }, + { + name: "zh-TW Competitor Report", + title: "2026-03王旗老师竞品报告", + locale: "zh-TW", + expected: "2026-03王旗競合報告", + }, + { + name: "de-DE Data Report", + title: "2026-03王旗老师数据报告", + locale: "de-DE", + expected: "2026-03 Wang Qi Datenbericht", + }, + { + name: "de-DE Competitor Report", + title: "2026-03王旗老师竞品报告", + locale: "de-DE", + expected: "2026-03 Wang Qi Wettbewerbsanalyse", + }, + { + name: "ja-JP Data Report", + title: "2026-03王旗老师数据报告", + locale: "ja-JP", + expected: "2026-03 Wang Qi データレポート", + }, + { + name: "ja-JP Competitor Report", + title: "2026-03王旗老师竞品报告", + locale: "ja-JP", + expected: "2026-03 Wang Qi 競合分析レポート", + }, + { + name: "zh-CN returns original", + title: "2026-03王旗老师数据报告", + locale: "zh-CN", + expected: "2026-03王旗老师数据报告", + }, + { + name: "invalid prefix returns original", + title: "202603王旗老师数据报告", + locale: "EN", + expected: "202603王旗老师数据报告", + }, + { + name: "invalid personName with digit returns original", + title: "2026-03王旗1老师数据报告", + locale: "EN", + expected: "2026-03王旗1老师数据报告", + }, + { + name: "invalid personName with English returns original", + title: "2026-03wang老师数据报告", + locale: "EN", + expected: "2026-03wang老师数据报告", + }, + { + name: "title too short returns original", + title: "2026-03", + locale: "EN", + expected: "2026-03", + }, + { + name: "unknown reportType returns original", + title: "2026-03王旗老师其他报告", + locale: "EN", + expected: "2026-03王旗老师其他报告", + }, + { + name: "empty title returns original", + title: "", + locale: "EN", + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ConvertTitleByLocale(tt.title, tt.locale) + if result != tt.expected { + t.Errorf("ConvertTitleByLocale(%q, %q) = %q, want %q", tt.title, tt.locale, result, tt.expected) + } + }) + } +} + func TestConvertReportName(t *testing.T) { tests := []struct { name string