// 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 "" }