Files

134 lines
3.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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"
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 ""
}