index.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. export const DEFAULT_LOCALE = 'zh-CN';
  2. export const supportedLocales = ['zh-CN', 'en-US'];
  3. const messages = {
  4. 'zh-CN': {
  5. 'common.account': '账号',
  6. 'common.addDomain': '添加域名',
  7. 'common.cancel': '取消',
  8. 'common.confirm': '确认',
  9. 'common.copy': '复制',
  10. 'common.copied': '已复制',
  11. 'common.delete': '删除',
  12. 'common.details': '详情',
  13. 'common.error': '操作失败',
  14. 'common.loadingConfig': '加载运行配置中',
  15. 'common.logout': '退出登录',
  16. 'common.manual': '手动',
  17. 'common.next': '下一步',
  18. 'common.notConfigured': '未配置',
  19. 'common.notFound': '暂无',
  20. 'common.previous': '上一步',
  21. 'common.refresh': '刷新',
  22. 'common.save': '保存',
  23. 'common.status': '状态',
  24. 'common.user': '用户',
  25. 'common.unsetSendingIp': '未设置发信 IP',
  26. 'auth.email': '邮箱',
  27. 'auth.emailPlaceholder': 'name@example.com',
  28. 'auth.backToLogin': '返回登录',
  29. 'auth.forgotPassword': '忘记密码?',
  30. 'auth.forgotPasswordButton': '发送重置邮件',
  31. 'auth.forgotPasswordTitle': '找回密码',
  32. 'auth.login': '登录',
  33. 'auth.loginEyebrow': 'Sign in',
  34. 'auth.loginTitle': '登录控制台',
  35. 'auth.newPassword': '新密码',
  36. 'auth.password': '密码',
  37. 'auth.register': '注册',
  38. 'auth.registerButton': '注册并进入',
  39. 'auth.registerEyebrow': 'Register',
  40. 'auth.registerTitle': '创建账号',
  41. 'auth.resendVerification': '重发验证邮件',
  42. 'auth.resendVerificationButton': '发送验证邮件',
  43. 'auth.resendVerificationTitle': '重发验证邮件',
  44. 'auth.resetPasswordButton': '重置密码',
  45. 'auth.resetPasswordTitle': '重置密码',
  46. 'auth.resetTokenMissing': '重置链接缺少 token,请重新发起密码重置。',
  47. 'auth.submitLogin': '登录',
  48. 'auth.username': '用户名',
  49. 'auth.usernameOrEmail': '用户名或邮箱',
  50. 'auth.valueDns': 'DNS 自动化',
  51. 'auth.valueIsolation': '多用户隔离',
  52. 'auth.valueObservability': '发送可观测',
  53. 'auth.subtitle': '发信域名、DNS、SMTP 与 API Token 的统一控制台',
  54. 'auth.requestFailed': '请求失败。',
  55. 'dashboard.title': '统计概览',
  56. 'dashboard.verifiedDomains': '已验证域名',
  57. 'dashboard.todaySent': '今日发送量',
  58. 'dashboard.successRate': '成功率',
  59. 'dashboard.bounceRate': '退信率',
  60. 'dashboard.complaintRate': '投诉率',
  61. 'dashboard.lastSentAt': '最近一次发送',
  62. 'dashboard.dnsIssues': 'DNS 异常数量',
  63. 'dashboard.smtpStatus': 'SMTP 状态',
  64. 'dashboard.smtpReady': '可用',
  65. 'dashboard.smtpNotConfigured': '未配置',
  66. 'dashboard.trend': '发送趋势',
  67. 'dashboard.statusDistribution': '状态分布',
  68. 'dashboard.domainRanking': '域名发送排行',
  69. 'dashboard.domainHealth': '域名健康',
  70. 'dashboard.hourlyHeatmap': '小时发送分布',
  71. 'dashboard.recentFailures': '最近失败原因',
  72. 'dashboard.recentLogs': '最近发送记录',
  73. 'dashboard.noTrend': '暂无发送趋势数据',
  74. 'dashboard.noDomains': '暂无域名',
  75. 'dashboard.noFailures': '暂无失败记录',
  76. 'dashboard.defaultPasswordWarning': '当前仍在使用默认管理密码,请修改 .env 后重启服务。',
  77. 'dashboard.acceptedMail': '已接收邮件',
  78. 'dashboard.failedMail': '失败邮件',
  79. 'dashboard.dnsActionHint': '优先处理 DNS 异常域名,避免影响新域名投递。',
  80. 'dashboard.statusQueued': '已接收',
  81. 'dashboard.statusFailed': '失败',
  82. 'dashboard.statusUnknown': '未知',
  83. 'domains.title': '发信域名',
  84. 'domains.domain': '域名',
  85. 'domains.senderHost': '发信主机',
  86. 'domains.sendingIp': '发信 IP',
  87. 'domains.dnsApi': 'DNS API',
  88. 'domains.smtp': 'SMTP',
  89. 'domains.lastSent': '最近发送',
  90. 'domains.overallStatus': '整体状态',
  91. 'domains.actions': '操作',
  92. 'domains.searchPlaceholder': '搜索域名或发信主机',
  93. 'domains.statusPlaceholder': '整体状态',
  94. 'domains.healthy': '健康',
  95. 'domains.pending': '等待生效',
  96. 'domains.needsAction': '需要处理',
  97. 'domains.waitingDns': '等待 DNS 生效',
  98. 'domains.sendable': '可发送',
  99. 'domains.waitingVerify': '待验证',
  100. 'domains.oneClickDns': '一键 DNS',
  101. 'domains.check': '检查',
  102. 'domains.test': '测试',
  103. 'domains.deleteConfirm': '确认删除该域名?',
  104. 'domainDetail.back': '返回域名列表',
  105. 'domainDetail.overview': '域名概览',
  106. 'domainDetail.danger': '危险操作',
  107. 'domainDetail.deleteHint': '删除域名会移除该域名配置,但不会删除 DNS 服务商中的记录。',
  108. 'domainDetail.editTitle': '修改域名配置',
  109. 'domainDetail.lastCheck': '最后检查',
  110. 'domainDetail.notChecked': '尚未检查',
  111. 'domainDetail.noDnsResult': '尚未生成 DNS 检查结果',
  112. 'domainDetail.currentDnsResult': '当前 DNS 检测结果',
  113. 'domainDetail.recheckAll': '重新检查全部',
  114. 'domainDetail.copyAll': '复制全部配置',
  115. 'domainDetail.noPublicDns': '暂无公共 DNS 查询数据',
  116. 'domainDetail.notFoundRecord': '未发现',
  117. 'domainDetail.needAttention': '需要关注',
  118. 'domainDetail.noSmtpPassword': '请在 SMTP 页面重新设置后复制',
  119. 'domainDetail.noApiToken': '尚未创建',
  120. 'domainDetail.apiExample': '发送 API 示例',
  121. 'domainDetail.placeholder': '配置将在后续版本接入',
  122. 'dnsRecord.hostname': '主机名',
  123. 'dnsRecord.targetValue': '目标值',
  124. 'dnsRecord.currentValue': '当前值',
  125. 'dnsRecord.emptyCurrent': '未查询到记录',
  126. 'dnsRecord.ptrHint': 'PTR 通常需要在服务器商、云厂商或 IP 提供商处配置,DNS API 一般无法直接写入。',
  127. 'dnsRecord.recheck': '重新检测',
  128. 'dnsRecord.copyLabel': '复制',
  129. 'dnsRecord.rootTxt': '根域 TXT',
  130. 'dnsRecord.verificationTxt': '验证 TXT',
  131. 'dnsRecord.dkimTxt': 'DKIM TXT',
  132. 'dnsRecord.dmarcTxt': 'DMARC TXT',
  133. 'dnsRecord.senderA': '发信主机 A',
  134. 'dnsRecord.ptr': '发信 IP PTR',
  135. 'domainHealth.sendingDomain': 'Sending domain',
  136. 'domainHealth.dnsProgress': 'DNS 检查进度',
  137. 'domainHealth.passed': '通过',
  138. 'domainHealth.dnsIssues': 'DNS 异常',
  139. 'domainHealth.dnsApi': 'DNS API',
  140. 'domainHealth.oneClickDns': '一键配置 DNS',
  141. 'domainHealth.checkNow': '立即检查',
  142. 'domainHealth.sendTest': '发送测试邮件',
  143. 'domainHealth.edit': '修改配置',
  144. 'addDomain.title': '添加发信域名',
  145. 'addDomain.stepDomain': '域名信息',
  146. 'addDomain.stepDns': 'DNS 配置方式',
  147. 'addDomain.stepPolicy': 'DKIM / SPF / DMARC',
  148. 'addDomain.stepConfirm': '确认并创建',
  149. 'addDomain.create': '确认创建',
  150. 'addDomain.domainExtra': '填写根域名,不需要 http、路径或邮箱地址。',
  151. 'addDomain.domainRequired': '请输入发信域名',
  152. 'addDomain.senderHostRequired': '请输入发信主机',
  153. 'addDomain.sendingIpRequired': '请输入发信 IP',
  154. 'addDomain.dnsExtra': '未选择时仍可创建域名,稍后手动配置 DNS 或绑定凭据。',
  155. 'addDomain.manualDns': '手动配置 DNS',
  156. 'addDomain.dnsHint': '选择 DNS API 后,域名详情页可以使用“一键配置 DNS”写入验证、DKIM、SPF、DMARC 和发信主机 A 记录。',
  157. 'addDomain.selectorRequired': '请输入 DKIM selector',
  158. 'addDomain.spfExtra': '兼容第三方 SPF include',
  159. 'addDomain.generatedTitle': '创建后会生成以下配置',
  160. 'addDomain.recordVerification': '域名验证 TXT',
  161. 'addDomain.recordDkim': 'DKIM TXT',
  162. 'addDomain.recordSpf': 'SPF TXT',
  163. 'addDomain.recordDmarc': 'DMARC TXT',
  164. 'addDomain.recordSenderA': '发信主机 A 记录',
  165. 'addDomain.recordPtr': 'PTR 反向解析检查提示',
  166. 'addDomain.immediateCheck': '创建后立即检查 DNS',
  167. 'logs.title': '发送记录',
  168. 'logs.time': '时间',
  169. 'logs.recipient': '收件人',
  170. 'logs.domain': '发件域名',
  171. 'logs.errorReason': '错误原因',
  172. 'logs.viewDetail': '查看详情',
  173. 'logs.domainPlaceholder': '发信域名',
  174. 'logs.statusPlaceholder': '状态',
  175. 'logs.recipientPlaceholder': '搜索收件人',
  176. 'logs.detailTitle': '发送详情',
  177. 'logs.deliveryLog': '完整投递日志',
  178. 'logs.copyDeliveryLog': '复制投递日志',
  179. 'logs.noDeliveryLog': '暂无结构化投递日志,可能是历史发送记录。',
  180. 'logs.sender': '发件人',
  181. 'logs.subject': '主题',
  182. 'logs.messageId': 'Message ID',
  183. 'logs.finalResponse': '最终响应',
  184. 'logs.messageBytes': '邮件字节数',
  185. 'logs.queueId': 'Postfix 队列 ID',
  186. 'logs.deliveredAt': '最终投递时间',
  187. 'logs.deliveryAttempts': '投递尝试',
  188. 'logs.noDeliveryAttempts': '暂无最终投递回执,可能仍在队列中或属于历史记录。',
  189. 'logs.statusQueued': '队列中',
  190. 'logs.statusSent': '已送达',
  191. 'logs.statusDeferred': '暂时失败',
  192. 'logs.statusBounced': '已退信',
  193. 'logs.statusFailed': '失败',
  194. 'smtp.connectionTitle': 'SMTP 连接信息',
  195. 'smtp.loginCredentialsTitle': '发信登录凭据',
  196. 'smtp.username': '用户名',
  197. 'smtp.password': '密码',
  198. 'smtp.usernameRequired': '请输入 SMTP Username',
  199. 'smtp.passwordRequired': '请输入 SMTP Password',
  200. 'smtp.passwordSet': '已设置',
  201. 'smtp.passwordEmpty': '未设置',
  202. 'smtp.passwordUnavailable': '请重新设置后复制',
  203. 'smtp.create': '新增凭据',
  204. 'smtp.createTitle': '新增发信登录凭据',
  205. 'smtp.editTitle': '编辑发信登录凭据',
  206. 'smtp.deleteConfirm': '确认删除该 SMTP 登录凭据?',
  207. 'smtp.passwordExtra': '留空保存时会保留原密码;当前密码可在上方连接信息中复制。',
  208. 'smtp.regenerate': '重新生成密码',
  209. 'smtp.resetToCopy': '请重新设置后复制',
  210. 'smtpRelay.title': '高级:外部 SMTP 出口',
  211. 'smtpRelay.create': '新增出口',
  212. 'smtpRelay.createTitle': '新增发信 SMTP 出口',
  213. 'smtpRelay.editTitle': '编辑发信 SMTP 出口',
  214. 'smtpRelay.name': '名称',
  215. 'smtpRelay.nameRequired': '请输入出口名称',
  216. 'smtpRelay.server': '服务器',
  217. 'smtpRelay.hostRequired': '请输入 SMTP Host',
  218. 'smtpRelay.portRequired': '请输入 SMTP Port',
  219. 'smtpRelay.username': '用户名',
  220. 'smtpRelay.password': '密码',
  221. 'smtpRelay.passwordSet': '已设置',
  222. 'smtpRelay.passwordEmpty': '未设置',
  223. 'smtpRelay.passwordExtra': '编辑时会回显已保存密码;清空该字段保存会移除密码。',
  224. 'smtpRelay.generatePassword': '生成密码',
  225. 'smtpRelay.heloExtra': '留空时使用系统默认 HELO。',
  226. 'smtpRelay.default': '默认',
  227. 'smtpRelay.domainDefault': '默认发信 SMTP 出口',
  228. 'smtpRelay.domainDefaultExtra': '未选择时按请求指定、用户默认出口、系统全局 SMTP 的顺序选择。',
  229. 'smtpRelay.useResolutionOrder': '按默认选择顺序',
  230. 'smtpRelay.deleteConfirm': '确认删除该 SMTP 出口?绑定到该出口的域名会改为按默认顺序选择。',
  231. 'dnsApi.title': 'DNS API 凭据',
  232. 'dnsApi.createTitle': '新增 DNS API',
  233. 'dnsApi.editTitle': '编辑',
  234. 'dnsApi.zone': 'Zone / 根域名',
  235. 'dnsApi.zoneRequired': '请输入 Zone 或根域名',
  236. 'dnsApi.cloudflareZoneExtra': 'Cloudflare 可填写任一可访问 Zone 用于测试;一键配置时会按当前发信域名自动匹配 Zone。',
  237. 'dnsApi.tokenExtra': '需要 Zone DNS Edit 权限。',
  238. 'dnsApi.keepSecret': '留空表示保留原密钥。',
  239. 'dnsApi.save': '保存修改',
  240. 'dnsApi.create': '新增凭据',
  241. 'dnsApi.secretHint': '密钥只在服务端加密保存,不会在列表中回显。',
  242. 'settings.checkItem': '检查项',
  243. 'settings.deliveryChecks': '发信环境检查',
  244. 'settings.noPermission': '当前账号没有系统设置权限。',
  245. 'settings.save': '保存设置',
  246. 'admin.title': '管理员面板',
  247. 'admin.users': '用户',
  248. 'admin.resources': '资源',
  249. 'admin.migration': '合并迁移',
  250. 'admin.systemEmail': '系统邮件',
  251. 'admin.auditLogs': '审计日志',
  252. 'metrics.accepted': '已接收',
  253. 'metrics.failed': '失败',
  254. 'metrics.recipients': '收件人',
  255. 'metrics.total': '总量',
  256. 'status.success': '已通过',
  257. 'status.pending': '等待生效',
  258. 'status.error': '配置错误',
  259. 'status.idle': '未配置',
  260. 'tokens.createTitle': '创建 API Token',
  261. 'tokens.name': '名称',
  262. 'tokens.namePlaceholder': 'Production API',
  263. 'tokens.nameRequired': '请输入 Token 名称',
  264. 'tokens.create': '创建 Token',
  265. 'tokens.listTitle': 'API Tokens',
  266. 'tokens.prefix': 'Token 前缀',
  267. 'tokens.fullToken': '完整 Token',
  268. 'tokens.copyFull': '复制完整 Token',
  269. 'tokens.copyPrefix': '复制前缀',
  270. 'tokens.createdTitle': 'API Token 已创建',
  271. 'tokens.createdWarning': '完整 Token 只会显示这一次。关闭后无法再次查看,请立即复制并保存到安全位置。',
  272. 'tokens.createdSuccess': 'Token 已创建',
  273. 'tokens.deletedSuccess': 'Token 已删除',
  274. 'tokens.secretUnavailable': '完整 Token 仅在创建时显示',
  275. 'tokens.lastUsed': '最近使用',
  276. 'tokens.neverUsed': '未使用',
  277. 'tokens.createdAt': '创建时间',
  278. 'tokens.actions': '操作',
  279. 'tokens.deleteConfirm': '确认删除该 Token?',
  280. 'tokens.copyCreated': '复制完整 Token',
  281. 'tokens.prefixOnlyHelp': '历史 Token 不保存明文,只能复制前缀用于识别。',
  282. 'tokens.docsTitle': '发送 API 使用文档',
  283. 'tokens.endpoint': 'API Endpoint',
  284. 'tokens.authHeader': '认证方式',
  285. 'tokens.authHeaderValue': 'Authorization: Bearer <USER_API_TOKEN>',
  286. 'tokens.contentType': 'Content-Type',
  287. 'tokens.requestFields': '请求字段',
  288. 'tokens.fieldFrom': 'from:发件地址,域名必须已添加并通过验证。',
  289. 'tokens.fieldTo': 'to:收件人地址,支持单个邮箱或邮箱数组。',
  290. 'tokens.fieldSubject': 'subject:邮件主题。',
  291. 'tokens.fieldText': 'text:纯文本正文。',
  292. 'tokens.fieldHtml': 'html:HTML 正文,可选。',
  293. 'tokens.curlExample': 'curl 示例',
  294. 'tokens.nodeExample': 'Node / Fetch 示例',
  295. 'tokens.requestExample': '请求 Body 示例',
  296. 'tokens.responseExample': '成功响应示例',
  297. 'tokens.securityTips': '安全建议',
  298. 'tokens.securityTipStore': '只在服务端环境保存 Token,不要放进浏览器前端代码或公开仓库。',
  299. 'tokens.securityTipRotate': '不同环境使用不同 Token,泄露后立即删除并重新创建。',
  300. 'tokens.securityTipDomain': 'From 域名必须属于当前账号,建议先完成 DNS 验证再接入生产发送。',
  301. 'tokens.noTokenHint': '创建 Token 后可复制完整密钥;历史 Token 只显示前缀,示例中使用占位符。',
  302. 'webhooks.title': 'Webhooks',
  303. 'webhooks.subtitle': '在投递状态变为已送达、退信或失败时,向你的 HTTPS 端点推送通知。',
  304. 'webhooks.create': '新建 Webhook',
  305. 'webhooks.createTitle': '新建 Webhook',
  306. 'webhooks.editTitle': '编辑 Webhook',
  307. 'webhooks.name': '名称',
  308. 'webhooks.namePlaceholder': 'Production deliveries',
  309. 'webhooks.nameRequired': '请输入 Webhook 名称',
  310. 'webhooks.url': '回调 URL',
  311. 'webhooks.urlPlaceholder': 'https://example.com/webhooks/mailhub',
  312. 'webhooks.urlRequired': '请输入回调 URL',
  313. 'webhooks.urlHint': '生产环境请使用 HTTPS。签名校验使用 X-MailHub-Signature 请求头。',
  314. 'webhooks.events': '订阅事件',
  315. 'webhooks.eventsRequired': '请至少选择一个事件',
  316. 'webhooks.eventSent': '已送达',
  317. 'webhooks.eventBounced': '已退信',
  318. 'webhooks.eventFailed': '失败',
  319. 'webhooks.enabled': '启用',
  320. 'webhooks.disabled': '已停用',
  321. 'webhooks.scope': '作用域',
  322. 'webhooks.scopeAccount': '账号级',
  323. 'webhooks.scopeDomain': '域名级',
  324. 'webhooks.domain': '域名',
  325. 'webhooks.domainAccount': '整个账号',
  326. 'webhooks.domainOverrideHelp': '若某域名对某一事件存在任何已启用的端点,则该事件不会再投递到账号级端点。',
  327. 'webhooks.secret': '签名密钥',
  328. 'webhooks.secretPrefix': '密钥前缀',
  329. 'webhooks.secretCreatedTitle': 'Webhook 密钥已创建',
  330. 'webhooks.secretRotatedTitle': 'Webhook 密钥已轮换',
  331. 'webhooks.secretCreatedWarning': '完整密钥只会显示这一次。关闭后无法再次查看,请立即复制并保存到安全位置。',
  332. 'webhooks.copySecret': '复制完整密钥',
  333. 'webhooks.rotateSecret': '轮换密钥',
  334. 'webhooks.rotateConfirm': '确认轮换该 Webhook 的签名密钥?旧密钥将立即失效。',
  335. 'webhooks.test': '发送测试',
  336. 'webhooks.testQueued': '测试投递已入队',
  337. 'webhooks.deleteConfirm': '确认删除该 Webhook?相关投递记录也会一并删除。',
  338. 'webhooks.empty': '暂无 Webhook。创建后即可接收投递状态回调。',
  339. 'webhooks.listTitle': '端点列表',
  340. 'webhooks.actions': '操作',
  341. 'webhooks.deliveriesTitle': '投递记录',
  342. 'webhooks.deliveriesEmpty': '暂无投递记录',
  343. 'webhooks.deliveriesFilterWebhook': '按 Webhook 筛选',
  344. 'webhooks.deliveriesFilterStatus': '按状态筛选',
  345. 'webhooks.deliveriesFilterEvent': '按事件筛选',
  346. 'webhooks.allWebhooks': '全部 Webhook',
  347. 'webhooks.allStatuses': '全部状态',
  348. 'webhooks.allEvents': '全部事件',
  349. 'webhooks.statusPending': '待投递',
  350. 'webhooks.statusProcessing': '投递中',
  351. 'webhooks.statusSuccess': '成功',
  352. 'webhooks.statusDead': '已放弃',
  353. 'webhooks.attemptCount': '尝试次数',
  354. 'webhooks.responseStatus': 'HTTP 状态',
  355. 'webhooks.error': '错误',
  356. 'webhooks.replay': '重放',
  357. 'webhooks.replaySuccess': '投递已重新入队',
  358. 'webhooks.lastAttemptAt': '最近尝试',
  359. 'webhooks.nextAttemptAt': '下次尝试',
  360. 'webhooks.createdAt': '创建时间',
  361. 'webhooks.viewDeliveries': '查看投递',
  362. 'webhooks.docsTitle': '回调说明',
  363. 'webhooks.docsSignature': '使用 HMAC-SHA256 校验请求体;签名放在 X-MailHub-Signature。',
  364. 'webhooks.docsEvents': '事件类型:sent、bounced、failed(终端状态)。',
  365. 'testMail.title': '发送测试邮件',
  366. 'testMail.fromRequired': '请输入发件人',
  367. 'testMail.toRequired': '请输入收件人',
  368. 'actions.domainCreated': '域名已创建',
  369. 'actions.dnsCheckCompleted': 'DNS 检查已完成',
  370. 'actions.dnsCheckRefreshed': 'DNS 检查已刷新',
  371. 'actions.dnsApplyCompleted': 'DNS 写入请求已完成',
  372. 'actions.dnsApplyPartial': 'DNS 写入部分失败',
  373. 'actions.domainSaved': '域名配置已保存',
  374. 'actions.domainDeleted': '域名已删除',
  375. 'actions.testMailQueued': '已提交到发信队列',
  376. 'actions.dnsApiCreated': 'DNS API 已新增',
  377. 'actions.dnsApiUpdated': 'DNS API 已更新',
  378. 'actions.dnsApiDeleted': 'DNS API 已删除',
  379. 'actions.dnsApiTestCompleted': '连接测试完成',
  380. 'actions.smtpCreated': 'SMTP 登录凭据已新增',
  381. 'actions.smtpUpdated': 'SMTP 登录凭据已更新',
  382. 'actions.smtpDeleted': 'SMTP 登录凭据已删除',
  383. 'actions.smtpRelayCreated': 'SMTP 出口已新增',
  384. 'actions.smtpRelayUpdated': 'SMTP 出口已更新',
  385. 'actions.smtpRelayDeleted': 'SMTP 出口已删除',
  386. 'actions.settingsSaved': '系统设置已保存',
  387. 'actions.webhookCreated': 'Webhook 已创建',
  388. 'actions.webhookUpdated': 'Webhook 已更新',
  389. 'actions.webhookDeleted': 'Webhook 已删除',
  390. 'actions.webhookSecretRotated': 'Webhook 密钥已轮换',
  391. 'actions.webhookTestQueued': 'Webhook 测试已入队',
  392. 'actions.webhookDeliveryReplayed': 'Webhook 投递已重放',
  393. 'nav.dashboard': '仪表盘',
  394. 'nav.domains': '发信域名',
  395. 'nav.dnsApi': 'DNS API',
  396. 'nav.smtp': 'SMTP 凭据',
  397. 'nav.tokens': 'API Token',
  398. 'nav.logs': '发送记录',
  399. 'nav.webhooks': 'Webhooks',
  400. 'nav.admin': '管理员',
  401. 'nav.settings': '系统设置',
  402. 'nav.group.overview': '概览',
  403. 'nav.group.delivery': '投递',
  404. 'nav.group.system': '系统'
  405. },
  406. 'en-US': {
  407. 'common.account': 'Account',
  408. 'common.addDomain': 'Add Domain',
  409. 'common.cancel': 'Cancel',
  410. 'common.confirm': 'Confirm',
  411. 'common.copy': 'Copy',
  412. 'common.copied': 'Copied',
  413. 'common.delete': 'Delete',
  414. 'common.details': 'Details',
  415. 'common.error': 'Operation failed',
  416. 'common.loadingConfig': 'Loading runtime config',
  417. 'common.logout': 'Log out',
  418. 'common.manual': 'Manual',
  419. 'common.next': 'Next',
  420. 'common.notConfigured': 'Not configured',
  421. 'common.notFound': 'None',
  422. 'common.previous': 'Previous',
  423. 'common.refresh': 'Refresh',
  424. 'common.save': 'Save',
  425. 'common.status': 'Status',
  426. 'common.user': 'User',
  427. 'common.unsetSendingIp': 'Sending IP not set',
  428. 'auth.email': 'Email',
  429. 'auth.emailPlaceholder': 'name@example.com',
  430. 'auth.backToLogin': 'Back to sign in',
  431. 'auth.forgotPassword': 'Forgot password?',
  432. 'auth.forgotPasswordButton': 'Send reset email',
  433. 'auth.forgotPasswordTitle': 'Recover password',
  434. 'auth.login': 'Sign in',
  435. 'auth.loginEyebrow': 'Sign in',
  436. 'auth.loginTitle': 'Sign in to console',
  437. 'auth.newPassword': 'New password',
  438. 'auth.password': 'Password',
  439. 'auth.register': 'Register',
  440. 'auth.registerButton': 'Create account',
  441. 'auth.registerEyebrow': 'Register',
  442. 'auth.registerTitle': 'Create account',
  443. 'auth.resendVerification': 'Resend verification email',
  444. 'auth.resendVerificationButton': 'Send verification email',
  445. 'auth.resendVerificationTitle': 'Resend verification email',
  446. 'auth.resetPasswordButton': 'Reset password',
  447. 'auth.resetPasswordTitle': 'Reset password',
  448. 'auth.resetTokenMissing': 'The reset link is missing a token. Please request a new password reset.',
  449. 'auth.submitLogin': 'Sign in',
  450. 'auth.username': 'Username',
  451. 'auth.usernameOrEmail': 'Username or email',
  452. 'auth.valueDns': 'DNS automation',
  453. 'auth.valueIsolation': 'User isolation',
  454. 'auth.valueObservability': 'Delivery visibility',
  455. 'auth.subtitle': 'One console for sending domains, DNS, SMTP, and API tokens',
  456. 'auth.requestFailed': 'Request failed.',
  457. 'dashboard.title': 'Analytics',
  458. 'dashboard.verifiedDomains': 'Verified domains',
  459. 'dashboard.todaySent': 'Sent today',
  460. 'dashboard.successRate': 'Success rate',
  461. 'dashboard.bounceRate': 'Bounce rate',
  462. 'dashboard.complaintRate': 'Complaint rate',
  463. 'dashboard.lastSentAt': 'Last sent',
  464. 'dashboard.dnsIssues': 'DNS issues',
  465. 'dashboard.smtpStatus': 'SMTP status',
  466. 'dashboard.smtpReady': 'Ready',
  467. 'dashboard.smtpNotConfigured': 'Not configured',
  468. 'dashboard.trend': 'Sending trend',
  469. 'dashboard.statusDistribution': 'Status distribution',
  470. 'dashboard.domainRanking': 'Domain ranking',
  471. 'dashboard.domainHealth': 'Domain health',
  472. 'dashboard.hourlyHeatmap': 'Hourly distribution',
  473. 'dashboard.recentFailures': 'Recent failures',
  474. 'dashboard.recentLogs': 'Recent sending logs',
  475. 'dashboard.noTrend': 'No trend data yet',
  476. 'dashboard.noDomains': 'No domains yet',
  477. 'dashboard.noFailures': 'No failures yet',
  478. 'dashboard.defaultPasswordWarning': 'The default admin password is still in use. Update .env and restart the service.',
  479. 'dashboard.acceptedMail': 'Accepted mail',
  480. 'dashboard.failedMail': 'Failed mail',
  481. 'dashboard.dnsActionHint': 'Handle domains with DNS issues first to protect delivery for new senders.',
  482. 'dashboard.statusQueued': 'Accepted',
  483. 'dashboard.statusFailed': 'Failed',
  484. 'dashboard.statusUnknown': 'Unknown',
  485. 'domains.title': 'Sending domains',
  486. 'domains.domain': 'Domain',
  487. 'domains.senderHost': 'Sending host',
  488. 'domains.sendingIp': 'Sending IP',
  489. 'domains.dnsApi': 'DNS API',
  490. 'domains.smtp': 'SMTP',
  491. 'domains.lastSent': 'Last sent',
  492. 'domains.overallStatus': 'Overall status',
  493. 'domains.actions': 'Actions',
  494. 'domains.searchPlaceholder': 'Search domain or sending host',
  495. 'domains.statusPlaceholder': 'Overall status',
  496. 'domains.healthy': 'Healthy',
  497. 'domains.pending': 'Pending',
  498. 'domains.needsAction': 'Needs action',
  499. 'domains.waitingDns': 'Waiting for DNS',
  500. 'domains.sendable': 'Sendable',
  501. 'domains.waitingVerify': 'Waiting verification',
  502. 'domains.oneClickDns': 'One-click DNS',
  503. 'domains.check': 'Check',
  504. 'domains.test': 'Test',
  505. 'domains.deleteConfirm': 'Delete this domain?',
  506. 'domainDetail.back': 'Back to domains',
  507. 'domainDetail.overview': 'Domain overview',
  508. 'domainDetail.danger': 'Danger zone',
  509. 'domainDetail.deleteHint': 'Deleting the domain removes MailHub configuration, but does not delete records at your DNS provider.',
  510. 'domainDetail.editTitle': 'Edit domain settings',
  511. 'domainDetail.lastCheck': 'Last check',
  512. 'domainDetail.notChecked': 'Not checked',
  513. 'domainDetail.noDnsResult': 'No DNS check result yet',
  514. 'domainDetail.currentDnsResult': 'Current DNS results',
  515. 'domainDetail.recheckAll': 'Recheck all',
  516. 'domainDetail.copyAll': 'Copy all records',
  517. 'domainDetail.noPublicDns': 'No public DNS query data',
  518. 'domainDetail.notFoundRecord': 'Not found',
  519. 'domainDetail.needAttention': 'Needs attention',
  520. 'domainDetail.noSmtpPassword': 'Reset it on the SMTP page before copying',
  521. 'domainDetail.noApiToken': 'No token yet',
  522. 'domainDetail.apiExample': 'Sending API example',
  523. 'domainDetail.placeholder': 'configuration will be connected in a later version',
  524. 'dnsRecord.hostname': 'Hostname',
  525. 'dnsRecord.targetValue': 'Target value',
  526. 'dnsRecord.currentValue': 'Current value',
  527. 'dnsRecord.emptyCurrent': 'No record found',
  528. 'dnsRecord.ptrHint': 'PTR is usually configured at your server, cloud, or IP provider. DNS APIs usually cannot write it directly.',
  529. 'dnsRecord.recheck': 'Recheck',
  530. 'dnsRecord.copyLabel': 'Copy',
  531. 'dnsRecord.rootTxt': 'Root TXT',
  532. 'dnsRecord.verificationTxt': 'Verification TXT',
  533. 'dnsRecord.dkimTxt': 'DKIM TXT',
  534. 'dnsRecord.dmarcTxt': 'DMARC TXT',
  535. 'dnsRecord.senderA': 'Sending host A',
  536. 'dnsRecord.ptr': 'Sending IP PTR',
  537. 'domainHealth.sendingDomain': 'Sending domain',
  538. 'domainHealth.dnsProgress': 'DNS check progress',
  539. 'domainHealth.passed': 'passed',
  540. 'domainHealth.dnsIssues': 'DNS issues',
  541. 'domainHealth.dnsApi': 'DNS API',
  542. 'domainHealth.oneClickDns': 'Configure DNS',
  543. 'domainHealth.checkNow': 'Check now',
  544. 'domainHealth.sendTest': 'Send test email',
  545. 'domainHealth.edit': 'Edit settings',
  546. 'addDomain.title': 'Add sending domain',
  547. 'addDomain.stepDomain': 'Domain',
  548. 'addDomain.stepDns': 'DNS method',
  549. 'addDomain.stepPolicy': 'DKIM / SPF / DMARC',
  550. 'addDomain.stepConfirm': 'Confirm',
  551. 'addDomain.create': 'Create domain',
  552. 'addDomain.domainExtra': 'Use the root domain without http, paths, or email addresses.',
  553. 'addDomain.domainRequired': 'Enter the sending domain',
  554. 'addDomain.senderHostRequired': 'Enter the sending host',
  555. 'addDomain.sendingIpRequired': 'Enter the sending IP',
  556. 'addDomain.dnsExtra': 'You can create the domain without a credential and configure DNS manually later.',
  557. 'addDomain.manualDns': 'Manual DNS',
  558. 'addDomain.dnsHint': 'With a DNS API credential, the detail page can write verification, DKIM, SPF, DMARC, and sending host A records.',
  559. 'addDomain.selectorRequired': 'Enter the DKIM selector',
  560. 'addDomain.spfExtra': 'Third-party SPF includes',
  561. 'addDomain.generatedTitle': 'MailHub will generate',
  562. 'addDomain.recordVerification': 'Domain verification TXT',
  563. 'addDomain.recordDkim': 'DKIM TXT',
  564. 'addDomain.recordSpf': 'SPF TXT',
  565. 'addDomain.recordDmarc': 'DMARC TXT',
  566. 'addDomain.recordSenderA': 'Sending host A record',
  567. 'addDomain.recordPtr': 'PTR reverse DNS check hint',
  568. 'addDomain.immediateCheck': 'Check DNS immediately after creation',
  569. 'logs.title': 'Sending logs',
  570. 'logs.time': 'Time',
  571. 'logs.recipient': 'Recipient',
  572. 'logs.domain': 'Sending domain',
  573. 'logs.errorReason': 'Error reason',
  574. 'logs.viewDetail': 'View detail',
  575. 'logs.domainPlaceholder': 'Sending domain',
  576. 'logs.statusPlaceholder': 'Status',
  577. 'logs.recipientPlaceholder': 'Search recipient',
  578. 'logs.detailTitle': 'Sending detail',
  579. 'logs.deliveryLog': 'Full delivery log',
  580. 'logs.copyDeliveryLog': 'Copy delivery log',
  581. 'logs.noDeliveryLog': 'No structured delivery log. This may be a historical event.',
  582. 'logs.sender': 'Sender',
  583. 'logs.subject': 'Subject',
  584. 'logs.messageId': 'Message ID',
  585. 'logs.finalResponse': 'Final response',
  586. 'logs.messageBytes': 'Message bytes',
  587. 'logs.queueId': 'Postfix Queue ID',
  588. 'logs.deliveredAt': 'Delivered at',
  589. 'logs.deliveryAttempts': 'Delivery attempts',
  590. 'logs.noDeliveryAttempts': 'No final delivery receipt yet. The message may still be queued or historical.',
  591. 'logs.statusQueued': 'Queued',
  592. 'logs.statusSent': 'Sent',
  593. 'logs.statusDeferred': 'Deferred',
  594. 'logs.statusBounced': 'Bounced',
  595. 'logs.statusFailed': 'Failed',
  596. 'smtp.connectionTitle': 'SMTP connection',
  597. 'smtp.loginCredentialsTitle': 'Sending login credentials',
  598. 'smtp.username': 'Username',
  599. 'smtp.password': 'Password',
  600. 'smtp.usernameRequired': 'Enter SMTP username',
  601. 'smtp.passwordRequired': 'Enter SMTP password',
  602. 'smtp.passwordSet': 'Set',
  603. 'smtp.passwordEmpty': 'Empty',
  604. 'smtp.passwordUnavailable': 'Reset before copying',
  605. 'smtp.create': 'New credential',
  606. 'smtp.createTitle': 'New sending login credential',
  607. 'smtp.editTitle': 'Edit sending login credential',
  608. 'smtp.deleteConfirm': 'Delete this SMTP login credential?',
  609. 'smtp.passwordExtra': 'Leave empty to keep the current password. Copy the current password from the connection section above.',
  610. 'smtp.regenerate': 'Regenerate password',
  611. 'smtp.resetToCopy': 'Reset before copying',
  612. 'smtpRelay.title': 'Advanced: external SMTP relays',
  613. 'smtpRelay.create': 'New relay',
  614. 'smtpRelay.createTitle': 'New outbound SMTP relay',
  615. 'smtpRelay.editTitle': 'Edit outbound SMTP relay',
  616. 'smtpRelay.name': 'Name',
  617. 'smtpRelay.nameRequired': 'Enter the relay name',
  618. 'smtpRelay.server': 'Server',
  619. 'smtpRelay.hostRequired': 'Enter SMTP Host',
  620. 'smtpRelay.portRequired': 'Enter SMTP Port',
  621. 'smtpRelay.username': 'Username',
  622. 'smtpRelay.password': 'Password',
  623. 'smtpRelay.passwordSet': 'Set',
  624. 'smtpRelay.passwordEmpty': 'Empty',
  625. 'smtpRelay.passwordExtra': 'Saved passwords are shown when editing. Save an empty value to remove the password.',
  626. 'smtpRelay.generatePassword': 'Generate password',
  627. 'smtpRelay.heloExtra': 'Leave empty to use the system default HELO.',
  628. 'smtpRelay.default': 'Default',
  629. 'smtpRelay.domainDefault': 'Default outbound SMTP relay',
  630. 'smtpRelay.domainDefaultExtra': 'When empty, MailHub uses request relay, user default relay, then system SMTP.',
  631. 'smtpRelay.useResolutionOrder': 'Use default selection order',
  632. 'smtpRelay.deleteConfirm': 'Delete this SMTP relay? Bound domains will fall back to the default selection order.',
  633. 'dnsApi.title': 'DNS API credentials',
  634. 'dnsApi.createTitle': 'New DNS API',
  635. 'dnsApi.editTitle': 'Edit',
  636. 'dnsApi.zone': 'Zone / root domain',
  637. 'dnsApi.zoneRequired': 'Enter the Zone or root domain',
  638. 'dnsApi.cloudflareZoneExtra': 'For Cloudflare, use any accessible Zone for testing. One-click DNS matches the current sending domain automatically.',
  639. 'dnsApi.tokenExtra': 'Requires Zone DNS Edit permission.',
  640. 'dnsApi.keepSecret': 'Leave empty to keep the existing secret.',
  641. 'dnsApi.save': 'Save changes',
  642. 'dnsApi.create': 'Create credential',
  643. 'dnsApi.secretHint': 'Secrets are encrypted server-side and never shown in the list.',
  644. 'settings.checkItem': 'Check',
  645. 'settings.deliveryChecks': 'Sending Environment Checks',
  646. 'settings.noPermission': 'This account cannot access system settings.',
  647. 'settings.save': 'Save settings',
  648. 'admin.title': 'Admin Panel',
  649. 'admin.users': 'Users',
  650. 'admin.resources': 'Resources',
  651. 'admin.migration': 'Merge',
  652. 'admin.systemEmail': 'System Email',
  653. 'admin.auditLogs': 'Audit Logs',
  654. 'metrics.accepted': 'Accepted',
  655. 'metrics.failed': 'Failed',
  656. 'metrics.recipients': 'Recipients',
  657. 'metrics.total': 'Total',
  658. 'status.success': 'Passed',
  659. 'status.pending': 'Pending',
  660. 'status.error': 'Misconfigured',
  661. 'status.idle': 'Not configured',
  662. 'tokens.createTitle': 'Create API Token',
  663. 'tokens.name': 'Name',
  664. 'tokens.namePlaceholder': 'Production API',
  665. 'tokens.nameRequired': 'Enter a token name',
  666. 'tokens.create': 'Create Token',
  667. 'tokens.listTitle': 'API Tokens',
  668. 'tokens.prefix': 'Token Prefix',
  669. 'tokens.fullToken': 'Full Token',
  670. 'tokens.copyFull': 'Copy full token',
  671. 'tokens.copyPrefix': 'Copy prefix',
  672. 'tokens.createdTitle': 'API Token created',
  673. 'tokens.createdWarning': 'The full token is shown only once. Copy it now and store it somewhere secure.',
  674. 'tokens.createdSuccess': 'Token created',
  675. 'tokens.deletedSuccess': 'Token deleted',
  676. 'tokens.secretUnavailable': 'Full token is only shown at creation time',
  677. 'tokens.lastUsed': 'Last used',
  678. 'tokens.neverUsed': 'Never used',
  679. 'tokens.createdAt': 'Created at',
  680. 'tokens.actions': 'Actions',
  681. 'tokens.deleteConfirm': 'Delete this token?',
  682. 'tokens.copyCreated': 'Copy full token',
  683. 'tokens.prefixOnlyHelp': 'Historical tokens do not store plaintext. The prefix is only for identification.',
  684. 'tokens.docsTitle': 'Sending API guide',
  685. 'tokens.endpoint': 'API Endpoint',
  686. 'tokens.authHeader': 'Authentication',
  687. 'tokens.authHeaderValue': 'Authorization: Bearer <USER_API_TOKEN>',
  688. 'tokens.contentType': 'Content-Type',
  689. 'tokens.requestFields': 'Request fields',
  690. 'tokens.fieldFrom': 'from: sender address. The domain must be added and verified.',
  691. 'tokens.fieldTo': 'to: recipient address. Single email or an array of emails.',
  692. 'tokens.fieldSubject': 'subject: email subject.',
  693. 'tokens.fieldText': 'text: plain text body.',
  694. 'tokens.fieldHtml': 'html: optional HTML body.',
  695. 'tokens.curlExample': 'curl example',
  696. 'tokens.nodeExample': 'Node / Fetch example',
  697. 'tokens.requestExample': 'Request body example',
  698. 'tokens.responseExample': 'Success response example',
  699. 'tokens.securityTips': 'Security tips',
  700. 'tokens.securityTipStore': 'Store tokens only on the server side. Do not put them in browser code or public repositories.',
  701. 'tokens.securityTipRotate': 'Use separate tokens per environment. Delete and recreate immediately after a leak.',
  702. 'tokens.securityTipDomain': 'The From domain must belong to this account. Verify DNS before production sending.',
  703. 'tokens.noTokenHint': 'Copy the full secret right after creation. Historical tokens show prefixes only, so examples use a placeholder.',
  704. 'webhooks.title': 'Webhooks',
  705. 'webhooks.subtitle': 'Push delivery updates to your HTTPS endpoint when mail is sent, bounced, or failed.',
  706. 'webhooks.create': 'Create webhook',
  707. 'webhooks.createTitle': 'Create webhook',
  708. 'webhooks.editTitle': 'Edit webhook',
  709. 'webhooks.name': 'Name',
  710. 'webhooks.namePlaceholder': 'Production deliveries',
  711. 'webhooks.nameRequired': 'Enter a webhook name',
  712. 'webhooks.url': 'Callback URL',
  713. 'webhooks.urlPlaceholder': 'https://example.com/webhooks/mailhub',
  714. 'webhooks.urlRequired': 'Enter a callback URL',
  715. 'webhooks.urlHint': 'Use HTTPS in production. Verify requests with the X-MailHub-Signature header.',
  716. 'webhooks.events': 'Events',
  717. 'webhooks.eventsRequired': 'Select at least one event',
  718. 'webhooks.eventSent': 'Sent',
  719. 'webhooks.eventBounced': 'Bounced',
  720. 'webhooks.eventFailed': 'Failed',
  721. 'webhooks.enabled': 'Enabled',
  722. 'webhooks.disabled': 'Disabled',
  723. 'webhooks.scope': 'Scope',
  724. 'webhooks.scopeAccount': 'Account',
  725. 'webhooks.scopeDomain': 'Domain',
  726. 'webhooks.domain': 'Domain',
  727. 'webhooks.domainAccount': 'Entire account',
  728. 'webhooks.domainOverrideHelp': 'If this domain has any enabled endpoint for an event, account-level endpoints for that event are skipped.',
  729. 'webhooks.secret': 'Signing secret',
  730. 'webhooks.secretPrefix': 'Secret prefix',
  731. 'webhooks.secretCreatedTitle': 'Webhook secret created',
  732. 'webhooks.secretRotatedTitle': 'Webhook secret rotated',
  733. 'webhooks.secretCreatedWarning': 'The full secret is shown only once. Copy it now and store it somewhere secure.',
  734. 'webhooks.copySecret': 'Copy full secret',
  735. 'webhooks.rotateSecret': 'Rotate secret',
  736. 'webhooks.rotateConfirm': 'Rotate this webhook signing secret? The previous secret stops working immediately.',
  737. 'webhooks.test': 'Send test',
  738. 'webhooks.testQueued': 'Test delivery queued',
  739. 'webhooks.deleteConfirm': 'Delete this webhook? Related delivery records will also be removed.',
  740. 'webhooks.empty': 'No webhooks yet. Create one to receive delivery status callbacks.',
  741. 'webhooks.listTitle': 'Endpoints',
  742. 'webhooks.actions': 'Actions',
  743. 'webhooks.deliveriesTitle': 'Deliveries',
  744. 'webhooks.deliveriesEmpty': 'No deliveries yet',
  745. 'webhooks.deliveriesFilterWebhook': 'Filter by webhook',
  746. 'webhooks.deliveriesFilterStatus': 'Filter by status',
  747. 'webhooks.deliveriesFilterEvent': 'Filter by event',
  748. 'webhooks.allWebhooks': 'All webhooks',
  749. 'webhooks.allStatuses': 'All statuses',
  750. 'webhooks.allEvents': 'All events',
  751. 'webhooks.statusPending': 'Pending',
  752. 'webhooks.statusProcessing': 'Processing',
  753. 'webhooks.statusSuccess': 'Success',
  754. 'webhooks.statusDead': 'Dead',
  755. 'webhooks.attemptCount': 'Attempts',
  756. 'webhooks.responseStatus': 'HTTP status',
  757. 'webhooks.error': 'Error',
  758. 'webhooks.replay': 'Replay',
  759. 'webhooks.replaySuccess': 'Delivery re-queued',
  760. 'webhooks.lastAttemptAt': 'Last attempt',
  761. 'webhooks.nextAttemptAt': 'Next attempt',
  762. 'webhooks.createdAt': 'Created at',
  763. 'webhooks.viewDeliveries': 'View deliveries',
  764. 'webhooks.docsTitle': 'Callback notes',
  765. 'webhooks.docsSignature': 'Verify the body with HMAC-SHA256; the signature is in X-MailHub-Signature.',
  766. 'webhooks.docsEvents': 'Event types: sent, bounced, and failed (terminal statuses).',
  767. 'testMail.title': 'Send test email',
  768. 'testMail.fromRequired': 'Enter the sender',
  769. 'testMail.toRequired': 'Enter the recipient',
  770. 'actions.domainCreated': 'Domain created',
  771. 'actions.dnsCheckCompleted': 'DNS check completed',
  772. 'actions.dnsCheckRefreshed': 'DNS check refreshed',
  773. 'actions.dnsApplyCompleted': 'DNS write request completed',
  774. 'actions.dnsApplyPartial': 'DNS write partially failed',
  775. 'actions.domainSaved': 'Domain settings saved',
  776. 'actions.domainDeleted': 'Domain deleted',
  777. 'actions.testMailQueued': 'Submitted to sending queue',
  778. 'actions.dnsApiCreated': 'DNS API created',
  779. 'actions.dnsApiUpdated': 'DNS API updated',
  780. 'actions.dnsApiDeleted': 'DNS API deleted',
  781. 'actions.dnsApiTestCompleted': 'Connection test completed',
  782. 'actions.smtpCreated': 'SMTP login credential created',
  783. 'actions.smtpUpdated': 'SMTP login credential updated',
  784. 'actions.smtpDeleted': 'SMTP login credential deleted',
  785. 'actions.smtpRelayCreated': 'SMTP relay created',
  786. 'actions.smtpRelayUpdated': 'SMTP relay updated',
  787. 'actions.smtpRelayDeleted': 'SMTP relay deleted',
  788. 'actions.settingsSaved': 'System settings saved',
  789. 'actions.webhookCreated': 'Webhook created',
  790. 'actions.webhookUpdated': 'Webhook updated',
  791. 'actions.webhookDeleted': 'Webhook deleted',
  792. 'actions.webhookSecretRotated': 'Webhook secret rotated',
  793. 'actions.webhookTestQueued': 'Webhook test queued',
  794. 'actions.webhookDeliveryReplayed': 'Webhook delivery replayed',
  795. 'nav.dashboard': 'Dashboard',
  796. 'nav.domains': 'Domains',
  797. 'nav.dnsApi': 'DNS API',
  798. 'nav.smtp': 'SMTP Credentials',
  799. 'nav.tokens': 'API Tokens',
  800. 'nav.logs': 'Sending Logs',
  801. 'nav.webhooks': 'Webhooks',
  802. 'nav.admin': 'Admin',
  803. 'nav.settings': 'Settings',
  804. 'nav.group.overview': 'Overview',
  805. 'nav.group.delivery': 'Delivery',
  806. 'nav.group.system': 'System'
  807. }
  808. };
  809. export function normalizeLocale(locale = DEFAULT_LOCALE) {
  810. const value = String(locale || '').trim();
  811. if (supportedLocales.includes(value)) return value;
  812. const lower = value.toLowerCase();
  813. if (lower.startsWith('zh')) return 'zh-CN';
  814. if (lower.startsWith('en')) return 'en-US';
  815. return DEFAULT_LOCALE;
  816. }
  817. export function createTranslator(locale = DEFAULT_LOCALE) {
  818. const normalized = normalizeLocale(locale);
  819. return (key) => messages[normalized]?.[key] || messages[DEFAULT_LOCALE]?.[key] || key;
  820. }
  821. export function getLocaleLabel(locale) {
  822. return {
  823. 'zh-CN': '简体中文',
  824. 'en-US': 'English'
  825. }[normalizeLocale(locale)] || String(locale || DEFAULT_LOCALE);
  826. }