Some checks failed
CI / Build & Test (push) Failing after 1m31s
- Add user management endpoints (list/create/get/update/delete) with pagination and search - Add dashboard stats endpoint with tenant/user/online counts and growth metrics - Add tenant resolver middleware for multi-tenant request scoping - Add i18n kernel with zh/en message files and AcceptLanguage middleware - Add WebSocket hub/handler for real-time communication - Add job scheduler kernel with cron support - Add plugin sandbox for isolated execution - Add storage kernel (local filesystem) - Add event bus kernel for pub/sub - Add cache kernel abstraction - Add database migration runner and version upgrade checker - Add rate limiting middleware with Redis backend - Add SQL migrations for rbac, audit_logs, settings, notifications, examples - Extend user repository with list/delete/count operations - Register all module routes with tenant resolver
81 lines
1.5 KiB
Go
81 lines
1.5 KiB
Go
package i18n
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type ctxKey string
|
|
|
|
const langKey ctxKey = "lang"
|
|
|
|
func WithLang(ctx context.Context, lang string) context.Context {
|
|
return context.WithValue(ctx, langKey, lang)
|
|
}
|
|
|
|
func LangFromContext(ctx context.Context) string {
|
|
v, _ := ctx.Value(langKey).(string)
|
|
if v == "" {
|
|
return fallback
|
|
}
|
|
return v
|
|
}
|
|
|
|
type langWeight struct {
|
|
lang string
|
|
weight float64
|
|
}
|
|
|
|
func ParseAcceptLanguage(header string) string {
|
|
if header == "" {
|
|
return fallback
|
|
}
|
|
|
|
var items []langWeight
|
|
for _, part := range strings.Split(header, ",") {
|
|
part = strings.TrimSpace(part)
|
|
if part == "" {
|
|
continue
|
|
}
|
|
segments := strings.SplitN(part, ";", 2)
|
|
lang := strings.TrimSpace(segments[0])
|
|
w := 1.0
|
|
if len(segments) == 2 {
|
|
qPart := strings.TrimSpace(segments[1])
|
|
if strings.HasPrefix(qPart, "q=") {
|
|
if v, err := strconv.ParseFloat(qPart[2:], 64); err == nil {
|
|
w = v
|
|
}
|
|
}
|
|
}
|
|
items = append(items, langWeight{lang: normalizeLang(lang), weight: w})
|
|
}
|
|
|
|
sort.Slice(items, func(i, j int) bool {
|
|
return items[i].weight > items[j].weight
|
|
})
|
|
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
|
|
for _, item := range items {
|
|
if _, ok := messages[item.lang]; ok {
|
|
return item.lang
|
|
}
|
|
base := strings.SplitN(item.lang, "-", 2)[0]
|
|
if _, ok := messages[base]; ok {
|
|
return base
|
|
}
|
|
}
|
|
|
|
return fallback
|
|
}
|
|
|
|
func normalizeLang(lang string) string {
|
|
lang = strings.ToLower(strings.TrimSpace(lang))
|
|
lang = strings.ReplaceAll(lang, "_", "-")
|
|
return lang
|
|
}
|