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.
5.1 KiB
5.1 KiB
投票页中文提示 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,前端弹通用提示,影响低)。
四、建议的下一步
- 先修 P0(公开页):与投票页同类,直接决定匿名访客的语言体验,工作量约 8 个文件 + 约 30 个 i18n 键。
- 再修 P1(箱主后台)+ P2(可选)。
- db 层中文错误哨兵建议统一改为「哨兵错误 + handler 层按
errors.Is映射 i18n」,避免翻译逻辑下沉到 db 包。
请确认是否按上述批次继续修复(特别是 P0 公开页),我可立即开工。