🌐 dashboard v0.13.1 improve localization

This commit is contained in:
naiba 2022-04-30 09:32:57 +08:00
parent 9eb50a5b9d
commit 833519e974
25 changed files with 305 additions and 237 deletions

View File

@ -4,7 +4,7 @@
<br>
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
<br><br>
<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.13.0&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.9.1-brightgreen?style=for-the-badge&logo=linux">&nbsp;<a title="Crowdin" target="_blank" href="https://crowdin.com/project/nezha"><img src="https://badges.crowdin.net/nezha/localized.svg"></a>
<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.13.1&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.9.1-brightgreen?style=for-the-badge&logo=linux">&nbsp;<a title="Crowdin" target="_blank" href="https://crowdin.com/project/nezha"><img src="https://badges.crowdin.net/nezha/localized.svg"></a>
<br>
<br>
<p>:trollface: <b>Nezha Monitoring</b> One-stop light monitoring and light operation and maintenance system. Supports system status, HTTP (SSL certificate change, upcoming expiration, expiration), TCP, Ping monitoring and alarm, scheduled tasks and web terminal.</p>
@ -25,7 +25,7 @@
## User Guide
- [中文文档](docs/UserGuide_zh.md)
- [English](docs/UserGuide_en.md)
- [English](docs/UserGuide_en.md) WIP
## Special Thanks
@ -33,6 +33,6 @@
- [@Erope](https://github.com/JackieSung4ev) for contributed a lot to our installation scripts and community building.
- [@MikoyChinese](https://github.com/MikoyChinese) for our second community-contributed front-end theme.
- [@AkkiaS7](https://github.com/Akkia) and [hhhkkk520](https://github.com/hhhkkk520) for the excellent contribution in the early days of globalization.
- [@dysf888](https://gitub.com/dysf888) for the installation script in windows.
- [@dysf888](https://gitub.com/dysf888) for the installation script in Windows.
- [@MartijnLindeman](https://github.com/MartijnLindeman) for his perseverance has taken us to the international market.
- and other [contributors](https://github.com/naiba/nezha/graphs/contributors).

View File

@ -2,7 +2,6 @@ package controller
import (
"errors"
"fmt"
"log"
"net/http"
"regexp"
@ -14,6 +13,7 @@ import (
"github.com/gorilla/websocket"
"github.com/hashicorp/go-uuid"
"github.com/jinzhu/copier"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/crypto/bcrypt"
"golang.org/x/sync/singleflight"
@ -60,16 +60,18 @@ func (p *commonPage) issueViewPassword(c *gin.Context) {
err := c.ShouldBind(&vpf)
var hash []byte
if err == nil && vpf.Password != singleton.Conf.Site.ViewPassword {
err = errors.New("查看密码错误")
err = errors.New(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "WrongAccessPassword"}))
}
if err == nil {
hash, err = bcrypt.GenerateFromPassword([]byte(vpf.Password), bcrypt.DefaultCost)
}
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusOK,
Title: "出现错误",
Msg: fmt.Sprintf("请求错误:%s", err),
Code: http.StatusOK,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "AnErrorEccurred",
}),
Msg: err.Error(),
}, true)
c.Abort()
return
@ -92,7 +94,7 @@ func (p *commonPage) checkViewPassword(c *gin.Context) {
viewPassword, _ := c.Cookie(singleton.Conf.Site.CookieName + "-vp")
if err := bcrypt.CompareHashAndPassword([]byte(viewPassword), []byte(singleton.Conf.Site.ViewPassword)); err != nil {
c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/viewpassword", mygin.CommonEnvironment(c, gin.H{
"Title": "验证查看密码",
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "VerifyPassword"}),
"CustomCode": singleton.Conf.Site.CustomCode,
}))
c.Abort()
@ -116,7 +118,7 @@ func (p *commonPage) service(c *gin.Context) {
}, nil
})
c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/service", mygin.CommonEnvironment(c, gin.H{
"Title": "服务状态",
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesStatus"}),
"Services": res.([]interface{})[0],
"CycleTransferStats": res.([]interface{})[1],
"CustomCode": singleton.Conf.Site.CustomCode,
@ -139,11 +141,13 @@ func (cp *commonPage) home(c *gin.Context) {
stat, err := cp.getServerStat()
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: "系统错误",
Msg: "服务器状态获取失败",
Link: "/",
Btn: "返回首页",
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "SystemError",
}),
Msg: "服务器状态获取失败",
Link: "/",
Btn: "返回首页",
}, true)
return
}
@ -167,11 +171,13 @@ func (cp *commonPage) ws(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: "网络错误",
Msg: "Websocket协议切换失败",
Link: "/",
Btn: "返回首页",
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "NetowrkError",
}),
Msg: "Websocket协议切换失败",
Link: "/",
Btn: "返回首页",
}, true)
return
}
@ -312,11 +318,13 @@ func (cp *commonPage) terminal(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: "网络错误",
Msg: "Websocket协议切换失败",
Link: "/",
Btn: "返回首页",
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "NetowrkError",
}),
Msg: "Websocket协议切换失败",
Link: "/",
Btn: "返回首页",
}, true)
return
}
@ -447,11 +455,13 @@ func (cp *commonPage) createTerminal(c *gin.Context) {
id, err := uuid.GenerateUUID()
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: "系统错误",
Msg: "生成会话ID失败",
Link: "/server",
Btn: "返回重试",
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "SystemError",
}),
Msg: "生成会话ID失败",
Link: "/server",
Btn: "返回重试",
}, true)
return
}

View File

@ -26,116 +26,7 @@ func ServeWeb(port uint) *http.Server {
pprof.Register(r)
}
r.Use(mygin.RecordPath)
r.SetFuncMap(template.FuncMap{
"tr": func(id string, dataAndCount ...interface{}) string {
conf := i18n.LocalizeConfig{
MessageID: id,
}
if len(dataAndCount) > 0 {
conf.TemplateData = dataAndCount[0]
}
if len(dataAndCount) > 1 {
conf.PluralCount = dataAndCount[1]
}
return singleton.Localizer.MustLocalize(&conf)
},
"toValMap": func(val interface{}) map[string]interface{} {
return map[string]interface{}{
"Value": val,
}
},
"tf": func(t time.Time) string {
return t.In(singleton.Loc).Format("2006年1月2号 15:04:05")
},
"len": func(slice []interface{}) string {
return strconv.Itoa(len(slice))
},
"safe": func(s string) template.HTML {
return template.HTML(s) // #nosec
},
"tag": func(s string) template.HTML {
return template.HTML(`<` + s + `>`) // #nosec
},
"stf": func(s uint64) string {
return time.Unix(int64(s), 0).In(singleton.Loc).Format("2006年1月2号 15:04")
},
"sf": func(duration uint64) string {
return time.Duration(time.Duration(duration) * time.Second).String()
},
"sft": func(future time.Time) string {
return time.Until(future).Round(time.Second).String()
},
"bf": func(b uint64) string {
return bytefmt.ByteSize(b)
},
"ts": func(s string) string {
return strings.TrimSpace(s)
},
"float32f": func(f float32) string {
return fmt.Sprintf("%.2f", f)
},
"divU64": func(a, b uint64) float32 {
if b == 0 {
if a > 0 {
return 100
}
return 0
}
if a == 0 {
// 这是从未在线的情况
return 0.00001 / float32(b) * 100
}
return float32(a) / float32(b) * 100
},
"div": func(a, b int) float32 {
if b == 0 {
if a > 0 {
return 100
}
return 0
}
if a == 0 {
// 这是从未在线的情况
return 0.00001 / float32(b) * 100
}
return float32(a) / float32(b) * 100
},
"addU64": func(a, b uint64) uint64 {
return a + b
},
"add": func(a, b int) int {
return a + b
},
"dayBefore": func(i int) string {
year, month, day := time.Now().Date()
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
return today.AddDate(0, 0, i-29).Format("1月2号")
},
"className": func(percent float32) string {
if percent == 0 {
return ""
}
if percent > 95 {
return "good"
}
if percent > 80 {
return "warning"
}
return "danger"
},
"statusName": func(percent float32) string {
if percent == 0 {
return "无数据"
}
if percent > 95 {
return "良好"
}
if percent > 80 {
return "低可用"
}
return "故障"
},
})
r.SetFuncMap(funcMap)
r.Static("/static", "resource/static")
r.LoadHTMLGlob("resource/template/**/*.html")
routers(r)
@ -176,3 +67,114 @@ func routers(r *gin.Engine) {
ma.serve()
}
}
var funcMap = template.FuncMap{
"tr": func(id string, dataAndCount ...interface{}) string {
conf := i18n.LocalizeConfig{
MessageID: id,
}
if len(dataAndCount) > 0 {
conf.TemplateData = dataAndCount[0]
}
if len(dataAndCount) > 1 {
conf.PluralCount = dataAndCount[1]
}
return singleton.Localizer.MustLocalize(&conf)
},
"toValMap": func(val interface{}) map[string]interface{} {
return map[string]interface{}{
"Value": val,
}
},
"tf": func(t time.Time) string {
return t.In(singleton.Loc).Format("2006年1月2号 15:04:05")
},
"len": func(slice []interface{}) string {
return strconv.Itoa(len(slice))
},
"safe": func(s string) template.HTML {
return template.HTML(s) // #nosec
},
"tag": func(s string) template.HTML {
return template.HTML(`<` + s + `>`) // #nosec
},
"stf": func(s uint64) string {
return time.Unix(int64(s), 0).In(singleton.Loc).Format("2006年1月2号 15:04")
},
"sf": func(duration uint64) string {
return time.Duration(time.Duration(duration) * time.Second).String()
},
"sft": func(future time.Time) string {
return time.Until(future).Round(time.Second).String()
},
"bf": func(b uint64) string {
return bytefmt.ByteSize(b)
},
"ts": func(s string) string {
return strings.TrimSpace(s)
},
"float32f": func(f float32) string {
return fmt.Sprintf("%.2f", f)
},
"divU64": func(a, b uint64) float32 {
if b == 0 {
if a > 0 {
return 100
}
return 0
}
if a == 0 {
// 这是从未在线的情况
return 0.00001 / float32(b) * 100
}
return float32(a) / float32(b) * 100
},
"div": func(a, b int) float32 {
if b == 0 {
if a > 0 {
return 100
}
return 0
}
if a == 0 {
// 这是从未在线的情况
return 0.00001 / float32(b) * 100
}
return float32(a) / float32(b) * 100
},
"addU64": func(a, b uint64) uint64 {
return a + b
},
"add": func(a, b int) int {
return a + b
},
"dayBefore": func(i int) string {
year, month, day := time.Now().Date()
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
return today.AddDate(0, 0, i-29).Format("1月2号")
},
"className": func(percent float32) string {
if percent == 0 {
return ""
}
if percent > 95 {
return "good"
}
if percent > 80 {
return "warning"
}
return "danger"
},
"statusName": func(percent float32) string {
if percent == 0 {
return "无数据"
}
if percent > 95 {
return "良好"
}
if percent > 80 {
return "低可用"
}
return "故障"
},
}

View File

@ -4,6 +4,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/pkg/mygin"
@ -40,7 +41,7 @@ func (gp *guestPage) login(c *gin.Context) {
RegistrationLink = "https://gitee.com/signup"
}
c.HTML(http.StatusOK, "dashboard/login", mygin.CommonEnvironment(c, gin.H{
"Title": "登录",
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
"LoginType": LoginType,
"RegistrationLink": RegistrationLink,
}))

View File

@ -7,6 +7,7 @@ import (
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/pkg/mygin"
"github.com/naiba/nezha/service/singleton"
"github.com/nicksnyder/go-i18n/v2/i18n"
)
type memberPage struct {
@ -18,8 +19,8 @@ func (mp *memberPage) serve() {
mr.Use(mygin.Authorize(mygin.AuthorizeOption{
Member: true,
IsPage: true,
Msg: "此页面需要登录",
Btn: "点此登录",
Msg: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "YouAreNotAuthorized"}),
Btn: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
Redirect: "/login",
}))
mr.GET("/server", mp.server)
@ -33,14 +34,14 @@ func (mp *memberPage) server(c *gin.Context) {
singleton.SortedServerLock.RLock()
defer singleton.SortedServerLock.RUnlock()
c.HTML(http.StatusOK, "dashboard/server", mygin.CommonEnvironment(c, gin.H{
"Title": "服务器管理",
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServersManagement"}),
"Servers": singleton.SortedServerList,
}))
}
func (mp *memberPage) monitor(c *gin.Context) {
c.HTML(http.StatusOK, "dashboard/monitor", mygin.CommonEnvironment(c, gin.H{
"Title": "服务监控",
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesManagement"}),
"Monitors": singleton.ServiceSentinelShared.Monitors(),
}))
}
@ -49,7 +50,7 @@ func (mp *memberPage) cron(c *gin.Context) {
var crons []model.Cron
singleton.DB.Find(&crons)
c.HTML(http.StatusOK, "dashboard/cron", mygin.CommonEnvironment(c, gin.H{
"Title": "计划任务",
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ScheduledTasks"}),
"Crons": crons,
}))
}
@ -60,7 +61,7 @@ func (mp *memberPage) notification(c *gin.Context) {
var ar []model.AlertRule
singleton.DB.Find(&ar)
c.HTML(http.StatusOK, "dashboard/notification", mygin.CommonEnvironment(c, gin.H{
"Title": "报警通知",
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Notification"}),
"Notifications": nf,
"AlertRules": ar,
}))
@ -68,6 +69,6 @@ func (mp *memberPage) notification(c *gin.Context) {
func (mp *memberPage) setting(c *gin.Context) {
c.HTML(http.StatusOK, "dashboard/setting", mygin.CommonEnvironment(c, gin.H{
"Title": "系统设置",
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Settings"}),
}))
}

View File

@ -1,51 +1,5 @@
package main
import (
"fmt"
"github.com/naiba/nezha/service/singleton"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
)
func htmlTemplateTranslateFn(id string, data interface{}, count interface{}) string {
return singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: id,
TemplateData: data,
PluralCount: count,
})
}
func main() {
singleton.InitConfigFromPath("data/config.yaml")
singleton.InitLocalizer()
fmt.Println(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "nezhaMonitor",
}))
fmt.Println(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "nezhaMonitor",
}))
fmt.Println("tr nezhaMonitor", htmlTemplateTranslateFn("nezhaMonitor", nil, nil))
fmt.Println("tr nezhaMonitor", htmlTemplateTranslateFn("nezhaMonitor", nil, 2))
fmt.Println("tr nezhaMonitor", htmlTemplateTranslateFn("nezhaMonitor", map[string]string{
"Ext": "Plus",
}, 2))
bundle := i18n.NewBundle(language.English)
localizer := i18n.NewLocalizer(bundle, "en")
catsMessage := &i18n.Message{
ID: "Cats",
One: "I have {{.PluralCount}} cat.",
Other: "I have {{.PluralCount}} cats.",
}
fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
DefaultMessage: catsMessage,
PluralCount: 1,
}))
fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
DefaultMessage: catsMessage,
PluralCount: 2,
}))
}

View File

@ -5,6 +5,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/service/singleton"
@ -34,6 +35,15 @@ func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
if ok {
data["Admin"] = u
}
data["LANG"] = map[string]string{
"Add": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Add"}),
"Edit": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Edit"}),
"AlarmRule": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "AlarmRule"}),
"Notification": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "NotificationMethod"}),
"Server": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Server"}),
"Monitor": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesManagement"}),
"Cron": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ScheduledTasks"}),
}
return data
}

View File

@ -1,4 +1,4 @@
[nezhaMonitor]
[NezhaMonitoring]
other = "Nezha Monitoring"
[Server]
@ -76,7 +76,7 @@ other = "Specific Servers"
[EnterIdAndNameToSearch]
other = "Input Server ID/Name to search"
[NotificationMethod]
[NotificationMethodGroup]
other = "Notification Group"
[PushSuccessMessages]
@ -250,9 +250,6 @@ other = "One Key Install"
[ClickToCopyTheInstallationCommand]
other = "Click To Copy Install Command"
[NotSupportedYet]
other = "Not supported yet, check the release page for manual install"
[DeleteServer]
other = "Delete Server"
@ -453,3 +450,42 @@ other = "Total Inbound"
[WrongPassword]
other = "Incorrect Password"
[AnErrorEccurred]
other = "An error occurred"
[SystemError]
other = "System Error"
[NetowrkError]
other = "Netowrk Error"
[ServicesStatus]
other = "Services Status"
[ServersManagement]
other = "Servers"
[ServicesManagement]
other = "Services"
[ScheduledTasks]
other = "Scheduled Tasks"
[YouAreNotAuthorized]
other = "You are not authorized"
[WrongAccessPassword]
other = "Wrong access password"
[Add]
other = "Add"
[Edit]
other = "Edit"
[AlarmRule]
other = "Alarm Rule"
[NotificationMethod]
other = "Notification Method"

View File

@ -1,4 +1,4 @@
[nezhaMonitor]
[NezhaMonitoring]
other = "哪吒监控"
[Server]
@ -76,7 +76,7 @@ other = "特定服务器"
[EnterIdAndNameToSearch]
other = "输入ID/名称以搜索"
[NotificationMethod]
[NotificationMethodGroup]
other = "通知方式组"
[PushSuccessMessages]
@ -250,9 +250,6 @@ other = "一键安装"
[ClickToCopyTheInstallationCommand]
other = "点击复制安装命令"
[NotSupportedYet]
other = "尚未支持请下载release手动安装"
[DeleteServer]
other = "删除主机"
@ -453,3 +450,42 @@ other = "总下行"
[WrongPassword]
other = "密码错误"
[AnErrorEccurred]
other = "出现错误"
[SystemError]
other = "系统错误"
[NetowrkError]
other = "网络错误"
[ServicesStatus]
other = "服务状态"
[ServersManagement]
other = "服务器管理"
[ServicesManagement]
other = "服务监控"
[ScheduledTasks]
other = "计划任务"
[YouAreNotAuthorized]
other = "此页面需要登录"
[WrongAccessPassword]
other = "查看密码错误"
[Add]
other = "添加"
[Edit]
other = "修改"
[AlarmRule]
other = "报警规则"
[NotificationMethod]
other = "通知方式"

View File

@ -1,3 +1,19 @@
let LANG = {
Add: "添加",
Edit: "修改",
AlarmRule: "报警规则",
Notification: "通知方式",
Server: "服务器",
Monitor: "监控",
Cron: "计划任务",
}
function updateLang(newLang) {
if (newLang) {
LANG = newLang;
}
}
function readableBytes(bytes) {
if (!bytes) {
return '0B'
@ -105,11 +121,11 @@ function showFormModal(modelSelector, formID, URL, getData) {
function addOrEditAlertRule(rule) {
const modal = $(".rule.modal");
modal.children(".header").text((rule ? "修改" : "添加") + "报警规则");
modal.children(".header").text((rule ? LANG.Edit : LANG.Add) + ' ' + LANG.AlarmRule);
modal
.find(".nezha-primary-btn.button")
.html(
rule ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>'
rule ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(rule ? rule.ID : null);
modal.find("input[name=Name]").val(rule ? rule.Name : null);
@ -125,13 +141,13 @@ function addOrEditAlertRule(rule) {
function addOrEditNotification(notification) {
const modal = $(".notification.modal");
modal.children(".header").text((notification ? "修改" : "添加") + "通知方式");
modal.children(".header").text((notification ? LANG.Edit : LANG.Add) + ' ' + LANG.Notification);
modal
.find(".nezha-primary-btn.button")
.html(
notification
? '修改<i class="edit icon"></i>'
: '添加<i class="add icon"></i>'
? LANG.Edit + '<i class="edit icon"></i>'
: LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(notification ? notification.ID : null);
modal.find("input[name=Name]").val(notification ? notification.Name : null);
@ -188,11 +204,11 @@ function post(path, params, method = 'post') {
function addOrEditServer(server, conf) {
const modal = $(".server.modal");
modal.children(".header").text((server ? "修改" : "添加") + "服务器");
modal.children(".header").text((server ? LANG.Edit : LANG.Add) + ' ' + LANG.Server);
modal
.find(".nezha-primary-btn.button")
.html(
server ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>'
server ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=id]").val(server ? server.ID : null);
modal.find("input[name=name]").val(server ? server.Name : null);
@ -216,11 +232,11 @@ function addOrEditServer(server, conf) {
function addOrEditMonitor(monitor) {
const modal = $(".monitor.modal");
modal.children(".header").text((monitor ? "修改" : "添加") + "监控");
modal.children(".header").text((monitor ? LANG.Edit : LANG.Add) + ' ' + LANG.Monitor);
modal
.find(".nezha-primary-btn.button")
.html(
monitor ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>'
monitor ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(monitor ? monitor.ID : null);
modal.find("input[name=Name]").val(monitor ? monitor.Name : null);
@ -257,11 +273,11 @@ function addOrEditMonitor(monitor) {
function addOrEditCron(cron) {
const modal = $(".cron.modal");
modal.children(".header").text((cron ? "修改" : "添加") + "计划任务");
modal.children(".header").text((cron ? LANG.Edit : LANG.Add) + ' ' + LANG.Cron);
modal
.find(".nezha-primary-btn.button")
.html(
cron ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>'
cron ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(cron ? cron.ID : null);
modal.find("input[name=Name]").val(cron ? cron.Name : null);

View File

@ -1,15 +1,21 @@
{{define "common/footer"}}
<div class="ui inverted vertical footer segment">
<div class="ui center aligned is-size-7 container">
<b>&copy; <a style="color: white;" href="/">{{.Conf.Site.Brand}}</a></b> | <small>Powered by <a href="https://github.com/naiba/nezha"
style="color: white;" target="_blank">{{tr "nezhaMonitor"}}</a> {{.Version}}</small>
<b>&copy; <a style="color: white;" href="/">{{.Conf.Site.Brand}}</a></b> | <small>Powered by <a
href="https://github.com/naiba/nezha" style="color: white;" target="_blank">{{tr "NezhaMonitoring"}}</a>
{{.Version}}</small>
</div>
</div>
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.4.1/jquery.min.js"></script>
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/semantic-ui/2.4.1/semantic.min.js"></script>
<script src="/static/semantic-ui-alerts.min.js"></script>
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.12/vue.min.js"></script>
<script src="/static/main.js?v20220423"></script>
<script src="/static/main.js?v20220430"></script>
<script>
(function () {
updateLang({{.LANG }});
})();
</script>
</body>
</html>

View File

@ -33,7 +33,7 @@
</div>
</div>
<div class="field">
<label>{{tr "NotificationMethod"}}}</label>
<label>{{tr "NotificationMethodGroup"}}}</label>
<input type="text" name="NotificationTag" placeholder="default">
</div>
<div class="field">

View File

@ -45,7 +45,7 @@
</div>
</div>
<div class="field">
<label>{{tr "NotificationMethod"}}</label>
<label>{{tr "NotificationMethodGroup"}}</label>
<input type="text" name="NotificationTag" placeholder="default" />
</div>
<div class="field">

View File

@ -13,7 +13,7 @@
<textarea name="RulesRaw"></textarea>
</div>
<div class="field">
<label>{{tr "NotificationMethod"}}</label>
<label>{{tr "NotificationMethodGroup"}}</label>
<input type="text" name="NotificationTag" placeholder="default">
</div>
<div class="field">

View File

@ -17,7 +17,7 @@
<th>{{tr "Name"}}</th>
<th>{{tr "Scheduler"}}</th>
<th>{{tr "Command"}}</th>
<th>{{tr "NotificationMethod"}}</th>
<th>{{tr "NotificationMethodGroup"}}</th>
<th>{{tr "PushSuccessfully"}}</th>
<th>{{tr "Coverage"}}</th>
<th>{{tr "SpecificServers"}}</th>

View File

@ -19,7 +19,7 @@
<th>{{tr "SpecificServers"}}</th>
<th>{{tr "Type"}}</th>
<th>{{tr "Duration"}}</th>
<th>{{tr "NotificationMethod"}}</th>
<th>{{tr "NotificationMethodGroup"}}</th>
<th>{{tr "Notification"}}</th>
<th>{{tr "Administration"}}</th>
</tr>

View File

@ -57,7 +57,7 @@
<tr>
<th>ID</th>
<th>{{tr "Name"}}</th>
<th>{{tr "NotificationMethod"}}</th>
<th>{{tr "NotificationMethodGroup"}}</th>
<th>{{tr "Rules"}}</th>
<th>{{tr "Enable"}}</th>
<th>{{tr "Administration"}}</th>

View File

@ -44,15 +44,11 @@
data-tooltip="{{tr "ClickToCopyTheInstallationCommand"}}">
<i class="linux icon"></i>
</button>
<button class="ui icon mini button" data-tooltip="{{tr "NotSupportedYet"}}">
<button class="ui icon green mini button"
data-clipboard-text="{{if $.Conf.GRPCHost}}set-ExecutionPolicy RemoteSigned;Invoke-WebRequest https://raw.githubusercontent.com/naiba/nezha/master/script/install.ps1 -OutFile C:\install.ps1;powershell.exe C:\install.ps1 {{$.Conf.GRPCHost}}:{{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
data-tooltip="{{tr "ClickToCopyTheInstallationCommand"}}">
<i class="windows icon"></i>
</button>
<button class="ui icon mini button" data-tooltip="{{tr "NotSupportedYet"}}">
<i class="apple icon"></i>
</button>
</td>
<td style="word-break: break-word;">{{$server.Note}}</td>
<td>

View File

@ -6,7 +6,7 @@
<form id="settingForm" class="ui large form" onsubmit="return false;">
<div class="field">
<label>{{tr "SiteTitle"}}</label>
<input type="text" name="Title" placeholder="{{tr "nezhaMonitor"}}" value="{{.Conf.Site.Brand}}">
<input type="text" name="Title" placeholder="{{tr "NezhaMonitoring"}}" value="{{.Conf.Site.Brand}}">
</div>
<div class="field">
<label>{{tr "AdministratorList"}}</label>

View File

@ -23,7 +23,7 @@
<section class="nav-bar clearfix">
<figure class="logo">
<a href="/">
<img src="/static/logo.svg?v20210804" alt='{{tr "nezhaMonitor"}}' width="50" height="50">
<img src="/static/logo.svg?v20210804" alt='{{tr "NezhaMonitoring"}}' width="50" height="50">
</a>
<a href="/">{{.Conf.Site.Brand}}</a>
</figure>
@ -155,7 +155,7 @@
<footer>
<div class="footer-container">
<div><a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor"}} · {{.Version}}</a>
<div><a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "NezhaMonitoring"}} · {{.Version}}</a>
<p>&copy; <span id="copyright-date">
<script>document.getElementById('copyright-date').appendChild(document.createTextNode(new Date().getFullYear()))</script>
</span> · <a href="https://blog.jackiesung.com" target="_blank">Theme designed by Jackie Sung</a>

View File

@ -118,7 +118,7 @@
<footer>
<div class="footer-container">
<div>
<a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor"}} · {{.Version}}</a>
<a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "NezhaMonitoring"}} · {{.Version}}</a>
<p>
&copy;
<span id="copyright-date"

View File

@ -42,7 +42,7 @@
<footer>
<div class="footer-container">
<div>
<a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor"}} · {{.Version}}</a>
<a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "NezhaMonitoring"}} · {{.Version}}</a>
<p>
&copy;<span id="copyright-date"
><script>

View File

@ -135,7 +135,7 @@
</ul>
</div>
<footer>
<p style="text-align:center;padding: 15px;">Powered by <a href="https://github.com/naiba/nezha">{{tr "nezhaMonitor"}}</a> build ·
<p style="text-align:center;padding: 15px;">Powered by <a href="https://github.com/naiba/nezha">{{tr "NezhaMonitoring"}}</a> build ·
{{.Version}}
<a href="/service">{{tr "Services"}}</a>
<a href="/server">{{tr "AdminPanel"}}</a>

View File

@ -5,7 +5,7 @@
<center>
<p>
<a href="/"><at>{{.Title}}</at></a>
Powered by <a href="https://github.com/naiba/nezha"><st>{{tr "nezhaMonitor"}}&lt;{{.Version}}&gt;</st></a>&nbsp;| Theme designed by Mikoy Chinese
Powered by <a href="https://github.com/naiba/nezha"><st>{{tr "NezhaMonitoring"}}&lt;{{.Version}}&gt;</st></a>&nbsp;| Theme designed by Mikoy Chinese
</p>
</center>
</div>

View File

@ -12,7 +12,7 @@ import (
"github.com/naiba/nezha/pkg/utils"
)
var Version = "v0.13.0" // !!记得修改 README 中的 badge 版本!!
var Version = "v0.13.1" // !!记得修改 README 中的 badge 版本!!
var (
Conf *model.Config