134 lines
3.5 KiB
Go
134 lines
3.5 KiB
Go
// Copyright 2022 E99p1ant. All rights reserved.
|
||
// Use of this source code is governed by a MIT-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
// Package i18n 提供多语言翻译支持,支持简体中文、繁体中文、英文、日语四种语言。
|
||
package i18n
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
)
|
||
|
||
// Language 语言代码常量。
|
||
const (
|
||
LangZhCN = "zh-CN" // 简体中文
|
||
LangZhTW = "zh-TW" // 繁體中文
|
||
LangEn = "en" // English
|
||
LangJa = "ja" // 日本語
|
||
|
||
Default = LangZhCN
|
||
)
|
||
|
||
// LangInfo 描述一种支持的语言。
|
||
type LangInfo struct {
|
||
Code string // 语言代码,如 "zh-CN"
|
||
Name string // 语言自身名称,如 "简体中文" / "繁體中文" / "English" / "日本語"
|
||
}
|
||
|
||
// supported 支持的语语言列表,顺序即切换按钮展示顺序。
|
||
var supported = []LangInfo{
|
||
{Code: LangZhCN, Name: "简体中文"},
|
||
{Code: LangZhTW, Name: "繁體中文"},
|
||
{Code: LangEn, Name: "English"},
|
||
{Code: LangJa, Name: "日本語"},
|
||
}
|
||
|
||
// Supported 返回全部支持的语言列表。
|
||
func Supported() []LangInfo {
|
||
out := make([]LangInfo, len(supported))
|
||
copy(out, supported)
|
||
return out
|
||
}
|
||
|
||
// Resolve 规范化语言代码:支持返回对应代码,未知代码回退到默认语言。
|
||
func Resolve(lang string) string {
|
||
lang = strings.TrimSpace(lang)
|
||
if lang == "" {
|
||
return Default
|
||
}
|
||
switch strings.ToLower(lang) {
|
||
case "zh-cn", "zh_cn", "zh":
|
||
return LangZhCN
|
||
case "zh-tw", "zh_tw", "zh-hant", "zh_hant", "zh-hk", "zh_hk", "zh_mo", "tw":
|
||
return LangZhTW
|
||
case "en", "en-us", "en_us", "en-gb":
|
||
return LangEn
|
||
case "ja", "ja-jp", "ja_jp":
|
||
return LangJa
|
||
}
|
||
return Default
|
||
}
|
||
|
||
// Name 返回语言代码对应的显示名。
|
||
func Name(lang string) string {
|
||
lang = Resolve(lang)
|
||
for _, l := range supported {
|
||
if l.Code == lang {
|
||
return l.Name
|
||
}
|
||
}
|
||
return "简体中文"
|
||
}
|
||
|
||
// dictionary 翻译字典:语言代码 -> (key -> 文案)。
|
||
// 文案中的 %s 等占位符由 T 函数按传入参数填充。
|
||
var dictionary = map[string]map[string]string{
|
||
LangZhCN: zhCNDict,
|
||
LangZhTW: zhTWDict,
|
||
LangEn: enDict,
|
||
LangJa: jaDict,
|
||
}
|
||
|
||
// T 返回指定语言下 key 对应的翻译文案,支持 fmt 风格参数填充。
|
||
// 若 key 不存在,回退顺序:指定语言 -> 简体中文 -> 返回 key 本身,
|
||
// 方便开发期发现缺失词条。
|
||
func T(lang, key string, args ...interface{}) string {
|
||
lang = Resolve(lang)
|
||
text := lookup(lang, key)
|
||
if text == "" {
|
||
text = lookup(LangZhCN, key)
|
||
}
|
||
if text == "" {
|
||
return key
|
||
}
|
||
if len(args) > 0 {
|
||
text = fmt.Sprintf(text, args...)
|
||
}
|
||
return text
|
||
}
|
||
|
||
// FeatureClosedMessage 返回功能被关闭时面向访客的提示文案。
|
||
// feature 取值见 db.FeatureQuestion / db.FeatureChat / db.FeatureVote;
|
||
// reason 为空串表示功能可用,此时返回空串(调用方应先用 Reason 判断是否可用)。
|
||
//
|
||
// 放在 i18n 而非 db 包,避免 i18n 反向依赖数据层。
|
||
func FeatureClosedMessage(lang, feature, reason string) string {
|
||
if reason == "" {
|
||
return ""
|
||
}
|
||
return T(lang, "feature."+reason+"."+feature)
|
||
}
|
||
|
||
// FeatureName 返回功能的显示名称。
|
||
func FeatureName(lang, feature string) string {
|
||
return T(lang, "feature.name."+feature)
|
||
}
|
||
|
||
// FeatureStatusText 返回管理页展示的功能状态文案。
|
||
func FeatureStatusText(lang, reason string) string {
|
||
if reason == "" {
|
||
return T(lang, "feature.statusOpen")
|
||
}
|
||
return T(lang, "feature.status."+reason)
|
||
}
|
||
|
||
func lookup(lang, key string) string {
|
||
if dict, ok := dictionary[lang]; ok {
|
||
if text, ok := dict[key]; ok {
|
||
return text
|
||
}
|
||
}
|
||
return ""
|
||
}
|