🌐 localization [skip ci]

This commit is contained in:
naiba 2022-04-27 23:51:45 +08:00
parent 0a6658fcb4
commit 7bd67b2233
15 changed files with 92 additions and 34 deletions

View File

@ -12,6 +12,7 @@ import (
"code.cloudfoundry.org/bytefmt"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/naiba/nezha/pkg/mygin"
"github.com/naiba/nezha/service/singleton"
@ -26,6 +27,18 @@ func ServeWeb(port uint) *http.Server {
}
r.Use(mygin.RecordPath)
r.SetFuncMap(template.FuncMap{
"tr": func(id string, dataAndCount ...interface{}) string {
conf := i18n.LocalizeConfig{
MessageID: id,
}
if len(dataAndCount) > 1 {
conf.TemplateData = dataAndCount[1]
}
if len(dataAndCount) > 2 {
conf.PluralCount = dataAndCount[2]
}
return singleton.Localizer.MustLocalize(&conf)
},
"tf": func(t time.Time) string {
return t.In(singleton.Loc).Format("2006年1月2号 15:04:05")
},

View File

@ -2,12 +2,13 @@ package main
import (
"context"
"log"
"github.com/naiba/nezha/cmd/dashboard/controller"
"github.com/naiba/nezha/cmd/dashboard/rpc"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/service/singleton"
"github.com/ory/graceful"
"log"
)
func init() {
@ -15,6 +16,7 @@ func init() {
singleton.Init()
singleton.InitConfigFromPath("data/config.yaml")
singleton.InitDBFromPath("data/sqlite.db")
singleton.InitLocalizer()
initSystem()
}

View File

@ -3,25 +3,48 @@ package main
import (
"fmt"
"github.com/jinzhu/copier"
"github.com/naiba/nezha/service/singleton"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
)
type Cat struct {
age int
name string
friends []string
func htmlTemplateTranslateFn(id string, data interface{}, count interface{}) string {
return singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: id,
TemplateData: data,
PluralCount: count,
})
}
func main() {
a := Cat{7, "Wilson", []string{"Tom", "Tabata", "Willie"}}
b := Cat{7, "Wilson", []string{"Tom", "Tabata", "Willie"}}
c := Cat{7, "Wilson", []string{"Tom", "Tabata", "Willie"}}
wilson := []*Cat{&a, &b, &c}
nikita := []Cat{}
copier.Copy(&nikita, &wilson)
singleton.InitLocalizer()
fmt.Println(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "nezhaMonitor",
}))
nikita[0].friends = append(nikita[0].friends, "Syd")
fmt.Println(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "nezhaMonitor",
}))
fmt.Println(wilson[0])
fmt.Println(nikita[0])
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,
}))
}

4
go.mod
View File

@ -5,6 +5,7 @@ go 1.18
require (
code.cloudfoundry.org/bytefmt v0.0.0-20211005130812-5bb3c17173e5
github.com/AlecAivazis/survey/v2 v2.3.4
github.com/BurntSushi/toml v1.0.0
github.com/Erope/goss v0.0.0-20211230093305-df3c03fd1ed4
github.com/artdarek/go-unzip v1.0.0
github.com/blang/semver v3.5.1+incompatible
@ -19,6 +20,7 @@ require (
github.com/iamacarpet/go-winpty v1.0.2
github.com/jinzhu/copier v0.3.5
github.com/json-iterator/go v1.1.12
github.com/nicksnyder/go-i18n/v2 v2.2.0
github.com/ory/graceful v0.1.2
github.com/p14yground/go-github-selfupdate v0.0.0-20220205132106-76a6d59b925b
github.com/patrickmn/go-cache v2.1.0+incompatible
@ -30,6 +32,7 @@ require (
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/text v0.3.7
google.golang.org/grpc v1.46.0
google.golang.org/protobuf v1.28.0
gopkg.in/yaml.v2 v2.4.0
@ -80,7 +83,6 @@ require (
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect
gopkg.in/ini.v1 v1.66.4 // indirect

12
go.sum
View File

@ -41,6 +41,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/AlecAivazis/survey/v2 v2.3.4 h1:pchTU9rsLUSvWEl2Aq9Pv3k0IE2fkqtGxazskAMd9Ng=
github.com/AlecAivazis/survey/v2 v2.3.4/go.mod h1:hrV6Y/kQCLhIZXGcriDCUBtB3wnN7156gMXJ3+b23xM=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Erope/goss v0.0.0-20211230093305-df3c03fd1ed4 h1:X35U3bryt+j2a9RZyXyBPISNIYQsfNKWC/d/B8J861I=
github.com/Erope/goss v0.0.0-20211230093305-df3c03fd1ed4/go.mod h1:gl55GUYOV6rvsL/V23GdfRNdnreh+McD5Yo1sNc+Qe0=
@ -203,7 +205,6 @@ github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
@ -238,9 +239,6 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsFrzQ=
github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
@ -253,6 +251,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nicksnyder/go-i18n/v2 v2.2.0 h1:MNXbyPvd141JJqlU6gJKrczThxJy+kdCNivxZpBQFkw=
github.com/nicksnyder/go-i18n/v2 v2.2.0/go.mod h1:4OtLfzqyAxsscyCb//3gfqSvBc81gImX91LrZzczN1o=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@ -652,7 +652,6 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
@ -691,11 +690,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.3.1 h1:bwfE+zTEWklBYoEodIOIBwuWHpnx52Z9zJFW5F33WLk=
gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg=
gorm.io/driver/sqlite v1.3.2 h1:nWTy4cE52K6nnMhv23wLmur9Y3qWbZvOBz+V4PrGAxg=
gorm.io/driver/sqlite v1.3.2/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U=
gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.4 h1:1BKWM67O6CflSLcwGQR7ccfmC4ebOxQrTfOQGRE9wjg=
gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -51,8 +51,9 @@ func (c *AgentConfig) Save() error {
// Config 站点配置
type Config struct {
Debug bool // debug模式开关
Site struct {
Debug bool // debug模式开关
Language string // 系统语言,默认 zh-CN
Site struct {
Brand string // 站点名称
CookieName string // 浏览器 Cookie 名称
Theme string
@ -100,6 +101,9 @@ func (c *Config) Read(path string) error {
if c.Site.Theme == "" {
c.Site.Theme = "default"
}
if c.Language == "" {
c.Language = "zh-CN"
}
if c.GRPCPort == 0 {
c.GRPCPort = 5555
}

2
resource/l10n/zh-CN.toml vendored Normal file
View File

@ -0,0 +1,2 @@
[nezhaMonitor]
other = "哪吒监控"

View File

@ -2,7 +2,7 @@
<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">哪吒监控</a> {{.Version}}</small>
style="color: white;" target="_blank">{{tr "nezhaMonitor" nil nil}}</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>

View File

@ -6,7 +6,7 @@
<form id="settingForm" class="ui large form" onsubmit="return false;">
<div class="field">
<label>站点标题</label>
<input type="text" name="Title" placeholder="哪吒监控" value="{{.Conf.Site.Brand}}">
<input type="text" name="Title" placeholder="{{tr "nezhaMonitor" nil nil}}" value="{{.Conf.Site.Brand}}">
</div>
<div class="field">
<label>管理员列表</label>

View File

@ -23,7 +23,7 @@
<section class="nav-bar clearfix">
<figure class="logo">
<a href="/">
<img src="/static/logo.svg?v20210804" alt="哪吒监控" width="50" height="50">
<img src="/static/logo.svg?v20210804" alt="{{tr "nezhaMonitor" nil nil}}" 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 哪吒监控 · {{.Version}}</a>
<div><a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor" nil nil}} · {{.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 哪吒监控 · {{.Version}}</a>
<a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor" nil nil}} · {{.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 哪吒监控 · {{.Version}}</a>
<a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "nezhaMonitor" nil nil}} · {{.Version}}</a>
<p>
&copy;<span id="copyright-date"
><script>

View File

@ -140,7 +140,7 @@
</ul>
</div>
<footer>
<p style="text-align:center;padding: 15px;">Powered by <a href="https://github.com/naiba/nezha">哪吒监控</a> build ·
<p style="text-align:center;padding: 15px;">Powered by <a href="https://github.com/naiba/nezha">{{tr "nezhaMonitor" nil nil}}</a> build ·
{{.Version}}
<a href="/service">服务状态</a>
<a href="/server">管理后台</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>哪吒监控&lt;{{.Version}}&gt;</st></a>&nbsp;| Theme designed by Mikoy Chinese
Powered by <a href="https://github.com/naiba/nezha"><st>{{tr "nezhaMonitor" nil nil}}&lt;{{.Version}}&gt;</st></a>&nbsp;| Theme designed by Mikoy Chinese
</p>
</center>
</div>

16
service/singleton/l10n.go Normal file
View File

@ -0,0 +1,16 @@
package singleton
import (
"github.com/BurntSushi/toml"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
)
var Localizer *i18n.Localizer
func InitLocalizer() {
bundle := i18n.NewBundle(language.Chinese)
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
bundle.LoadMessageFile("resource/l10n/zh-CN.toml")
Localizer = i18n.NewLocalizer(bundle, "zh-CN")
}