feat(notify): 新增站级 Webhook 与用户级 Telegram 通知通道

在现有邮件通知之外补两条广播/点对点通道:

- 站级 Webhook([notify] webhook_url):新提问 / 新回答 / 新追问 / 新私聊 /
  新投票回复统一 POST JSON 到通用 Webhook(Discord / Slack / 企业微信机器人等)。
  消息体同时带 content(Discord 直接可用)与结构化 event/title/body/link 字段。
- 用户级 Telegram([notify] telegram_bot_token + users.telegram_chat_id):箱主
  自填 Chat ID,新提问 / 新投票回复点对点推送。

设计约束:通知是「尽力而为」旁路 —— 任一通道发送失败只记日志、不向上抛错,
绝不影响提问/回答的主流程;通道未配置时静默跳过。发送放在 shared.SafeGo 异步
执行,与现有邮件通知同一条路径。

6 处业务触发点接入 notify;私聊消息保留仅邮件(已有 5 分钟节流,避免广播刷屏)。
profile 页新增 Telegram Chat ID 输入框 + 四语言字典。app.sample.ini 加 [notify] 段。

测试覆盖 webhook 的 JSON 结构与未配置时的静默跳过。
This commit is contained in:
tamakyi
2026-10-29 19:27:23 +08:00
parent 1e9ffc0718
commit b9060c982b
17 changed files with 519 additions and 218 deletions
+57 -54
View File
@@ -200,34 +200,37 @@ var enDict = map[string]string{
"admin.export": "Export data",
// Admin settings (additional)
"admin.oldPasswordHint": "Only needed when changing password; leave empty to keep it unchanged",
"admin.newPasswordHint": "6-64 characters; leave empty to keep it unchanged",
"admin.notifyEmail": "Email",
"admin.useCustomFg": "Use custom foreground color (otherwise auto-matched)",
"admin.customFgHint": "Only takes effect when enabled; otherwise the color is auto-generated",
"admin.avatarPlaceholder": "Upload avatar (non-1:1 images will be squished)",
"admin.backgroundPlaceholder": "Upload box background",
"admin.qrBackgroundPlaceholder": "Upload QR background (a background that is too dark may make the QR code unreadable)",
"admin.qrPreviewHint": "The preview updates instantly after choosing an image",
"admin.preview": "Live preview",
"admin.themePreset": "Preset themes",
"admin.themeDefault": "Default",
"admin.themeDark": "Dark",
"admin.themeOcean": "Ocean",
"admin.themeSunset": "Sunset",
"admin.resetDefaults": "🔄 Reset to defaults",
"admin.previewHint": "Adjustments are for preview only; click \"Save changes\" to apply",
"admin.socialHint": "Check the box and fill in the profile URL (no https:// needed). Unchecked items won't be shown on your page.",
"admin.enableAcfun": "Enable AcFun",
"admin.enableBili": "Enable Bilibili",
"admin.enableWeibo": "Enable Weibo",
"admin.enableXiaohongshu": "Enable Xiaohongshu",
"admin.enableBlog": "Enable Personal Blog",
"admin.registerOnly": "Only allow registered users to ask me questions",
"admin.updateHarassment": "Update anti-harassment settings",
"admin.globalBlockWords": "Global blocked words",
"admin.globalBlockWordsHint": "Blocked words apply to questions, chat messages sent to you, and vote submissions. This single setting is shared across the question / chat / vote panels and takes effect immediately from any of them.",
"admin.updateBlockWords": "Save blocked words",
"admin.oldPasswordHint": "Only needed when changing password; leave empty to keep it unchanged",
"admin.newPasswordHint": "6-64 characters; leave empty to keep it unchanged",
"admin.notifyEmail": "Email",
"admin.notifyTelegram": "Telegram",
"admin.notifyTelegramPlaceholder": "Telegram Chat ID (empty = disabled)",
"admin.notifyTelegramHint": "Send any message to @userinfobot to get your Chat ID. Requires a site-configured Telegram Bot.",
"admin.useCustomFg": "Use custom foreground color (otherwise auto-matched)",
"admin.customFgHint": "Only takes effect when enabled; otherwise the color is auto-generated",
"admin.avatarPlaceholder": "Upload avatar (non-1:1 images will be squished)",
"admin.backgroundPlaceholder": "Upload box background",
"admin.qrBackgroundPlaceholder": "Upload QR background (a background that is too dark may make the QR code unreadable)",
"admin.qrPreviewHint": "The preview updates instantly after choosing an image",
"admin.preview": "Live preview",
"admin.themePreset": "Preset themes",
"admin.themeDefault": "Default",
"admin.themeDark": "Dark",
"admin.themeOcean": "Ocean",
"admin.themeSunset": "Sunset",
"admin.resetDefaults": "🔄 Reset to defaults",
"admin.previewHint": "Adjustments are for preview only; click \"Save changes\" to apply",
"admin.socialHint": "Check the box and fill in the profile URL (no https:// needed). Unchecked items won't be shown on your page.",
"admin.enableAcfun": "Enable AcFun",
"admin.enableBili": "Enable Bilibili",
"admin.enableWeibo": "Enable Weibo",
"admin.enableXiaohongshu": "Enable Xiaohongshu",
"admin.enableBlog": "Enable Personal Blog",
"admin.registerOnly": "Only allow registered users to ask me questions",
"admin.updateHarassment": "Update anti-harassment settings",
"admin.globalBlockWords": "Global blocked words",
"admin.globalBlockWordsHint": "Blocked words apply to questions, chat messages sent to you, and vote submissions. This single setting is shared across the question / chat / vote panels and takes effect immediately from any of them.",
"admin.updateBlockWords": "Save blocked words",
// Moderation strictness: shared by questions / polls / chat. Decision rules live in internal/security/censor/policy.go.
"admin.moderationStrictness": "Moderation strictness",
@@ -1055,36 +1058,36 @@ var enDict = map[string]string{
"stats.weekday.7": "Sunday",
// Owner insights panel (/user/insights)
"insights.title": "Insights",
"insights.heading": "Your insights",
"insights.lead": "These numbers are yours alone: how many people opened your box, how many questions arrived, and how many are still waiting. Everything is aggregated — no visitor or asker is ever identified.",
"insights.back": "Back to settings",
"insights.entryTitle": "Insights",
"insights.entryDesc": "See how many people visit your box and how your questions are doing",
"insights.summary": "At a glance",
"insights.noViews": "No visits recorded yet. Numbers will appear once someone opens your box.",
"insights.today": "Today",
"insights.week": "Last 7 days",
"insights.month": "Last 30 days",
"insights.newQuestions": "new questions",
"insights.pv": "views",
"insights.uv": "visitors",
"insights.trendTitle": "Views over the last 30 days",
"insights.trendNote": "One bar per day: the light part is page views, the dark part is unique visitors that day. Hover a bar for its views / visitors / questions.",
"insights.legendPV": "Page views",
"insights.legendUV": "Unique visitors (per day)",
"insights.legendHover": "Hover for daily details",
"insights.hourTitle": "When people show up",
"insights.hourNote": "When questions arrived during the last 30 days. The brightest bar is your busiest hour.",
"insights.funnelTitle": "Question handling",
"insights.funnelNote": "All questions split into answered / read but unanswered / untouched.",
"insights.title": "Insights",
"insights.heading": "Your insights",
"insights.lead": "These numbers are yours alone: how many people opened your box, how many questions arrived, and how many are still waiting. Everything is aggregated — no visitor or asker is ever identified.",
"insights.back": "Back to settings",
"insights.entryTitle": "Insights",
"insights.entryDesc": "See how many people visit your box and how your questions are doing",
"insights.summary": "At a glance",
"insights.noViews": "No visits recorded yet. Numbers will appear once someone opens your box.",
"insights.today": "Today",
"insights.week": "Last 7 days",
"insights.month": "Last 30 days",
"insights.newQuestions": "new questions",
"insights.pv": "views",
"insights.uv": "visitors",
"insights.trendTitle": "Views over the last 30 days",
"insights.trendNote": "One bar per day: the light part is page views, the dark part is unique visitors that day. Hover a bar for its views / visitors / questions.",
"insights.legendPV": "Page views",
"insights.legendUV": "Unique visitors (per day)",
"insights.legendHover": "Hover for daily details",
"insights.hourTitle": "When people show up",
"insights.hourNote": "When questions arrived during the last 30 days. The brightest bar is your busiest hour.",
"insights.funnelTitle": "Question handling",
"insights.funnelNote": "All questions split into answered / read but unanswered / untouched.",
"insights.funnelTotal": "All questions",
"insights.funnelAnswered": "Answered",
"insights.funnelReadOnly": "Read, not answered",
"insights.funnelUnread": "Not read",
"insights.answerRate": "Answer rate: answered ÷ all questions",
"insights.privacyTitle": "About these numbers",
"insights.privacyNote": "Visit stats only record \"someone visited N times on a given day\". A visitor is an IP hash with a per-day salt — no IP, no user agent, no page path is stored, and the same person cannot be linked across days. The 7-day / 30-day visitor counts are therefore the sum of daily uniques: someone visiting on several days counts several times. Your own visits to your own box are excluded.",
"insights.answerRate": "Answer rate: answered ÷ all questions",
"insights.privacyTitle": "About these numbers",
"insights.privacyNote": "Visit stats only record \"someone visited N times on a given day\". A visitor is an IP hash with a per-day salt — no IP, no user agent, no page path is stored, and the same person cannot be linked across days. The 7-day / 30-day visitor counts are therefore the sum of daily uniques: someone visiting on several days counts several times. Your own visits to your own box are excluded.",
"insights.insight.empty": "No data yet. This page comes alive once you get your first question or someone opens your box.",
"insights.insight.weekViews": "%s views from %s visitors in the last 7 days.",
+57 -54
View File
@@ -200,34 +200,37 @@ var jaDict = map[string]string{
"admin.export": "データをエクスポート",
// 管理画面設定(追加)
"admin.oldPasswordHint": "パスワード変更時のみ使用。空欄のままなら変更されません",
"admin.newPasswordHint": "6〜64文字。空欄のままなら変更されません",
"admin.notifyEmail": "メール",
"admin.useCustomFg": "カスタム前景色を使用(それ以外は自動マッチ)",
"admin.customFgHint": "有効時のみ適用されます。それ以外は自動生成されます",
"admin.avatarPlaceholder": "アバターをアップロード(1:1 以外は縦横比が崩れます)",
"admin.backgroundPlaceholder": "質問箱の背景をアップロード",
"admin.qrBackgroundPlaceholder": "QRコードの背景画像をアップロード(暗すぎる背景はQRコードが読み取れなくなることがあります)",
"admin.qrPreviewHint": "画像を選択するとプレビューが即時更新されます",
"admin.preview": "ライブプレビュー",
"admin.themePreset": "プリセットテーマ",
"admin.themeDefault": "デフォルト",
"admin.themeDark": "ダーク",
"admin.themeOcean": "オーシャン",
"admin.themeSunset": "サンセット",
"admin.resetDefaults": "🔄 デフォルトに戻す",
"admin.previewHint": "調整はプレビューのみです。「変更を保存」をクリックすると反映されます",
"admin.socialHint": "チェックを入れてプロフィールURLを入力してください(https:// は不要)。チェックのない項目は表示されません。",
"admin.enableAcfun": "AcFun を有効にする",
"admin.enableBili": "Bilibili を有効にする",
"admin.enableWeibo": "Weibo を有効にする",
"admin.enableXiaohongshu": "小紅書 を有効にする",
"admin.enableBlog": "個人ブログを有効にする",
"admin.registerOnly": "登録ユーザーのみ質問を許可",
"admin.updateHarassment": "迷惑行為対策を更新",
"admin.globalBlockWords": "共通ブロックワード",
"admin.globalBlockWordsHint": "ブロックワードは質問・チャット(相手からあなたへのメッセージ)・投票の投稿内容に適用されます。この設定は質問/チャット/投票の3つのタブで共有され、どこで変更してもすぐに反映されます。",
"admin.updateBlockWords": "ブロックワードを保存",
"admin.oldPasswordHint": "パスワード変更時のみ使用。空欄のままなら変更されません",
"admin.newPasswordHint": "6〜64文字。空欄のままなら変更されません",
"admin.notifyEmail": "メール",
"admin.notifyTelegram": "Telegram 通知",
"admin.notifyTelegramPlaceholder": "Telegram Chat ID(空欄なら送信しない)",
"admin.notifyTelegramHint": "@userinfobot に何か送ると Chat ID を取得できます。サイト側で Telegram Bot の設定が必要です。",
"admin.useCustomFg": "カスタム前景色を使用(それ以外は自動マッチ)",
"admin.customFgHint": "有効時のみ適用されます。それ以外は自動生成されます",
"admin.avatarPlaceholder": "アバターをアップロード(1:1 以外は縦横比が崩れます)",
"admin.backgroundPlaceholder": "質問箱の背景をアップロード",
"admin.qrBackgroundPlaceholder": "QRコードの背景画像をアップロード(暗すぎる背景はQRコードが読み取れなくなることがあります)",
"admin.qrPreviewHint": "画像を選択するとプレビューが即時更新されます",
"admin.preview": "ライブプレビュー",
"admin.themePreset": "プリセットテーマ",
"admin.themeDefault": "デフォルト",
"admin.themeDark": "ダーク",
"admin.themeOcean": "オーシャン",
"admin.themeSunset": "サンセット",
"admin.resetDefaults": "🔄 デフォルトに戻す",
"admin.previewHint": "調整はプレビューのみです。「変更を保存」をクリックすると反映されます",
"admin.socialHint": "チェックを入れてプロフィールURLを入力してください(https:// は不要)。チェックのない項目は表示されません。",
"admin.enableAcfun": "AcFun を有効にする",
"admin.enableBili": "Bilibili を有効にする",
"admin.enableWeibo": "Weibo を有効にする",
"admin.enableXiaohongshu": "小紅書 を有効にする",
"admin.enableBlog": "個人ブログを有効にする",
"admin.registerOnly": "登録ユーザーのみ質問を許可",
"admin.updateHarassment": "迷惑行為対策を更新",
"admin.globalBlockWords": "共通ブロックワード",
"admin.globalBlockWordsHint": "ブロックワードは質問・チャット(相手からあなたへのメッセージ)・投票の投稿内容に適用されます。この設定は質問/チャット/投票の3つのタブで共有され、どこで変更してもすぐに反映されます。",
"admin.updateBlockWords": "ブロックワードを保存",
// 審核の厳格度:質問 / 投票 / チャットで共通。判定規則は internal/security/censor/policy.go。
"admin.moderationStrictness": "審核の厳格度",
@@ -1054,36 +1057,36 @@ var jaDict = map[string]string{
"stats.weekday.7": "日曜日",
// 質問箱オーナーのインサイト(/user/insights)
"insights.title": "インサイト",
"insights.heading": "あなたのインサイト",
"insights.lead": "この数字はあなただけのものです。何人が質問箱を開いたか、いくつ質問が届いたか、まだ手つかずの質問がいくつあるか。すべて集計値で、訪問者や質問者の身元は一切含みません。",
"insights.back": "設定に戻る",
"insights.entryTitle": "インサイト",
"insights.entryDesc": "質問箱に何人来たか、質問の対応状況を見る",
"insights.summary": "ひと目で",
"insights.noViews": "まだ訪問の記録がありません。誰かが質問箱を開くと数字が出はじめます。",
"insights.today": "今日",
"insights.week": "過去 7 日間",
"insights.month": "過去 30 日間",
"insights.newQuestions": "新着の質問",
"insights.pv": "回表示",
"insights.uv": "人",
"insights.trendTitle": "過去 30 日間の閲覧推移",
"insights.trendNote": "1 本が 1 日分。淡い部分が閲覧数、濃い部分がその日の重複を除いた訪問者数です。棒にカーソルを合わせると当日の閲覧/訪問者/質問数が出ます。",
"insights.legendPV": "閲覧数(PV)",
"insights.legendUV": "ユニーク訪問者(日ごとに重複排除)",
"insights.legendHover": "カーソルで当日の内訳",
"insights.hourTitle": "いつ来ているか",
"insights.hourNote": "過去 30 日に届いた質問の時間帯分布。最も明るい棒が一番忙しい時間帯です。",
"insights.funnelTitle": "質問の対応状況",
"insights.funnelNote": "すべての質問を「回答済み/既読・未回答/未読」に分けたものです。",
"insights.title": "インサイト",
"insights.heading": "あなたのインサイト",
"insights.lead": "この数字はあなただけのものです。何人が質問箱を開いたか、いくつ質問が届いたか、まだ手つかずの質問がいくつあるか。すべて集計値で、訪問者や質問者の身元は一切含みません。",
"insights.back": "設定に戻る",
"insights.entryTitle": "インサイト",
"insights.entryDesc": "質問箱に何人来たか、質問の対応状況を見る",
"insights.summary": "ひと目で",
"insights.noViews": "まだ訪問の記録がありません。誰かが質問箱を開くと数字が出はじめます。",
"insights.today": "今日",
"insights.week": "過去 7 日間",
"insights.month": "過去 30 日間",
"insights.newQuestions": "新着の質問",
"insights.pv": "回表示",
"insights.uv": "人",
"insights.trendTitle": "過去 30 日間の閲覧推移",
"insights.trendNote": "1 本が 1 日分。淡い部分が閲覧数、濃い部分がその日の重複を除いた訪問者数です。棒にカーソルを合わせると当日の閲覧/訪問者/質問数が出ます。",
"insights.legendPV": "閲覧数(PV)",
"insights.legendUV": "ユニーク訪問者(日ごとに重複排除)",
"insights.legendHover": "カーソルで当日の内訳",
"insights.hourTitle": "いつ来ているか",
"insights.hourNote": "過去 30 日に届いた質問の時間帯分布。最も明るい棒が一番忙しい時間帯です。",
"insights.funnelTitle": "質問の対応状況",
"insights.funnelNote": "すべての質問を「回答済み/既読・未回答/未読」に分けたものです。",
"insights.funnelTotal": "すべての質問",
"insights.funnelAnswered": "回答済み",
"insights.funnelReadOnly": "既読・未回答",
"insights.funnelUnread": "未読",
"insights.answerRate": "回答率:回答済み ÷ 全質問",
"insights.privacyTitle": "この数字について",
"insights.privacyNote": "訪問統計は「ある日に何回来たか」だけを記録します。訪問者の識別子は日ごとに塩を変えた IP ハッシュで、IP・UA・閲覧ページは保存しません。そのため日をまたいで同一人物を紐付けることはできず、7 日/30 日の訪問者数は各日の重複排除後の合計です(同じ人が数日来るとその人数分カウントされます)。質問箱の持ち主自身のアクセスは含みません。",
"insights.answerRate": "回答率:回答済み ÷ 全質問",
"insights.privacyTitle": "この数字について",
"insights.privacyNote": "訪問統計は「ある日に何回来たか」だけを記録します。訪問者の識別子は日ごとに塩を変えた IP ハッシュで、IP・UA・閲覧ページは保存しません。そのため日をまたいで同一人物を紐付けることはできず、7 日/30 日の訪問者数は各日の重複排除後の合計です(同じ人が数日来るとその人数分カウントされます)。質問箱の持ち主自身のアクセスは含みません。",
"insights.insight.empty": "まだデータがありません。最初の質問が届くか、誰かが質問箱を開くと表示されはじめます。",
"insights.insight.weekViews": "過去 7 日間に %s 回の閲覧、%s 人の訪問者。",
+57 -54
View File
@@ -200,34 +200,37 @@ var zhCNDict = map[string]string{
"admin.export": "导出数据",
// 后台设置(补充)
"admin.oldPasswordHint": "修改密码使用,留空则不修改",
"admin.newPasswordHint": "6-64 位,留空则不修改",
"admin.notifyEmail": "邮件",
"admin.useCustomFg": "启用自定义前景色(否则自动匹配)",
"admin.customFgHint": "仅在启用时生效,否则颜色由系统自动生成",
"admin.avatarPlaceholder": "上传个人头像(头像比例不为1:1就扁了你哦)",
"admin.backgroundPlaceholder": "上传提问箱背景",
"admin.qrBackgroundPlaceholder": "上传二维码背景(颜色过深的背景会导致二维码无法识别)",
"admin.qrPreviewHint": "选择图片后预览将即时更新",
"admin.preview": "实时预览",
"admin.themePreset": "预设主题",
"admin.themeDefault": "默认",
"admin.themeDark": "暗夜",
"admin.themeOcean": "海洋",
"admin.themeSunset": "日落",
"admin.resetDefaults": "🔄 恢复默认值",
"admin.previewHint": "调整仅用于预览,最终效果点击「保存修改」后生效",
"admin.socialHint": "勾选后填写主页地址(无需 https://),未勾选的项将不会在前台显示。",
"admin.enableAcfun": "启用 AcFun",
"admin.enableBili": "启用 Bilibili",
"admin.enableWeibo": "启用 微博",
"admin.enableXiaohongshu": "启用 小红书",
"admin.enableBlog": "启用 个人博客",
"admin.registerOnly": "仅允许注册用户向我提问",
"admin.updateHarassment": "更新防骚扰设置",
"admin.globalBlockWords": "全局屏蔽词",
"admin.globalBlockWordsHint": "屏蔽词对提问、私聊(对方发给你的消息)与投票提交内容生效;三个设置页同步显示同一份设置,任意一处修改即时生效。",
"admin.updateBlockWords": "保存屏蔽词",
"admin.oldPasswordHint": "修改密码使用,留空则不修改",
"admin.newPasswordHint": "6-64 位,留空则不修改",
"admin.notifyEmail": "邮件",
"admin.notifyTelegram": "Telegram 通知",
"admin.notifyTelegramPlaceholder": "Telegram Chat ID(留空则不发送)",
"admin.notifyTelegramHint": "向 @userinfobot 发送任意消息即可获得你的 Chat ID。需站方配置了 Telegram Bot。",
"admin.useCustomFg": "启用自定义前景色(否则自动匹配)",
"admin.customFgHint": "仅在启用时生效,否则颜色由系统自动生成",
"admin.avatarPlaceholder": "上传个人头像(头像比例不为1:1就扁了你哦)",
"admin.backgroundPlaceholder": "上传提问箱背景",
"admin.qrBackgroundPlaceholder": "上传二维码背景(颜色过深的背景会导致二维码无法识别)",
"admin.qrPreviewHint": "选择图片后预览将即时更新",
"admin.preview": "实时预览",
"admin.themePreset": "预设主题",
"admin.themeDefault": "默认",
"admin.themeDark": "暗夜",
"admin.themeOcean": "海洋",
"admin.themeSunset": "日落",
"admin.resetDefaults": "🔄 恢复默认值",
"admin.previewHint": "调整仅用于预览,最终效果点击「保存修改」后生效",
"admin.socialHint": "勾选后填写主页地址(无需 https://),未勾选的项将不会在前台显示。",
"admin.enableAcfun": "启用 AcFun",
"admin.enableBili": "启用 Bilibili",
"admin.enableWeibo": "启用 微博",
"admin.enableXiaohongshu": "启用 小红书",
"admin.enableBlog": "启用 个人博客",
"admin.registerOnly": "仅允许注册用户向我提问",
"admin.updateHarassment": "更新防骚扰设置",
"admin.globalBlockWords": "全局屏蔽词",
"admin.globalBlockWordsHint": "屏蔽词对提问、私聊(对方发给你的消息)与投票提交内容生效;三个设置页同步显示同一份设置,任意一处修改即时生效。",
"admin.updateBlockWords": "保存屏蔽词",
// 审核严格度:提问 / 投票 / 私聊共用一份,判定规则见 internal/security/censor/policy.go
"admin.moderationStrictness": "审核严格度",
@@ -1055,36 +1058,36 @@ var zhCNDict = map[string]string{
"stats.weekday.7": "周日",
// 箱主数据面板(/user/insights)
"insights.title": "数据面板",
"insights.heading": "你的数据面板",
"insights.lead": "这些数字只属于你自己:有多少人打开过你的提问箱、你收到了多少提问、还有多少没处理。全部是聚合结果,不含任何一位访客或提问者的身份。",
"insights.back": "返回设置",
"insights.entryTitle": "数据面板",
"insights.entryDesc": "看看有多少人来过你的提问箱、提问处理得怎么样",
"insights.summary": "一眼看懂",
"insights.noViews": "还没有访客记录。有人打开过你的提问箱之后,这里就会开始有数字。",
"insights.today": "今天",
"insights.week": "近 7 天",
"insights.month": "近 30 天",
"insights.newQuestions": "新提问",
"insights.pv": "次浏览",
"insights.uv": "位访客",
"insights.trendTitle": "近 30 天浏览趋势",
"insights.trendNote": "每根柱子是一天,浅色是浏览量,深色是当天去重后的访客数。把鼠标停在柱子上能看到当天的浏览 / 访客 / 提问。",
"insights.legendPV": "浏览量(PV)",
"insights.legendUV": "独立访客(按日去重)",
"insights.legendHover": "悬停查看当天明细",
"insights.hourTitle": "大家什么时候来",
"insights.hourNote": "近 30 天收到的提问分布在一天里的哪个时段,最亮的一根是你最忙的时段。",
"insights.funnelTitle": "提问处理情况",
"insights.funnelNote": "全部提问按「已回答 / 已读未答 / 未读未答」三类拆开。",
"insights.title": "数据面板",
"insights.heading": "你的数据面板",
"insights.lead": "这些数字只属于你自己:有多少人打开过你的提问箱、你收到了多少提问、还有多少没处理。全部是聚合结果,不含任何一位访客或提问者的身份。",
"insights.back": "返回设置",
"insights.entryTitle": "数据面板",
"insights.entryDesc": "看看有多少人来过你的提问箱、提问处理得怎么样",
"insights.summary": "一眼看懂",
"insights.noViews": "还没有访客记录。有人打开过你的提问箱之后,这里就会开始有数字。",
"insights.today": "今天",
"insights.week": "近 7 天",
"insights.month": "近 30 天",
"insights.newQuestions": "新提问",
"insights.pv": "次浏览",
"insights.uv": "位访客",
"insights.trendTitle": "近 30 天浏览趋势",
"insights.trendNote": "每根柱子是一天,浅色是浏览量,深色是当天去重后的访客数。把鼠标停在柱子上能看到当天的浏览 / 访客 / 提问。",
"insights.legendPV": "浏览量(PV)",
"insights.legendUV": "独立访客(按日去重)",
"insights.legendHover": "悬停查看当天明细",
"insights.hourTitle": "大家什么时候来",
"insights.hourNote": "近 30 天收到的提问分布在一天里的哪个时段,最亮的一根是你最忙的时段。",
"insights.funnelTitle": "提问处理情况",
"insights.funnelNote": "全部提问按「已回答 / 已读未答 / 未读未答」三类拆开。",
"insights.funnelTotal": "全部提问",
"insights.funnelAnswered": "已回答",
"insights.funnelReadOnly": "已读未答",
"insights.funnelUnread": "未读未答",
"insights.answerRate": "回答率:已回答 ÷ 全部提问",
"insights.privacyTitle": "关于这些数字",
"insights.privacyNote": "访客统计只记录「某天有人来过几次」。访客身份是每天更换盐值的 IP 哈希,不保存 IP、不保存 UA、也不保存访问了哪个页面。因此跨天的同一个人无法被关联,近 7 天 / 30 天的访客数是各天去重后相加 —— 同一个人连续几天来访会被记成几个人。箱主自己打开自己的提问箱不计入统计。",
"insights.answerRate": "回答率:已回答 ÷ 全部提问",
"insights.privacyTitle": "关于这些数字",
"insights.privacyNote": "访客统计只记录「某天有人来过几次」。访客身份是每天更换盐值的 IP 哈希,不保存 IP、不保存 UA、也不保存访问了哪个页面。因此跨天的同一个人无法被关联,近 7 天 / 30 天的访客数是各天去重后相加 —— 同一个人连续几天来访会被记成几个人。箱主自己打开自己的提问箱不计入统计。",
"insights.insight.empty": "还没有任何数据。等你收到第一条提问,或者有人打开过你的提问箱,这里就会有变化。",
"insights.insight.weekViews": "近 7 天有 %s 次浏览,%s 位访客。",
+57 -54
View File
@@ -200,34 +200,37 @@ var zhTWDict = map[string]string{
"admin.export": "匯出資料",
// 後台設定(補充)
"admin.oldPasswordHint": "修改密碼使用,留空則不修改",
"admin.newPasswordHint": "6-64 位,留空則不修改",
"admin.notifyEmail": "郵件",
"admin.useCustomFg": "啟用自訂前景色(否則自動比對)",
"admin.customFgHint": "僅在啟用時生效,否則顏色由系統自動產生",
"admin.avatarPlaceholder": "上傳個人頭像(頭像比例不為1:1就扁了你哦)",
"admin.backgroundPlaceholder": "上傳提問箱背景",
"admin.qrBackgroundPlaceholder": "上傳QR Code背景(顏色過深的背景會導致QR Code無法辨識)",
"admin.qrPreviewHint": "選擇圖片後預覽將即時更新",
"admin.preview": "即時預覽",
"admin.themePreset": "預設主題",
"admin.themeDefault": "預設",
"admin.themeDark": "暗夜",
"admin.themeOcean": "海洋",
"admin.themeSunset": "日落",
"admin.resetDefaults": "🔄 恢復預設值",
"admin.previewHint": "調整僅用於預覽,最終效果點擊「儲存修改」後生效",
"admin.socialHint": "勾選後填寫主頁地址(無需 https://),未勾選的項目將不會在前台顯示。",
"admin.enableAcfun": "啟用 AcFun",
"admin.enableBili": "啟用 Bilibili",
"admin.enableWeibo": "啟用 微博",
"admin.enableXiaohongshu": "啟用 小紅書",
"admin.enableBlog": "啟用 個人部落格",
"admin.registerOnly": "僅允許註冊使用者向我提問",
"admin.updateHarassment": "更新防騷擾設定",
"admin.globalBlockWords": "全局屏蔽詞",
"admin.globalBlockWordsHint": "屏蔽詞對提問、私聊(對方傳送給你的訊息)與投票提交內容生效;三個設定頁同步顯示同一份設定,任意一處修改即時生效。",
"admin.updateBlockWords": "儲存屏蔽詞",
"admin.oldPasswordHint": "修改密碼使用,留空則不修改",
"admin.newPasswordHint": "6-64 位,留空則不修改",
"admin.notifyEmail": "郵件",
"admin.notifyTelegram": "Telegram 通知",
"admin.notifyTelegramPlaceholder": "Telegram Chat ID(留空則不發送)",
"admin.notifyTelegramHint": "向 @userinfobot 發送任意訊息即可取得你的 Chat ID。需站方配置了 Telegram Bot。",
"admin.useCustomFg": "啟用自訂前景色(否則自動比對)",
"admin.customFgHint": "僅在啟用時生效,否則顏色由系統自動產生",
"admin.avatarPlaceholder": "上傳個人頭像(頭像比例不為1:1就扁了你哦)",
"admin.backgroundPlaceholder": "上傳提問箱背景",
"admin.qrBackgroundPlaceholder": "上傳QR Code背景(顏色過深的背景會導致QR Code無法辨識)",
"admin.qrPreviewHint": "選擇圖片後預覽將即時更新",
"admin.preview": "即時預覽",
"admin.themePreset": "預設主題",
"admin.themeDefault": "預設",
"admin.themeDark": "暗夜",
"admin.themeOcean": "海洋",
"admin.themeSunset": "日落",
"admin.resetDefaults": "🔄 恢復預設值",
"admin.previewHint": "調整僅用於預覽,最終效果點擊「儲存修改」後生效",
"admin.socialHint": "勾選後填寫主頁地址(無需 https://),未勾選的項目將不會在前台顯示。",
"admin.enableAcfun": "啟用 AcFun",
"admin.enableBili": "啟用 Bilibili",
"admin.enableWeibo": "啟用 微博",
"admin.enableXiaohongshu": "啟用 小紅書",
"admin.enableBlog": "啟用 個人部落格",
"admin.registerOnly": "僅允許註冊使用者向我提問",
"admin.updateHarassment": "更新防騷擾設定",
"admin.globalBlockWords": "全局屏蔽詞",
"admin.globalBlockWordsHint": "屏蔽詞對提問、私聊(對方傳送給你的訊息)與投票提交內容生效;三個設定頁同步顯示同一份設定,任意一處修改即時生效。",
"admin.updateBlockWords": "儲存屏蔽詞",
// 審核嚴格度:提問 / 投票 / 私聊共用一份,判定規則見 internal/security/censor/policy.go
"admin.moderationStrictness": "審核嚴格度",
@@ -1054,36 +1057,36 @@ var zhTWDict = map[string]string{
"stats.weekday.7": "週日",
// 箱主數據面板(/user/insights)
"insights.title": "數據面板",
"insights.heading": "你的數據面板",
"insights.lead": "這些數字只屬於你自己:有多少人開啟過你的提問箱、你收到了多少提問、還有多少沒處理。全部是彙總結果,不含任何一位訪客或提問者的身分。",
"insights.back": "返回設定",
"insights.entryTitle": "數據面板",
"insights.entryDesc": "看看有多少人來過你的提問箱、提問處理得怎麼樣",
"insights.summary": "一眼看懂",
"insights.noViews": "還沒有訪客紀錄。有人開啟過你的提問箱之後,這裡就會開始有數字。",
"insights.today": "今天",
"insights.week": "近 7 天",
"insights.month": "近 30 天",
"insights.newQuestions": "新提問",
"insights.pv": "次瀏覽",
"insights.uv": "位訪客",
"insights.trendTitle": "近 30 天瀏覽趨勢",
"insights.trendNote": "每根柱子是一天,淺色是瀏覽量,深色是當天去重後的訪客數。把游標停在柱子上能看到當天的瀏覽/訪客/提問。",
"insights.legendPV": "瀏覽量(PV)",
"insights.legendUV": "獨立訪客(按日去重)",
"insights.legendHover": "停留查看當天明細",
"insights.hourTitle": "大家什麼時候來",
"insights.hourNote": "近 30 天收到的提問分布在一天裡的哪個時段,最亮的一根是你最忙的時段。",
"insights.funnelTitle": "提問處理情況",
"insights.funnelNote": "全部提問按「已回答/已讀未答/未讀未答」三類拆開。",
"insights.title": "數據面板",
"insights.heading": "你的數據面板",
"insights.lead": "這些數字只屬於你自己:有多少人開啟過你的提問箱、你收到了多少提問、還有多少沒處理。全部是彙總結果,不含任何一位訪客或提問者的身分。",
"insights.back": "返回設定",
"insights.entryTitle": "數據面板",
"insights.entryDesc": "看看有多少人來過你的提問箱、提問處理得怎麼樣",
"insights.summary": "一眼看懂",
"insights.noViews": "還沒有訪客紀錄。有人開啟過你的提問箱之後,這裡就會開始有數字。",
"insights.today": "今天",
"insights.week": "近 7 天",
"insights.month": "近 30 天",
"insights.newQuestions": "新提問",
"insights.pv": "次瀏覽",
"insights.uv": "位訪客",
"insights.trendTitle": "近 30 天瀏覽趨勢",
"insights.trendNote": "每根柱子是一天,淺色是瀏覽量,深色是當天去重後的訪客數。把游標停在柱子上能看到當天的瀏覽/訪客/提問。",
"insights.legendPV": "瀏覽量(PV)",
"insights.legendUV": "獨立訪客(按日去重)",
"insights.legendHover": "停留查看當天明細",
"insights.hourTitle": "大家什麼時候來",
"insights.hourNote": "近 30 天收到的提問分布在一天裡的哪個時段,最亮的一根是你最忙的時段。",
"insights.funnelTitle": "提問處理情況",
"insights.funnelNote": "全部提問按「已回答/已讀未答/未讀未答」三類拆開。",
"insights.funnelTotal": "全部提問",
"insights.funnelAnswered": "已回答",
"insights.funnelReadOnly": "已讀未答",
"insights.funnelUnread": "未讀未答",
"insights.answerRate": "回答率:已回答 ÷ 全部提問",
"insights.privacyTitle": "關於這些數字",
"insights.privacyNote": "訪客統計只記錄「某天有人來過幾次」。訪客身分是每天更換鹽值的 IP 雜湊,不保存 IP、不保存 UA、也不保存造訪了哪個頁面。因此跨天的同一個人無法被關聯,近 7 天/30 天的訪客數是各天去重後相加 —— 同一個人連續幾天造訪會被記成幾個人。箱主自己開啟自己的提問箱不計入統計。",
"insights.answerRate": "回答率:已回答 ÷ 全部提問",
"insights.privacyTitle": "關於這些數字",
"insights.privacyNote": "訪客統計只記錄「某天有人來過幾次」。訪客身分是每天更換鹽值的 IP 雜湊,不保存 IP、不保存 UA、也不保存造訪了哪個頁面。因此跨天的同一個人無法被關聯,近 7 天/30 天的訪客數是各天去重後相加 —— 同一個人連續幾天造訪會被記成幾個人。箱主自己開啟自己的提問箱不計入統計。",
"insights.insight.empty": "還沒有任何資料。等你收到第一條提問,或有人開啟過你的提問箱,這裡就會有變化。",
"insights.insight.weekViews": "近 7 天有 %s 次瀏覽,%s 位訪客。",