package langx_test import ( "context" "testing" "github.com/yuninks/langx" ) func TestGetCtxLang(t *testing.T) { reset(t) langx.RegisterTrans("zh", map[string]string{"k": "中文"}) langx.RegisterTrans("en", map[string]string{"k": "English"}) mustInit(t, langx.SetDefaultLanguage("zh")) // Accept-Language 会与已注册语言协商, 而不是原样返回 ctx := context.WithValue(context.Background(), "Accept-Language", "en-US,en;q=0.9") if got := langx.GetCtxLang(ctx); got != "en" { t.Fatalf("GetCtxLang = %q, 期望 en", got) } if got := langx.GetMsgCtx(ctx, "k"); got != "English" { t.Fatalf("GetMsgCtx = %q", got) } // []string 形式(http.Header 风格) ctx = context.WithValue(context.Background(), "Accept-Language", []string{"en-GB"}) if got := langx.GetMsgCtx(ctx, "k"); got != "English" { t.Fatalf("[]string 形式 = %q", got) } // 空 []string ctx = context.WithValue(context.Background(), "Accept-Language", []string{}) if got := langx.GetCtxLang(ctx); got != "zh" { t.Fatalf("空 []string = %q", got) } // 无法协商时回落默认语言 ctx = context.WithValue(context.Background(), "Accept-Language", "fr-FR,de;q=0.8") if got := langx.GetCtxLang(ctx); got != "zh" { t.Fatalf("无法协商 = %q", got) } // 通配符 ctx = context.WithValue(context.Background(), "Accept-Language", "*") if got := langx.GetCtxLang(ctx); got != "zh" { t.Fatalf("通配符 = %q", got) } // 显式设置的语言即使没注册也照用 if got := langx.GetCtxLang(langx.SetCtxLang(context.Background(), "fr")); got != "fr" { t.Fatalf("显式未注册语言 = %q", got) } // 空字符串的显式设置会被忽略 if got := langx.GetCtxLang(langx.SetCtxLang(context.Background(), " ")); got != "zh" { t.Fatalf("空显式语言 = %q", got) } } // 旧实现在这里会 panic, 现在必须安全回退 func TestGetCtxLangNeverPanics(t *testing.T) { reset(t) langx.RegisterTrans("zh", map[string]string{"k": "中文"}) mustInit(t, langx.SetDefaultLanguage("zh")) if got := langx.GetCtxLang(nil); got != "zh" { t.Fatalf("nil ctx = %q", got) } if got := langx.GetMsgCtx(nil, "k"); got != "中文" { t.Fatalf("nil ctx GetMsgCtx = %q", got) } for _, value := range []interface{}{123, []int{1}, struct{}{}, true} { ctx := context.WithValue(context.Background(), "Accept-Language", value) if got := langx.GetCtxLang(ctx); got != "zh" { t.Fatalf("非法类型 %T = %q", value, got) } } } func TestParseAcceptLanguage(t *testing.T) { cases := []struct { in string want []string }{ {"zh-CN,zh;q=0.9,en;q=0.8", []string{"zh-cn", "zh", "en"}}, {"en;q=0.5,zh;q=1.0", []string{"zh", "en"}}, {"en", []string{"en"}}, {" EN-US , zh ", []string{"en-us", "zh"}}, {"*", []string{"*"}}, {"de;q=0", nil}, {"", nil}, {" , ,, ", nil}, {"garbage;;q=x,en", []string{"garbage", "en"}}, {"zh;q=1;charset=utf-8,en;q=0.7", []string{"zh", "en"}}, } for _, c := range cases { got := langx.ParseAcceptLanguage(c.in) assertStrings(t, "ParseAcceptLanguage("+c.in+")", got, c.want) } } func TestNegotiateLang(t *testing.T) { reset(t) // 未注册任何语言时无法协商 if got := langx.NegotiateLang("en"); got != "" { t.Fatalf("无语言时 = %q", got) } langx.RegisterTrans("zh", map[string]string{"k": "中文"}) langx.RegisterTrans("en-GB", map[string]string{"k": "English"}) if got := langx.NegotiateLang("en-GB,en;q=0.9"); got != "en-gb" { t.Fatalf("精确匹配 = %q", got) } if got := langx.NegotiateLang("en-US,en;q=0.9"); got != "en-gb" { t.Fatalf("区域回退 = %q", got) } if got := langx.NegotiateLang("fr,zh;q=0.3"); got != "zh" { t.Fatalf("跳过不支持的语言 = %q", got) } if got := langx.NegotiateLang("fr"); got != "" { t.Fatalf("无匹配 = %q", got) } }