Files
tamabox/outputs/vote-i18n-audit-2026-09-01.md
T
tamakyi e3e59e7c69 chore: baseline snapshot before moderation-strictness feature
Repo .git was damaged (refs/ missing, index truncated, object store near-empty).
Repaired via git init (rebuilt refs), stale index preserved as .git/index.corrupt-20260910.bak,
then full worktree committed as a rollback baseline.
2026-09-10 10:56:27 +08:00

5.1 KiB
Raw Blame History

投票页中文提示 Bug 排查 + 同类 i18n 缺口审计(2026-09-01)

一、结论先行

  • 你报告的 投票成功!感谢参与 确属 Bug:route/vote/vote.go 的 Submit 之前把成功提示硬编码成了中文,未走 i18n,所以无论访客界面语言设成什么,弹出的都是中文。
  • 已修复:投票页全部用户提示 + 验证码包(共享根因,影响 6 个页面)。
  • 还有大量同类问题:route 层另有 40+ 处硬编码中文 flash(含登录页直接把 db 中文错误弹给用户),以及 db 层的中文错误哨兵,属于系统性 i18n 缺口,建议作为下一批次修复(见第三节)。

二、本次已修复(可直接验收)

1. route/vote/vote.go(投票参与页,访客可见)

  • SetSuccessFlash("投票成功!感谢参与") → i18n.T(lang, "vote.flash.success")。
  • Page / Submit 的全部 SetErrorFlash("中文") 改为对应 i18n 键(vote.flash.notFound/notPublished/archived/ended/notStarted、vote.page.loginRequired/alreadyVoted)。
  • 表单解析 parseSubmission 内约 25 条校验错误(单选/多选/评分/排名/表单字段必填、超长、自定义选项、序列化失败等)全部改为 i18n.T(lang, ...),动态字段名以 %s 占位注入(标签本身是箱主自定的内容,不翻译)。
  • censorCheck 签名改为 (ctx, lang, text),失败文案走 censor.unavailable 键。
  • 新增 i18n 键:vote.err.fieldRequired/fieldCustomRequired/fieldCustomTooLong/fieldInvalidOption/fieldConfigError/fieldRankIncomplete/fieldRankRange/fieldRankDuplicate/fieldTooLong/fieldNotNumber/fieldRating/customTooLong/serialize/unknownType/invalidOption/optionDuplicate(四语言已补齐)。

2. internal/captcha/math.go(验证码,共享根因)

  • Verify / VerifyMath 增加 lang 参数,6 处硬编码中文错误(不能为空/格式错误/答案格式/已过期/服务异常/答案错误/验证码错误)改为 i18n 键。
  • 新增 i18n 键:captcha.errEmpty/errFormat/errAnswerFormat/errExpired/errService/errAnswerWrong(四语言已补齐)。
  • 副作用:登录、注册、找回密码、提问箱页的验证码错误现在也跟随界面语言(这 6 个调用点已同步传 ctx.Lang() 并把 if !ok 分支的硬编码 验证码错误 改为 captcha.error 键)。
  • 配套:internal/context/context.go 新增 (*Context).Lang() 方法(返回中间件注入的界面语言,未注入回退 i18n.Default),供后端 flash/错误本地化复用。

验证:gofmt 通过;go build -overlay(含 webp 屏障包)全绿;go vet 全绿;全量可运行测试(templates / i18n / vote / auth / question 等)通过。

三、尚未修复的同类问题(建议下一批次)

判定标准:用户可见的 flash / 错误信息硬编码中文、不跟随界面语言。按「访客可见 / 箱主后台」分级。

P0 — 访客/公开页(与投票页同类,匿名用户可见,优先级最高)

文件:行 当前硬编码 建议键
route/auth/login.go:49 errors.Cause(err).Error() → ErrBadCredential "邮箱或密码错误" auth.errBadCredential
route/auth/recover.go:124 用户不存在 auth.errUserNotFound
route/auth/recover.go:70 / 86 / 105 / 169 邮件频繁/失败/验证码过期/密码修改成功 auth.*
route/question/page.go:232 密码错误 question.errWrongPassword
route/question/page.go:313 仅注册用户才能提问… question.errLoginRequired
route/question/page.go:322 / 345 不能给自己发起私聊 / 你已被对方拉黑… question.*
route/question/page.go:384 检测到重复提交,请稍后再试 question.errDuplicate
route/question/follow_up.go:38/45/75/90/149/161/180 无权操作/未回答不能追问/等上一条/审核不可用/追问不存在/回答成功 等 question.*
route/question/question.go:215/281/299/313/325 回答发布成功/操作成功/已读/未读 等 question.*
internal/db/users.go:206-208 ErrBadCredential/ErrDuplicateEmail/ErrDuplicateDomain 中文哨兵 改为键或 handler 层映射

P1 — 箱主后台(登录态可见,影响较小)

route/user/vote.go、profile.go、password.go、tags.go、harassment.go 等约 25 处硬编码中文 flash (如 投票已发布!分享链接:…、更新标签成功、页面访问密码已更新、私聊设置更新成功 等)。

P2 — 内部 API(JS 消费的 JSON,非 flash)

internal/captcha/math.go VerifyHandler 返回的 请求格式错误 / 验证码 ID 不能为空(JSON message,前端弹通用提示,影响低)。

四、建议的下一步

  1. 先修 P0(公开页):与投票页同类,直接决定匿名访客的语言体验,工作量约 8 个文件 + 约 30 个 i18n 键。
  2. 再修 P1(箱主后台)+ P2(可选)。
  3. db 层中文错误哨兵建议统一改为「哨兵错误 + handler 层按 errors.Is 映射 i18n」,避免翻译逻辑下沉到 db 包。

请确认是否按上述批次继续修复(特别是 P0 公开页),我可立即开工。