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 }