From a95fdcb2d2bf2d666e48e1dc5ee35fb2c97b3b01 Mon Sep 17 00:00:00 2001 From: cjy Date: Fri, 10 Apr 2026 09:41:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=86=E7=AB=9E=E5=93=81=E6=8A=A5?= =?UTF-8?q?=E5=91=8A=E5=92=8C=E6=95=B0=E6=8D=AE=E6=8A=A5=E5=91=8A=E7=9A=84?= =?UTF-8?q?title=E9=92=88=E5=AF=B9=E4=B8=8D=E5=90=8C=E7=9A=84=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 1 + go.sum | 2 + pkg/utils/reportname.go | 120 ++++++++++++++++++++++++++++++ pkg/utils/reportname_test.go | 137 +++++++++++++++++++++++++++++++++++ 4 files changed, 260 insertions(+) create mode 100644 pkg/utils/reportname.go create mode 100644 pkg/utils/reportname_test.go diff --git a/go.mod b/go.mod index 3beeb778..faa98549 100644 --- a/go.mod +++ b/go.mod @@ -176,6 +176,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/mozillazg/go-pinyin v0.21.0 // indirect github.com/nwaples/rardecode v1.1.3 // indirect github.com/nxadm/tail v1.4.11 // indirect github.com/onsi/ginkgo v1.16.5 // indirect diff --git a/go.sum b/go.sum index 9fa53579..569ce754 100644 --- a/go.sum +++ b/go.sum @@ -678,6 +678,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/mozillazg/go-pinyin v0.21.0 h1:Wo8/NT45z7P3er/9YSLHA3/kjZzbLz5hR7i+jGeIGao= +github.com/mozillazg/go-pinyin v0.21.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= diff --git a/pkg/utils/reportname.go b/pkg/utils/reportname.go new file mode 100644 index 00000000..169191e4 --- /dev/null +++ b/pkg/utils/reportname.go @@ -0,0 +1,120 @@ +package utils + +import ( + "fmt" + "strings" + + "github.com/mozillazg/go-pinyin" +) + +// reportTypeTranslations locale 到 数据报告/竞品报告 翻译的映射 +var reportTypeTranslations = map[string]map[string]string{ + "zh-CN": { + "数据报告": "数据报告", + "竞品报告": "竞品报告", + }, + "zh-TW": { + "数据报告": "數據報告", + "竞品报告": "競合報告", + }, + "EN": { + "数据报告": "Data Report", + "竞品报告": "Competitor Report", + }, + "de-DE": { + "数据报告": "Datenbericht", + "竞品报告": "Wettbewerbsanalyse", + }, + "ja-JP": { + "数据报告": "データレポート", + "竞品报告": "競合分析レポート", + }, +} + +// pinyinTitles 中文称谓"老师"对应的拼音形式(用于检测) +var pinyinTitles = []string{"lao shi", "laoshi"} + +// ConvertNameToPinyin 将中文姓名转换为拼音,单词首字母大写,单词间用空格分隔。 +// 对于非中文 locale,会去除"老师"称谓。 +// 示例:"王旗老师" -> "Wang Qi" +func ConvertNameToPinyin(name string) string { + args := pinyin.NewArgs() + slices := pinyin.Pinyin(name, args) + + var result []string + for _, s := range slices { + if len(s) > 0 { + // 首字母大写 + runes := []rune(s[0]) + if len(runes) > 0 { + uppered := string([]rune{runes[0] - 32}) + string(runes[1:]) + result = append(result, uppered) + } + } + } + + pinyinName := joinWithSpace(result) + + // 对于非中文 locale,去除拼音 "Lao Shi" + lowerName := strings.ToLower(pinyinName) + for _, pt := range pinyinTitles { + if strings.HasSuffix(lowerName, pt) { + // 提取去掉称谓后的姓名部分 + nameWithoutTitle := strings.TrimSuffix(pinyinName, " Lao Shi") + nameWithoutTitle = strings.TrimSuffix(nameWithoutTitle, " Laoshi") + return nameWithoutTitle + } + } + + return pinyinName +} + +// joinWithSpace 用空格连接字符串,过滤空字符串 +func joinWithSpace(parts []string) string { + var nonEmpty []string + for _, p := range parts { + if p != "" { + nonEmpty = append(nonEmpty, p) + } + } + if len(nonEmpty) == 0 { + return "" + } + result := nonEmpty[0] + for i := 1; i < len(nonEmpty); i++ { + result += " " + nonEmpty[i] + } + return result +} + +// ConvertReportName 将报告名转换为指定语言版本。 +// prefix: YYYY-MM 格式,如 "2026-03" +// personName: 中文姓名,如 "王旗老师" +// reportType: "数据报告" 或 "竞品报告" +// locale: "zh-CN", "zh-TW", "EN", "de-DE", 或 "ja-JP" +func ConvertReportName(prefix, personName, reportType, locale string) string { + reportTypeTrans, ok := reportTypeTranslations[locale] + if !ok { + reportTypeTrans = reportTypeTranslations["zh-CN"] + } + + translatedReportType, ok := reportTypeTrans[reportType] + if !ok { + translatedReportType = reportType + } + + // 对于中文 locale(zh-CN, zh-TW),保持原样 + if locale == "zh-CN" || locale == "zh-TW" { + displayName := personName + if locale == "zh-TW" { + // zh-TW 去掉"老师",繁体报告类型已通过 translatedReportType 获取 + displayName = strings.ReplaceAll(personName, "老师", "") + } + return fmt.Sprintf("%s%s%s", prefix, displayName, translatedReportType) + } + + // 对于其他 locale,转换为拼音 + pinyinName := ConvertNameToPinyin(personName) + return fmt.Sprintf("%s %s %s", prefix, pinyinName, translatedReportType) +} + diff --git a/pkg/utils/reportname_test.go b/pkg/utils/reportname_test.go new file mode 100644 index 00000000..46baa052 --- /dev/null +++ b/pkg/utils/reportname_test.go @@ -0,0 +1,137 @@ +package utils + +import "testing" + +func TestConvertReportName(t *testing.T) { + tests := []struct { + name string + prefix string // YYYY-MM + personName string // 中文姓名 + reportType string // 数据报告 或 竞品报告 + locale string + expected string + }{ + { + name: "EN Data Report", + prefix: "2026-03", + personName: "王旗老师", + reportType: "数据报告", + locale: "EN", + expected: "2026-03 Wang Qi Data Report", + }, + { + name: "EN Competitor Report", + prefix: "2026-03", + personName: "王旗老师", + reportType: "竞品报告", + locale: "EN", + expected: "2026-03 Wang Qi Competitor Report", + }, + { + name: "zh-TW Data Report", + prefix: "2026-03", + personName: "王旗老师", + reportType: "数据报告", + locale: "zh-TW", + expected: "2026-03王旗數據報告", + }, + { + name: "zh-TW Competitor Report", + prefix: "2026-03", + personName: "王旗老师", + reportType: "竞品报告", + locale: "zh-TW", + expected: "2026-03王旗競合報告", + }, + { + name: "de-DE Data Report", + prefix: "2026-03", + personName: "王旗老师", + reportType: "数据报告", + locale: "de-DE", + expected: "2026-03 Wang Qi Datenbericht", + }, + { + name: "de-DE Competitor Report", + prefix: "2026-03", + personName: "王旗老师", + reportType: "竞品报告", + locale: "de-DE", + expected: "2026-03 Wang Qi Wettbewerbsanalyse", + }, + { + name: "ja-JP Data Report", + prefix: "2026-03", + personName: "王旗老师", + reportType: "数据报告", + locale: "ja-JP", + expected: "2026-03 Wang Qi データレポート", + }, + { + name: "ja-JP Competitor Report", + prefix: "2026-03", + personName: "王旗老师", + reportType: "竞品报告", + locale: "ja-JP", + expected: "2026-03 Wang Qi 競合分析レポート", + }, + { + name: "zh-CN Data Report (no conversion)", + prefix: "2026-03", + personName: "王旗老师", + reportType: "数据报告", + locale: "zh-CN", + expected: "2026-03王旗老师数据报告", + }, + { + name: "zh-CN Competitor Report (no conversion)", + prefix: "2026-03", + personName: "王旗老师", + reportType: "竞品报告", + locale: "zh-CN", + expected: "2026-03王旗老师竞品报告", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ConvertReportName(tt.prefix, tt.personName, tt.reportType, tt.locale) + if result != tt.expected { + t.Errorf("ConvertReportName() = %v, want %v", result, tt.expected) + } + }) + } +} + +func TestConvertNameToPinyin(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "simple name", + input: "王旗", + expected: "Wang Qi", + }, + { + name: "name with title", + input: "王旗老师", + expected: "Wang Qi", + }, + { + name: "two word name with title", + input: "王小明老师", + expected: "Wang Xiao Ming", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ConvertNameToPinyin(tt.input) + if result != tt.expected { + t.Errorf("ConvertNameToPinyin() = %v, want %v", result, tt.expected) + } + }) + } +}