- 新增 internal/i18n 包:以原始中文字符串为 key 的翻译目录(zh 恒等, en 兜底,ja 缺译回退 en),t/tf 模板函数与 Accept-Language 解析 (按 q 值排序,兜底英语) - User 模型新增 language 字段(auto|en|zh|ja,默认 auto), AutoMigrate 自动加列;UserStore 新增 UpdateLanguage - 语言解析:登录用户按偏好(auto 时取浏览器 Accept-Language), 登录/封禁页按浏览器语言;所有 c.HTML 渲染注入 Lang 模板数据 - 全部页面模板(用户页 + 管理后台 12 页)接入翻译:导航、文件夹、 邮件列表/阅读/写信、设置、登录、封禁页、表单、表格、JS 确认框等; html lang 属性随语言切换;日期函数(shortDate/time12/time12m) 与 folderLabel 改为语言感知(上午/下午 vs AM/PM vs 午前/午後) - 设置页新增「界面语言」选择(自动/English/中文/日本語), /settings 表单支持单独提交语言偏好;管理后台用户表单可预设语言 - 封禁原因等入库中文文案在展示时经 t 翻译(未知 key 原样回退) - 测试:i18n 单测(解析/回退/译文)、render 测试补 Lang 数据、 时间格式化测试适配新签名;全量 go test 通过
122 lines
8.0 KiB
HTML
122 lines
8.0 KiB
HTML
{{define "view"}}
|
||
<!DOCTYPE html>
|
||
<html lang="{{htmlLang .Lang}}">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||
<title>{{t .Lang "查看邮件"}} - MailGo</title>
|
||
{{template "styles" .}}
|
||
</head>
|
||
<body class="page-view">
|
||
{{template "navbar" .}}
|
||
<div class="app-body">
|
||
{{template "sidebar" .}}
|
||
<main class="mail-main">
|
||
<div class="view-toolbar">
|
||
<a href="javascript:history.back()" class="tb-btn">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
|
||
{{t .Lang "返回"}}
|
||
</a>
|
||
<a href="/compose?to={{mailEmail .message.FromAddr}}&subject={{if .message.Subject}}Re: {{.message.Subject}}{{end}}" class="tb-btn">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>
|
||
{{t .Lang "回复"}}
|
||
</a>
|
||
{{if .inTrash}}
|
||
<form method="POST" action="/mail/restore/{{.message.ID}}" style="display:inline;">
|
||
<button type="submit" class="tb-btn">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>
|
||
{{t .Lang "恢复"}}
|
||
</button>
|
||
</form>
|
||
<form method="POST" action="/mail/purge/{{.message.ID}}" style="display:inline;"
|
||
onsubmit="return confirm('{{t .Lang "确定要彻底删除这封邮件吗?此操作不可恢复。"}}');">
|
||
<button type="submit" class="tb-btn danger">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
||
{{t .Lang "彻底删除"}}
|
||
</button>
|
||
</form>
|
||
{{else}}
|
||
<form method="POST" action="/mail/delete/{{.message.ID}}" style="display:inline;"
|
||
onsubmit="return confirm('{{t .Lang "确定要删除这封邮件吗?"}}');">
|
||
<button type="submit" class="tb-btn danger">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
||
{{t .Lang "删除"}}
|
||
</button>
|
||
</form>
|
||
{{end}}
|
||
</div>
|
||
|
||
<div class="mail-head">
|
||
<h1 class="mail-title">{{if .message.Subject}}{{.message.Subject}}{{else}}{{t .Lang "(无主题)"}}{{end}}</h1>
|
||
<div class="mail-from-row">
|
||
<span class="avatar" style="{{avatarStyle .message.FromAddr}}">{{initial (mailName (decodeHeader .message.FromAddr))}}</span>
|
||
<div>
|
||
<div class="mail-from-name">{{mailName (decodeHeader .message.FromAddr)}}</div>
|
||
<div class="mail-from-addr" title="{{decodeHeader .message.FromAddr}}">{{mailEmail .message.FromAddr}}</div>
|
||
</div>
|
||
<span class="mail-date">{{time12 .Lang .message.Date}}</span>
|
||
</div>
|
||
{{if .message.CcAddr}}
|
||
<div class="mail-from-addr" style="margin:-8px 0 16px 48px;">
|
||
{{t .Lang "抄送:"}}{{.message.CcAddr}}
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
<div class="mail-body-wrap">
|
||
<div class="mail-body">
|
||
{{if .message.HtmlBody}}
|
||
<iframe class="mail-body-iframe" srcdoc="{{.message.HtmlBody}}" sandbox="allow-same-origin" onload="this.style.height=this.contentDocument.body.scrollHeight+20+'px'"></iframe>
|
||
{{else}}
|
||
<pre>{{.message.TextBody}}</pre>
|
||
{{end}}
|
||
</div>
|
||
|
||
{{if .attachments}}
|
||
<div class="attachment-list">
|
||
{{range .attachments}}
|
||
<span class="attachment-item">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
|
||
<a href="/attachment/{{.ID}}">{{.FileName}}</a>
|
||
<span style="color:var(--text-3);font-size:12px;">({{formatBytes .FileSize}})</span>
|
||
</span>
|
||
{{end}}
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
<div class="view-actions">
|
||
<a href="/compose?to={{mailEmail .message.FromAddr}}&subject={{if .message.Subject}}Re: {{.message.Subject}}{{end}}" class="btn btn-primary">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px;"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>
|
||
{{t .Lang "回复"}}
|
||
</a>
|
||
{{if .inTrash}}
|
||
<form method="POST" action="/mail/restore/{{.message.ID}}" style="display:inline;">
|
||
<button type="submit" class="btn">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px;"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>
|
||
{{t .Lang "恢复到收件箱"}}
|
||
</button>
|
||
</form>
|
||
<form method="POST" action="/mail/purge/{{.message.ID}}" style="display:inline;"
|
||
onsubmit="return confirm('{{t .Lang "确定要彻底删除这封邮件吗?此操作不可恢复。"}}');">
|
||
<button type="submit" class="btn btn-danger">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px;"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
||
{{t .Lang "彻底删除"}}
|
||
</button>
|
||
</form>
|
||
{{else}}
|
||
<form method="POST" action="/mail/delete/{{.message.ID}}" style="display:inline;"
|
||
onsubmit="return confirm('{{t .Lang "确定要删除这封邮件吗?"}}');">
|
||
<button type="submit" class="btn btn-danger">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px;"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
||
{{t .Lang "删除邮件"}}
|
||
</button>
|
||
</form>
|
||
{{end}}
|
||
</div>
|
||
</main>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
{{end}}
|