feat: publish sanitized custom.97 source

This commit is contained in:
cneicy committed 2026-10-27 20:43:39 +08:00
1 parent 8e6ed0317b
commit 86c0276156
1022 files changed
+69903 -19207

No files matched your search

+38 -52
View File
@@ -2,6 +2,7 @@ package i18n
import (
"embed"
"slices"
"strings"
"sync"
@@ -86,14 +87,17 @@ func GetLocalizer(lang string) *i18n.Localizer {
return loc
}
// T translates a message key using the language from gin context
// T translates a message key in the language the reader of the request stated
func T(c *gin.Context, key string, args ...map[string]any) string {
lang := GetLangFromContext(c)
return Translate(lang, key, args...)
return Translate(StatedLang(c), key, args...)
}
// Translate translates a message key for the specified language
// Translate translates a message key for the specified language. An empty
// language means the reader stated none and gets common.DefaultLanguage.
func Translate(lang, key string, args ...map[string]any) string {
if lang == "" {
lang = common.DefaultLanguage
}
loc := GetLocalizer(lang)
config := &i18n.LocalizeConfig{
@@ -121,29 +125,30 @@ func SetUserLangLoader(loader func(userId int) string) {
userLangLoaderFunc = loader
}
// GetLangFromContext extracts the language setting from gin context
// It checks multiple sources in priority order:
// StatedLang returns the language the reader of a request stated, or "" when
// there is none. It checks multiple sources in priority order:
// 1. User settings (ContextKeyUserSetting) - if already loaded (e.g., by TokenAuth)
// 2. Lazy load user language from cache/DB using user ID
// 2. Lazy load user language from cache/DB using user ID, when step 1 found no settings
// 3. Language set by middleware (ContextKeyLanguage) - from Accept-Language header
// 4. Default language (English)
func GetLangFromContext(c *gin.Context) string {
// 4. The Accept-Language header
func StatedLang(c *gin.Context) string {
if c == nil {
return DefaultLang
return ""
}
// 1. Try to get language from user settings (if already loaded by TokenAuth or other middleware)
if userSetting, ok := common.GetContextKeyType[dto.UserSetting](c, constant.ContextKeyUserSetting); ok {
if userSetting.Language != "" {
normalized := normalizeLang(userSetting.Language)
if IsSupported(normalized) {
return normalized
}
userSetting, settingLoaded := common.GetContextKeyType[dto.UserSetting](c, constant.ContextKeyUserSetting)
if settingLoaded && userSetting.Language != "" {
normalized := normalizeLang(userSetting.Language)
if IsSupported(normalized) {
return normalized
}
}
// 2. Lazy load user language using user ID (for session-based auth where full settings aren't loaded)
if userLangLoaderFunc != nil {
// 2. Lazy load user language using user ID (for session-based auth where full settings aren't loaded).
// Loaded settings without a language mean the user saved none; loading the user again would cost
// a cache or database read on every relay request.
if !settingLoaded && userLangLoaderFunc != nil {
if userId, exists := c.Get("id"); exists {
if uid, ok := userId.(int); ok && uid > 0 {
lang := userLangLoaderFunc(uid)
@@ -166,44 +171,30 @@ func GetLangFromContext(c *gin.Context) string {
}
// 4. Try Accept-Language header directly (fallback if middleware didn't run)
if acceptLang := c.GetHeader("Accept-Language"); acceptLang != "" {
lang := ParseAcceptLanguage(acceptLang)
if IsSupported(lang) {
return lang
}
}
return DefaultLang
return ParseAcceptLanguage(c.GetHeader("Accept-Language"))
}
// ParseAcceptLanguage parses the Accept-Language header and returns the preferred language
// ParseAcceptLanguage returns the first language of an Accept-Language header,
// or "" when the header is absent or states no preference ("*").
func ParseAcceptLanguage(header string) string {
if header == "" {
return DefaultLang
first, _, _ := strings.Cut(header, ",")
first, _, _ = strings.Cut(first, ";")
first = strings.TrimSpace(first)
if first == "" || first == "*" {
return ""
}
// Simple parsing: take the first language tag
parts := strings.Split(header, ",")
if len(parts) == 0 {
return DefaultLang
}
// Get the first language and remove quality value
firstLang := strings.TrimSpace(parts[0])
if idx := strings.Index(firstLang, ";"); idx > 0 {
firstLang = firstLang[:idx]
}
return normalizeLang(firstLang)
return normalizeLang(first)
}
// normalizeLang normalizes language code to supported format
func normalizeLang(lang string) string {
lang = strings.ToLower(strings.TrimSpace(lang))
lang = strings.ToLower(strings.ReplaceAll(strings.TrimSpace(lang), "_", "-"))
// Handle common variations
// Handle common variations. The web console saves its own codes zhCN and
// zhTW, and maps zh-HK, zh-MO and zh-Hant to Traditional Chinese.
switch {
case strings.HasPrefix(lang, "zh-tw"):
case lang == "zhtw" || strings.HasPrefix(lang, "zh-tw") || strings.HasPrefix(lang, "zh-hk") ||
strings.HasPrefix(lang, "zh-mo") || strings.HasPrefix(lang, "zh-hant"):
return LangZhTW
case strings.HasPrefix(lang, "zh"):
return LangZhCN
@@ -222,10 +213,5 @@ func SupportedLanguages() []string {
// IsSupported checks if a language code is supported
func IsSupported(lang string) bool {
lang = normalizeLang(lang)
for _, supported := range SupportedLanguages() {
if lang == supported {
return true
}
}
return false
return slices.Contains(SupportedLanguages(), lang)
}