fix(stats): 环比句点明月份与条数,不再写「上月…环比 -75%」
「上月提问量环比 -75.0%」这句要读者做两次翻译:先把「上月」翻成具体月份, 再把「环比」翻成「比上上月」。两个相对词叠在一起,站长本人看到就以为 是「上月同期 vs 本月同期」—— 而它其实比的是两个完整自然月。 改前:上月提问量环比 -75.0%。 改后:9 月收到 5,620 条提问,比 8 月的 4,890 条多了 14.9%。 口径一个字没改(仍是上月 vs 上上月,本月没过完不参与),只是把月份和条数 写进句子:读者不需要知道「环比」的定义也能判断这句话在说什么,还能顺手 核对百分比(5620/4890 确实是 +14.9%)。 实现: - `monthText` 按语言出月份名 —— CJK 一律「9 月」,英文要 "September" ("month 9" 不是英语的说法)。不带年份:相比的两个月相邻。 - 一个词条拆成 momUp / momDown / momFlat:方向词塞不进同一个模板, 四种语言里「多了 / 少了」的位置和词形都不一样。 - `|pct| < 0.05` 走持平,否则会出现「多了 0.0%」。 测试:`TestInsightMoMNamesBothMonths` 锁住「句子里同时有两个月份名和两个条数」, 覆盖上升/下降/持平;`TestMonthText` 锁语言差异。 顺手修预览数据:`zz_preview_test.go` 的 `GrowthMoM` 原来写死 12.3,和它造的 monthly 对不上。以前句子里只有百分比无所谓,现在会连条数一起印出来, 截图就成了「5,620 比 4,890 多了 12.3%」这种假证据,改成从数据算。
This commit is contained in:
+39
-2
@@ -7,6 +7,8 @@ package stats
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tamakyi/TamaBox/internal/i18n"
|
||||
)
|
||||
@@ -119,7 +121,27 @@ func insights(lang string, ov *Overview) []string {
|
||||
}
|
||||
|
||||
if ov.HasPrevMonth {
|
||||
out = append(out, t("stats.insight.mom", fmt.Sprintf("%+.1f", ov.GrowthMoM)))
|
||||
// 句子必须点明是哪两个月、各多少条。
|
||||
//
|
||||
// 原来写「上月提问量环比 -75.0%」:读者得自己先翻译「上月 = 9 月」、
|
||||
// 再翻译「环比 = 比 8 月」,于是很容易读成「上月同期 vs 本月同期」。
|
||||
// 两个相对词叠在一起,全靠脑补;把月份和条数写出来就没有歧义了。
|
||||
n := len(ov.Monthly)
|
||||
cur, prev := ov.Monthly[n-2], ov.Monthly[n-3]
|
||||
pct := math.Abs(ov.GrowthMoM)
|
||||
// pct 四舍五入后是 0.0 时按持平处理:别写「多了 0.0%」。
|
||||
key := "stats.insight.momFlat"
|
||||
if pct >= 0.05 {
|
||||
if ov.GrowthMoM > 0 {
|
||||
key = "stats.insight.momUp"
|
||||
} else {
|
||||
key = "stats.insight.momDown"
|
||||
}
|
||||
}
|
||||
out = append(out, t(key,
|
||||
monthText(lang, cur.Month), numText(cur.N),
|
||||
monthText(lang, prev.Month), numText(prev.N),
|
||||
pct))
|
||||
}
|
||||
|
||||
if ov.Answered > 0 {
|
||||
@@ -132,8 +154,23 @@ func insights(lang string, ov *Overview) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// numText 加千分位(2148 → "2,148")。
|
||||
// monthText 把 "2026-09" 变成句子里能用的月份名。
|
||||
//
|
||||
// 中文 / 日文用「9 月」,英文要 "September"("month 9" 不是英语的说法)。
|
||||
// 不带年份:要比较的两个月相邻,读者知道哪个月是「上个月」,年份只是噪音。
|
||||
func monthText(lang, month string) string {
|
||||
m, err := time.Parse("2006-01", month)
|
||||
if err != nil {
|
||||
// 解析不了就把原始 key 原样带出去,总比句子里空一格强。
|
||||
return month
|
||||
}
|
||||
if strings.HasPrefix(lang, i18n.LangEn) {
|
||||
return m.Month().String()
|
||||
}
|
||||
return fmt.Sprintf("%d 月", int(m.Month()))
|
||||
}
|
||||
|
||||
// numText 加千分位(2148 → "2,148")。
|
||||
// 模板侧有同名功能的 NumInt,但它在 internal/template 里;统计层反过来依赖渲染层
|
||||
// 会让依赖方向变脏,所以这里重新写一份十行的实现。
|
||||
func numText(v int64) string {
|
||||
|
||||
Reference in New Issue
Block a user