Commit d0c4305a by Calcium-Ion Committed by GitHub

feat(audit): add localized security audit logs (#5462)

parent 27b2b2c4
......@@ -135,3 +135,11 @@ For request structs that are parsed from client JSON and then re-marshaled to up
### Rule 7: Billing Expression System — Read `pkg/billingexpr/expr.md`
When working on tiered/dynamic billing (expression-based pricing), you MUST read `pkg/billingexpr/expr.md` first. It documents the design philosophy, expression language (variables, functions, examples), full system architecture (editor → storage → pre-consume → settlement → log display), token normalization rules (`p`/`c` auto-exclusion), quota conversion, and expression versioning. All code changes to the billing expression system must follow the patterns described in that document.
### Rule 8: Pull Requests — Identify AI-Generated Contributions When Appropriate
When creating a pull request:
- First compare the current git user (`git config user.name` / `git config user.email`) with the repository's historical core developers (for example, the recurring top authors in `git log`). Do not change git config.
- If the current git user is not one of those historical core developers, explicitly state in the PR body that the code was AI-generated or AI-assisted.
- Always use the repository PR template at `.github/PULL_REQUEST_TEMPLATE.md` when drafting the PR title/body. Preserve the template structure and fill in the relevant sections instead of replacing it with an ad hoc format.
......@@ -135,3 +135,11 @@ For request structs that are parsed from client JSON and then re-marshaled to up
### Rule 7: Billing Expression System — Read `pkg/billingexpr/expr.md`
When working on tiered/dynamic billing (expression-based pricing), you MUST read `pkg/billingexpr/expr.md` first. It documents the design philosophy, expression language (variables, functions, examples), full system architecture (editor → storage → pre-consume → settlement → log display), token normalization rules (`p`/`c` auto-exclusion), quota conversion, and expression versioning. All code changes to the billing expression system must follow the patterns described in that document.
### Rule 8: Pull Requests — Identify AI-Generated Contributions When Appropriate
When creating a pull request:
- First compare the current git user (`git config user.name` / `git config user.email`) with the repository's historical core developers (for example, the recurring top authors in `git log`). Do not change git config.
- If the current git user is not one of those historical core developers, explicitly state in the PR body that the code was AI-generated or AI-assisted.
- Always use the repository PR template at `.github/PULL_REQUEST_TEMPLATE.md` when drafting the PR title/body. Preserve the template structure and fill in the relevant sections instead of replacing it with an ad hoc format.
......@@ -66,4 +66,10 @@ const (
// ContextKeyLanguage stores the user's language preference for i18n
ContextKeyLanguage ContextKey = "language"
ContextKeyIsStream ContextKey = "is_stream"
// ContextKeyAuditLogged marks that the current request has already recorded
// a manage/operation audit log inside the handler. When set, the admin-audit
// fallback in authHelper (finishAdminAudit) skips its record to avoid
// duplicate entries.
ContextKeyAuditLogged ContextKey = "audit_logged"
)
package controller
import (
"fmt"
"os"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/constant"
"github.com/QuantumNous/new-api/model"
"github.com/gin-gonic/gin"
)
// auditContentTemplates 将稳定的操作标识 action 映射为英文兜底模板,渲染后写入
// Log.Content(供导出 / 经典前端等非本地化消费者使用)。占位符为 ${name},由该
// action 的 params 填充。本地化展示文案在前端 i18n 模板中维护,本表是语言中立的
// 英文基线——调用方因此无需在每个埋点处手写句子(避免与 params 重复书写同一份值)。
var auditContentTemplates = map[string]string{
"user.create": "Created user ${username} (role ${role})",
"user.update": "Updated user ${username} (ID: ${id})",
"user.delete": "Deleted user ${username} (ID: ${id})",
"user.manage": "Performed ${action} on user ${username} (ID: ${id})",
"user.quota_add": "Increased user quota by ${quota}",
"user.quota_subtract": "Decreased user quota by ${quota}",
"user.quota_override": "Overrode user quota from ${from} to ${to}",
"user.binding_clear": "Cleared ${bindingType} binding for user ${username}",
"user.2fa_disable": "Force-disabled two-factor authentication for the user",
"user.passkey_register": "Registered a passkey",
"user.passkey_delete": "Deleted a passkey",
"user.reset_passkey": "Reset the user passkey",
"option.update": "Updated system setting ${key}",
"channel.create": "Created channel ${name} (type ${type}, count ${count})",
"channel.update": "Updated channel ${name} (ID: ${id})",
"channel.delete": "Deleted channel ${name} (ID: ${id})",
"channel.delete_batch": "Batch deleted ${count} channels",
"channel.delete_disabled": "Deleted all disabled channels (${count})",
"channel.key_view": "Viewed channel key ${name} (ID: ${id})",
"channel.tag_disable": "Disabled channels with tag ${tag}",
"channel.tag_enable": "Enabled channels with tag ${tag}",
"channel.tag_edit": "Edited channels with tag ${tag}",
"channel.tag_batch_set": "Batch set tag for ${count} channels",
"channel.copy": "Copied channel (source ID: ${sourceId}) to ${name} (new ID: ${id})",
"channel.multi_key_manage": "Multi-key management ${action} on channel (ID: ${id})",
"channel.upstream_apply": "Applied upstream model changes to channel (ID: ${id})",
"channel.upstream_apply_all": "Applied upstream model changes to ${count} channels",
"redemption.create": "Created ${count} redemption codes named ${name} (${quota} each)",
}
// auditContentEN 按 action 模板渲染英文兜底文本;未登记的 action 退回 action 本身。
func auditContentEN(action string, params map[string]interface{}) string {
tmpl, ok := auditContentTemplates[action]
if !ok {
return action
}
return os.Expand(tmpl, func(key string) string {
if v, ok := params[key]; ok {
return fmt.Sprintf("%v", v)
}
return ""
})
}
// auditOperatorInfo 从上下文构建操作者身份信息(管理员 id/用户名/角色)。
func auditOperatorInfo(c *gin.Context) map[string]interface{} {
return map[string]interface{}{
"admin_id": c.GetInt("id"),
"admin_username": c.GetString("username"),
"admin_role": c.GetInt("role"),
}
}
// markAuditLogged 标记当前请求已在 handler 内手动记录审计日志,
// 使鉴权链路中的审计兜底(finishAdminAudit)跳过兜底记录,避免重复。
func markAuditLogged(c *gin.Context) {
common.SetContextKey(c, constant.ContextKeyAuditLogged, true)
}
// recordManageAudit 记录一条由操作者本人归属的管理/高危审计日志(资源类操作:
// 渠道 / 系统设置 / 兑换码等)。content 由 action+params 自动渲染。
func recordManageAudit(c *gin.Context, action string, params map[string]interface{}) {
recordManageAuditFor(c, c.GetInt("id"), action, params)
}
// recordManageAuditFor 记录一条归属于 logUserId 的管理审计日志(面向用户的操作:
// 对目标用户的额度调整 / 解绑 / 2FA 等,使该用户也能在自己的日志中看到)。
func recordManageAuditFor(c *gin.Context, logUserId int, action string, params map[string]interface{}) {
model.RecordOperationAuditLog(logUserId, auditContentEN(action, params), c.ClientIP(), action, params, auditOperatorInfo(c), nil)
markAuditLogged(c)
}
// recordUserSecurityAudit 记录普通用户自己的安全敏感操作(如 passkey 绑定/解绑)。
// 这类日志没有管理员操作者,不写 admin_info;同时不依赖 AdminAuth/RootAuth 的兜底。
func recordUserSecurityAudit(c *gin.Context, userId int, action string, params map[string]interface{}) {
model.RecordOperationAuditLog(userId, auditContentEN(action, params), c.ClientIP(), action, params, nil, nil)
}
......@@ -404,7 +404,6 @@ func GetChannel(c *gin.Context) {
// GetChannelKey 获取渠道密钥(需要通过安全验证中间件)
// 此函数依赖 SecureVerificationRequired 中间件,确保用户已通过安全验证
func GetChannelKey(c *gin.Context) {
userId := c.GetInt("id")
channelId, err := strconv.Atoi(c.Param("id"))
if err != nil {
common.ApiError(c, fmt.Errorf("渠道ID格式错误: %v", err))
......@@ -423,8 +422,11 @@ func GetChannelKey(c *gin.Context) {
return
}
// 记录操作日志
model.RecordLog(userId, model.LogTypeSystem, fmt.Sprintf("查看渠道密钥信息 (渠道ID: %d)", channelId))
// 记录操作审计日志(高危:查看渠道密钥)
recordManageAudit(c, "channel.key_view", map[string]interface{}{
"id": channelId,
"name": channel.Name,
})
// 返回渠道密钥
c.JSON(http.StatusOK, gin.H{
......@@ -677,6 +679,11 @@ func AddChannel(c *gin.Context) {
return
}
service.ResetProxyClientCache()
recordManageAudit(c, "channel.create", map[string]interface{}{
"name": addChannelRequest.Channel.Name,
"type": addChannelRequest.Channel.Type,
"count": len(channels),
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -686,6 +693,10 @@ func AddChannel(c *gin.Context) {
func DeleteChannel(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
channelName := ""
if existing, err := model.GetChannelById(id, false); err == nil && existing != nil {
channelName = existing.Name
}
channel := model.Channel{Id: id}
err := channel.Delete()
if err != nil {
......@@ -693,6 +704,10 @@ func DeleteChannel(c *gin.Context) {
return
}
model.InitChannelCache()
recordManageAudit(c, "channel.delete", map[string]interface{}{
"id": id,
"name": channelName,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -707,6 +722,9 @@ func DeleteDisabledChannel(c *gin.Context) {
return
}
model.InitChannelCache()
recordManageAudit(c, "channel.delete_disabled", map[string]interface{}{
"count": rows,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -743,6 +761,9 @@ func DisableTagChannels(c *gin.Context) {
return
}
model.InitChannelCache()
recordManageAudit(c, "channel.tag_disable", map[string]interface{}{
"tag": channelTag.Tag,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -766,6 +787,9 @@ func EnableTagChannels(c *gin.Context) {
return
}
model.InitChannelCache()
recordManageAudit(c, "channel.tag_enable", map[string]interface{}{
"tag": channelTag.Tag,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -818,6 +842,9 @@ func EditTagChannels(c *gin.Context) {
return
}
model.InitChannelCache()
recordManageAudit(c, "channel.tag_edit", map[string]interface{}{
"tag": channelTag.Tag,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -846,6 +873,9 @@ func DeleteChannelBatch(c *gin.Context) {
return
}
model.InitChannelCache()
recordManageAudit(c, "channel.delete_batch", map[string]interface{}{
"count": len(channelBatch.Ids),
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -981,6 +1011,31 @@ func UpdateChannel(c *gin.Context) {
}
model.InitChannelCache()
service.ResetProxyClientCache()
// 记录变更的字段名(语言无关的字段标识),密钥仅记录"已更换"绝不记录内容。
changedFields := make([]string, 0)
if channel.Status != originChannel.Status {
changedFields = append(changedFields, "status")
}
if channel.Models != originChannel.Models {
changedFields = append(changedFields, "models")
}
if channel.Group != originChannel.Group {
changedFields = append(changedFields, "group")
}
if channel.Type != originChannel.Type {
changedFields = append(changedFields, "type")
}
if !equalStringPtr(channel.BaseURL, originChannel.BaseURL) {
changedFields = append(changedFields, "base_url")
}
if channel.Key != "" && channel.Key != originChannel.Key {
changedFields = append(changedFields, "key")
}
recordManageAudit(c, "channel.update", map[string]interface{}{
"id": channel.Id,
"name": channel.Name,
"changed_fields": changedFields,
})
channel.Key = ""
clearChannelInfo(&channel.Channel)
c.JSON(http.StatusOK, gin.H{
......@@ -991,6 +1046,17 @@ func UpdateChannel(c *gin.Context) {
return
}
// equalStringPtr 比较两个 *string 是否相等(均为 nil 视为相等)。
func equalStringPtr(a, b *string) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
return *a == *b
}
func FetchModels(c *gin.Context) {
var req struct {
BaseURL string `json:"base_url"`
......@@ -1127,6 +1193,9 @@ func BatchSetChannelTag(c *gin.Context) {
return
}
model.InitChannelCache()
recordManageAudit(c, "channel.tag_batch_set", map[string]interface{}{
"count": len(channelBatch.Ids),
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -1224,6 +1293,11 @@ func CopyChannel(c *gin.Context) {
return
}
model.InitChannelCache()
recordManageAudit(c, "channel.copy", map[string]interface{}{
"sourceId": id,
"id": clone.Id,
"name": clone.Name,
})
// success
c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": gin.H{"id": clone.Id}})
}
......@@ -1285,6 +1359,16 @@ func ManageMultiKeys(c *gin.Context) {
return
}
// get_key_status 为只读查询,不记录审计;其余为修改操作,记录审计并跳过中间件兜底。
if request.Action == "get_key_status" {
markAuditLogged(c)
} else {
recordManageAudit(c, "channel.multi_key_manage", map[string]interface{}{
"action": request.Action,
"id": channel.Id,
})
}
lock := model.GetChannelPollingLock(channel.Id)
lock.Lock()
defer lock.Unlock()
......
......@@ -717,6 +717,9 @@ func ApplyChannelUpstreamModelUpdates(c *gin.Context) {
refreshChannelRuntimeCache()
}
recordManageAudit(c, "channel.upstream_apply", map[string]interface{}{
"id": channel.Id,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -912,6 +915,9 @@ func ApplyAllChannelUpstreamModelUpdates(c *gin.Context) {
refreshChannelRuntimeCache()
}
recordManageAudit(c, "channel.upstream_apply_all", map[string]interface{}{
"count": len(results),
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......
......@@ -337,6 +337,10 @@ func UpdateOption(c *gin.Context) {
common.ApiError(c, err)
return
}
// 出于安全考虑只记录被修改的配置项名称,不记录配置值(可能含密钥等敏感信息)。
recordManageAudit(c, "option.update", map[string]interface{}{
"key": option.Key,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......
......@@ -143,6 +143,7 @@ func PasskeyRegisterFinish(c *gin.Context) {
return
}
recordUserSecurityAudit(c, user.Id, "user.passkey_register", nil)
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Passkey 注册成功",
......@@ -168,6 +169,7 @@ func PasskeyDelete(c *gin.Context) {
return
}
recordUserSecurityAudit(c, user.Id, "user.passkey_delete", nil)
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Passkey 已解绑",
......@@ -335,7 +337,6 @@ func PasskeyLoginFinish(c *gin.Context) {
}
setupLogin(modelUser, c)
return
}
func AdminResetPasskey(c *gin.Context) {
......@@ -373,6 +374,10 @@ func AdminResetPasskey(c *gin.Context) {
return
}
recordManageAuditFor(c, user.Id, "user.reset_passkey", map[string]interface{}{
"username": user.Username,
"id": user.Id,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Passkey 已重置",
......
......@@ -7,6 +7,7 @@ import (
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/i18n"
"github.com/QuantumNous/new-api/logger"
"github.com/QuantumNous/new-api/model"
"github.com/QuantumNous/new-api/setting/operation_setting"
......@@ -110,6 +111,11 @@ func AddRedemption(c *gin.Context) {
}
keys = append(keys, key)
}
recordManageAudit(c, "redemption.create", map[string]interface{}{
"name": redemption.Name,
"count": redemption.Count,
"quota": logger.LogQuota(redemption.Quota),
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......
......@@ -541,15 +541,7 @@ func AdminDisable2FA(c *gin.Context) {
return
}
// 记录操作日志:管理员身份通过 admin_info 传递,避免在非管理员可见的日志内容中泄露。
adminId := c.GetInt("id")
adminName := c.GetString("username")
adminInfo := map[string]interface{}{
"admin_id": adminId,
"admin_username": adminName,
}
model.RecordLogWithAdminInfo(userId, model.LogTypeManage,
"管理员强制禁用了用户的两步验证", adminInfo)
recordManageAuditFor(c, userId, "user.2fa_disable", nil)
c.JSON(http.StatusOK, gin.H{
"success": true,
......
......@@ -90,6 +90,43 @@ func Login(c *gin.Context) {
setupLogin(&user, c)
}
// loginMethodFromContext 根据请求路径推导登录方式,用于登录审计日志。
func loginMethodFromContext(c *gin.Context) string {
switch c.FullPath() {
case "/api/user/login":
return "password"
case "/api/user/login/2fa":
return "2fa"
case "/api/user/passkey/login/finish":
return "passkey"
case "/api/oauth/wechat":
return "wechat"
case "/api/oauth/telegram/login":
return "telegram"
case "/api/oauth/:provider":
if provider := c.Param("provider"); provider != "" {
return "oauth:" + provider
}
return "oauth"
default:
return "unknown"
}
}
// recordLoginAudit 记录登录成功审计日志(对所有用户启用,仅记录成功,不记录失败)。
func recordLoginAudit(user *model.User, c *gin.Context) {
method := loginMethodFromContext(c)
ip := c.ClientIP()
extra := map[string]interface{}{
"login_method": method,
"user_agent": c.Request.UserAgent(),
}
content := fmt.Sprintf("Logged in successfully via %s", method)
model.RecordLoginLog(user.Id, user.Username, content, ip, "login", map[string]interface{}{
"method": method,
}, extra)
}
// setup session & cookies and then return user info
func setupLogin(user *model.User, c *gin.Context) {
model.UpdateUserLastLoginAt(user.Id)
......@@ -104,6 +141,7 @@ func setupLogin(user *model.User, c *gin.Context) {
common.ApiErrorI18n(c, i18n.MsgUserSessionSaveFailed)
return
}
recordLoginAudit(user, c)
c.JSON(http.StatusOK, gin.H{
"message": "",
"success": true,
......@@ -599,6 +637,10 @@ func UpdateUser(c *gin.Context) {
common.ApiError(c, err)
return
}
recordManageAuditFor(c, updatedUser.Id, "user.update", map[string]interface{}{
"username": originUser.Username,
"id": updatedUser.Id,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -636,7 +678,10 @@ func AdminClearUserBinding(c *gin.Context) {
return
}
model.RecordLog(user.Id, model.LogTypeManage, fmt.Sprintf("admin cleared %s binding for user %s", bindingType, user.Username))
recordManageAuditFor(c, user.Id, "user.binding_clear", map[string]interface{}{
"bindingType": bindingType,
"username": user.Username,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
......@@ -797,6 +842,10 @@ func DeleteUser(c *gin.Context) {
common.ApiError(c, err)
return
}
recordManageAuditFor(c, originUser.Id, "user.delete", map[string]interface{}{
"username": originUser.Username,
"id": originUser.Id,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -857,6 +906,10 @@ func CreateUser(c *gin.Context) {
return
}
recordManageAuditFor(c, cleanUser.Id, "user.create", map[string]interface{}{
"username": cleanUser.Username,
"role": cleanUser.Role,
})
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
......@@ -941,12 +994,6 @@ func ManageUser(c *gin.Context) {
}
user.Role = common.RoleCommonUser
case "add_quota":
adminName := c.GetString("username")
adminId := c.GetInt("id")
adminInfo := map[string]interface{}{
"admin_id": adminId,
"admin_username": adminName,
}
switch req.Mode {
case "add":
if req.Value <= 0 {
......@@ -957,8 +1004,9 @@ func ManageUser(c *gin.Context) {
common.ApiError(c, err)
return
}
model.RecordLogWithAdminInfo(user.Id, model.LogTypeManage,
fmt.Sprintf("管理员增加用户额度 %s", logger.LogQuota(req.Value)), adminInfo)
recordManageAuditFor(c, user.Id, "user.quota_add", map[string]interface{}{
"quota": logger.LogQuota(req.Value),
})
case "subtract":
if req.Value <= 0 {
common.ApiErrorI18n(c, i18n.MsgUserQuotaChangeZero)
......@@ -968,16 +1016,19 @@ func ManageUser(c *gin.Context) {
common.ApiError(c, err)
return
}
model.RecordLogWithAdminInfo(user.Id, model.LogTypeManage,
fmt.Sprintf("管理员减少用户额度 %s", logger.LogQuota(req.Value)), adminInfo)
recordManageAuditFor(c, user.Id, "user.quota_subtract", map[string]interface{}{
"quota": logger.LogQuota(req.Value),
})
case "override":
oldQuota := user.Quota
if err := model.DB.Model(&model.User{}).Where("id = ?", user.Id).Update("quota", req.Value).Error; err != nil {
common.ApiError(c, err)
return
}
model.RecordLogWithAdminInfo(user.Id, model.LogTypeManage,
fmt.Sprintf("管理员覆盖用户额度从 %s 为 %s", logger.LogQuota(oldQuota), logger.LogQuota(req.Value)), adminInfo)
recordManageAuditFor(c, user.Id, "user.quota_override", map[string]interface{}{
"from": logger.LogQuota(oldQuota),
"to": logger.LogQuota(req.Value),
})
default:
common.ApiErrorI18n(c, i18n.MsgInvalidParams)
return
......@@ -1005,6 +1056,11 @@ func ManageUser(c *gin.Context) {
common.SysLog(fmt.Sprintf("failed to invalidate tokens cache for user %d: %s", user.Id, err.Error()))
}
}
recordManageAuditFor(c, user.Id, "user.manage", map[string]interface{}{
"action": req.Action,
"username": user.Username,
"id": user.Id,
})
clearUser := model.User{
Role: user.Role,
Status: user.Status,
......
package middleware
import (
"bytes"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/constant"
"github.com/QuantumNous/new-api/model"
"github.com/bytedance/gopkg/util/gopool"
"github.com/gin-gonic/gin"
)
// auditResponseWriter 包装 gin.ResponseWriter,捕获响应状态码并将响应体复制一份到
// 有限大小的缓冲区,用于判断业务是否成功(解析响应 JSON 的 success 字段)。
// 缓冲区有上限,避免大响应(如密钥导出)占用过多内存;超出上限则不再缓存,
// 此时仅依据 HTTP 状态码判断成败。
type auditResponseWriter struct {
gin.ResponseWriter
body *bytes.Buffer
maxSize int
}
func (w *auditResponseWriter) Write(b []byte) (int, error) {
if w.body.Len() < w.maxSize {
remain := w.maxSize - w.body.Len()
if remain >= len(b) {
w.body.Write(b)
} else {
w.body.Write(b[:remain])
}
}
return w.ResponseWriter.Write(b)
}
func (w *auditResponseWriter) WriteString(s string) (int, error) {
return w.Write([]byte(s))
}
// auditRouteActions 将「METHOD + 路由模板」映射为语言无关的操作标识 action。
// 这些是未被 handler 手动埋点的写操作,由中间件兜底记录;前端依据 action 用 i18n 本地化展示。
// 未命中的写操作回退为 action="generic",前端展示 "METHOD route"。
var auditRouteActions = map[string]string{
// 用户管理
"POST /api/user/topup/complete": "user.topup_complete",
"DELETE /api/user/:id/reset_passkey": "user.reset_passkey",
"DELETE /api/user/:id/oauth/bindings/:provider_id": "user.oauth_unbind",
// 系统设置(root)
"POST /api/option/payment_compliance": "option.payment_compliance",
"POST /api/option/rest_model_ratio": "option.reset_ratio",
"DELETE /api/option/channel_affinity_cache": "option.clear_affinity_cache",
// 自定义 OAuth(root)
"POST /api/custom-oauth-provider/": "custom_oauth.create",
"PUT /api/custom-oauth-provider/:id": "custom_oauth.update",
"DELETE /api/custom-oauth-provider/:id": "custom_oauth.delete",
// 性能/缓存(root)
"DELETE /api/performance/disk_cache": "performance.clear_disk_cache",
"POST /api/performance/gc": "performance.gc",
"DELETE /api/performance/logs": "performance.clear_logs",
// 兑换码
"PUT /api/redemption/": "redemption.update",
"DELETE /api/redemption/:id": "redemption.delete",
"DELETE /api/redemption/invalid": "redemption.delete_invalid",
// 预填组
"POST /api/prefill_group/": "prefill_group.create",
"PUT /api/prefill_group/": "prefill_group.update",
"DELETE /api/prefill_group/:id": "prefill_group.delete",
// 供应商
"POST /api/vendors/": "vendor.create",
"PUT /api/vendors/": "vendor.update",
"DELETE /api/vendors/:id": "vendor.delete",
// 模型元数据
"POST /api/models/": "model.create",
"PUT /api/models/": "model.update",
"DELETE /api/models/:id": "model.delete",
"POST /api/models/sync_upstream": "model.sync_upstream",
// 部署
"POST /api/deployments/": "deployment.create",
"PUT /api/deployments/:id": "deployment.update",
"DELETE /api/deployments/:id": "deployment.delete",
// 订阅(管理员)
"POST /api/subscription/admin/plans": "subscription.plan_create",
"PUT /api/subscription/admin/plans/:id": "subscription.plan_update",
"POST /api/subscription/admin/bind": "subscription.bind",
// 日志
"DELETE /api/log/": "log.clear",
}
// beginAdminAudit 在管理/root 写操作进入 handler 前包装 ResponseWriter,
// 以便事后解析响应判断业务是否成功。仅对写方法(POST/PUT/PATCH/DELETE)生效;
// 只读请求返回 nil,调用方据此跳过事后兜底记录。
//
// 该函数由 authHelper 在鉴权通过、c.Next() 之前调用:因为任何管理/root 接口都
// 必然经过 AdminAuth/RootAuth,将审计兜底内聚到鉴权链路即可保证「新增接口自动留痕」,
// 无需在路由上再单独挂一层审计中间件(避免漏挂)。
func beginAdminAudit(c *gin.Context) *auditResponseWriter {
method := c.Request.Method
if method != "POST" && method != "PUT" && method != "PATCH" && method != "DELETE" {
return nil
}
writer := &auditResponseWriter{
ResponseWriter: c.Writer,
body: bytes.NewBuffer(nil),
maxSize: 64 * 1024,
}
c.Writer = writer
return writer
}
// finishAdminAudit 在 c.Next() 之后对管理/高危写操作做兜底审计记录。
// 若 handler 内已手动埋点(设置 ContextKeyAuditLogged),则跳过,避免重复。
func finishAdminAudit(c *gin.Context, writer *auditResponseWriter) {
if writer == nil {
return
}
method := c.Request.Method
// handler 已手动记录更精细的审计日志,跳过兜底。
if common.GetContextKeyBool(c, constant.ContextKeyAuditLogged) {
return
}
operatorId := c.GetInt("id")
operatorName := c.GetString("username")
operatorRole := c.GetInt("role")
ip := c.ClientIP()
status := writer.Status()
success := auditResponseSuccess(status, writer.body.Bytes())
route := c.FullPath()
action := auditRouteActions[method+" "+route]
if action == "" {
action = "generic"
}
routeParams := map[string]string{}
for _, p := range c.Params {
routeParams[p.Key] = p.Value
}
// op.params 为语言无关参数,供前端 i18n 渲染;generic 时携带 method/route。
opParams := map[string]interface{}{}
if action == "generic" {
opParams["method"] = method
opParams["route"] = route
}
// content 为英文兜底文本(导出/经典前端用)。
content := method + " " + route
adminInfo := map[string]interface{}{
"admin_id": operatorId,
"admin_username": operatorName,
"admin_role": operatorRole,
}
auditInfo := map[string]interface{}{
"method": method,
"route": route,
"path": c.Request.URL.Path,
"status": status,
"success": success,
}
if len(routeParams) > 0 {
auditInfo["params"] = routeParams
}
gopool.Go(func() {
model.RecordOperationAuditLog(operatorId, content, ip, action, opParams, adminInfo, auditInfo)
})
}
// auditResponseSuccess 依据 HTTP 状态码与响应体推断操作是否成功。
// 优先解析响应 JSON 中的 success 字段;无法解析时退回到状态码判断。
func auditResponseSuccess(status int, body []byte) bool {
if status >= 400 {
return false
}
trimmed := bytes.TrimSpace(body)
if len(trimmed) > 0 && trimmed[0] == '{' {
var resp struct {
Success *bool `json:"success"`
}
if err := common.Unmarshal(trimmed, &resp); err == nil && resp.Success != nil {
return *resp.Success
}
}
return status < 400
}
......@@ -153,7 +153,17 @@ func authHelper(c *gin.Context, minRole int) {
c.Set("user_group", session.Get("group"))
c.Set("use_access_token", useAccessToken)
// 管理/root 写操作审计兜底:内聚在鉴权链路里,保证任何经过 AdminAuth/RootAuth
// 的写接口都会自动留痕(无需在路由上单独挂审计中间件,避免漏挂)。
// handler 内手动埋点者会设置 ContextKeyAuditLogged,finishAdminAudit 据此跳过。
var auditWriter *auditResponseWriter
if minRole >= common.RoleAdminUser {
auditWriter = beginAdminAudit(c)
}
c.Next()
finishAdminAudit(c, auditWriter)
}
func TryUserAuth() func(c *gin.Context) {
......
......@@ -64,6 +64,7 @@ const (
LogTypeSystem = 4
LogTypeError = 5
LogTypeRefund = 6
LogTypeLogin = 7
)
func formatUserLogs(logs []*Log, startIdx int) {
......@@ -74,6 +75,8 @@ func formatUserLogs(logs []*Log, startIdx int) {
if otherMap != nil {
// Remove admin-only debug fields.
delete(otherMap, "admin_info")
// Remove operation-audit details (operator/route info), admin-only.
delete(otherMap, "audit_info")
// delete(otherMap, "reject_reason")
delete(otherMap, "stream_status")
}
......@@ -130,6 +133,74 @@ func RecordLogWithAdminInfo(userId int, logType int, content string, adminInfo m
}
}
// buildOpField 构建语言无关的操作描述(写入 Other.op)。
// 前端依据 action(稳定操作标识) + params(结构化参数) 在渲染期用 i18n 本地化展示,
// 因此不在数据库中存储自然语言句子。
func buildOpField(action string, params map[string]interface{}) map[string]interface{} {
op := map[string]interface{}{
"action": action,
}
if len(params) > 0 {
op["params"] = params
}
return op
}
// RecordLoginLog 记录用户登录成功的审计日志(type=LogTypeLogin)。
// username 由调用方传入(登录流程已持有用户对象),避免额外的数据库查询。
// content 为英文兜底文本(用于导出/经典前端);action+params 供前端本地化渲染。
// extra 可携带 login_method、user_agent 等附加信息(普通用户可见)。
func RecordLoginLog(userId int, username string, content string, ip string, action string, params map[string]interface{}, extra map[string]interface{}) {
other := map[string]interface{}{}
for k, v := range extra {
other[k] = v
}
other["op"] = buildOpField(action, params)
log := &Log{
UserId: userId,
Username: username,
CreatedAt: common.GetTimestamp(),
Type: LogTypeLogin,
Content: content,
Ip: ip,
Other: common.MapToJsonStr(other),
}
if err := LOG_DB.Create(log).Error; err != nil {
common.SysLog("failed to record login log: " + err.Error())
}
}
// RecordOperationAuditLog 记录管理/高危操作审计日志(type=LogTypeManage)。
// logUserId 为日志归属者(面向用户的操作如额度调整归属目标用户,资源类操作如渠道/系统设置归属操作者),
// username 内部按 logUserId 查询。content 为英文兜底文本(导出/经典前端用)。
// action+params 写入 Other.op,供前端本地化渲染(普通用户可见,不含敏感信息)。
// adminInfo 存放操作者身份(写入 Other.admin_info,普通用户查询时剥离);
// auditInfo 存放路由/方法/结果等中间件兜底信息(写入 Other.audit_info,普通用户查询时剥离)。
func RecordOperationAuditLog(logUserId int, content string, ip string, action string, params map[string]interface{}, adminInfo map[string]interface{}, auditInfo map[string]interface{}) {
username, _ := GetUsernameById(logUserId, false)
other := map[string]interface{}{
"op": buildOpField(action, params),
}
if len(adminInfo) > 0 {
other["admin_info"] = adminInfo
}
if len(auditInfo) > 0 {
other["audit_info"] = auditInfo
}
log := &Log{
UserId: logUserId,
Username: username,
CreatedAt: common.GetTimestamp(),
Type: LogTypeManage,
Content: content,
Ip: ip,
Other: common.MapToJsonStr(other),
}
if err := LOG_DB.Create(log).Error; err != nil {
common.SysLog("failed to record operation audit log: " + err.Error())
}
}
func RecordTopupLog(userId int, content string, callerIp string, paymentMethod string, callbackPaymentMethod string) {
username, _ := GetUsernameById(userId, false)
adminInfo := map[string]interface{}{
......
......@@ -46,6 +46,7 @@ import {
hasAnyCacheTokens,
parseLogOther,
isViolationFeeLog,
renderAuditContent,
} from '../../lib/format'
import {
isDisplayableLogType,
......@@ -100,6 +101,13 @@ function buildDetailSegments(
other: LogOtherData | null,
t: (key: string, opts?: Record<string, unknown>) => string
): DetailSegment[] {
// Audit (type=3) and login (type=7) logs: render localized content from the
// structured op descriptor instead of the raw (English-fallback) content.
if (log.type === 3 || log.type === 7) {
const text = renderAuditContent(other, t)
return text ? [{ text }] : []
}
if (log.type === 6) {
return [{ text: t('Async task refund') }]
}
......
......@@ -29,6 +29,7 @@ import {
ShieldCheck,
UserCog,
Info,
LogIn,
} from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { formatBillingCurrencyFromUSD } from '@/lib/currency'
......@@ -52,6 +53,7 @@ import {
isViolationFeeLog,
getFirstResponseTimeColor,
getResponseTimeColor,
renderAuditContent,
} from '../../lib/format'
import {
getLogTypeConfig,
......@@ -60,6 +62,17 @@ import {
} from '../../lib/utils'
import type { LogOtherData } from '../../types'
// Maps a channel-update changed-field token (as recorded by the backend audit)
// to its i18n label key for display in the audit details.
const CHANNEL_FIELD_LABELS: Record<string, string> = {
status: 'Status',
models: 'Models',
group: 'Group',
type: 'Type',
base_url: 'Base URL',
key: 'Key',
}
function timingTextColorClass(
variant: 'success' | 'warning' | 'danger'
): string {
......@@ -461,6 +474,41 @@ export function DetailsDialog(props: DetailsDialogProps) {
return `ID: ${id}`
})()
// Localized operation text rendered from the language-independent op
// descriptor (shared by audit type=3 and login type=7).
const operationText = renderAuditContent(other, t)
const auditRoute = isManage && props.isAdmin ? other?.audit_info : undefined
// Channel update records which fields changed (stable field tokens); render
// them with their localized labels for admins.
const changedFieldTokens =
isManage && props.isAdmin && Array.isArray(other?.op?.params?.changed_fields)
? (other.op.params.changed_fields as string[])
: []
const changedFieldsText = changedFieldTokens
.map((field) => t(CHANNEL_FIELD_LABELS[field] ?? field))
.join(', ')
const showManageAuditSection =
isManage && props.isAdmin && (operationText != null || auditRoute != null)
// Login audit (type=7); visible to the log owner, not admin-only.
const isLogin = props.log.type === 7
const loginAuditFields = isLogin
? ([
other?.login_method && {
label: t('Login Method'),
value: String(other.login_method),
},
props.log.ip && {
label: t('IP Address'),
value: props.log.ip,
},
other?.user_agent && {
label: t('User Agent'),
value: String(other.user_agent),
},
].filter(Boolean) as Array<{ label: string; value: string }>)
: []
const conversionChain =
other && Array.isArray(other.request_conversion)
? other.request_conversion.filter(Boolean)
......@@ -749,6 +797,62 @@ export function DetailsDialog(props: DetailsDialogProps) {
/>
)}
{/* Operation audit info (type=3, admin only) */}
{showManageAuditSection && (
<DetailSection
icon={<ShieldCheck className='size-3.5' aria-hidden='true' />}
label={t('Operation Audit Info')}
>
{operationText != null && (
<DetailRow label={t('Operation')} value={operationText} />
)}
{changedFieldsText !== '' && (
<DetailRow
label={t('Changed Fields')}
value={changedFieldsText}
/>
)}
{auditRoute?.method && auditRoute?.route && (
<DetailRow
label={t('Request')}
value={`${auditRoute.method} ${auditRoute.route}`}
mono
/>
)}
{auditRoute?.status != null && (
<DetailRow
label={t('Result')}
value={
auditRoute.success
? `${t('Success')} (${auditRoute.status})`
: `${t('Failed')} (${auditRoute.status})`
}
mono
/>
)}
</DetailSection>
)}
{/* Login audit info (type=7) */}
{isLogin && loginAuditFields.length > 0 && (
<DetailSection
icon={<LogIn className='size-3.5' aria-hidden='true' />}
label={t('Login Info')}
>
{operationText != null && (
<DetailRow label={t('Operation')} value={operationText} />
)}
{loginAuditFields.map((field, idx) => (
<DetailRow
key={idx}
label={field.label}
value={field.value}
mono
/>
))}
</DetailSection>
)}
{/* Audio/WebSocket token breakdown */}
{hasAudioTokens && other && (
<DetailSection
......
......@@ -58,6 +58,7 @@ export const LOG_TYPE_ENUM = {
SYSTEM: 4,
ERROR: 5,
REFUND: 6,
LOGIN: 7,
} as const
/**
......@@ -95,6 +96,7 @@ export const LOG_TYPES = [
{ value: 4, label: 'System', color: 'purple' },
{ value: 5, label: 'Error', color: 'red' },
{ value: 6, label: 'Refund', color: 'blue' },
{ value: 7, label: 'Login', color: 'teal' },
] as const
/**
......
......@@ -298,3 +298,109 @@ export function formatDuration(
return { durationSec, variant: durationSec > 60 ? 'red' : 'green' }
}
/**
* Maps a language-independent audit/login operation `action` to an i18n
* template string (the template itself is the i18n key, with {{placeholders}}).
*
* The backend stores only `action` + structured `params` in `other.op`; the UI
* renders localized content at display time so audit/login logs are fully
* translatable instead of being frozen to whatever language was written to DB.
*/
const AUDIT_TEMPLATES: Record<string, string> = {
login: 'Logged in successfully via {{method}}',
// User management
'user.create': 'Created user {{username}} (role {{role}})',
'user.update': 'Updated user {{username}} (ID: {{id}})',
'user.delete': 'Deleted user {{username}} (ID: {{id}})',
'user.manage': 'Performed {{action}} on user {{username}} (ID: {{id}})',
'user.quota_add': 'Increased user quota by {{quota}}',
'user.quota_subtract': 'Decreased user quota by {{quota}}',
'user.quota_override': 'Overrode user quota from {{from}} to {{to}}',
'user.binding_clear': 'Cleared {{bindingType}} binding for user {{username}}',
'user.2fa_disable': 'Force-disabled two-factor authentication for the user',
'user.passkey_register': 'Registered a passkey',
'user.passkey_delete': 'Deleted a passkey',
'user.topup_complete': 'Completed top-up order for the user',
'user.reset_passkey': 'Reset the user passkey',
'user.oauth_unbind': 'Removed an OAuth binding for the user',
// System settings
'option.update': 'Updated system setting {{key}}',
'option.payment_compliance': 'Confirmed payment compliance',
'option.reset_ratio': 'Reset model ratios',
'option.clear_affinity_cache': 'Cleared channel affinity cache',
// Custom OAuth
'custom_oauth.create': 'Created a custom OAuth provider',
'custom_oauth.update': 'Updated a custom OAuth provider',
'custom_oauth.delete': 'Deleted a custom OAuth provider',
// Performance / cache
'performance.clear_disk_cache': 'Cleared disk cache',
'performance.gc': 'Triggered garbage collection',
'performance.clear_logs': 'Cleared log files',
// Channel
'channel.create': 'Created channel {{name}} (type {{type}}, count {{count}})',
'channel.update': 'Updated channel {{name}} (ID: {{id}})',
'channel.delete': 'Deleted channel {{name}} (ID: {{id}})',
'channel.delete_batch': 'Batch deleted {{count}} channels',
'channel.delete_disabled': 'Deleted all disabled channels ({{count}})',
'channel.key_view': 'Viewed channel key {{name}} (ID: {{id}})',
'channel.tag_disable': 'Disabled channels with tag {{tag}}',
'channel.tag_enable': 'Enabled channels with tag {{tag}}',
'channel.tag_edit': 'Edited channels with tag {{tag}}',
'channel.tag_batch_set': 'Batch set tag for {{count}} channels',
'channel.copy':
'Copied channel (source ID: {{sourceId}}) to {{name}} (new ID: {{id}})',
'channel.multi_key_manage':
'Multi-key management {{action}} on channel (ID: {{id}})',
'channel.upstream_apply':
'Applied upstream model changes to channel (ID: {{id}})',
'channel.upstream_apply_all':
'Applied upstream model changes to {{count}} channels',
// Redemption codes
'redemption.create':
'Created {{count}} redemption codes named {{name}} ({{quota}} each)',
'redemption.update': 'Updated a redemption code',
'redemption.delete': 'Deleted a redemption code',
'redemption.delete_invalid': 'Deleted invalid redemption codes',
// Prefill groups
'prefill_group.create': 'Created a prefill group',
'prefill_group.update': 'Updated a prefill group',
'prefill_group.delete': 'Deleted a prefill group',
// Vendors
'vendor.create': 'Created a vendor',
'vendor.update': 'Updated a vendor',
'vendor.delete': 'Deleted a vendor',
// Model metadata
'model.create': 'Created a model',
'model.update': 'Updated a model',
'model.delete': 'Deleted a model',
'model.sync_upstream': 'Synced upstream models',
// Deployments
'deployment.create': 'Created a deployment',
'deployment.update': 'Updated a deployment',
'deployment.delete': 'Deleted a deployment',
// Subscriptions
'subscription.plan_create': 'Created a subscription plan',
'subscription.plan_update': 'Updated a subscription plan',
'subscription.bind': 'Bound a subscription',
// Logs
'log.clear': 'Cleared historical logs',
// Generic middleware fallback
generic: '{{method}} {{route}}',
}
/**
* Render the localized content of an audit/login log from its structured
* `other.op` descriptor. Returns null when the log has no recognized action,
* letting callers fall back to the raw `content` field.
*/
export function renderAuditContent(
other: LogOtherData | null | undefined,
t: (key: string, opts?: Record<string, unknown>) => string
): string | null {
const op = other?.op
if (!op?.action) return null
const template = AUDIT_TEMPLATES[op.action]
if (!template) return null
return t(template, (op.params ?? {}) as Record<string, unknown>)
}
......@@ -106,10 +106,29 @@ export interface LogOtherData {
server_ip?: string
version?: string
node_name?: string
// Manage audit fields (type=3, admin only)
// Operator identity for audit logs (type=3, admin only)
admin_username?: string
admin_id?: number | string
admin_role?: number
}
// Language-independent operation descriptor (audit/login logs).
// Frontend renders localized content from action + params via i18n templates.
op?: {
action?: string
params?: Record<string, string | number | boolean | string[]>
}
// Operation audit details written by the admin-audit fallback in authHelper (type=3, admin only)
audit_info?: {
method?: string
route?: string
path?: string
status?: number
success?: boolean
params?: Record<string, string>
}
// Login audit fields (type=7); visible to the log owner
login_method?: string
user_agent?: string
request_path?: string
request_conversion?: string[]
ws?: boolean
......
......@@ -46,6 +46,7 @@
"{{count}} weeks ago": "{{count}} weeks ago",
"{{field}} updated to {{value}}": "{{field}} updated to {{value}}",
"{{field}} updated to {{value}} for tag: {{tag}}": "{{field}} updated to {{value}} for tag: {{tag}}",
"{{method}} {{route}}": "{{method}} {{route}}",
"{{modality}} not supported": "{{modality}} not supported",
"{{modality}} supported": "{{modality}} supported",
"{{n}} model(s) selected": "{{n}} model(s) selected",
......@@ -122,6 +123,7 @@
"Account used when authenticating with the SMTP server": "Account used when authenticating with the SMTP server",
"acknowledge the related legal risks": "acknowledge the related legal risks",
"Across all groups": "Across all groups",
"Action": "Action",
"Action confirmation": "Action Confirmation",
"Actions": "Actions",
"active": "active",
......@@ -372,6 +374,8 @@
"appended": "appended",
"Application": "Application",
"Applied {{name}} pricing to {{count}} models": "Applied {{name}} pricing to {{count}} models",
"Applied upstream model changes to {{count}} channels": "Applied upstream model changes to {{count}} channels",
"Applied upstream model changes to channel (ID: {{id}})": "Applied upstream model changes to channel (ID: {{id}})",
"Applies to custom completion endpoints. JSON map of model → ratio.": "Applies to custom completion endpoints. JSON map of model → ratio.",
"Apply All Upstream Updates": "Apply All Upstream Updates",
"Apply Filters": "Apply Filters",
......@@ -519,6 +523,7 @@
"Basic Templates": "Basic Templates",
"Batch Add (one key per line)": "Batch Add (one key per line)",
"Batch delete failed": "Batch delete failed",
"Batch deleted {{count}} channels": "Batch deleted {{count}} channels",
"Batch detection complete: {{channels}} channels, {{add}} to add, {{remove}} to remove, {{fails}} failed": "Batch detection complete: {{channels}} channels, {{add}} to add, {{remove}} to remove, {{fails}} failed",
"Batch detection failed": "Batch detection failed",
"Batch disable failed": "Batch disable failed",
......@@ -527,6 +532,7 @@
"Batch Edit by Tag": "Batch Edit by Tag",
"Batch enable failed": "Batch enable failed",
"Batch processing failed": "Batch processing failed",
"Batch set tag for {{count}} channels": "Batch set tag for {{count}} channels",
"Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed",
"Best for single-tenant deployments. Pricing and billing options stay hidden.": "Best for single-tenant deployments. Pricing and billing options stay hidden.",
"Best TTFT": "Best TTFT",
......@@ -566,6 +572,7 @@
"Bot Token": "Bot Token",
"Bot:": "Bot:",
"Bound": "Bound",
"Bound a subscription": "Bound a subscription",
"Bound Channels": "Bound Channels",
"Bound Only": "Bound Only",
"Bound product:": "Bound product:",
......@@ -639,6 +646,7 @@
"Change language": "Change language",
"Change Password": "Change Password",
"Change To": "Change To",
"Changed Fields": "Changed Fields",
"Changes are written to the settings draft on save.": "Changes are written to the settings draft on save.",
"Changing...": "Changing...",
"Channel": "Channel",
......@@ -735,7 +743,12 @@
"Clear selection": "Clear selection",
"Clear selection (Escape)": "Clear selection (Escape)",
"Cleared": "Cleared",
"Cleared {{bindingType}} binding for user {{username}}": "Cleared {{bindingType}} binding for user {{username}}",
"Cleared all models": "Cleared all models",
"Cleared channel affinity cache": "Cleared channel affinity cache",
"Cleared disk cache": "Cleared disk cache",
"Cleared historical logs": "Cleared historical logs",
"Cleared log files": "Cleared log files",
"Click \"Create Plan\" to create your first subscription plan": "Click \"Create Plan\" to create your first subscription plan",
"Click \"Generate\" to create a token": "Click \"Generate\" to create a token",
"Click any category to drill into its models, apps, and trends": "Click any category to drill into its models, apps, and trends",
......@@ -808,6 +821,7 @@
"Complete Order": "Complete Order",
"Complete these steps to finish the initial installation.": "Complete these steps to finish the initial installation.",
"Completed": "Completed",
"Completed top-up order for the user": "Completed top-up order for the user",
"Completion": "Completion",
"Completion price": "Completion price",
"Completion price ($/1M tokens)": "Completion price ($/1M tokens)",
......@@ -887,6 +901,7 @@
"Confirm your identity before removing this Passkey from your account.": "Confirm your identity before removing this Passkey from your account.",
"Confirm your identity with Two-factor Authentication before registering a Passkey.": "Confirm your identity with Two-factor Authentication before registering a Passkey.",
"Confirmed at {{time}} by user #{{userId}}": "Confirmed at {{time}} by user #{{userId}}",
"Confirmed payment compliance": "Confirmed payment compliance",
"Conflict": "Conflict",
"Connect": "Connect",
"Connect through OpenAI, Claude, Gemini, and other compatible API routes": "Connect through OpenAI, Claude, Gemini, and other compatible API routes",
......@@ -929,6 +944,7 @@
"Convert string to uppercase": "Convert string to uppercase",
"Copied": "Copied",
"Copied {{count}} key(s)": "Copied {{count}} key(s)",
"Copied channel (source ID: {{sourceId}}) to {{name}} (new ID: {{id}})": "Copied channel (source ID: {{sourceId}}) to {{name}} (new ID: {{id}})",
"Copied to clipboard": "Copied to clipboard",
"Copied: {{model}}": "Copied: {{model}}",
"Copied!": "Copied!",
......@@ -1010,7 +1026,16 @@
"Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.",
"Create, revoke, and audit API tokens.": "Create, revoke, and audit API tokens.",
"Created": "Created",
"Created {{count}} redemption codes named {{name}} ({{quota}} each)": "Created {{count}} redemption codes named {{name}} ({{quota}} each)",
"Created a custom OAuth provider": "Created a custom OAuth provider",
"Created a deployment": "Created a deployment",
"Created a model": "Created a model",
"Created a prefill group": "Created a prefill group",
"Created a subscription plan": "Created a subscription plan",
"Created a vendor": "Created a vendor",
"Created At": "Created At",
"Created channel {{name}} (type {{type}}, count {{count}})": "Created channel {{name}} (type {{type}}, count {{count}})",
"Created user {{username}} (role {{role}})": "Created user {{username}} (role {{role}})",
"Creates a Pancake product in the saved store using this plan’s title and price. Requires Waffo Pancake to be fully configured in Payment settings first.": "Creates a Pancake product in the saved store using this plan’s title and price. Requires Waffo Pancake to be fully configured in Payment settings first.",
"Creating...": "Creating...",
"Creation failed": "Creation failed",
......@@ -1090,6 +1115,7 @@
"Day of month": "Day of month",
"days": "days",
"Days to Retain": "Days to Retain",
"Decreased user quota by {{quota}}": "Decreased user quota by {{quota}}",
"Deducted by subscription": "Deducted by subscription",
"DeepSeek": "DeepSeek",
"default": "default",
......@@ -1144,7 +1170,18 @@
"Delete selected channels": "Delete selected channels",
"Delete selected models": "Delete selected models",
"Deleted": "Deleted",
"Deleted a custom OAuth provider": "Deleted a custom OAuth provider",
"Deleted a deployment": "Deleted a deployment",
"Deleted a model": "Deleted a model",
"Deleted a passkey": "Deleted a passkey",
"Deleted a prefill group": "Deleted a prefill group",
"Deleted a redemption code": "Deleted a redemption code",
"Deleted a vendor": "Deleted a vendor",
"Deleted all disabled channels ({{count}})": "Deleted all disabled channels ({{count}})",
"Deleted channel {{name}} (ID: {{id}})": "Deleted channel {{name}} (ID: {{id}})",
"Deleted invalid redemption codes": "Deleted invalid redemption codes",
"Deleted successfully": "Deleted successfully",
"Deleted user {{username}} (ID: {{id}})": "Deleted user {{username}} (ID: {{id}})",
"Deleting will permanently remove this subscription record (including benefit details). Continue?": "Deleting will permanently remove this subscription record (including benefit details). Continue?",
"Deleting...": "Deleting...",
"Demo site": "Demo site",
......@@ -1200,6 +1237,7 @@
"disabled": "disabled",
"Disabled": "Disabled",
"Disabled all channels with tag: {{tag}}": "Disabled all channels with tag: {{tag}}",
"Disabled channels with tag {{tag}}": "Disabled channels with tag {{tag}}",
"Disabled lanes are omitted on save.": "Disabled lanes are omitted on save.",
"Disabled Reason": "Disabled Reason",
"Disabled Time": "Disabled Time",
......@@ -1346,6 +1384,7 @@
"Edit Uptime Kuma Group": "Edit Uptime Kuma Group",
"Edit Vendor": "Edit Vendor",
"edit_this": "edit_this",
"Edited channels with tag {{tag}}": "Edited channels with tag {{tag}}",
"Editor mode": "Editor mode",
"Education": "Education",
"Email": "Email",
......@@ -1404,6 +1443,7 @@
"Enable when proxying workers that fetch images over HTTP.": "Enable when proxying workers that fetch images over HTTP.",
"Enabled": "Enabled",
"Enabled all channels with tag: {{tag}}": "Enabled all channels with tag: {{tag}}",
"Enabled channels with tag {{tag}}": "Enabled channels with tag {{tag}}",
"Enabled Status": "Enabled Status",
"Enabling...": "Enabling...",
"Encourages introducing new topics": "Encourages introducing new topics",
......@@ -1528,8 +1568,8 @@
"Exists": "Exists",
"Expand": "Expand",
"Expand All": "Expand All",
"Expected a JSON array.": "Expected a JSON array.",
"Expected a JSON array of group identifiers": "Expected a JSON array of group identifiers",
"Expected a JSON array.": "Expected a JSON array.",
"Experiment with prompts and models in real time.": "Experiment with prompts and models in real time.",
"Expiration Time": "Expiration Time",
"expired": "expired",
......@@ -1786,6 +1826,7 @@
"Force format response to OpenAI standard (OpenAI channel only)": "Force format response to OpenAI standard (OpenAI channel only)",
"Force JSON object or schema-conforming output": "Force JSON object or schema-conforming output",
"Force SMTP authentication using AUTH LOGIN method": "Force SMTP authentication using AUTH LOGIN method",
"Force-disabled two-factor authentication for the user": "Force-disabled two-factor authentication for the user",
"Forest Whisper": "Forest Whisper",
"Forgot password": "Forgot password",
"Forgot password?": "Forgot password?",
......@@ -2024,6 +2065,7 @@
"Include Rule Name": "Include Rule Name",
"Includes request rules": "Includes request rules",
"Including failed requests, 0 = unlimited": "Including failed requests, 0 = unlimited",
"Increased user quota by {{quota}}": "Increased user quota by {{quota}}",
"Index": "Index",
"Initial quota given to new users": "Initial quota given to new users",
"Initialization failed, please try again.": "Initialization failed, please try again.",
......@@ -2226,8 +2268,12 @@
"Log IP address for usage and error logs": "Log IP address for usage and error logs",
"Log Maintenance": "Log Maintenance",
"Log Type": "Log Type",
"Logged in successfully via {{method}}": "Logged in successfully via {{method}}",
"Logic": "Logic",
"Login": "Login",
"Login failed": "Login failed",
"Login Info": "Login Info",
"Login Method": "Login Method",
"Logo": "Logo",
"Logo URL": "Logo URL",
"Logs": "Logs",
......@@ -2433,6 +2479,7 @@
"ms": "ms",
"Multi-key channel: Keys will be": "Multi-key channel: Keys will be",
"Multi-Key Management": "Multi-Key Management",
"Multi-key management {{action}} on channel (ID: {{id}})": "Multi-key management {{action}} on channel (ID: {{id}})",
"Multi-Key Mode (multiple keys, one channel)": "Multi-Key Mode (multiple keys, one channel)",
"Multi-Key Strategy": "Multi-Key Strategy",
"Multi-key: Polling rotation": "Multi-key: Polling rotation",
......@@ -2748,6 +2795,7 @@
"opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.",
"Operation": "Operation",
"operation and charging behavior": "operation and charging behavior",
"Operation Audit Info": "Operation Audit Info",
"Operation failed": "Operation failed",
"Operation successful": "Operation successful",
"Operation Type": "Operation Type",
......@@ -2799,6 +2847,7 @@
"Override Rules": "Override Rules",
"Override the endpoint used for testing. Leave empty to auto detect.": "Override the endpoint used for testing. Leave empty to auto detect.",
"overrides for matching model prefix.": "overrides for matching model prefix.",
"Overrode user quota from {{from}} to {{to}}": "Overrode user quota from {{from}} to {{to}}",
"Overview": "Overview",
"Overwritten": "Overwritten",
"Page": "Page",
......@@ -2912,6 +2961,7 @@
"Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.",
"Performance Monitor": "Performance Monitor",
"Performance Settings": "Performance Settings",
"Performed {{action}} on user {{username}} (ID: {{id}})": "Performed {{action}} on user {{username}} (ID: {{id}})",
"Period": "Period",
"Periodically check for upstream model changes": "Periodically check for upstream model changes",
"Periodically send ping frames to keep streaming connections active.": "Periodically send ping frames to keep streaming connections active.",
......@@ -3248,6 +3298,7 @@
"Regex Replace": "Regex Replace",
"Register each URL into the matching Test Mode / Production Mode webhook slot in the Pancake dashboard. Separate endpoints prevent test traffic from accidentally crediting production accounts.": "Register each URL into the matching Test Mode / Production Mode webhook slot in the Pancake dashboard. Separate endpoints prevent test traffic from accidentally crediting production accounts.",
"Register Passkey": "Register Passkey",
"Registered a passkey": "Registered a passkey",
"Registration Enabled": "Registration Enabled",
"Registry (optional)": "Registry (optional)",
"Registry secret": "Registry secret",
......@@ -3283,6 +3334,7 @@
"Remove tier": "Remove tier",
"Removed": "Removed",
"Removed {{removed}} duplicate key(s). Before: {{before}}, After: {{after}}": "Removed {{removed}} duplicate key(s). Before: {{before}}, After: {{after}}",
"Removed an OAuth binding for the user": "Removed an OAuth binding for the user",
"Removed Models ({{count}})": "Removed Models ({{count}})",
"Removes Midjourney flags such as --fast, --relax, and --turbo from user prompts.": "Removes Midjourney flags such as --fast, --relax, and --turbo from user prompts.",
"Removing Passkey will require you to sign in with your password next time. You can re-register anytime.": "Removing Passkey will require you to sign in with your password next time. You can re-register anytime.",
......@@ -3354,12 +3406,14 @@
"Reset Cycle": "Reset Cycle",
"Reset email sent, please check your inbox": "Reset email sent, please check your inbox",
"Reset failed": "Reset failed",
"Reset model ratios": "Reset model ratios",
"Reset Passkey": "Reset Passkey",
"Reset password": "Reset password",
"Reset Period": "Reset Period",
"Reset prices": "Reset prices",
"Reset ratios": "Reset ratios",
"Reset Stats": "Reset Stats",
"Reset the user passkey": "Reset the user passkey",
"Reset to default": "Reset to default",
"Reset to Default": "Reset to Default",
"Reset to default configuration": "Reset to default configuration",
......@@ -3372,6 +3426,7 @@
"Responses API Version": "Responses API Version",
"Restore defaults": "Restore defaults",
"Restrict user model request frequency (may impact high concurrency performance)": "Restrict user model request frequency (may impact high concurrency performance)",
"Result": "Result",
"Retain last N days": "Retain last N days",
"Retain last N files": "Retain last N files",
"Retention days": "Retention days",
......@@ -3635,6 +3690,7 @@
"Set tag for selected channels": "Set tag for selected channels",
"Set the language used across the interface": "Set the language used across the interface",
"Set the user's role (cannot be Root)": "Set the user's role (cannot be Root)",
"Setting Key": "Setting Key",
"Setting saved": "Setting saved",
"Setting up 2FA...": "Setting up 2FA...",
"Setting updated successfully": "Setting updated successfully",
......@@ -3827,6 +3883,7 @@
"Sync this model with official upstream": "Sync this model with official upstream",
"Sync Upstream": "Sync Upstream",
"Sync Upstream Models": "Sync Upstream Models",
"Synced upstream models": "Synced upstream models",
"Synchronize models and vendors from an upstream source": "Synchronize models and vendors from an upstream source",
"Syncing prices, please wait...": "Syncing prices, please wait...",
"Syncing...": "Syncing...",
......@@ -3872,6 +3929,7 @@
"Target group": "Target group",
"Target Header": "Target Header",
"Target Path (optional)": "Target Path (optional)",
"Target User": "Target User",
"Task": "Task",
"Task ID": "Task ID",
"Task ID:": "Task ID:",
......@@ -4127,6 +4185,7 @@
"Trend": "Trend",
"Trending down": "Trending down",
"Trending up": "Trending up",
"Triggered garbage collection": "Triggered garbage collection",
"Trim leading/trailing whitespace": "Trim leading/trailing whitespace",
"Trim Prefix": "Trim Prefix",
"Trim Space": "Trim Space",
......@@ -4217,8 +4276,18 @@
"Update your password for account:": "Update your password for account:",
"Update your password to keep your account secure": "Update your password to keep your account secure",
"Updated": "Updated",
"Updated a custom OAuth provider": "Updated a custom OAuth provider",
"Updated a deployment": "Updated a deployment",
"Updated a model": "Updated a model",
"Updated a prefill group": "Updated a prefill group",
"Updated a redemption code": "Updated a redemption code",
"Updated a subscription plan": "Updated a subscription plan",
"Updated a vendor": "Updated a vendor",
"Updated channel {{name}} (ID: {{id}})": "Updated channel {{name}} (ID: {{id}})",
"Updated daily": "Updated daily",
"Updated successfully": "Updated successfully",
"Updated system setting {{key}}": "Updated system setting {{key}}",
"Updated user {{username}} (ID: {{id}})": "Updated user {{username}} (ID: {{id}})",
"Updating all channel balances. This may take a while. Please refresh to see results.": "Updating all channel balances. This may take a while. Please refresh to see results.",
"Upgrade Group": "Upgrade Group",
"Upload": "Upload",
......@@ -4290,6 +4359,7 @@
"Used:": "Used:",
"User": "User",
"User {{id}}": "User {{id}}",
"User Agent": "User Agent",
"User Agreement": "User Agreement",
"User Analytics": "User Analytics",
"User Consumption Ranking": "User Consumption Ranking",
......@@ -4384,6 +4454,7 @@
"View the complete prompt and its English translation": "View the complete prompt and its English translation",
"View the generated image": "View the generated image",
"View your topup transaction records and payment history": "View your topup transaction records and payment history",
"Viewed channel key {{name}} (ID: {{id}})": "Viewed channel key {{name}} (ID: {{id}})",
"Violation Code": "Violation Code",
"Violation deduction amount": "Violation deduction amount",
"Violation Fee": "Violation Fee",
......
......@@ -46,6 +46,7 @@
"{{count}} weeks ago": "il y a {{count}} semaines",
"{{field}} updated to {{value}}": "{{field}} mis à jour en {{value}}",
"{{field}} updated to {{value}} for tag: {{tag}}": "{{field}} mis à jour en {{value}} pour le tag : {{tag}}",
"{{method}} {{route}}": "{{method}} {{route}}",
"{{modality}} not supported": "{{modality}} non pris en charge",
"{{modality}} supported": "{{modality}} pris en charge",
"{{n}} model(s) selected": "{{n}} modèle(s) sélectionné(s)",
......@@ -122,6 +123,7 @@
"Account used when authenticating with the SMTP server": "Compte utilisé lors de l'authentification auprès du serveur SMTP",
"acknowledge the related legal risks": "reconnais les risques juridiques associés",
"Across all groups": "Tous groupes confondus",
"Action": "Action",
"Action confirmation": "Confirmation de l'action",
"Actions": "Actions",
"active": "actif",
......@@ -372,6 +374,8 @@
"appended": "ajouté",
"Application": "Application",
"Applied {{name}} pricing to {{count}} models": "Tarification de {{name}} appliquée à {{count}} modèles",
"Applied upstream model changes to {{count}} channels": "Modifications des modèles en amont appliquées à {{count}} canaux",
"Applied upstream model changes to channel (ID: {{id}})": "Modifications des modèles en amont appliquées au canal (ID : {{id}})",
"Applies to custom completion endpoints. JSON map of model → ratio.": "S'applique aux points de terminaison de complétion personnalisés. Mappage JSON de modèle → ratio.",
"Apply All Upstream Updates": "Appliquer toutes les mises à jour upstream",
"Apply Filters": "Appliquer les filtres",
......@@ -519,6 +523,7 @@
"Basic Templates": "Modèles de base",
"Batch Add (one key per line)": "Ajout par lots (une clé par ligne)",
"Batch delete failed": "Échec de la suppression par lots",
"Batch deleted {{count}} channels": "{{count}} canaux supprimés par lot",
"Batch detection complete: {{channels}} channels, {{add}} to add, {{remove}} to remove, {{fails}} failed": "Détection par lots terminée : {{channels}} canaux, {{add}} à ajouter, {{remove}} à supprimer, {{fails}} échoués",
"Batch detection failed": "Échec de la détection par lot",
"Batch disable failed": "Échec de la désactivation par lots",
......@@ -527,6 +532,7 @@
"Batch Edit by Tag": "Modification par lot par tag",
"Batch enable failed": "Échec de l'activation par lots",
"Batch processing failed": "Échec du traitement par lot",
"Batch set tag for {{count}} channels": "Étiquette définie par lot pour {{count}} canaux",
"Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "Mises à jour par lot des modèles en amont appliquées : {{channels}} canaux, {{added}} ajoutés, {{removed}} supprimés, {{fails}} échoués",
"Best for single-tenant deployments. Pricing and billing options stay hidden.": "Idéal pour les déploiements mono-utilisateur. Les options de tarification et de facturation restent masquées.",
"Best TTFT": "Meilleur TTFT",
......@@ -566,6 +572,7 @@
"Bot Token": "Jeton du bot",
"Bot:": "Bot :",
"Bound": "Lié",
"Bound a subscription": "Abonnement lié",
"Bound Channels": "Canaux liés",
"Bound Only": "Liés uniquement",
"Bound product:": "Produit associé :",
......@@ -639,6 +646,7 @@
"Change language": "Changer de langue",
"Change Password": "Changer le mot de passe",
"Change To": "Changer en",
"Changed Fields": "Champs modifiés",
"Changes are written to the settings draft on save.": "Les modifications sont écrites dans le brouillon des paramètres lors de l’enregistrement.",
"Changing...": "Modification en cours...",
"Channel": "Canal",
......@@ -735,7 +743,12 @@
"Clear selection": "Effacer la sélection",
"Clear selection (Escape)": "Effacer la sélection (Échap)",
"Cleared": "Vidé",
"Cleared {{bindingType}} binding for user {{username}}": "Liaison {{bindingType}} de l'utilisateur {{username}} supprimée",
"Cleared all models": "Tous les modèles effacés",
"Cleared channel affinity cache": "Cache d'affinité des canaux vidé",
"Cleared disk cache": "Cache disque vidé",
"Cleared historical logs": "Journaux historiques effacés",
"Cleared log files": "Fichiers journaux effacés",
"Click \"Create Plan\" to create your first subscription plan": "Cliquez sur « Créer un plan » pour créer votre premier abonnement",
"Click \"Generate\" to create a token": "Cliquez sur \"Générer\" pour créer un jeton",
"Click any category to drill into its models, apps, and trends": "Cliquez sur une catégorie pour explorer ses modèles, applications et tendances",
......@@ -808,6 +821,7 @@
"Complete Order": "Compléter la commande",
"Complete these steps to finish the initial installation.": "Suivez ces étapes pour terminer l'installation initiale.",
"Completed": "Terminé",
"Completed top-up order for the user": "Commande de recharge complétée pour l'utilisateur",
"Completion": "Achèvement",
"Completion price": "Prix de complétion",
"Completion price ($/1M tokens)": "Prix de la complétion (USD/1M jetons)",
......@@ -887,6 +901,7 @@
"Confirm your identity before removing this Passkey from your account.": "Confirmez votre identité avant de supprimer cette Passkey de votre compte.",
"Confirm your identity with Two-factor Authentication before registering a Passkey.": "Confirmez votre identité avec l’authentification à deux facteurs avant d’enregistrer une Passkey.",
"Confirmed at {{time}} by user #{{userId}}": "Confirmé le {{time}} par l’utilisateur #{{userId}}",
"Confirmed payment compliance": "Conformité de paiement confirmée",
"Conflict": "Conflit",
"Connect": "Connecter",
"Connect through OpenAI, Claude, Gemini, and other compatible API routes": "Connectez-vous via OpenAI, Claude, Gemini et d'autres routes API compatibles",
......@@ -929,6 +944,7 @@
"Convert string to uppercase": "Convertir la chaîne en majuscules",
"Copied": "Copié",
"Copied {{count}} key(s)": "{{count}} clé(s) copiée(s)",
"Copied channel (source ID: {{sourceId}}) to {{name}} (new ID: {{id}})": "Canal copié (ID source : {{sourceId}}) vers {{name}} (nouvel ID : {{id}})",
"Copied to clipboard": "Copié dans le presse-papiers",
"Copied: {{model}}": "Copié : {{model}}",
"Copied!": "Copié !",
......@@ -1010,7 +1026,16 @@
"Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "Créez votre premier groupe pour réutiliser les sélections de modèles, de balises ou de points de terminaison n'importe où dans le tableau de bord.",
"Create, revoke, and audit API tokens.": "Créer, révoquer et auditer les jetons API.",
"Created": "Créé",
"Created {{count}} redemption codes named {{name}} ({{quota}} each)": "{{count}} codes de réduction nommés {{name}} créés ({{quota}} chacun)",
"Created a custom OAuth provider": "Fournisseur OAuth personnalisé créé",
"Created a deployment": "Déploiement créé",
"Created a model": "Modèle créé",
"Created a prefill group": "Groupe de préremplissage créé",
"Created a subscription plan": "Forfait d'abonnement créé",
"Created a vendor": "Fournisseur créé",
"Created At": "Créé le",
"Created channel {{name}} (type {{type}}, count {{count}})": "Canal {{name}} créé (type {{type}}, nombre {{count}})",
"Created user {{username}} (role {{role}})": "Utilisateur {{username}} créé (rôle {{role}})",
"Creates a Pancake product in the saved store using this plan’s title and price. Requires Waffo Pancake to be fully configured in Payment settings first.": "Crée un produit Pancake dans la boutique enregistrée avec le titre et le prix de ce forfait. Waffo Pancake doit d’abord être entièrement configuré dans les paramètres de paiement.",
"Creating...": "Création...",
"Creation failed": "Échec de la création",
......@@ -1090,6 +1115,7 @@
"Day of month": "Jour du mois",
"days": "jours",
"Days to Retain": "Jours à conserver",
"Decreased user quota by {{quota}}": "Quota de l'utilisateur diminué de {{quota}}",
"Deducted by subscription": "Déduit par abonnement",
"DeepSeek": "DeepSeek",
"default": "par défaut",
......@@ -1144,7 +1170,18 @@
"Delete selected channels": "Supprimer les canaux sélectionnés",
"Delete selected models": "Supprimer les modèles sélectionnés",
"Deleted": "Supprimé",
"Deleted a custom OAuth provider": "Fournisseur OAuth personnalisé supprimé",
"Deleted a deployment": "Déploiement supprimé",
"Deleted a model": "Modèle supprimé",
"Deleted a passkey": "Clé d'accès supprimée",
"Deleted a prefill group": "Groupe de préremplissage supprimé",
"Deleted a redemption code": "Code de réduction supprimé",
"Deleted a vendor": "Fournisseur supprimé",
"Deleted all disabled channels ({{count}})": "Tous les canaux désactivés supprimés ({{count}})",
"Deleted channel {{name}} (ID: {{id}})": "Canal {{name}} supprimé (ID : {{id}})",
"Deleted invalid redemption codes": "Codes de réduction invalides supprimés",
"Deleted successfully": "Supprimé avec succès",
"Deleted user {{username}} (ID: {{id}})": "Utilisateur {{username}} supprimé (ID : {{id}})",
"Deleting will permanently remove this subscription record (including benefit details). Continue?": "La suppression supprimera définitivement cet enregistrement d'abonnement (y compris les détails des avantages). Continuer ?",
"Deleting...": "Suppression...",
"Demo site": "Site de démonstration",
......@@ -1200,6 +1237,7 @@
"disabled": "désactivé",
"Disabled": "Désactivé",
"Disabled all channels with tag: {{tag}}": "Tous les canaux avec le tag {{tag}} ont été désactivés",
"Disabled channels with tag {{tag}}": "Canaux avec l'étiquette {{tag}} désactivés",
"Disabled lanes are omitted on save.": "Les voies désactivées sont omises à l’enregistrement.",
"Disabled Reason": "Raison de la désactivation",
"Disabled Time": "Heure de désactivation",
......@@ -1346,6 +1384,7 @@
"Edit Uptime Kuma Group": "Modifier le groupe Uptime Kuma",
"Edit Vendor": "Modifier le fournisseur",
"edit_this": "modifier_ceci",
"Edited channels with tag {{tag}}": "Canaux avec l'étiquette {{tag}} modifiés",
"Editor mode": "Mode éditeur",
"Education": "Éducation",
"Email": "E-mail",
......@@ -1404,6 +1443,7 @@
"Enable when proxying workers that fetch images over HTTP.": "Activer lors de la mise en proxy des workers qui récupèrent des images via HTTP.",
"Enabled": "Activé",
"Enabled all channels with tag: {{tag}}": "Tous les canaux avec le tag {{tag}} ont été activés",
"Enabled channels with tag {{tag}}": "Canaux avec l'étiquette {{tag}} activés",
"Enabled Status": "Statut activé",
"Enabling...": "Activation en cours...",
"Encourages introducing new topics": "Encourage l'introduction de nouveaux sujets",
......@@ -1528,8 +1568,8 @@
"Exists": "Existe",
"Expand": "Développer",
"Expand All": "Tout développer",
"Expected a JSON array.": "Un tableau JSON est attendu.",
"Expected a JSON array of group identifiers": "Un tableau JSON d'identifiants de groupe est attendu",
"Expected a JSON array.": "Un tableau JSON est attendu.",
"Experiment with prompts and models in real time.": "Expérimentez avec des prompts et des modèles en temps réel.",
"Expiration Time": "Heure d'expiration",
"expired": "expiré",
......@@ -1786,6 +1826,7 @@
"Force format response to OpenAI standard (OpenAI channel only)": "Forcer la réponse au format standard OpenAI (canal OpenAI uniquement)",
"Force JSON object or schema-conforming output": "Forcer une sortie JSON ou conforme à un schéma",
"Force SMTP authentication using AUTH LOGIN method": "Forcer l'authentification SMTP en utilisant la méthode AUTH LOGIN",
"Force-disabled two-factor authentication for the user": "Authentification à deux facteurs désactivée de force pour l'utilisateur",
"Forest Whisper": "Murmure forestier",
"Forgot password": "Mot de passe oublié",
"Forgot password?": "Mot de passe oublié ?",
......@@ -2024,6 +2065,7 @@
"Include Rule Name": "Inclure le nom de la règle",
"Includes request rules": "Inclut des règles de requête",
"Including failed requests, 0 = unlimited": "Y compris les requêtes échouées, 0 = illimité",
"Increased user quota by {{quota}}": "Quota de l'utilisateur augmenté de {{quota}}",
"Index": "Index",
"Initial quota given to new users": "Quota initial donné aux nouveaux utilisateurs",
"Initialization failed, please try again.": "L'initialisation a échoué, veuillez réessayer.",
......@@ -2226,8 +2268,12 @@
"Log IP address for usage and error logs": "Enregistrer l'adresse IP pour les journaux d'utilisation et d'erreurs",
"Log Maintenance": "Maintenance des journaux",
"Log Type": "Type de journal",
"Logged in successfully via {{method}}": "Connexion réussie via {{method}}",
"Logic": "Logique",
"Login": "Connexion",
"Login failed": "Échec de la connexion",
"Login Info": "Informations de connexion",
"Login Method": "Méthode de connexion",
"Logo": "Logo",
"Logo URL": "URL du logo",
"Logs": "Journaux",
......@@ -2433,6 +2479,7 @@
"ms": "ms",
"Multi-key channel: Keys will be": "Canal multi-clés : Les clés seront",
"Multi-Key Management": "Gestion multi-clés",
"Multi-key management {{action}} on channel (ID: {{id}})": "Gestion multi-clés {{action}} sur le canal (ID : {{id}})",
"Multi-Key Mode (multiple keys, one channel)": "Mode multi-clés (plusieurs clés, un canal)",
"Multi-Key Strategy": "Stratégie multi-clés",
"Multi-key: Polling rotation": "Multi-clé : Rotation par sondage",
......@@ -2748,6 +2795,7 @@
"opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "s'ouvre dans un client externe. Déclenchez-le depuis la barre latérale ou les actions de clé API pour lancer l'application configurée.",
"Operation": "Opération",
"operation and charging behavior": "exploitation et facturation",
"Operation Audit Info": "Informations d'audit d'opération",
"Operation failed": "Opération échouée",
"Operation successful": "Opération réussie",
"Operation Type": "Type d'opération",
......@@ -2799,6 +2847,7 @@
"Override Rules": "Règles de remplacement",
"Override the endpoint used for testing. Leave empty to auto detect.": "Remplacer le point de terminaison utilisé pour les tests. Laisser vide pour la détection automatique.",
"overrides for matching model prefix.": "remplace le tarif si le modèle a ce préfixe.",
"Overrode user quota from {{from}} to {{to}}": "Quota de l'utilisateur remplacé de {{from}} à {{to}}",
"Overview": "Vue d'ensemble",
"Overwritten": "Écrasé",
"Page": "Page",
......@@ -2912,6 +2961,7 @@
"Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "Les indicateurs de performance présentés ici sont simulés à des fins de prévisualisation et seront remplacés par des données d'observabilité réelles une fois l'intégration du backend terminée.",
"Performance Monitor": "Moniteur de performances",
"Performance Settings": "Paramètres de performances",
"Performed {{action}} on user {{username}} (ID: {{id}})": "Action {{action}} effectuée sur l'utilisateur {{username}} (ID : {{id}})",
"Period": "Période",
"Periodically check for upstream model changes": "Vérifier périodiquement les changements de modèles en amont",
"Periodically send ping frames to keep streaming connections active.": "Envoyer périodiquement des trames ping pour maintenir les connexions de streaming actives.",
......@@ -3248,6 +3298,7 @@
"Regex Replace": "Remplacement regex",
"Register each URL into the matching Test Mode / Production Mode webhook slot in the Pancake dashboard. Separate endpoints prevent test traffic from accidentally crediting production accounts.": "Enregistrez chaque URL dans l’emplacement webhook correspondant au mode test ou production dans le tableau de bord Pancake. Des points de terminaison séparés évitent que le trafic de test crédite accidentellement les comptes de production.",
"Register Passkey": "Enregistrer un Passkey",
"Registered a passkey": "Passkey enregistré",
"Registration Enabled": "Inscription activée",
"Registry (optional)": "Registre (optionnel)",
"Registry secret": "Secret du registre",
......@@ -3283,6 +3334,7 @@
"Remove tier": "Supprimer le palier",
"Removed": "Supprimé",
"Removed {{removed}} duplicate key(s). Before: {{before}}, After: {{after}}": "{{removed}} clé(s) en double supprimée(s). Avant : {{before}}, Après : {{after}}",
"Removed an OAuth binding for the user": "Liaison OAuth de l'utilisateur supprimée",
"Removed Models ({{count}})": "Modèles supprimés ({{count}})",
"Removes Midjourney flags such as --fast, --relax, and --turbo from user prompts.": "Supprime les drapeaux Midjourney tels que --fast, --relax et --turbo des prompts utilisateur.",
"Removing Passkey will require you to sign in with your password next time. You can re-register anytime.": "La suppression de la clé d'accès (Passkey) vous obligera à vous connecter avec votre mot de passe la prochaine fois. Vous pouvez vous réinscrire à tout moment.",
......@@ -3354,12 +3406,14 @@
"Reset Cycle": "Cycle de réinitialisation",
"Reset email sent, please check your inbox": "Email de réinitialisation envoyé, veuillez vérifier votre boîte de réception",
"Reset failed": "Échec de la réinitialisation",
"Reset model ratios": "Ratios de modèle réinitialisés",
"Reset Passkey": "Réinitialiser le Passkey",
"Reset password": "Réinitialiser le mot de passe",
"Reset Period": "Période de réinitialisation",
"Reset prices": "Réinitialiser les prix",
"Reset ratios": "Réinitialiser les ratios",
"Reset Stats": "Réinitialiser les statistiques",
"Reset the user passkey": "Clé d'accès de l'utilisateur réinitialisée",
"Reset to default": "Réinitialiser par défaut",
"Reset to Default": "Réinitialiser par défaut",
"Reset to default configuration": "Réinitialisé à la configuration par défaut",
......@@ -3372,6 +3426,7 @@
"Responses API Version": "Version de l'API des réponses",
"Restore defaults": "Restaurer les paramètres par défaut",
"Restrict user model request frequency (may impact high concurrency performance)": "Restreindre la fréquence des requêtes du modèle utilisateur (peut impacter les performances en cas de forte concurrence)",
"Result": "Résultat",
"Retain last N days": "Conserver les N derniers jours",
"Retain last N files": "Conserver les N derniers fichiers",
"Retention days": "Jours de rétention",
......@@ -3635,6 +3690,7 @@
"Set tag for selected channels": "Définir un tag pour les canaux sélectionnés",
"Set the language used across the interface": "Définir la langue utilisée dans l'interface",
"Set the user's role (cannot be Root)": "Définir le rôle de l'utilisateur (ne peut pas être Root)",
"Setting Key": "Clé de paramètre",
"Setting saved": "Paramètre sauvegardé",
"Setting up 2FA...": "Configuration de la 2FA...",
"Setting updated successfully": "Paramètre mis à jour avec succès",
......@@ -3827,6 +3883,7 @@
"Sync this model with official upstream": "Synchroniser ce modèle avec la source amont officielle",
"Sync Upstream": "Synchroniser l'amont",
"Sync Upstream Models": "Synchroniser les modèles amont",
"Synced upstream models": "Modèles en amont synchronisés",
"Synchronize models and vendors from an upstream source": "Synchroniser les modèles et les fournisseurs à partir d'une source amont",
"Syncing prices, please wait...": "Synchronisation des prix, veuillez patienter...",
"Syncing...": "Synchronisation...",
......@@ -3872,6 +3929,7 @@
"Target group": "Groupe cible",
"Target Header": "En-tête cible",
"Target Path (optional)": "Chemin cible (optionnel)",
"Target User": "Utilisateur cible",
"Task": "Tâche",
"Task ID": "ID de la tâche",
"Task ID:": "ID de tâche :",
......@@ -4127,6 +4185,7 @@
"Trend": "Tendance",
"Trending down": "En baisse",
"Trending up": "En hausse",
"Triggered garbage collection": "Collecte des déchets déclenchée",
"Trim leading/trailing whitespace": "Supprimer les espaces en début/fin",
"Trim Prefix": "Supprimer le préfixe",
"Trim Space": "Supprimer les espaces",
......@@ -4217,8 +4276,18 @@
"Update your password for account:": "Mettez à jour votre mot de passe pour le compte :",
"Update your password to keep your account secure": "Mettez à jour votre mot de passe pour sécuriser votre compte",
"Updated": "Mis à jour",
"Updated a custom OAuth provider": "Fournisseur OAuth personnalisé mis à jour",
"Updated a deployment": "Déploiement mis à jour",
"Updated a model": "Modèle mis à jour",
"Updated a prefill group": "Groupe de préremplissage mis à jour",
"Updated a redemption code": "Code de réduction mis à jour",
"Updated a subscription plan": "Forfait d'abonnement mis à jour",
"Updated a vendor": "Fournisseur mis à jour",
"Updated channel {{name}} (ID: {{id}})": "Canal {{name}} mis à jour (ID : {{id}})",
"Updated daily": "Mis à jour quotidiennement",
"Updated successfully": "Mise à jour réussie",
"Updated system setting {{key}}": "Paramètre système {{key}} mis à jour",
"Updated user {{username}} (ID: {{id}})": "Utilisateur {{username}} mis à jour (ID : {{id}})",
"Updating all channel balances. This may take a while. Please refresh to see results.": "Mise à jour de tous les soldes des canaux. Cela peut prendre un certain temps. Veuillez actualiser pour voir les résultats.",
"Upgrade Group": "Groupe de mise à niveau",
"Upload": "Téléverser",
......@@ -4290,6 +4359,7 @@
"Used:": "Utilisé :",
"User": "Utilisateurs",
"User {{id}}": "Utilisateur {{id}}",
"User Agent": "Agent utilisateur",
"User Agreement": "Accord utilisateur",
"User Analytics": "Statistiques utilisateur",
"User Consumption Ranking": "Classement de consommation",
......@@ -4384,6 +4454,7 @@
"View the complete prompt and its English translation": "Voir l'invite complète et sa traduction anglaise",
"View the generated image": "Voir l'image générée",
"View your topup transaction records and payment history": "Afficher vos enregistrements de transactions de recharge et votre historique de paiement",
"Viewed channel key {{name}} (ID: {{id}})": "Clé du canal {{name}} consultée (ID : {{id}})",
"Violation Code": "Code de violation",
"Violation deduction amount": "Montant de la déduction pour violation",
"Violation Fee": "Frais de violation",
......
......@@ -46,6 +46,7 @@
"{{count}} weeks ago": "{{count}} 週間前",
"{{field}} updated to {{value}}": "{{field}} を {{value}} に更新しました",
"{{field}} updated to {{value}} for tag: {{tag}}": "タグ「{{tag}}」の {{field}} を {{value}} に更新しました",
"{{method}} {{route}}": "{{method}} {{route}}",
"{{modality}} not supported": "{{modality}} はサポートされていません",
"{{modality}} supported": "{{modality}} をサポート",
"{{n}} model(s) selected": "{{n}} 件のモデルを選択済み",
......@@ -122,6 +123,7 @@
"Account used when authenticating with the SMTP server": "SMTPサーバーで認証する際に使用されるアカウント",
"acknowledge the related legal risks": "関連する法的リスクを認識します",
"Across all groups": "全グループを通じて",
"Action": "アクション",
"Action confirmation": "操作確認",
"Actions": "操作",
"active": "有効",
......@@ -372,6 +374,8 @@
"appended": "追加済み",
"Application": "アプリケーション",
"Applied {{name}} pricing to {{count}} models": "{{name}} の料金を {{count}} 個のモデルに適用しました",
"Applied upstream model changes to {{count}} channels": "{{count}} 件のチャネルに上流モデルの変更を適用しました",
"Applied upstream model changes to channel (ID: {{id}})": "チャネル(ID: {{id}})に上流モデルの変更を適用しました",
"Applies to custom completion endpoints. JSON map of model → ratio.": "カスタム補完エンドポイントに適用されます。モデル → 比率のJSONマップ。",
"Apply All Upstream Updates": "すべてのアップストリーム更新を適用",
"Apply Filters": "フィルターを適用",
......@@ -519,6 +523,7 @@
"Basic Templates": "基本テンプレート",
"Batch Add (one key per line)": "一括追加(1行に1つのキー)",
"Batch delete failed": "一括削除に失敗しました",
"Batch deleted {{count}} channels": "{{count}} 件のチャネルを一括削除しました",
"Batch detection complete: {{channels}} channels, {{add}} to add, {{remove}} to remove, {{fails}} failed": "一括検出完了:{{channels}} チャネル、{{add}} 個追加、{{remove}} 個削除、{{fails}} 個失敗",
"Batch detection failed": "一括検出に失敗しました",
"Batch disable failed": "一括無効化に失敗しました",
......@@ -527,6 +532,7 @@
"Batch Edit by Tag": "タグによる一括編集",
"Batch enable failed": "一括有効化に失敗しました",
"Batch processing failed": "一括処理に失敗しました",
"Batch set tag for {{count}} channels": "{{count}} 件のチャネルにタグを一括設定しました",
"Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "一括上流モデル更新を処理しました:{{channels}} チャネル、{{added}} 個追加、{{removed}} 個削除、{{fails}} 個失敗",
"Best for single-tenant deployments. Pricing and billing options stay hidden.": "シングルテナント環境に最適です。料金設定や請求オプションは非表示になります。",
"Best TTFT": "最良 TTFT",
......@@ -566,6 +572,7 @@
"Bot Token": "ボットトークン",
"Bot:": "ボット:",
"Bound": "連携済み",
"Bound a subscription": "サブスクリプションを紐付けました",
"Bound Channels": "バインドされたチャネル",
"Bound Only": "バインド済みのみ",
"Bound product:": "紐付け済み商品:",
......@@ -639,6 +646,7 @@
"Change language": "言語を変更",
"Change Password": "パスワードの変更",
"Change To": "変更先",
"Changed Fields": "変更されたフィールド",
"Changes are written to the settings draft on save.": "保存すると変更は設定ドラフトに書き込まれます。",
"Changing...": "変更中...",
"Channel": "チャネル",
......@@ -735,7 +743,12 @@
"Clear selection": "選択をクリア",
"Clear selection (Escape)": "選択をクリア (Escape)",
"Cleared": "クリア済み",
"Cleared {{bindingType}} binding for user {{username}}": "ユーザー {{username}} の {{bindingType}} 連携を解除しました",
"Cleared all models": "すべてのモデルをクリアしました",
"Cleared channel affinity cache": "チャネルアフィニティキャッシュをクリアしました",
"Cleared disk cache": "ディスクキャッシュをクリアしました",
"Cleared historical logs": "履歴ログをクリアしました",
"Cleared log files": "ログファイルをクリアしました",
"Click \"Create Plan\" to create your first subscription plan": "「プラン作成」をクリックして最初のプランを作成してください",
"Click \"Generate\" to create a token": "「生成」をクリックしてトークンを作成",
"Click any category to drill into its models, apps, and trends": "カテゴリをクリックすると、そのモデル・アプリ・トレンドを掘り下げて確認できます",
......@@ -808,6 +821,7 @@
"Complete Order": "手動チャージ",
"Complete these steps to finish the initial installation.": "初期インストールを完了するには、これらの手順を完了してください。",
"Completed": "完了",
"Completed top-up order for the user": "ユーザーのチャージ注文を完了しました",
"Completion": "補完",
"Completion price": "補完価格",
"Completion price ($/1M tokens)": "完了価格 (トークン100万あたり$)",
......@@ -887,6 +901,7 @@
"Confirm your identity before removing this Passkey from your account.": "このパスキーをアカウントから削除する前に、本人確認を行ってください。",
"Confirm your identity with Two-factor Authentication before registering a Passkey.": "パスキーを登録する前に、二要素認証で本人確認を行ってください。",
"Confirmed at {{time}} by user #{{userId}}": "ユーザー #{{userId}} が {{time}} に確認しました",
"Confirmed payment compliance": "支払いコンプライアンスを確認しました",
"Conflict": "競合",
"Connect": "接続",
"Connect through OpenAI, Claude, Gemini, and other compatible API routes": "OpenAI、Claude、Gemini、その他の互換APIルートから接続",
......@@ -929,6 +944,7 @@
"Convert string to uppercase": "文字列を大文字に変換",
"Copied": "コピーしました",
"Copied {{count}} key(s)": "{{count}} 件のキーをコピーしました",
"Copied channel (source ID: {{sourceId}}) to {{name}} (new ID: {{id}})": "チャネルを複製しました(元 ID: {{sourceId}})→ {{name}}(新 ID: {{id}})",
"Copied to clipboard": "クリップボードにコピーしました",
"Copied: {{model}}": "コピーしました: {{model}}",
"Copied!": "コピーしました!",
......@@ -1010,7 +1026,16 @@
"Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "ダッシュボードのどこでもモデル、タグ、またはエンドポイントの選択を再利用するために、最初のグループを作成します。",
"Create, revoke, and audit API tokens.": "APIトークンを作成、取り消し、監査。",
"Created": "作成済み",
"Created {{count}} redemption codes named {{name}} ({{quota}} each)": "{{count}} 件の引換コード {{name}} を作成しました(各 {{quota}})",
"Created a custom OAuth provider": "カスタム OAuth プロバイダーを作成しました",
"Created a deployment": "デプロイメントを作成しました",
"Created a model": "モデルを作成しました",
"Created a prefill group": "プリフィルグループを作成しました",
"Created a subscription plan": "サブスクリプションプランを作成しました",
"Created a vendor": "ベンダーを作成しました",
"Created At": "作成日時",
"Created channel {{name}} (type {{type}}, count {{count}})": "チャネル {{name}} を作成しました(タイプ {{type}}、数 {{count}})",
"Created user {{username}} (role {{role}})": "ユーザー {{username}} を作成しました(ロール {{role}})",
"Creates a Pancake product in the saved store using this plan’s title and price. Requires Waffo Pancake to be fully configured in Payment settings first.": "保存済みストアに、このプランのタイトルと価格を使って Pancake 商品を作成します。事前に支払い設定で Waffo Pancake を完全に設定する必要があります。",
"Creating...": "作成中...",
"Creation failed": "作成に失敗しました",
......@@ -1090,6 +1115,7 @@
"Day of month": "月内の日",
"days": "日",
"Days to Retain": "保持日数",
"Decreased user quota by {{quota}}": "ユーザーのクォータを {{quota}} 減らしました",
"Deducted by subscription": "サブスクリプションで控除",
"DeepSeek": "DeepSeek",
"default": "デフォルト",
......@@ -1144,7 +1170,18 @@
"Delete selected channels": "選択したチャネルを削除",
"Delete selected models": "選択したモデルを削除",
"Deleted": "削除済み",
"Deleted a custom OAuth provider": "カスタム OAuth プロバイダーを削除しました",
"Deleted a deployment": "デプロイメントを削除しました",
"Deleted a model": "モデルを削除しました",
"Deleted a passkey": "パスキーを削除しました",
"Deleted a prefill group": "プリフィルグループを削除しました",
"Deleted a redemption code": "引換コードを削除しました",
"Deleted a vendor": "ベンダーを削除しました",
"Deleted all disabled channels ({{count}})": "無効なチャネルをすべて削除しました({{count}})",
"Deleted channel {{name}} (ID: {{id}})": "チャネル {{name}} を削除しました(ID: {{id}})",
"Deleted invalid redemption codes": "無効な引換コードを削除しました",
"Deleted successfully": "削除しました",
"Deleted user {{username}} (ID: {{id}})": "ユーザー {{username}} を削除しました(ID: {{id}})",
"Deleting will permanently remove this subscription record (including benefit details). Continue?": "削除するとこのサブスクリプション記録(特典詳細を含む)が完全に削除されます。続行しますか?",
"Deleting...": "削除中...",
"Demo site": "デモサイト",
......@@ -1200,6 +1237,7 @@
"disabled": "無効",
"Disabled": "無効",
"Disabled all channels with tag: {{tag}}": "タグ「{{tag}}」の全チャネルを無効にしました",
"Disabled channels with tag {{tag}}": "タグ {{tag}} のチャネルを無効化しました",
"Disabled lanes are omitted on save.": "無効な価格レーンは保存時に省略されます。",
"Disabled Reason": "無効化の理由",
"Disabled Time": "無効化された時刻",
......@@ -1346,6 +1384,7 @@
"Edit Uptime Kuma Group": "Uptime Kuma グループを編集",
"Edit Vendor": "ベンダーを編集",
"edit_this": "edit_this",
"Edited channels with tag {{tag}}": "タグ {{tag}} のチャネルを編集しました",
"Editor mode": "エディターモード",
"Education": "教育",
"Email": "メールアドレス",
......@@ -1404,6 +1443,7 @@
"Enable when proxying workers that fetch images over HTTP.": "HTTP経由で画像をフェッチするワーカーをプロキシする場合に有効にします。",
"Enabled": "有効",
"Enabled all channels with tag: {{tag}}": "タグ「{{tag}}」の全チャネルを有効にしました",
"Enabled channels with tag {{tag}}": "タグ {{tag}} のチャネルを有効化しました",
"Enabled Status": "有効ステータス",
"Enabling...": "有効化中...",
"Encourages introducing new topics": "新しい話題への展開を促進します",
......@@ -1528,8 +1568,8 @@
"Exists": "存在",
"Expand": "展開",
"Expand All": "すべて展開",
"Expected a JSON array.": "JSON 配列が必要です。",
"Expected a JSON array of group identifiers": "グループ識別子の JSON 配列が必要です",
"Expected a JSON array.": "JSON 配列が必要です。",
"Experiment with prompts and models in real time.": "プロンプトとモデルをリアルタイムで実験する。",
"Expiration Time": "有効期限",
"expired": "期限切れ",
......@@ -1786,6 +1826,7 @@
"Force format response to OpenAI standard (OpenAI channel only)": "応答をOpenAI標準に強制フォーマット (OpenAIチャネルのみ)",
"Force JSON object or schema-conforming output": "JSON オブジェクトまたはスキーマ準拠の出力を強制します",
"Force SMTP authentication using AUTH LOGIN method": "AUTH LOGIN方式を使用してSMTP認証を強制する",
"Force-disabled two-factor authentication for the user": "ユーザーの二段階認証を強制的に無効化しました",
"Forest Whisper": "フォレストウィスパー",
"Forgot password": "パスワードを忘れた場合",
"Forgot password?": "パスワードをお忘れですか?",
......@@ -2024,6 +2065,7 @@
"Include Rule Name": "ルール名を含む",
"Includes request rules": "リクエストルールを含む",
"Including failed requests, 0 = unlimited": "失敗したリクエストを含む、0 = 無制限",
"Increased user quota by {{quota}}": "ユーザーのクォータを {{quota}} 増やしました",
"Index": "インデックス",
"Initial quota given to new users": "新規ユーザーに付与される初期クォータ",
"Initialization failed, please try again.": "初期化に失敗しました。もう一度お試しください。",
......@@ -2226,8 +2268,12 @@
"Log IP address for usage and error logs": "使用状況およびエラーログのためにIPアドレスを記録する",
"Log Maintenance": "ログのメンテナンス",
"Log Type": "ログタイプ",
"Logged in successfully via {{method}}": "{{method}} でログインに成功しました",
"Logic": "ロジック",
"Login": "ログイン",
"Login failed": "ログインに失敗しました",
"Login Info": "ログイン情報",
"Login Method": "ログイン方法",
"Logo": "ロゴ",
"Logo URL": "ロゴURL",
"Logs": "ログ",
......@@ -2433,6 +2479,7 @@
"ms": "ms",
"Multi-key channel: Keys will be": "マルチキーチャネル: キーは",
"Multi-Key Management": "マルチキー管理",
"Multi-key management {{action}} on channel (ID: {{id}})": "チャネル(ID: {{id}})でマルチキー管理操作 {{action}} を実行しました",
"Multi-Key Mode (multiple keys, one channel)": "マルチキー モード (複数のキー、1つのチャネル)",
"Multi-Key Strategy": "マルチキー戦略",
"Multi-key: Polling rotation": "マルチキー:ポーリングローテーション",
......@@ -2748,6 +2795,7 @@
"opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "外部クライアントで開きます。サイドバーまたはAPIキーアクションからトリガーして、設定されたアプリケーションを起動します。",
"Operation": "操作",
"operation and charging behavior": "運用および課金行為",
"Operation Audit Info": "操作監査情報",
"Operation failed": "操作に失敗しました",
"Operation successful": "操作が成功しました",
"Operation Type": "操作タイプ",
......@@ -2799,6 +2847,7 @@
"Override Rules": "上書きルール",
"Override the endpoint used for testing. Leave empty to auto detect.": "テストに使用されるエンドポイントを上書きします。自動検出するには空のままにします。",
"overrides for matching model prefix.": "は一致するモデル接頭辞に上書きします。",
"Overrode user quota from {{from}} to {{to}}": "ユーザーのクォータを {{from}} から {{to}} に上書きしました",
"Overview": "概要",
"Overwritten": "上書き済み",
"Page": "ページ",
......@@ -2912,6 +2961,7 @@
"Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "ここに表示されているパフォーマンス指標はプレビュー用のシミュレーションデータです。バックエンド連携の完了後、実データに置き換えられます。",
"Performance Monitor": "パフォーマンス監視",
"Performance Settings": "パフォーマンス設定",
"Performed {{action}} on user {{username}} (ID: {{id}})": "ユーザー {{username}}(ID: {{id}})に対して {{action}} を実行しました",
"Period": "期間",
"Periodically check for upstream model changes": "アップストリームモデルの変更を定期的にチェック",
"Periodically send ping frames to keep streaming connections active.": "ストリーミング接続をアクティブに保つために、定期的にpingフレームを送信します。",
......@@ -3248,6 +3298,7 @@
"Regex Replace": "正規表現置換",
"Register each URL into the matching Test Mode / Production Mode webhook slot in the Pancake dashboard. Separate endpoints prevent test traffic from accidentally crediting production accounts.": "Pancake ダッシュボードで、各 URL を対応するテストモードまたは本番モードの Webhook スロットに登録してください。エンドポイントを分けることで、テスト通信が誤って本番アカウントに入金されることを防ぎます。",
"Register Passkey": "Passkeyの登録",
"Registered a passkey": "パスキーを登録しました",
"Registration Enabled": "登録が有効",
"Registry (optional)": "レジストリ (オプション)",
"Registry secret": "レジストリ シークレット",
......@@ -3283,6 +3334,7 @@
"Remove tier": "ティアを削除",
"Removed": "削除済み",
"Removed {{removed}} duplicate key(s). Before: {{before}}, After: {{after}}": "{{removed}} 個の重複キーを削除しました。削除前:{{before}}、削除後:{{after}}",
"Removed an OAuth binding for the user": "ユーザーの OAuth 連携を解除しました",
"Removed Models ({{count}})": "削除済みモデル ({{count}})",
"Removes Midjourney flags such as --fast, --relax, and --turbo from user prompts.": "ユーザー プロンプトから --fast、--relax、--turbo などの Midjourney フラグを削除します。",
"Removing Passkey will require you to sign in with your password next time. You can re-register anytime.": "Passkeyを削除すると、次回からパスワードでサインインする必要があります。いつでも再登録できます。",
......@@ -3354,12 +3406,14 @@
"Reset Cycle": "リセット周期",
"Reset email sent, please check your inbox": "リセットメールを送信しました、受信箱を確認してください",
"Reset failed": "リセット失敗",
"Reset model ratios": "モデル倍率をリセットしました",
"Reset Passkey": "Passkeyリセット",
"Reset password": "パスワードをリセット",
"Reset Period": "リセット期間",
"Reset prices": "価格をリセット",
"Reset ratios": "比率をリセット",
"Reset Stats": "統計をリセット",
"Reset the user passkey": "ユーザーのパスキーをリセットしました",
"Reset to default": "デフォルトにリセット",
"Reset to Default": "デフォルトにリセット",
"Reset to default configuration": "デフォルト設定にリセットしました",
......@@ -3372,6 +3426,7 @@
"Responses API Version": "応答APIバージョン",
"Restore defaults": "既定に戻す",
"Restrict user model request frequency (may impact high concurrency performance)": "ユーザーモデルのリクエスト頻度を制限する(高並行性パフォーマンスに影響を与える可能性があります)",
"Result": "結果",
"Retain last N days": "最新N日間を保持",
"Retain last N files": "最新N個のファイルを保持",
"Retention days": "保持日数",
......@@ -3635,6 +3690,7 @@
"Set tag for selected channels": "選択したチャネルにタグを設定",
"Set the language used across the interface": "インターフェースで使用する言語を設定します",
"Set the user's role (cannot be Root)": "ユーザーのロールを設定します(Rootにはできません)",
"Setting Key": "設定キー",
"Setting saved": "設定が保存されました",
"Setting up 2FA...": "2FAを設定中...",
"Setting updated successfully": "設定が正常に更新されました",
......@@ -3827,6 +3883,7 @@
"Sync this model with official upstream": "このモデルを公式アップストリームと同期",
"Sync Upstream": "アップストリームを同期",
"Sync Upstream Models": "アップストリームモデルを同期",
"Synced upstream models": "上流モデルを同期しました",
"Synchronize models and vendors from an upstream source": "アップストリームソースからモデルとベンダーを同期",
"Syncing prices, please wait...": "価格を同期中、しばらくお待ちください...",
"Syncing...": "同期中...",
......@@ -3872,6 +3929,7 @@
"Target group": "ターゲットグループ",
"Target Header": "コピー先ヘッダー",
"Target Path (optional)": "ターゲットパス(任意)",
"Target User": "対象ユーザー",
"Task": "タスク",
"Task ID": "タスクID",
"Task ID:": "タスクID:",
......@@ -4127,6 +4185,7 @@
"Trend": "トレンド",
"Trending down": "下降中",
"Trending up": "上昇中",
"Triggered garbage collection": "ガベージコレクションを実行しました",
"Trim leading/trailing whitespace": "先頭/末尾の空白を除去",
"Trim Prefix": "プレフィックス削除",
"Trim Space": "空白削除",
......@@ -4217,8 +4276,18 @@
"Update your password for account:": "アカウントのパスワードを更新:",
"Update your password to keep your account secure": "アカウントを安全に保つためにパスワードを更新してください",
"Updated": "更新されました",
"Updated a custom OAuth provider": "カスタム OAuth プロバイダーを更新しました",
"Updated a deployment": "デプロイメントを更新しました",
"Updated a model": "モデルを更新しました",
"Updated a prefill group": "プリフィルグループを更新しました",
"Updated a redemption code": "引換コードを更新しました",
"Updated a subscription plan": "サブスクリプションプランを更新しました",
"Updated a vendor": "ベンダーを更新しました",
"Updated channel {{name}} (ID: {{id}})": "チャネル {{name}} を更新しました(ID: {{id}})",
"Updated daily": "毎日更新",
"Updated successfully": "正常に更新されました",
"Updated system setting {{key}}": "システム設定 {{key}} を更新しました",
"Updated user {{username}} (ID: {{id}})": "ユーザー {{username}} を更新しました(ID: {{id}})",
"Updating all channel balances. This may take a while. Please refresh to see results.": "すべてのチャネル残高を更新中です。これには少し時間がかかる場合があります。結果を確認するには更新してください。",
"Upgrade Group": "グループをアップグレード",
"Upload": "アップロード",
......@@ -4290,6 +4359,7 @@
"Used:": "使用済み:",
"User": "ユーザー",
"User {{id}}": "ユーザー {{id}}",
"User Agent": "ユーザーエージェント",
"User Agreement": "ユーザー利用規約",
"User Analytics": "ユーザー統計",
"User Consumption Ranking": "ユーザー消費ランキング",
......@@ -4384,6 +4454,7 @@
"View the complete prompt and its English translation": "プロンプト全文と英語訳を表示",
"View the generated image": "生成された画像を表示",
"View your topup transaction records and payment history": "チャージ取引記録と支払い履歴を表示",
"Viewed channel key {{name}} (ID: {{id}})": "チャネルキー {{name}} を表示しました(ID: {{id}})",
"Violation Code": "違反コード",
"Violation deduction amount": "違反控除金額",
"Violation Fee": "違反料金",
......
......@@ -46,6 +46,7 @@
"{{count}} weeks ago": "{{count}} недель назад",
"{{field}} updated to {{value}}": "{{field}} обновлено на {{value}}",
"{{field}} updated to {{value}} for tag: {{tag}}": "{{field}} обновлено на {{value}} для тега: {{tag}}",
"{{method}} {{route}}": "{{method}} {{route}}",
"{{modality}} not supported": "{{modality}} не поддерживается",
"{{modality}} supported": "{{modality}} поддерживается",
"{{n}} model(s) selected": "Выбрано моделей: {{n}}",
......@@ -122,6 +123,7 @@
"Account used when authenticating with the SMTP server": "Учетная запись, используемая при аутентификации с SMTP-сервером",
"acknowledge the related legal risks": "признаю связанные правовые риски",
"Across all groups": "По всем группам",
"Action": "Действие",
"Action confirmation": "Подтверждение действия",
"Actions": "Операции",
"active": "активный",
......@@ -372,6 +374,8 @@
"appended": "добавлено",
"Application": "Приложение",
"Applied {{name}} pricing to {{count}} models": "Тариф {{name}} применён к {{count}} моделям",
"Applied upstream model changes to {{count}} channels": "Изменения вышестоящих моделей применены к {{count}} каналам",
"Applied upstream model changes to channel (ID: {{id}})": "Изменения вышестоящих моделей применены к каналу (ID: {{id}})",
"Applies to custom completion endpoints. JSON map of model → ratio.": "Применяется к пользовательским конечным точкам завершения. JSON-карта модель → коэффициент.",
"Apply All Upstream Updates": "Применить все обновления из upstream",
"Apply Filters": "Применить фильтры",
......@@ -519,6 +523,7 @@
"Basic Templates": "Базовые шаблоны",
"Batch Add (one key per line)": "Пакетное добавление (один ключ на строку)",
"Batch delete failed": "Пакетное удаление не удалось",
"Batch deleted {{count}} channels": "Пакетно удалено каналов: {{count}}",
"Batch detection complete: {{channels}} channels, {{add}} to add, {{remove}} to remove, {{fails}} failed": "Пакетное обнаружение завершено: {{channels}} каналов, {{add}} для добавления, {{remove}} для удаления, {{fails}} ошибок",
"Batch detection failed": "Пакетное обнаружение не удалось",
"Batch disable failed": "Пакетное отключение не удалось",
......@@ -527,6 +532,7 @@
"Batch Edit by Tag": "Пакетное редактирование по тегу",
"Batch enable failed": "Пакетное включение не удалось",
"Batch processing failed": "Пакетная обработка не удалась",
"Batch set tag for {{count}} channels": "Тег пакетно задан для {{count}} каналов",
"Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "Пакетное обновление моделей: {{channels}} каналов, {{added}} добавлено, {{removed}} удалено, {{fails}} ошибок",
"Best for single-tenant deployments. Pricing and billing options stay hidden.": "Лучший вариант для однопользовательских развёртываний. Опции ценообразования и биллинга будут скрыты.",
"Best TTFT": "Лучший TTFT",
......@@ -566,6 +572,7 @@
"Bot Token": "Токен бота",
"Bot:": "Бот:",
"Bound": "Привязано",
"Bound a subscription": "Подписка привязана",
"Bound Channels": "Привязанные каналы",
"Bound Only": "Только привязанные",
"Bound product:": "Привязанный продукт:",
......@@ -639,6 +646,7 @@
"Change language": "Изменить язык",
"Change Password": "Изменить пароль",
"Change To": "Изменить на",
"Changed Fields": "Изменённые поля",
"Changes are written to the settings draft on save.": "Изменения будут записаны в черновик настроек при сохранении.",
"Changing...": "Изменение...",
"Channel": "Канал",
......@@ -735,7 +743,12 @@
"Clear selection": "Снять выделение",
"Clear selection (Escape)": "Снять выделение (Escape)",
"Cleared": "Очищено",
"Cleared {{bindingType}} binding for user {{username}}": "Привязка {{bindingType}} пользователя {{username}} удалена",
"Cleared all models": "Все модели очищены",
"Cleared channel affinity cache": "Кэш привязки каналов очищен",
"Cleared disk cache": "Дисковый кэш очищен",
"Cleared historical logs": "Исторические журналы очищены",
"Cleared log files": "Файлы журналов очищены",
"Click \"Create Plan\" to create your first subscription plan": "Нажмите «Создать план», чтобы создать первый план подписки",
"Click \"Generate\" to create a token": "Нажмите \"Сгенерировать\", чтобы создать токен",
"Click any category to drill into its models, apps, and trends": "Нажмите на категорию, чтобы изучить её модели, приложения и тренды",
......@@ -808,6 +821,7 @@
"Complete Order": "Вывод заказа",
"Complete these steps to finish the initial installation.": "Выполните эти шаги, чтобы завершить начальную установку.",
"Completed": "Завершено",
"Completed top-up order for the user": "Заказ на пополнение для пользователя выполнен",
"Completion": "Вывод",
"Completion price": "Цена завершения",
"Completion price ($/1M tokens)": "Цена завершения ($/1 млн токенов)",
......@@ -887,6 +901,7 @@
"Confirm your identity before removing this Passkey from your account.": "Подтвердите свою личность перед удалением этой Passkey из вашей учётной записи.",
"Confirm your identity with Two-factor Authentication before registering a Passkey.": "Подтвердите свою личность с помощью двухфакторной аутентификации перед регистрацией Passkey.",
"Confirmed at {{time}} by user #{{userId}}": "Подтверждено {{time}} пользователем #{{userId}}",
"Confirmed payment compliance": "Соответствие платежа подтверждено",
"Conflict": "Противоречие",
"Connect": "Подключение",
"Connect through OpenAI, Claude, Gemini, and other compatible API routes": "Подключайтесь через OpenAI, Claude, Gemini и другие совместимые API-маршруты",
......@@ -929,6 +944,7 @@
"Convert string to uppercase": "Преобразовать строку в верхний регистр",
"Copied": "Скопировано",
"Copied {{count}} key(s)": "Скопировано {{count}} ключ(ей)",
"Copied channel (source ID: {{sourceId}}) to {{name}} (new ID: {{id}})": "Канал скопирован (исходный ID: {{sourceId}}) в {{name}} (новый ID: {{id}})",
"Copied to clipboard": "Скопировано в буфер обмена",
"Copied: {{model}}": "Скопировано: {{model}}",
"Copied!": "Скопировано!",
......@@ -1010,7 +1026,16 @@
"Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "Создайте свою первую группу для повторного использования выбранных моделей, тегов или конечных точек в любом месте панели управления.",
"Create, revoke, and audit API tokens.": "Создать, отозвать и аудитировать токены API.",
"Created": "Создано",
"Created {{count}} redemption codes named {{name}} ({{quota}} each)": "Создано кодов погашения: {{count}} с именем {{name}} (по {{quota}} каждый)",
"Created a custom OAuth provider": "Создан пользовательский провайдер OAuth",
"Created a deployment": "Создано развёртывание",
"Created a model": "Создана модель",
"Created a prefill group": "Создана группа предзаполнения",
"Created a subscription plan": "Создан тарифный план подписки",
"Created a vendor": "Создан поставщик",
"Created At": "Дата создания",
"Created channel {{name}} (type {{type}}, count {{count}})": "Создан канал {{name}} (тип {{type}}, количество {{count}})",
"Created user {{username}} (role {{role}})": "Создан пользователь {{username}} (роль {{role}})",
"Creates a Pancake product in the saved store using this plan’s title and price. Requires Waffo Pancake to be fully configured in Payment settings first.": "Создает продукт Pancake в сохраненном магазине с названием и ценой этого плана. Сначала необходимо полностью настроить Waffo Pancake в настройках платежей.",
"Creating...": "Создание...",
"Creation failed": "Создание не удалось",
......@@ -1090,6 +1115,7 @@
"Day of month": "День месяца",
"days": "дней",
"Days to Retain": "Дней хранения",
"Decreased user quota by {{quota}}": "Квота пользователя уменьшена на {{quota}}",
"Deducted by subscription": "Списано по подписке",
"DeepSeek": "DeepSeek",
"default": "по умолчанию",
......@@ -1144,7 +1170,18 @@
"Delete selected channels": "Удалить выбранные каналы",
"Delete selected models": "Удалить выбранные модели",
"Deleted": "Удалён",
"Deleted a custom OAuth provider": "Удалён пользовательский провайдер OAuth",
"Deleted a deployment": "Удалено развёртывание",
"Deleted a model": "Удалена модель",
"Deleted a passkey": "Ключ доступа удалён",
"Deleted a prefill group": "Удалена группа предзаполнения",
"Deleted a redemption code": "Код погашения удалён",
"Deleted a vendor": "Удалён поставщик",
"Deleted all disabled channels ({{count}})": "Удалены все отключённые каналы ({{count}})",
"Deleted channel {{name}} (ID: {{id}})": "Удалён канал {{name}} (ID: {{id}})",
"Deleted invalid redemption codes": "Недействительные коды погашения удалены",
"Deleted successfully": "Удалено успешно",
"Deleted user {{username}} (ID: {{id}})": "Удалён пользователь {{username}} (ID: {{id}})",
"Deleting will permanently remove this subscription record (including benefit details). Continue?": "Удаление безвозвратно удалит запись подписки (включая детали льгот). Продолжить?",
"Deleting...": "Удаление...",
"Demo site": "Демо-сайт",
......@@ -1200,6 +1237,7 @@
"disabled": "отключено",
"Disabled": "Отключено",
"Disabled all channels with tag: {{tag}}": "Все каналы с тегом {{tag}} отключены",
"Disabled channels with tag {{tag}}": "Отключены каналы с тегом {{tag}}",
"Disabled lanes are omitted on save.": "Отключённые каналы цен не сохраняются.",
"Disabled Reason": "Причина отключения",
"Disabled Time": "Время отключения",
......@@ -1346,6 +1384,7 @@
"Edit Uptime Kuma Group": "Редактировать группу Uptime Kuma",
"Edit Vendor": "Редактировать поставщика",
"edit_this": "изменить_это",
"Edited channels with tag {{tag}}": "Изменены каналы с тегом {{tag}}",
"Editor mode": "Режим редактора",
"Education": "Образование",
"Email": "Электронная почта",
......@@ -1404,6 +1443,7 @@
"Enable when proxying workers that fetch images over HTTP.": "Включить при проксировании воркеров, которые получают изображения по HTTP.",
"Enabled": "Включено",
"Enabled all channels with tag: {{tag}}": "Все каналы с тегом {{tag}} включены",
"Enabled channels with tag {{tag}}": "Включены каналы с тегом {{tag}}",
"Enabled Status": "Статус включения",
"Enabling...": "Включается...",
"Encourages introducing new topics": "Поощряет введение новых тем",
......@@ -1528,8 +1568,8 @@
"Exists": "Существует",
"Expand": "Развернуть",
"Expand All": "Развернуть все",
"Expected a JSON array.": "Ожидается JSON-массив.",
"Expected a JSON array of group identifiers": "Ожидается JSON-массив идентификаторов групп",
"Expected a JSON array.": "Ожидается JSON-массив.",
"Experiment with prompts and models in real time.": "Экспериментируйте с промптами и моделями в реальном времени.",
"Expiration Time": "Время истечения срока действия",
"expired": "истек",
......@@ -1786,6 +1826,7 @@
"Force format response to OpenAI standard (OpenAI channel only)": "Принудительно форматировать ответ в соответствии со стандартом OpenAI (только для канала OpenAI)",
"Force JSON object or schema-conforming output": "Принудительно вернуть JSON или соответствующий схеме вывод",
"Force SMTP authentication using AUTH LOGIN method": "Принудительная аутентификация SMTP с использованием метода AUTH LOGIN",
"Force-disabled two-factor authentication for the user": "Двухфакторная аутентификация пользователя принудительно отключена",
"Forest Whisper": "Лесной шёпот",
"Forgot password": "Забыли пароль",
"Forgot password?": "Забыли пароль?",
......@@ -2024,6 +2065,7 @@
"Include Rule Name": "Включить имя правила",
"Includes request rules": "Включает правила запросов",
"Including failed requests, 0 = unlimited": "Включая неудачные запросы, 0 = без ограничений",
"Increased user quota by {{quota}}": "Квота пользователя увеличена на {{quota}}",
"Index": "Индекс",
"Initial quota given to new users": "Начальная квота, предоставляемая новым пользователям",
"Initialization failed, please try again.": "Инициализация не удалась, попробуйте ещё раз.",
......@@ -2226,8 +2268,12 @@
"Log IP address for usage and error logs": "Записывать IP-адрес для журналов использования и ошибок",
"Log Maintenance": "Журнал обслуживания",
"Log Type": "Тип журнала",
"Logged in successfully via {{method}}": "Успешный вход через {{method}}",
"Logic": "Логика",
"Login": "Вход",
"Login failed": "Ошибка входа",
"Login Info": "Информация о входе",
"Login Method": "Способ входа",
"Logo": "Логотип",
"Logo URL": "URL логотипа",
"Logs": "Журналы",
......@@ -2433,6 +2479,7 @@
"ms": "мс",
"Multi-key channel: Keys will be": "Многоключевой канал: Ключи будут",
"Multi-Key Management": "Управление несколькими ключами",
"Multi-key management {{action}} on channel (ID: {{id}})": "Управление мультиключами {{action}} для канала (ID: {{id}})",
"Multi-Key Mode (multiple keys, one channel)": "Режим нескольких ключей (несколько ключей, один канал)",
"Multi-Key Strategy": "Стратегия нескольких ключей",
"Multi-key: Polling rotation": "Мульти-ключ: Циклическая ротация",
......@@ -2748,6 +2795,7 @@
"opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "открывается во внешнем клиенте. Запустите его из боковой панели или действий с ключом API, чтобы запустить настроенное приложение.",
"Operation": "Операция",
"operation and charging behavior": "эксплуатацию и взимание платы",
"Operation Audit Info": "Информация об аудите операций",
"Operation failed": "Операция не удалась",
"Operation successful": "Операция выполнена успешно",
"Operation Type": "Тип операции",
......@@ -2799,6 +2847,7 @@
"Override Rules": "Правила переопределения",
"Override the endpoint used for testing. Leave empty to auto detect.": "Переопределить конечную точку, используемую для тестирования. Оставьте пустым для автоматического определения.",
"overrides for matching model prefix.": "переопределяет цену по совпавшему префиксу модели.",
"Overrode user quota from {{from}} to {{to}}": "Квота пользователя изменена с {{from}} на {{to}}",
"Overview": "Обзор",
"Overwritten": "Перезаписано",
"Page": "Страница",
......@@ -2912,6 +2961,7 @@
"Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "Показанные метрики производительности сгенерированы для предпросмотра и будут заменены реальными данными наблюдаемости после интеграции бэкенда.",
"Performance Monitor": "Монитор производительности",
"Performance Settings": "Настройки производительности",
"Performed {{action}} on user {{username}} (ID: {{id}})": "Выполнено действие {{action}} над пользователем {{username}} (ID: {{id}})",
"Period": "Период",
"Periodically check for upstream model changes": "Периодически проверять изменения моделей провайдера",
"Periodically send ping frames to keep streaming connections active.": "Периодически отправлять пинг-кадры для поддержания активности потоковых соединений.",
......@@ -3248,6 +3298,7 @@
"Regex Replace": "Замена по regex",
"Register each URL into the matching Test Mode / Production Mode webhook slot in the Pancake dashboard. Separate endpoints prevent test traffic from accidentally crediting production accounts.": "Зарегистрируйте каждый URL в соответствующем слоте вебхука Test Mode / Production Mode в панели Pancake. Раздельные конечные точки предотвращают случайное зачисление тестового трафика на производственные аккаунты.",
"Register Passkey": "Регистрация Passkey",
"Registered a passkey": "Ключ доступа зарегистрирован",
"Registration Enabled": "Регистрация включена",
"Registry (optional)": "Реестр (необязательно)",
"Registry secret": "Секрет реестра",
......@@ -3283,6 +3334,7 @@
"Remove tier": "Удалить уровень",
"Removed": "Удалено",
"Removed {{removed}} duplicate key(s). Before: {{before}}, After: {{after}}": "Удалено {{removed}} дублирующихся ключей. До: {{before}}, После: {{after}}",
"Removed an OAuth binding for the user": "Привязка OAuth пользователя удалена",
"Removed Models ({{count}})": "Удалённые модели ({{count}})",
"Removes Midjourney flags such as --fast, --relax, and --turbo from user prompts.": "Удаляет флаги Midjourney, такие как --fast, --relax и --turbo, из промптов пользователя.",
"Removing Passkey will require you to sign in with your password next time. You can re-register anytime.": "Удаление ключа доступа потребует от вас входа с паролем в следующий раз. Вы можете перерегистрироваться в любое время.",
......@@ -3354,12 +3406,14 @@
"Reset Cycle": "Цикл сброса",
"Reset email sent, please check your inbox": "Письмо для сброса отправлено, проверьте входящие",
"Reset failed": "Ошибка сброса",
"Reset model ratios": "Коэффициенты моделей сброшены",
"Reset Passkey": "Сброс Passkey",
"Reset password": "Сбросить пароль",
"Reset Period": "Период сброса",
"Reset prices": "Сбросить цены",
"Reset ratios": "Сбросить соотношения",
"Reset Stats": "Сбросить статистику",
"Reset the user passkey": "Ключ доступа пользователя сброшен",
"Reset to default": "Сбросить до значений по умолчанию",
"Reset to Default": "Сбросить по умолчанию",
"Reset to default configuration": "Сброшено к конфигурации по умолчанию",
......@@ -3372,6 +3426,7 @@
"Responses API Version": "Версия API ответов",
"Restore defaults": "Сбросить к значениям по умолчанию",
"Restrict user model request frequency (may impact high concurrency performance)": "Ограничить частоту запросов пользовательских моделей (может повлиять на производительность при высокой конкуренции)",
"Result": "Результат",
"Retain last N days": "Хранить последние N дней",
"Retain last N files": "Хранить последние N файлов",
"Retention days": "Дней хранения",
......@@ -3635,6 +3690,7 @@
"Set tag for selected channels": "Установить тег для выбранных каналов",
"Set the language used across the interface": "Настроить язык интерфейса",
"Set the user's role (cannot be Root)": "Установить роль пользователя (не может быть Root)",
"Setting Key": "Ключ настройки",
"Setting saved": "Настройка сохранена",
"Setting up 2FA...": "Настройка 2FA...",
"Setting updated successfully": "Настройка успешно обновлена",
......@@ -3827,6 +3883,7 @@
"Sync this model with official upstream": "Синхронизировать эту модель с официальным upstream",
"Sync Upstream": "Синхронизировать Upstream",
"Sync Upstream Models": "Синхронизировать модели Upstream",
"Synced upstream models": "Вышестоящие модели синхронизированы",
"Synchronize models and vendors from an upstream source": "Синхронизировать модели и поставщиков из upstream источника",
"Syncing prices, please wait...": "Синхронизация цен, подождите...",
"Syncing...": "Синхронизация...",
......@@ -3872,6 +3929,7 @@
"Target group": "Целевая группа",
"Target Header": "Целевой заголовок",
"Target Path (optional)": "Целевой путь (необязательно)",
"Target User": "Целевой пользователь",
"Task": "Задача",
"Task ID": "ID задачи",
"Task ID:": "ID задачи:",
......@@ -4127,6 +4185,7 @@
"Trend": "Тренд",
"Trending down": "Падают",
"Trending up": "Растут",
"Triggered garbage collection": "Запущена сборка мусора",
"Trim leading/trailing whitespace": "Удалить пробелы в начале/конце",
"Trim Prefix": "Обрезать префикс",
"Trim Space": "Обрезать пробелы",
......@@ -4217,8 +4276,18 @@
"Update your password for account:": "Обновите свой пароль для учетной записи:",
"Update your password to keep your account secure": "Обновите пароль, чтобы обеспечить безопасность вашей учётной записи",
"Updated": "Обновлено",
"Updated a custom OAuth provider": "Обновлён пользовательский провайдер OAuth",
"Updated a deployment": "Обновлено развёртывание",
"Updated a model": "Обновлена модель",
"Updated a prefill group": "Обновлена группа предзаполнения",
"Updated a redemption code": "Код погашения обновлён",
"Updated a subscription plan": "Обновлён тарифный план подписки",
"Updated a vendor": "Обновлён поставщик",
"Updated channel {{name}} (ID: {{id}})": "Обновлён канал {{name}} (ID: {{id}})",
"Updated daily": "Обновляется ежедневно",
"Updated successfully": "Обновлено успешно",
"Updated system setting {{key}}": "Обновлён системный параметр {{key}}",
"Updated user {{username}} (ID: {{id}})": "Обновлён пользователь {{username}} (ID: {{id}})",
"Updating all channel balances. This may take a while. Please refresh to see results.": "Обновление балансов всех каналов. Это может занять некоторое время. Пожалуйста, обновите страницу, чтобы увидеть результаты.",
"Upgrade Group": "Повысить группу",
"Upload": "Загрузка",
......@@ -4290,6 +4359,7 @@
"Used:": "Использовано:",
"User": "Пользователь",
"User {{id}}": "Пользователь {{id}}",
"User Agent": "Пользовательский агент",
"User Agreement": "Пользовательское соглашение",
"User Analytics": "Аналитика пользователей",
"User Consumption Ranking": "Рейтинг потребления",
......@@ -4384,6 +4454,7 @@
"View the complete prompt and its English translation": "Просмотр полного промпта и его перевода на английский",
"View the generated image": "Просмотр сгенерированного изображения",
"View your topup transaction records and payment history": "Просмотреть записи о пополнении счета и историю платежей",
"Viewed channel key {{name}} (ID: {{id}})": "Просмотрен ключ канала {{name}} (ID: {{id}})",
"Violation Code": "Код нарушения",
"Violation deduction amount": "Сумма вычета за нарушение",
"Violation Fee": "Штраф за нарушение",
......
......@@ -46,6 +46,7 @@
"{{count}} weeks ago": "{{count}} tuần trước",
"{{field}} updated to {{value}}": "{{field}} đã cập nhật thành {{value}}",
"{{field}} updated to {{value}} for tag: {{tag}}": "{{field}} đã cập nhật thành {{value}} cho nhãn: {{tag}}",
"{{method}} {{route}}": "{{method}} {{route}}",
"{{modality}} not supported": "Không hỗ trợ {{modality}}",
"{{modality}} supported": "Hỗ trợ {{modality}}",
"{{n}} model(s) selected": "Đã chọn {{n}} model",
......@@ -122,6 +123,7 @@
"Account used when authenticating with the SMTP server": "Tài khoản được sử dụng khi xác thực với máy chủ SMTP",
"acknowledge the related legal risks": "thừa nhận các rủi ro pháp lý liên quan",
"Across all groups": "Trên mọi nhóm",
"Action": "Hành động",
"Action confirmation": "Xác nhận hành động",
"Actions": "Hành động",
"active": "hoạt động",
......@@ -372,6 +374,8 @@
"appended": "đã thêm vào cuối, được phụ lục",
"Application": "Ứng dụng",
"Applied {{name}} pricing to {{count}} models": "Đã áp dụng giá của {{name}} cho {{count}} mô hình",
"Applied upstream model changes to {{count}} channels": "Đã áp dụng thay đổi mô hình thượng nguồn cho {{count}} kênh",
"Applied upstream model changes to channel (ID: {{id}})": "Đã áp dụng thay đổi mô hình thượng nguồn cho kênh (ID: {{id}})",
"Applies to custom completion endpoints. JSON map of model → ratio.": "Áp dụng cho các điểm cuối hoàn thành tùy chỉnh. Bản đồ JSON của mô hình → tỷ lệ.",
"Apply All Upstream Updates": "Áp dụng Tất cả Cập nhật Upstream",
"Apply Filters": "Áp dụng bộ lọc",
......@@ -519,6 +523,7 @@
"Basic Templates": "Mẫu cơ bản",
"Batch Add (one key per line)": "Thêm hàng loạt (mỗi khóa một dòng)",
"Batch delete failed": "Xóa hàng loạt thất bại",
"Batch deleted {{count}} channels": "Đã xóa hàng loạt {{count}} kênh",
"Batch detection complete: {{channels}} channels, {{add}} to add, {{remove}} to remove, {{fails}} failed": "Phát hiện hàng loạt hoàn tất: {{channels}} kênh, {{add}} để thêm, {{remove}} để xóa, {{fails}} thất bại",
"Batch detection failed": "Phát hiện hàng loạt thất bại",
"Batch disable failed": "Vô hiệu hóa hàng loạt thất bại",
......@@ -527,6 +532,7 @@
"Batch Edit by Tag": "Chỉnh sửa hàng loạt theo Thẻ",
"Batch enable failed": "Kích hoạt hàng loạt thất bại",
"Batch processing failed": "Xử lý hàng loạt thất bại",
"Batch set tag for {{count}} channels": "Đã đặt thẻ hàng loạt cho {{count}} kênh",
"Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "Đã áp dụng cập nhật hàng loạt mô hình upstream: {{channels}} kênh, {{added}} đã thêm, {{removed}} đã xóa, {{fails}} thất bại",
"Best for single-tenant deployments. Pricing and billing options stay hidden.": "Phù hợp nhất cho triển khai đơn người dùng. Các tùy chọn giá và thanh toán sẽ được ẩn.",
"Best TTFT": "TTFT tốt nhất",
......@@ -566,6 +572,7 @@
"Bot Token": "Mã thông báo Bot",
"Bot:": "Bot:",
"Bound": "Ràng buộc",
"Bound a subscription": "Đã liên kết một gói đăng ký",
"Bound Channels": "Các kênh ràng buộc",
"Bound Only": "Chỉ đã liên kết",
"Bound product:": "Sản phẩm đã liên kết:",
......@@ -639,6 +646,7 @@
"Change language": "Đổi ngôn ngữ",
"Change Password": "Đổi mật khẩu",
"Change To": "Thay đổi thành",
"Changed Fields": "Trường đã thay đổi",
"Changes are written to the settings draft on save.": "Các thay đổi sẽ được ghi vào bản nháp cài đặt khi lưu.",
"Changing...": "Đang thay đổi...",
"Channel": "Kênh",
......@@ -735,7 +743,12 @@
"Clear selection": "Bỏ chọn",
"Clear selection (Escape)": "Bỏ chọn (Escape)",
"Cleared": "Đã xóa",
"Cleared {{bindingType}} binding for user {{username}}": "Đã xóa liên kết {{bindingType}} của người dùng {{username}}",
"Cleared all models": "Đã xóa tất cả các mô hình",
"Cleared channel affinity cache": "Đã xóa bộ nhớ đệm liên kết kênh",
"Cleared disk cache": "Đã xóa bộ nhớ đệm trên đĩa",
"Cleared historical logs": "Đã xóa nhật ký lịch sử",
"Cleared log files": "Đã xóa tệp nhật ký",
"Click \"Create Plan\" to create your first subscription plan": "Nhấp \"Tạo gói\" để tạo gói đăng ký đầu tiên",
"Click \"Generate\" to create a token": "Nhấp \"Tạo\" để tạo một token",
"Click any category to drill into its models, apps, and trends": "Bấm vào danh mục để xem chi tiết mô hình, ứng dụng và xu hướng",
......@@ -808,6 +821,7 @@
"Complete Order": "Hoàn thành đơn hàng",
"Complete these steps to finish the initial installation.": "Hoàn thành các bước này để hoàn tất quá trình cài đặt ban đầu.",
"Completed": "Hoàn thành",
"Completed top-up order for the user": "Đã hoàn tất đơn nạp tiền cho người dùng",
"Completion": "Hoàn thành",
"Completion price": "Giá hoàn thành",
"Completion price ($/1M tokens)": "Giá hoàn thành ($/1M tokens)",
......@@ -887,6 +901,7 @@
"Confirm your identity before removing this Passkey from your account.": "Hãy xác minh danh tính trước khi gỡ Passkey khỏi tài khoản.",
"Confirm your identity with Two-factor Authentication before registering a Passkey.": "Hãy xác minh danh tính bằng Xác thực hai yếu tố trước khi đăng ký Passkey.",
"Confirmed at {{time}} by user #{{userId}}": "Được xác nhận lúc {{time}} bởi người dùng #{{userId}}",
"Confirmed payment compliance": "Đã xác nhận tuân thủ thanh toán",
"Conflict": "Xung đột",
"Connect": "Kết nối",
"Connect through OpenAI, Claude, Gemini, and other compatible API routes": "Kết nối qua OpenAI, Claude, Gemini và các tuyến API tương thích khác",
......@@ -929,6 +944,7 @@
"Convert string to uppercase": "Chuyển chuỗi sang chữ hoa",
"Copied": "Đã sao chép",
"Copied {{count}} key(s)": "Đã sao chép {{count}} khóa",
"Copied channel (source ID: {{sourceId}}) to {{name}} (new ID: {{id}})": "Đã sao chép kênh (ID nguồn: {{sourceId}}) thành {{name}} (ID mới: {{id}})",
"Copied to clipboard": "Đã sao chép vào bộ nhớ tạm",
"Copied: {{model}}": "Đã sao chép: {{model}}",
"Copied!": "Đã sao chép!",
......@@ -1010,7 +1026,16 @@
"Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "Tạo nhóm đầu tiên của bạn để dùng lại các lựa chọn mô hình, thẻ hoặc điểm cuối ở bất cứ đâu trên bảng điều khiển.",
"Create, revoke, and audit API tokens.": "Tạo, thu hồi và kiểm toán token API.",
"Created": "Đã tạo",
"Created {{count}} redemption codes named {{name}} ({{quota}} each)": "Đã tạo {{count}} mã đổi thưởng tên {{name}} (mỗi mã {{quota}})",
"Created a custom OAuth provider": "Đã tạo nhà cung cấp OAuth tùy chỉnh",
"Created a deployment": "Đã tạo một triển khai",
"Created a model": "Đã tạo một mô hình",
"Created a prefill group": "Đã tạo một nhóm điền sẵn",
"Created a subscription plan": "Đã tạo một gói đăng ký",
"Created a vendor": "Đã tạo một nhà cung cấp",
"Created At": "Ngày tạo",
"Created channel {{name}} (type {{type}}, count {{count}})": "Đã tạo kênh {{name}} (loại {{type}}, số lượng {{count}})",
"Created user {{username}} (role {{role}})": "Đã tạo người dùng {{username}} (vai trò {{role}})",
"Creates a Pancake product in the saved store using this plan’s title and price. Requires Waffo Pancake to be fully configured in Payment settings first.": "Tạo một sản phẩm Pancake trong cửa hàng đã lưu bằng tiêu đề và giá của gói này. Trước tiên cần cấu hình đầy đủ Waffo Pancake trong cài đặt Thanh toán.",
"Creating...": "Đang tạo...",
"Creation failed": "Tạo thất bại",
......@@ -1090,6 +1115,7 @@
"Day of month": "Ngày trong tháng",
"days": "ngày",
"Days to Retain": "Số ngày giữ lại",
"Decreased user quota by {{quota}}": "Đã giảm hạn mức người dùng {{quota}}",
"Deducted by subscription": "Khấu trừ bởi gói đăng ký",
"DeepSeek": "DeepSeek",
"default": "mặc định",
......@@ -1144,7 +1170,18 @@
"Delete selected channels": "Xóa các kênh đã chọn",
"Delete selected models": "Xóa các mô hình đã chọn",
"Deleted": "Đã xóa",
"Deleted a custom OAuth provider": "Đã xóa nhà cung cấp OAuth tùy chỉnh",
"Deleted a deployment": "Đã xóa một triển khai",
"Deleted a model": "Đã xóa một mô hình",
"Deleted a passkey": "Đã xóa một passkey",
"Deleted a prefill group": "Đã xóa một nhóm điền sẵn",
"Deleted a redemption code": "Đã xóa một mã đổi thưởng",
"Deleted a vendor": "Đã xóa một nhà cung cấp",
"Deleted all disabled channels ({{count}})": "Đã xóa tất cả kênh bị vô hiệu hóa ({{count}})",
"Deleted channel {{name}} (ID: {{id}})": "Đã xóa kênh {{name}} (ID: {{id}})",
"Deleted invalid redemption codes": "Đã xóa các mã đổi thưởng không hợp lệ",
"Deleted successfully": "Xóa thành công",
"Deleted user {{username}} (ID: {{id}})": "Đã xóa người dùng {{username}} (ID: {{id}})",
"Deleting will permanently remove this subscription record (including benefit details). Continue?": "Xóa sẽ xóa vĩnh viễn bản ghi đăng ký này (bao gồm chi tiết quyền lợi). Tiếp tục?",
"Deleting...": "Đang xóa...",
"Demo site": "Trang demo",
......@@ -1200,6 +1237,7 @@
"disabled": "vô hiệu hóa",
"Disabled": "Đã tắt",
"Disabled all channels with tag: {{tag}}": "Đã tắt tất cả kênh với nhãn: {{tag}}",
"Disabled channels with tag {{tag}}": "Đã vô hiệu hóa các kênh có thẻ {{tag}}",
"Disabled lanes are omitted on save.": "Các kênh bị tắt sẽ được bỏ qua khi lưu.",
"Disabled Reason": "Lý do vô hiệu hóa",
"Disabled Time": "Thời gian vô hiệu hóa",
......@@ -1346,6 +1384,7 @@
"Edit Uptime Kuma Group": "Chỉnh sửa Nhóm Uptime Kuma",
"Edit Vendor": "Chỉnh sửa Nhà cung cấp",
"edit_this": "edit_this",
"Edited channels with tag {{tag}}": "Đã chỉnh sửa các kênh có thẻ {{tag}}",
"Editor mode": "Chế độ trình sửa",
"Education": "Giáo dục",
"Email": "Email",
......@@ -1404,6 +1443,7 @@
"Enable when proxying workers that fetch images over HTTP.": "Kích hoạt khi làm proxy cho các worker tìm nạp hình ảnh qua HTTP.",
"Enabled": "Đã bật",
"Enabled all channels with tag: {{tag}}": "Đã bật tất cả kênh với nhãn: {{tag}}",
"Enabled channels with tag {{tag}}": "Đã kích hoạt các kênh có thẻ {{tag}}",
"Enabled Status": "Trạng thái kích hoạt",
"Enabling...": "Đang bật...",
"Encourages introducing new topics": "Khuyến khích chủ đề mới",
......@@ -1528,8 +1568,8 @@
"Exists": "Tồn tại",
"Expand": "Mở rộng",
"Expand All": "Mở rộng tất cả",
"Expected a JSON array.": "Cần là một mảng JSON.",
"Expected a JSON array of group identifiers": "Cần là một mảng JSON gồm các định danh nhóm",
"Expected a JSON array.": "Cần là một mảng JSON.",
"Experiment with prompts and models in real time.": "Thử nghiệm với prompt và mô hình theo thời gian thực.",
"Expiration Time": "Thời gian hết hạn",
"expired": "Đã hết hạn",
......@@ -1786,6 +1826,7 @@
"Force format response to OpenAI standard (OpenAI channel only)": "Buộc định dạng phản hồi theo tiêu chuẩn OpenAI (chỉ kênh OpenAI)",
"Force JSON object or schema-conforming output": "Bắt buộc xuất JSON hoặc theo schema",
"Force SMTP authentication using AUTH LOGIN method": "Bắt buộc xác thực SMTP sử dụng phương thức AUTH LOGIN",
"Force-disabled two-factor authentication for the user": "Đã buộc tắt xác thực hai yếu tố của người dùng",
"Forest Whisper": "Tiếng thì thầm rừng cây",
"Forgot password": "Quên mật khẩu",
"Forgot password?": "Quên mật khẩu?",
......@@ -2024,6 +2065,7 @@
"Include Rule Name": "Bao gồm tên quy tắc",
"Includes request rules": "Bao gồm quy tắc yêu cầu",
"Including failed requests, 0 = unlimited": "Bao gồm các yêu cầu thất bại, 0 = không giới hạn",
"Increased user quota by {{quota}}": "Đã tăng hạn mức người dùng thêm {{quota}}",
"Index": "Chỉ mục",
"Initial quota given to new users": "Hạn mức ban đầu cấp cho người dùng mới",
"Initialization failed, please try again.": "Khởi tạo thất bại, vui lòng thử lại.",
......@@ -2226,8 +2268,12 @@
"Log IP address for usage and error logs": "Ghi lại địa chỉ IP cho nhật ký sử dụng và lỗi",
"Log Maintenance": "Bảo trì Nhật ký",
"Log Type": "Loại nhật ký",
"Logged in successfully via {{method}}": "Đăng nhập thành công qua {{method}}",
"Logic": "Logic",
"Login": "Đăng nhập",
"Login failed": "Đăng nhập thất bại",
"Login Info": "Thông tin đăng nhập",
"Login Method": "Phương thức đăng nhập",
"Logo": "Logo",
"Logo URL": "URL Logo",
"Logs": "Nhật ký",
......@@ -2433,6 +2479,7 @@
"ms": "ms",
"Multi-key channel: Keys will be": "Kênh đa khóa: Các khóa sẽ là",
"Multi-Key Management": "Quản lý đa khóa",
"Multi-key management {{action}} on channel (ID: {{id}})": "Quản lý đa khóa {{action}} trên kênh (ID: {{id}})",
"Multi-Key Mode (multiple keys, one channel)": "Chế độ đa phím (nhiều phím, một kênh)",
"Multi-Key Strategy": "Chiến lược đa khóa",
"Multi-key: Polling rotation": "Đa khóa: Xoay vòng tuần tự",
......@@ -2748,6 +2795,7 @@
"opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "mở trong một ứng dụng bên ngoài. Kích hoạt nó từ thanh bên hoặc các hành động khóa API để khởi chạy ứng dụng đã cấu hình.",
"Operation": "Thao tác",
"operation and charging behavior": "hành vi vận hành và thu phí",
"Operation Audit Info": "Thông tin kiểm toán thao tác",
"Operation failed": "Thao tác thất bại",
"Operation successful": "Thao tác thành công",
"Operation Type": "Loại thao tác",
......@@ -2799,6 +2847,7 @@
"Override Rules": "Quy tắc ghi đè",
"Override the endpoint used for testing. Leave empty to auto detect.": "Ghi đè điểm cuối dùng để kiểm thử. Để trống để tự động phát hiện.",
"overrides for matching model prefix.": "ghi đè theo tiền tố model tương ứng.",
"Overrode user quota from {{from}} to {{to}}": "Đã ghi đè hạn mức người dùng từ {{from}} thành {{to}}",
"Overview": "Tổng quan",
"Overwritten": "Đã ghi đè",
"Page": "Trang",
......@@ -2912,6 +2961,7 @@
"Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "Các chỉ số hiệu năng hiển thị tại đây là dữ liệu mô phỏng để xem trước và sẽ được thay thế bằng dữ liệu thực sau khi tích hợp backend.",
"Performance Monitor": "Giám sát hiệu suất",
"Performance Settings": "Cài đặt hiệu suất",
"Performed {{action}} on user {{username}} (ID: {{id}})": "Đã thực hiện {{action}} trên người dùng {{username}} (ID: {{id}})",
"Period": "Khoảng thời gian",
"Periodically check for upstream model changes": "Kiểm tra định kỳ các thay đổi mô hình nguồn",
"Periodically send ping frames to keep streaming connections active.": "Định kỳ gửi các khung ping để duy trì các kết nối truyền phát hoạt động.",
......@@ -3248,6 +3298,7 @@
"Regex Replace": "Thay thế regex",
"Register each URL into the matching Test Mode / Production Mode webhook slot in the Pancake dashboard. Separate endpoints prevent test traffic from accidentally crediting production accounts.": "Đăng ký từng URL vào ô webhook Test Mode / Production Mode tương ứng trong bảng điều khiển Pancake. Endpoint riêng biệt giúp tránh việc lưu lượng thử nghiệm vô tình cộng tiền vào tài khoản sản xuất.",
"Register Passkey": "Đăng ký Passkey",
"Registered a passkey": "Đã đăng ký một passkey",
"Registration Enabled": "Đăng ký đã bật",
"Registry (optional)": "Registry (tùy chọn)",
"Registry secret": "Bí mật Registry",
......@@ -3283,6 +3334,7 @@
"Remove tier": "Gỡ bậc",
"Removed": "Đã xóa",
"Removed {{removed}} duplicate key(s). Before: {{before}}, After: {{after}}": "Đã xóa {{removed}} khóa trùng lặp. Trước: {{before}}, Sau: {{after}}",
"Removed an OAuth binding for the user": "Đã gỡ một liên kết OAuth của người dùng",
"Removed Models ({{count}})": "Các mô hình đã xóa ({{count}})",
"Removes Midjourney flags such as --fast, --relax, and --turbo from user prompts.": "Loại bỏ các cờ Midjourney như --fast, --relax và --turbo khỏi lời nhắc của người dùng.",
"Removing Passkey will require you to sign in with your password next time. You can re-register anytime.": "Xóa Khóa truy cập sẽ yêu cầu bạn đăng nhập bằng mật khẩu của mình vào lần tới. Bạn có thể đăng ký lại bất cứ lúc nào.",
......@@ -3354,12 +3406,14 @@
"Reset Cycle": "Chu kỳ đặt lại",
"Reset email sent, please check your inbox": "Email đặt lại đã được gửi, vui lòng kiểm tra hộp thư đến",
"Reset failed": "Đặt lại thất bại",
"Reset model ratios": "Đã đặt lại tỷ lệ mô hình",
"Reset Passkey": "Đặt lại Khóa truy cập",
"Reset password": "Đặt lại mật khẩu",
"Reset Period": "Chu kỳ đặt lại",
"Reset prices": "Đặt lại giá",
"Reset ratios": "Đặt lại tỷ lệ",
"Reset Stats": "Đặt lại thống kê",
"Reset the user passkey": "Đã đặt lại passkey của người dùng",
"Reset to default": "Đặt lại mặc định",
"Reset to Default": "Đặt lại mặc định",
"Reset to default configuration": "Đã đặt lại cấu hình mặc định",
......@@ -3372,6 +3426,7 @@
"Responses API Version": "Phiên bản API Phản hồi",
"Restore defaults": "Khôi phục mặc định",
"Restrict user model request frequency (may impact high concurrency performance)": "Hạn chế tần suất yêu cầu mô hình người dùng (có thể ảnh hưởng đến hiệu suất khi có độ đồng thời cao)",
"Result": "Kết quả",
"Retain last N days": "Giữ lại N ngày gần nhất",
"Retain last N files": "Giữ lại N tệp gần nhất",
"Retention days": "Số ngày lưu giữ",
......@@ -3635,6 +3690,7 @@
"Set tag for selected channels": "Đặt thẻ cho các kênh đã chọn",
"Set the language used across the interface": "Đặt ngôn ngữ sử dụng trong giao diện",
"Set the user's role (cannot be Root)": "Đặt vai trò của người dùng (không được là Root)",
"Setting Key": "Khóa cài đặt",
"Setting saved": "Cài đặt đã được lưu",
"Setting up 2FA...": "Đang thiết lập 2FA...",
"Setting updated successfully": "Cài đặt đã được cập nhật thành công",
......@@ -3827,6 +3883,7 @@
"Sync this model with official upstream": "Synchronize this model with the official source.",
"Sync Upstream": "Đồng bộ nguồn",
"Sync Upstream Models": "Đồng bộ các mô hình nguồn",
"Synced upstream models": "Đã đồng bộ mô hình thượng nguồn",
"Synchronize models and vendors from an upstream source": "Đồng bộ hóa các mô hình và nhà cung cấp từ một nguồn thượng nguồn",
"Syncing prices, please wait...": "Đang đồng bộ giá, vui lòng đợi...",
"Syncing...": "Đang đồng bộ...",
......@@ -3872,6 +3929,7 @@
"Target group": "Target audience",
"Target Header": "Header đích",
"Target Path (optional)": "Đường dẫn đích (tùy chọn)",
"Target User": "Người dùng mục tiêu",
"Task": "Nhiệm vụ",
"Task ID": "Mã nhiệm vụ",
"Task ID:": "ID nhiệm vụ:",
......@@ -4127,6 +4185,7 @@
"Trend": "Xu hướng",
"Trending down": "Đang giảm",
"Trending up": "Đang tăng",
"Triggered garbage collection": "Đã kích hoạt thu gom rác",
"Trim leading/trailing whitespace": "Xóa khoảng trắng đầu/cuối",
"Trim Prefix": "Cắt tiền tố",
"Trim Space": "Cắt khoảng trắng",
......@@ -4217,8 +4276,18 @@
"Update your password for account:": "Cập nhật mật khẩu của bạn cho tài khoản:",
"Update your password to keep your account secure": "Cập nhật mật khẩu của bạn để bảo mật tài khoản.",
"Updated": "Đã cập nhật",
"Updated a custom OAuth provider": "Đã cập nhật nhà cung cấp OAuth tùy chỉnh",
"Updated a deployment": "Đã cập nhật một triển khai",
"Updated a model": "Đã cập nhật một mô hình",
"Updated a prefill group": "Đã cập nhật một nhóm điền sẵn",
"Updated a redemption code": "Đã cập nhật một mã đổi thưởng",
"Updated a subscription plan": "Đã cập nhật một gói đăng ký",
"Updated a vendor": "Đã cập nhật một nhà cung cấp",
"Updated channel {{name}} (ID: {{id}})": "Đã cập nhật kênh {{name}} (ID: {{id}})",
"Updated daily": "Cập nhật hàng ngày",
"Updated successfully": "Cập nhật thành công",
"Updated system setting {{key}}": "Đã cập nhật cài đặt hệ thống {{key}}",
"Updated user {{username}} (ID: {{id}})": "Đã cập nhật người dùng {{username}} (ID: {{id}})",
"Updating all channel balances. This may take a while. Please refresh to see results.": "Đang cập nhật tất cả số dư kênh. Quá trình này có thể mất một chút thời gian. Vui lòng làm mới để xem kết quả.",
"Upgrade Group": "Nhóm nâng cấp",
"Upload": "Tải lên",
......@@ -4290,6 +4359,7 @@
"Used:": "Đã dùng:",
"User": "Người dùng",
"User {{id}}": "Người dùng {{id}}",
"User Agent": "Tác nhân người dùng",
"User Agreement": "Thỏa thuận người dùng",
"User Analytics": "Thống kê người dùng",
"User Consumption Ranking": "Xếp hạng tiêu thụ",
......@@ -4384,6 +4454,7 @@
"View the complete prompt and its English translation": "Xem toàn bộ lời nhắc và bản dịch tiếng Anh",
"View the generated image": "Xem ảnh đã tạo",
"View your topup transaction records and payment history": "Xem lịch sử giao dịch nạp tiền và lịch sử thanh toán của bạn",
"Viewed channel key {{name}} (ID: {{id}})": "Đã xem khóa kênh {{name}} (ID: {{id}})",
"Violation Code": "Mã vi phạm",
"Violation deduction amount": "Số tiền trừ vi phạm",
"Violation Fee": "Phí vi phạm",
......
......@@ -46,6 +46,7 @@
"{{count}} weeks ago": "{{count}} 周前",
"{{field}} updated to {{value}}": "{{field}} 已更新为 {{value}}",
"{{field}} updated to {{value}} for tag: {{tag}}": "标签「{{tag}}」的 {{field}} 已更新为 {{value}}",
"{{method}} {{route}}": "{{method}} {{route}}",
"{{modality}} not supported": "不支持 {{modality}}",
"{{modality}} supported": "支持 {{modality}}",
"{{n}} model(s) selected": "已选 {{n}} 个模型",
......@@ -122,6 +123,7 @@
"Account used when authenticating with the SMTP server": "用于与 SMTP 服务器进行身份验证的账户",
"acknowledge the related legal risks": "确认相关法律风险",
"Across all groups": "跨所有分组",
"Action": "操作",
"Action confirmation": "操作确认",
"Actions": "操作",
"active": "活跃",
......@@ -372,6 +374,8 @@
"appended": "已追加",
"Application": "应用",
"Applied {{name}} pricing to {{count}} models": "已将 {{name}} 的定价应用到 {{count}} 个模型",
"Applied upstream model changes to {{count}} channels": "对 {{count}} 个渠道应用上游模型变更",
"Applied upstream model changes to channel (ID: {{id}})": "对渠道(ID: {{id}})应用上游模型变更",
"Applies to custom completion endpoints. JSON map of model → ratio.": "适用于自定义补全端点。模型 → 比例的 JSON 映射。",
"Apply All Upstream Updates": "应用所有上游更新",
"Apply Filters": "应用筛选器",
......@@ -519,6 +523,7 @@
"Basic Templates": "基础模板",
"Batch Add (one key per line)": "批量添加(每行一个密钥)",
"Batch delete failed": "批量删除失败",
"Batch deleted {{count}} channels": "批量删除 {{count}} 个渠道",
"Batch detection complete: {{channels}} channels, {{add}} to add, {{remove}} to remove, {{fails}} failed": "批量检测完成:渠道 {{channels}} 个,新增 {{add}} 个,删除 {{remove}} 个,失败 {{fails}} 个",
"Batch detection failed": "批量检测失败",
"Batch disable failed": "批量禁用失败",
......@@ -527,6 +532,7 @@
"Batch Edit by Tag": "按标签批量编辑",
"Batch enable failed": "批量启用失败",
"Batch processing failed": "批量处理失败",
"Batch set tag for {{count}} channels": "批量为 {{count}} 个渠道设置标签",
"Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "已批量处理上游模型更新:渠道 {{channels}} 个,加入 {{added}} 个,删除 {{removed}} 个,失败 {{fails}} 个",
"Best for single-tenant deployments. Pricing and billing options stay hidden.": "适合单用户部署。定价和计费选项将被隐藏。",
"Best TTFT": "最优 TTFT",
......@@ -566,6 +572,7 @@
"Bot Token": "机器人令牌",
"Bot:": "机器人:",
"Bound": "已绑定",
"Bound a subscription": "绑定了一个订阅",
"Bound Channels": "绑定渠道",
"Bound Only": "仅已绑定",
"Bound product:": "已绑定产品:",
......@@ -639,6 +646,7 @@
"Change language": "更改语言",
"Change Password": "更改密码",
"Change To": "更改为",
"Changed Fields": "变更字段",
"Changes are written to the settings draft on save.": "保存后会写入设置草稿。",
"Changing...": "修改中...",
"Channel": "渠道",
......@@ -735,7 +743,12 @@
"Clear selection": "清除选择",
"Clear selection (Escape)": "清除选择 (Escape)",
"Cleared": "已清空",
"Cleared {{bindingType}} binding for user {{username}}": "清除用户 {{username}} 的 {{bindingType}} 绑定",
"Cleared all models": "已清除所有模型",
"Cleared channel affinity cache": "清除渠道亲和缓存",
"Cleared disk cache": "清除磁盘缓存",
"Cleared historical logs": "清理历史日志",
"Cleared log files": "清理日志文件",
"Click \"Create Plan\" to create your first subscription plan": "点击「新建套餐」创建您的第一个订阅套餐",
"Click \"Generate\" to create a token": "点击“生成”以创建令牌",
"Click any category to drill into its models, apps, and trends": "点击任意分类可下钻查看其模型、应用与趋势",
......@@ -808,6 +821,7 @@
"Complete Order": "补单",
"Complete these steps to finish the initial installation.": "完成这些步骤以完成初始安装。",
"Completed": "已完成",
"Completed top-up order for the user": "为用户完成补单",
"Completion": "补全",
"Completion price": "补全价格",
"Completion price ($/1M tokens)": "完成价格(美元/百万令牌)",
......@@ -887,6 +901,7 @@
"Confirm your identity before removing this Passkey from your account.": "在解绑当前账号的 Passkey 前请确认你的身份。",
"Confirm your identity with Two-factor Authentication before registering a Passkey.": "在注册 Passkey 前请使用两步验证确认你的身份。",
"Confirmed at {{time}} by user #{{userId}}": "用户 #{{userId}} 于 {{time}} 确认",
"Confirmed payment compliance": "确认支付合规",
"Conflict": "矛盾",
"Connect": "连接",
"Connect through OpenAI, Claude, Gemini, and other compatible API routes": "通过 OpenAI、Claude、Gemini 以及其他兼容 API 路由接入",
......@@ -929,6 +944,7 @@
"Convert string to uppercase": "把字符串转成大写",
"Copied": "已复制",
"Copied {{count}} key(s)": "已复制 {{count}} 个密钥",
"Copied channel (source ID: {{sourceId}}) to {{name}} (new ID: {{id}})": "复制渠道(源 ID: {{sourceId}})为 {{name}}(新 ID: {{id}})",
"Copied to clipboard": "已复制到剪贴板",
"Copied: {{model}}": "已复制: {{model}}",
"Copied!": "已复制!",
......@@ -1010,7 +1026,16 @@
"Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "创建您的第一个分组,以便在仪表板的任何位置重用模型、标签或端点选择。",
"Create, revoke, and audit API tokens.": "创建、撤销和审计 API 令牌。",
"Created": "创建时间",
"Created {{count}} redemption codes named {{name}} ({{quota}} each)": "创建 {{count}} 个兑换码 {{name}}(每个 {{quota}})",
"Created a custom OAuth provider": "创建了一个自定义 OAuth 提供方",
"Created a deployment": "创建了一个部署",
"Created a model": "创建了一个模型",
"Created a prefill group": "创建了一个预填组",
"Created a subscription plan": "创建了一个订阅计划",
"Created a vendor": "创建了一个供应商",
"Created At": "创建时间",
"Created channel {{name}} (type {{type}}, count {{count}})": "创建渠道 {{name}}(类型 {{type}},数量 {{count}})",
"Created user {{username}} (role {{role}})": "创建用户 {{username}}(角色 {{role}})",
"Creates a Pancake product in the saved store using this plan’s title and price. Requires Waffo Pancake to be fully configured in Payment settings first.": "使用此套餐的标题和价格,在已保存的店铺中创建 Pancake 产品。需要先在支付设置中完整配置 Waffo Pancake。",
"Creating...": "创建中...",
"Creation failed": "创建失败",
......@@ -1090,6 +1115,7 @@
"Day of month": "日期(日)",
"days": "天",
"Days to Retain": "保留天数",
"Decreased user quota by {{quota}}": "减少用户额度 {{quota}}",
"Deducted by subscription": "由订阅抵扣",
"DeepSeek": "DeepSeek",
"default": "默认",
......@@ -1144,7 +1170,18 @@
"Delete selected channels": "删除所选渠道",
"Delete selected models": "删除选定的模型",
"Deleted": "已注销",
"Deleted a custom OAuth provider": "删除了一个自定义 OAuth 提供方",
"Deleted a deployment": "删除了一个部署",
"Deleted a model": "删除了一个模型",
"Deleted a passkey": "解绑了一个 Passkey",
"Deleted a prefill group": "删除了一个预填组",
"Deleted a redemption code": "删除了一个兑换码",
"Deleted a vendor": "删除了一个供应商",
"Deleted all disabled channels ({{count}})": "删除全部禁用渠道({{count}})",
"Deleted channel {{name}} (ID: {{id}})": "删除渠道 {{name}}(ID: {{id}})",
"Deleted invalid redemption codes": "删除无效兑换码",
"Deleted successfully": "删除成功",
"Deleted user {{username}} (ID: {{id}})": "删除用户 {{username}}(ID: {{id}})",
"Deleting will permanently remove this subscription record (including benefit details). Continue?": "删除会彻底移除该订阅记录(含权益明细)。是否继续?",
"Deleting...": "删除中...",
"Demo site": "演示站点",
......@@ -1200,6 +1237,7 @@
"disabled": "已禁用",
"Disabled": "已禁用",
"Disabled all channels with tag: {{tag}}": "已禁用标签「{{tag}}」下的所有渠道",
"Disabled channels with tag {{tag}}": "禁用标签为 {{tag}} 的渠道",
"Disabled lanes are omitted on save.": "关闭的价格通道保存时会被省略。",
"Disabled Reason": "禁用原因",
"Disabled Time": "禁用时间",
......@@ -1346,6 +1384,7 @@
"Edit Uptime Kuma Group": "编辑 Uptime Kuma 分组",
"Edit Vendor": "编辑供应商",
"edit_this": "edit_this",
"Edited channels with tag {{tag}}": "编辑标签为 {{tag}} 的渠道",
"Editor mode": "编辑器模式",
"Education": "教育",
"Email": "邮箱",
......@@ -1404,6 +1443,7 @@
"Enable when proxying workers that fetch images over HTTP.": "当代理通过 HTTP 获取图像的 worker 时启用。",
"Enabled": "已启用",
"Enabled all channels with tag: {{tag}}": "已启用标签「{{tag}}」下的所有渠道",
"Enabled channels with tag {{tag}}": "启用标签为 {{tag}} 的渠道",
"Enabled Status": "启用状态",
"Enabling...": "正在启用...",
"Encourages introducing new topics": "鼓励引入新话题",
......@@ -1528,8 +1568,8 @@
"Exists": "存在",
"Expand": "展开",
"Expand All": "全部展开",
"Expected a JSON array.": "应为 JSON 数组。",
"Expected a JSON array of group identifiers": "应为分组标识符的 JSON 数组",
"Expected a JSON array.": "应为 JSON 数组。",
"Experiment with prompts and models in real time.": "实时实验提示词和模型。",
"Expiration Time": "过期时间",
"expired": "已过期",
......@@ -1786,6 +1826,7 @@
"Force format response to OpenAI standard (OpenAI channel only)": "强制将响应格式化为 OpenAI 标准(仅限 OpenAI 渠道)",
"Force JSON object or schema-conforming output": "强制输出 JSON 对象或符合 Schema 的结果",
"Force SMTP authentication using AUTH LOGIN method": "强制使用 AUTH LOGIN 方法进行 SMTP 认证",
"Force-disabled two-factor authentication for the user": "强制关闭了用户的两步验证",
"Forest Whisper": "森林低语",
"Forgot password": "忘记密码",
"Forgot password?": "忘记密码?",
......@@ -2024,6 +2065,7 @@
"Include Rule Name": "包含规则名",
"Includes request rules": "包含请求规则",
"Including failed requests, 0 = unlimited": "包括失败的请求,0 = 无限制",
"Increased user quota by {{quota}}": "增加用户额度 {{quota}}",
"Index": "索引",
"Initial quota given to new users": "授予新用户的初始配额",
"Initialization failed, please try again.": "初始化失败,请重试。",
......@@ -2226,8 +2268,12 @@
"Log IP address for usage and error logs": "记录用于使用和错误日志的 IP 地址",
"Log Maintenance": "日志维护",
"Log Type": "日志类型",
"Logged in successfully via {{method}}": "登录成功(通过 {{method}})",
"Logic": "逻辑",
"Login": "登录",
"Login failed": "登录失败",
"Login Info": "登录信息",
"Login Method": "登录方式",
"Logo": "徽标",
"Logo URL": "徽标 URL",
"Logs": "日志",
......@@ -2433,6 +2479,7 @@
"ms": "毫秒",
"Multi-key channel: Keys will be": "多密钥渠道:密钥将",
"Multi-Key Management": "多密钥管理",
"Multi-key management {{action}} on channel (ID: {{id}})": "对渠道(ID: {{id}})执行多密钥管理操作 {{action}}",
"Multi-Key Mode (multiple keys, one channel)": "多密钥模式(多个密钥,一个渠道)",
"Multi-Key Strategy": "多密钥策略",
"Multi-key: Polling rotation": "多密钥:轮询",
......@@ -2748,6 +2795,7 @@
"opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "在外部客户端中打开。从侧边栏或 API 密钥操作中触发,以启动配置的应用。",
"Operation": "操作",
"operation and charging behavior": "运营和收费行为",
"Operation Audit Info": "操作审计信息",
"Operation failed": "操作失败",
"Operation successful": "操作成功",
"Operation Type": "操作类型",
......@@ -2799,6 +2847,7 @@
"Override Rules": "覆盖规则",
"Override the endpoint used for testing. Leave empty to auto detect.": "覆盖用于测试的端点。留空以自动检测。",
"overrides for matching model prefix.": "为匹配模型前缀的覆盖价。",
"Overrode user quota from {{from}} to {{to}}": "覆盖用户额度,从 {{from}} 改为 {{to}}",
"Overview": "概览",
"Overwritten": "已覆盖",
"Page": "页面",
......@@ -2912,6 +2961,7 @@
"Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "此处展示的性能指标为预览模拟数据,待后端对接完成后将替换为真实可观测数据。",
"Performance Monitor": "性能监控",
"Performance Settings": "性能设置",
"Performed {{action}} on user {{username}} (ID: {{id}})": "对用户 {{username}}(ID: {{id}})执行 {{action}}",
"Period": "时间范围",
"Periodically check for upstream model changes": "定期检查上游模型是否有变更",
"Periodically send ping frames to keep streaming connections active.": "定期发送 ping 帧以保持流连接处于活动状态。",
......@@ -3248,6 +3298,7 @@
"Regex Replace": "正则替换",
"Register each URL into the matching Test Mode / Production Mode webhook slot in the Pancake dashboard. Separate endpoints prevent test traffic from accidentally crediting production accounts.": "请在 Pancake 控制台中将每个 URL 注册到对应的测试模式/生产模式 webhook 槽位。分离端点可以避免测试流量误入生产账户。",
"Register Passkey": "注册 Passkey",
"Registered a passkey": "注册了一个 Passkey",
"Registration Enabled": "注册已启用",
"Registry (optional)": "注册表 (可选)",
"Registry secret": "注册表密钥",
......@@ -3283,6 +3334,7 @@
"Remove tier": "移除档位",
"Removed": "已移除",
"Removed {{removed}} duplicate key(s). Before: {{before}}, After: {{after}}": "已移除 {{removed}} 个重复密钥。移除前:{{before}},移除后:{{after}}",
"Removed an OAuth binding for the user": "解除了用户的一个 OAuth 绑定",
"Removed Models ({{count}})": "已移除模型 ({{count}})",
"Removes Midjourney flags such as --fast, --relax, and --turbo from user prompts.": "从用户提示中移除 Midjourney 参数,如 --fast、--relax 和 --turbo。",
"Removing Passkey will require you to sign in with your password next time. You can re-register anytime.": "移除通行密钥后,您下次将需要使用密码登录。您可以随时重新注册。",
......@@ -3354,12 +3406,14 @@
"Reset Cycle": "重置周期",
"Reset email sent, please check your inbox": "重置邮件已发送,请检查您的收件箱",
"Reset failed": "重置失败",
"Reset model ratios": "重置模型倍率",
"Reset Passkey": "重置 Passkey",
"Reset password": "重置密码",
"Reset Period": "重置周期",
"Reset prices": "重置价格",
"Reset ratios": "重置比例",
"Reset Stats": "重置统计",
"Reset the user passkey": "重置了用户的通行密钥",
"Reset to default": "重置为默认",
"Reset to Default": "重置为默认",
"Reset to default configuration": "已重置为默认配置",
......@@ -3372,6 +3426,7 @@
"Responses API Version": "响应 API 版本",
"Restore defaults": "恢复默认",
"Restrict user model request frequency (may impact high concurrency performance)": "限制用户模型请求频率(可能会影响高并发性能)",
"Result": "结果",
"Retain last N days": "保留最近N天",
"Retain last N files": "保留最近 N 个文件",
"Retention days": "保留天数",
......@@ -3635,6 +3690,7 @@
"Set tag for selected channels": "为选定的渠道设置标签",
"Set the language used across the interface": "设置界面显示语言",
"Set the user's role (cannot be Root)": "设置用户角色(不能是 Root)",
"Setting Key": "配置项",
"Setting saved": "设置已保存",
"Setting up 2FA...": "正在设置 2FA...",
"Setting updated successfully": "设置更新成功",
......@@ -3827,6 +3883,7 @@
"Sync this model with official upstream": "将此模型与官方上游同步",
"Sync Upstream": "同步上游",
"Sync Upstream Models": "同步上游模型",
"Synced upstream models": "同步上游模型",
"Synchronize models and vendors from an upstream source": "从上游源同步模型和供应商",
"Syncing prices, please wait...": "正在同步价格,请稍候...",
"Syncing...": "同步中...",
......@@ -3872,6 +3929,7 @@
"Target group": "目标分组",
"Target Header": "目标请求头",
"Target Path (optional)": "目标路径(可选)",
"Target User": "目标用户",
"Task": "任务",
"Task ID": "任务 ID",
"Task ID:": "任务 ID:",
......@@ -4127,6 +4185,7 @@
"Trend": "趋势",
"Trending down": "下降趋势",
"Trending up": "上升趋势",
"Triggered garbage collection": "触发垃圾回收",
"Trim leading/trailing whitespace": "去掉字符串头尾空白",
"Trim Prefix": "裁剪前缀",
"Trim Space": "去掉空白",
......@@ -4217,8 +4276,18 @@
"Update your password for account:": "更新账户密码:",
"Update your password to keep your account secure": "更新您的密码以确保账户安全",
"Updated": "更新时间",
"Updated a custom OAuth provider": "更新了一个自定义 OAuth 提供方",
"Updated a deployment": "更新了一个部署",
"Updated a model": "更新了一个模型",
"Updated a prefill group": "更新了一个预填组",
"Updated a redemption code": "更新了一个兑换码",
"Updated a subscription plan": "更新了一个订阅计划",
"Updated a vendor": "更新了一个供应商",
"Updated channel {{name}} (ID: {{id}})": "更新渠道 {{name}}(ID: {{id}})",
"Updated daily": "每日更新",
"Updated successfully": "更新成功",
"Updated system setting {{key}}": "修改系统设置 {{key}}",
"Updated user {{username}} (ID: {{id}})": "更新用户 {{username}}(ID: {{id}})",
"Updating all channel balances. This may take a while. Please refresh to see results.": "正在更新所有渠道余额。这可能需要一段时间。请刷新以查看结果。",
"Upgrade Group": "升级分组",
"Upload": "上传",
......@@ -4290,6 +4359,7 @@
"Used:": "已使用:",
"User": "用户",
"User {{id}}": "用户 {{id}}",
"User Agent": "用户代理",
"User Agreement": "用户协议",
"User Analytics": "用户统计",
"User Consumption Ranking": "用户消耗排行",
......@@ -4384,6 +4454,7 @@
"View the complete prompt and its English translation": "查看完整提示词及其英文翻译",
"View the generated image": "查看生成的图片",
"View your topup transaction records and payment history": "查看您的充值交易记录和付款历史",
"Viewed channel key {{name}} (ID: {{id}})": "查看渠道密钥 {{name}}(ID: {{id}})",
"Violation Code": "违规代码",
"Violation deduction amount": "违规扣费金额",
"Violation Fee": "违规扣费",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment