mengstack-api/internal/kernel/i18n/context.go
MengStack Dev df809f1045
Some checks failed
CI / Build & Test (push) Failing after 1m31s
feat: user CRUD API + dashboard stats + kernel infrastructure
- 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
2026-10-03 03:42:58 +08:00

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
}