feat: publish sanitized custom.97 source
This commit is contained in:
1022 files changed
+69903
-19207
No files matched your search
@@ -0,0 +1,207 @@
|
||||
package i18n
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"net/http/httptest"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/relaykit/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// The web console saves its own language codes (zhCN, zhTW, fr, ...) in the
|
||||
// user setting; backend messages must follow them, and languages without a
|
||||
// backend locale fall back to English.
|
||||
func TestLanguageFromUserSetting(t *testing.T) {
|
||||
require.NoError(t, Init())
|
||||
for _, tc := range []struct {
|
||||
saved string
|
||||
want string
|
||||
}{
|
||||
{"zhCN", LangZhCN},
|
||||
{"zhTW", LangZhTW},
|
||||
{"zh-HK", LangZhTW},
|
||||
{"zh_TW", LangZhTW},
|
||||
{"zh_HK", LangZhTW},
|
||||
{"zh-Hant-TW", LangZhTW},
|
||||
{"zh", LangZhCN},
|
||||
{"en", LangEn},
|
||||
{"fr", LangEn},
|
||||
{"ja", LangEn},
|
||||
} {
|
||||
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||
c.Request = httptest.NewRequest("GET", "/v1/chat/completions", nil)
|
||||
c.Set(string(constant.ContextKeyUserSetting), dto.UserSetting{Language: tc.saved})
|
||||
assert.Equal(t, tc.want, StatedLang(c), tc.saved)
|
||||
}
|
||||
}
|
||||
|
||||
// TokenAuth puts the user's settings into the request. A user who saved no
|
||||
// language must not be loaded again, which would cost a cache or database read
|
||||
// on every relay request; a request without loaded settings still loads them.
|
||||
func TestStatedLangLoadsTheUserOnlyWithoutLoadedSettings(t *testing.T) {
|
||||
previous := userLangLoaderFunc
|
||||
t.Cleanup(func() { userLangLoaderFunc = previous })
|
||||
loads := 0
|
||||
SetUserLangLoader(func(int) string {
|
||||
loads++
|
||||
return "zhTW"
|
||||
})
|
||||
|
||||
relay, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||
relay.Request = httptest.NewRequest("POST", "/v1/chat/completions", nil)
|
||||
relay.Set("id", 7)
|
||||
relay.Set(string(constant.ContextKeyUserSetting), dto.UserSetting{})
|
||||
assert.Equal(t, "", StatedLang(relay))
|
||||
assert.Zero(t, loads)
|
||||
|
||||
dashboard, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||
dashboard.Request = httptest.NewRequest("GET", "/api/user/self", nil)
|
||||
dashboard.Set("id", 7)
|
||||
assert.Equal(t, LangZhTW, StatedLang(dashboard))
|
||||
assert.Equal(t, 1, loads)
|
||||
}
|
||||
|
||||
// A saved language or an Accept-Language header selects the language of a
|
||||
// backend message. A reader who states neither gets DEFAULT_LANGUAGE, which is
|
||||
// English when unset.
|
||||
func TestBackendMessageLanguage(t *testing.T) {
|
||||
require.NoError(t, Init())
|
||||
t.Cleanup(func() { common.DefaultLanguage = "" })
|
||||
quota := map[string]any{"Remaining": "$0.10"}
|
||||
const english = "Insufficient user quota, remaining quota: $0.10"
|
||||
const chinese = "用户额度不足, 剩余额度: $0.10"
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
defaultLanguage string
|
||||
saved string
|
||||
acceptLanguage string
|
||||
want string
|
||||
}{
|
||||
{"nothing stated", "", "", "", english},
|
||||
{"no preference header", "", "", "*", english},
|
||||
{"nothing stated with a Chinese default", "zh-CN", "", "", chinese},
|
||||
{"nothing stated with an English default", "en", "", "", english},
|
||||
{"header wins over the default", "zh-CN", "", "en-US,en;q=0.9", english},
|
||||
{"header in a language without a locale", "zh-CN", "", "fr-FR", english},
|
||||
{"saved language wins over the header", "", "zhTW", "en-US", "使用者額度不足,剩餘額度:$0.10"},
|
||||
{"saved language", "zh-CN", "en", "", english},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
common.DefaultLanguage = tc.defaultLanguage
|
||||
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||
c.Request = httptest.NewRequest("POST", "/v1/chat/completions", nil)
|
||||
if tc.acceptLanguage != "" {
|
||||
c.Request.Header.Set("Accept-Language", tc.acceptLanguage)
|
||||
}
|
||||
if tc.saved != "" {
|
||||
c.Set(string(constant.ContextKeyUserSetting), dto.UserSetting{Language: tc.saved})
|
||||
}
|
||||
assert.Equal(t, tc.want, T(c, MsgQuotaUserInsufficient, quota))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A key missing from a locale, or a template that does not parse, reaches
|
||||
// clients as the raw key.
|
||||
func TestLocalesRenderEveryKey(t *testing.T) {
|
||||
require.NoError(t, Init())
|
||||
keysFile, err := parser.ParseFile(token.NewFileSet(), "keys.go", nil, parser.SkipObjectResolution)
|
||||
require.NoError(t, err)
|
||||
var declared []string
|
||||
ast.Inspect(keysFile, func(node ast.Node) bool {
|
||||
if spec, ok := node.(*ast.ValueSpec); ok {
|
||||
for _, value := range spec.Values {
|
||||
if literal, ok := value.(*ast.BasicLit); ok {
|
||||
key, err := strconv.Unquote(literal.Value)
|
||||
require.NoError(t, err)
|
||||
declared = append(declared, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
slices.Sort(declared)
|
||||
|
||||
keysByLang := make(map[string][]string)
|
||||
for _, lang := range SupportedLanguages() {
|
||||
data, err := localeFS.ReadFile("locales/" + lang + ".yaml")
|
||||
require.NoError(t, err)
|
||||
var messages map[string]string
|
||||
require.NoError(t, yaml.Unmarshal(data, &messages))
|
||||
for key := range messages {
|
||||
keysByLang[lang] = append(keysByLang[lang], key)
|
||||
}
|
||||
slices.Sort(keysByLang[lang])
|
||||
}
|
||||
for _, lang := range SupportedLanguages() {
|
||||
assert.Equal(t, declared, keysByLang[lang], lang)
|
||||
for _, key := range keysByLang[lang] {
|
||||
text := Translate(lang, key, map[string]any{})
|
||||
assert.NotEqual(t, key, text, "%s %s", lang, key)
|
||||
assert.False(t, strings.Contains(text, "{{"), "%s %s: %s", lang, key, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Web console responses carry the English source text as message_key plus its
|
||||
// params, and the web console translates them. The backend sends the same body
|
||||
// whatever language the request asks for.
|
||||
func TestWebConsoleMessageResponse(t *testing.T) {
|
||||
require.NoError(t, Init())
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
err error
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "params",
|
||||
err: common.NewMessage("Channel {{name}} (#{{id}}) does not exist", map[string]any{"name": "{{id}}", "id": 7}),
|
||||
want: `{"success":false,"message":"Channel {{id}} (#7) does not exist","message_key":"Channel {{name}} (#{{id}}) does not exist","message_params":{"id":7,"name":"{{id}}"}}`,
|
||||
},
|
||||
{
|
||||
name: "no params",
|
||||
err: common.NewMessage("Invalid parameters"),
|
||||
want: `{"success":false,"message":"Invalid parameters","message_key":"Invalid parameters"}`,
|
||||
},
|
||||
{
|
||||
name: "plain error",
|
||||
err: errors.New("record not found"),
|
||||
want: `{"success":false,"message":"record not found"}`,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(recorder)
|
||||
c.Request = httptest.NewRequest("GET", "/api/channel/7", nil)
|
||||
c.Request.Header.Set("Accept-Language", "zh-CN")
|
||||
common.ApiError(c, tc.err)
|
||||
assert.JSONEq(t, tc.want, recorder.Body.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Server log lines are English. DEFAULT_LANGUAGE=zh-CN prints the Chinese text of
|
||||
// the lines that have one in common/log_text.zh-CN.json.
|
||||
func TestServerLogLanguage(t *testing.T) {
|
||||
t.Cleanup(func() { common.SetLogLanguage("") })
|
||||
const line = "channel #%d has %d unfinished tasks"
|
||||
assert.Equal(t, "channel #7 has 2 unfinished tasks", common.LogText(line, 7, 2))
|
||||
common.SetLogLanguage("zh-CN")
|
||||
assert.Equal(t, "渠道 #7 未完成的任务有: 2", common.LogText(line, 7, 2))
|
||||
assert.Equal(t, "a line without a Chinese text: x", common.LogText("a line without a Chinese text: %s", "x"))
|
||||
assert.Equal(t, "任务进度轮询开始", common.LogText("task progress polling started"))
|
||||
common.SetLogLanguage("en")
|
||||
assert.Equal(t, "channel #7 has 2 unfinished tasks", common.LogText(line, 7, 2))
|
||||
}
|
||||
Reference in new issue
Block a user