From bbf6ea561d9e4a32add600cf6aa643e3549a83c8 Mon Sep 17 00:00:00 2001 From: keven1024 Date: Fri, 1 May 2026 23:44:19 +0800 Subject: [PATCH] feat(i18n): add initial i18n package with support for multiple languages and email notification translations --- pkg/i18n/go.mod | 9 +++ pkg/i18n/go.sum | 8 ++ pkg/i18n/i18n.go | 117 +++++++++++++++++++++++++++++ pkg/i18n/locales/active.de.toml | 5 ++ pkg/i18n/locales/active.en.toml | 5 ++ pkg/i18n/locales/active.fr.toml | 5 ++ pkg/i18n/locales/active.ja.toml | 5 ++ pkg/i18n/locales/active.ko.toml | 5 ++ pkg/i18n/locales/active.zh-CN.toml | 5 ++ pkg/i18n/locales/active.zh-TW.toml | 5 ++ 10 files changed, 169 insertions(+) create mode 100644 pkg/i18n/go.mod create mode 100644 pkg/i18n/go.sum create mode 100644 pkg/i18n/i18n.go create mode 100644 pkg/i18n/locales/active.de.toml create mode 100644 pkg/i18n/locales/active.en.toml create mode 100644 pkg/i18n/locales/active.fr.toml create mode 100644 pkg/i18n/locales/active.ja.toml create mode 100644 pkg/i18n/locales/active.ko.toml create mode 100644 pkg/i18n/locales/active.zh-CN.toml create mode 100644 pkg/i18n/locales/active.zh-TW.toml diff --git a/pkg/i18n/go.mod b/pkg/i18n/go.mod new file mode 100644 index 0000000..a915d85 --- /dev/null +++ b/pkg/i18n/go.mod @@ -0,0 +1,9 @@ +module pkg/i18n + +go 1.25.5 + +require ( + github.com/BurntSushi/toml v1.6.0 + github.com/nicksnyder/go-i18n/v2 v2.6.1 + golang.org/x/text v0.35.0 +) diff --git a/pkg/i18n/go.sum b/pkg/i18n/go.sum new file mode 100644 index 0000000..05b853f --- /dev/null +++ b/pkg/i18n/go.sum @@ -0,0 +1,8 @@ +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/nicksnyder/go-i18n/v2 v2.6.1 h1:JDEJraFsQE17Dut9HFDHzCoAWGEQJom5s0TRd17NIEQ= +github.com/nicksnyder/go-i18n/v2 v2.6.1/go.mod h1:Vee0/9RD3Quc/NmwEjzzD7VTZ+Ir7QbXocrkhOzmUKA= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= diff --git a/pkg/i18n/i18n.go b/pkg/i18n/i18n.go new file mode 100644 index 0000000..b81e8bc --- /dev/null +++ b/pkg/i18n/i18n.go @@ -0,0 +1,117 @@ +package i18n + +import ( + "embed" + "path" + "strings" + + "github.com/BurntSushi/toml" + "github.com/nicksnyder/go-i18n/v2/i18n" + "golang.org/x/text/language" +) + +//go:embed locales/*.toml +var translationFS embed.FS + +var ( + bundle *i18n.Bundle + defaultLanguage = language.English + supportedLanguages = []language.Tag{ + language.English, + language.Chinese, + language.French, + } +) + +// 初始化 i18n bundle +func Init() error { + bundle = i18n.NewBundle(defaultLanguage) + bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) + + // 加载所有翻译文件 + entries, err := translationFS.ReadDir("locales") + if err != nil { + return err + } + + for _, entry := range entries { + if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".toml") { + filePath := path.Join("locales", entry.Name()) + data, err := translationFS.ReadFile(filePath) + if err != nil { + return err + } + + _, err = bundle.ParseMessageFileBytes(data, filePath) + if err != nil { + return err + } + } + } + + return nil +} + +// 获取针对特定语言的本地化器 +func NewLocalizer(lang string) *i18n.Localizer { + // 如果传入空字符串,使用默认语言 + if lang == "" { + return i18n.NewLocalizer(bundle, defaultLanguage.String()) + } + + // 创建包含回退语言的本地化器 + return i18n.NewLocalizer(bundle, lang, defaultLanguage.String()) +} + +// T 是简化的翻译函数,用于没有参数的简单字符串 +func T(lang, messageID string) string { + localizer := NewLocalizer(lang) + msg, err := localizer.Localize(&i18n.LocalizeConfig{ + MessageID: messageID, + }) + + if err != nil { + // 记录错误但返回 messageID 作为回退 + return messageID + } + + return msg +} + +// TWithData 用于包含模板数据的翻译 +func TWithData(lang, messageID string, templateData map[string]interface{}) string { + localizer := NewLocalizer(lang) + msg, err := localizer.Localize(&i18n.LocalizeConfig{ + MessageID: messageID, + TemplateData: templateData, + }) + + if err != nil { + return messageID + } + + return msg +} + +// TPlural 用于处理复数形式 +func TPlural(lang, messageID string, count interface{}, templateData map[string]interface{}) string { + if templateData == nil { + templateData = make(map[string]interface{}) + } + + // 确保 templateData 中包含 Count + templateData["Count"] = count + + localizer := NewLocalizer(lang) + msg, err := localizer.Localize(&i18n.LocalizeConfig{ + MessageID: messageID, + PluralCount: count, + TemplateData: templateData, + }) + + if err != nil { + return messageID + } + + return msg +} diff --git a/pkg/i18n/locales/active.de.toml b/pkg/i18n/locales/active.de.toml new file mode 100644 index 0000000..c6137ac --- /dev/null +++ b/pkg/i18n/locales/active.de.toml @@ -0,0 +1,5 @@ +[notify_email_subject] +other = "Benachrichtigung zum Share-Download - {{.SiteURL}}" + +[notify_email_body] +other = "Ihr geteilter {{.ShareType}} {{.FileName}} wurde heruntergeladen." diff --git a/pkg/i18n/locales/active.en.toml b/pkg/i18n/locales/active.en.toml new file mode 100644 index 0000000..708f106 --- /dev/null +++ b/pkg/i18n/locales/active.en.toml @@ -0,0 +1,5 @@ +[notify_email_subject] +other = "Share download notification - {{.SiteURL}}" + +[notify_email_body] +other = "Your shared {{.ShareType}} {{.FileName}} was downloaded." diff --git a/pkg/i18n/locales/active.fr.toml b/pkg/i18n/locales/active.fr.toml new file mode 100644 index 0000000..f4d4f14 --- /dev/null +++ b/pkg/i18n/locales/active.fr.toml @@ -0,0 +1,5 @@ +[notify_email_subject] +other = "Notification de téléchargement du partage - {{.SiteURL}}" + +[notify_email_body] +other = "Votre {{.ShareType}} partagé {{.FileName}} a été téléchargé." diff --git a/pkg/i18n/locales/active.ja.toml b/pkg/i18n/locales/active.ja.toml new file mode 100644 index 0000000..67f86e0 --- /dev/null +++ b/pkg/i18n/locales/active.ja.toml @@ -0,0 +1,5 @@ +[notify_email_subject] +other = "共有ダウンロード通知 - {{.SiteURL}}" + +[notify_email_body] +other = "共有した{{.ShareType}} {{.FileName}} がダウンロードされました。" diff --git a/pkg/i18n/locales/active.ko.toml b/pkg/i18n/locales/active.ko.toml new file mode 100644 index 0000000..efd1440 --- /dev/null +++ b/pkg/i18n/locales/active.ko.toml @@ -0,0 +1,5 @@ +[notify_email_subject] +other = "공유 다운로드 알림 - {{.SiteURL}}" + +[notify_email_body] +other = "공유한 {{.ShareType}} {{.FileName}} 이(가) 다운로드되었습니다." diff --git a/pkg/i18n/locales/active.zh-CN.toml b/pkg/i18n/locales/active.zh-CN.toml new file mode 100644 index 0000000..86914ef --- /dev/null +++ b/pkg/i18n/locales/active.zh-CN.toml @@ -0,0 +1,5 @@ +[notify_email_subject] +other = "分享下载通知 - {{.SiteURL}}" + +[notify_email_body] +other = "IP为{{.IP}}的用户下载了你的{{.FileName}}的{{.ShareType}}。" diff --git a/pkg/i18n/locales/active.zh-TW.toml b/pkg/i18n/locales/active.zh-TW.toml new file mode 100644 index 0000000..d195ae3 --- /dev/null +++ b/pkg/i18n/locales/active.zh-TW.toml @@ -0,0 +1,5 @@ +[notify_email_subject] +other = "分享下載通知 - {{.SiteURL}}" + +[notify_email_body] +other = "IP為{{.IP}}的使用者下載了你的{{.FileName}}的{{.ShareType}}。"