Commit 90fa6fe6 by A_Words Committed by GitHub

fix(wallet): honor configured quota units for reward transfers (#5808)

* fix(wallet): honor configured quota units for reward transfers

* fix(i18n): localize quota preview descriptions

* fix(settings): normalize invalid quota input
parent a72e5082
...@@ -34,6 +34,7 @@ import { ...@@ -34,6 +34,7 @@ import {
} from '@/components/ui/form' } from '@/components/ui/form'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Switch } from '@/components/ui/switch' import { Switch } from '@/components/ui/switch'
import { formatQuota } from '@/lib/format'
import { FormDirtyIndicator } from '../components/form-dirty-indicator' import { FormDirtyIndicator } from '../components/form-dirty-indicator'
import { FormNavigationGuard } from '../components/form-navigation-guard' import { FormNavigationGuard } from '../components/form-navigation-guard'
...@@ -64,6 +65,11 @@ const quotaSchema = z.object({ ...@@ -64,6 +65,11 @@ const quotaSchema = z.object({
}) })
type QuotaFormValues = z.infer<typeof quotaSchema> type QuotaFormValues = z.infer<typeof quotaSchema>
type QuotaInputValue = number | ''
function formatQuotaInputValue(value: QuotaInputValue): string {
return formatQuota(value === '' ? 0 : value)
}
type QuotaSettingsSectionProps = { type QuotaSettingsSectionProps = {
defaultValues: QuotaFormValues defaultValues: QuotaFormValues
...@@ -77,11 +83,10 @@ export function QuotaSettingsSection({ ...@@ -77,11 +83,10 @@ export function QuotaSettingsSection({
const { t } = useTranslation() const { t } = useTranslation()
const updateOption = useUpdateOption() const updateOption = useUpdateOption()
const handleNumberChange = const handleNumberChange =
(onChange: (value: number | string) => void) => (onChange: (value: QuotaInputValue) => void) =>
(event: ChangeEvent<HTMLInputElement>) => { (event: ChangeEvent<HTMLInputElement>) => {
onChange( const value = event.currentTarget.valueAsNumber
event.target.value === '' ? '' : event.currentTarget.valueAsNumber onChange(Number.isNaN(value) ? '' : value)
)
} }
const { form, handleSubmit, isDirty, isSubmitting } = const { form, handleSubmit, isDirty, isSubmitting } =
...@@ -141,7 +146,12 @@ export function QuotaSettingsSection({ ...@@ -141,7 +146,12 @@ export function QuotaSettingsSection({
/> />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
{t('Initial quota given to new users')} {t(
'Initial quota given to new users ({{formattedQuota}})',
{
formattedQuota: formatQuotaInputValue(field.value),
}
)}
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
...@@ -189,7 +199,12 @@ export function QuotaSettingsSection({ ...@@ -189,7 +199,12 @@ export function QuotaSettingsSection({
/> />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
{t('Quota given to users who invite others')} {t(
'Quota given to users who invite others ({{formattedQuota}})',
{
formattedQuota: formatQuotaInputValue(field.value),
}
)}
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
...@@ -213,7 +228,9 @@ export function QuotaSettingsSection({ ...@@ -213,7 +228,9 @@ export function QuotaSettingsSection({
/> />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
{t('Quota given to invited users')} {t('Quota given to invited users ({{formattedQuota}})', {
formattedQuota: formatQuotaInputValue(field.value),
})}
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
......
...@@ -24,9 +24,15 @@ import { Dialog } from '@/components/dialog' ...@@ -24,9 +24,15 @@ import { Dialog } from '@/components/dialog'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { formatQuota } from '@/lib/format' import {
formatQuota,
import { QUOTA_PER_DOLLAR } from '../../constants' parseQuotaFromDollars,
quotaUnitsToDollars,
} from '@/lib/format'
import {
DEFAULT_CURRENCY_CONFIG,
useSystemConfigStore,
} from '@/stores/system-config-store'
interface TransferDialogProps { interface TransferDialogProps {
open: boolean open: boolean
...@@ -44,17 +50,34 @@ export function TransferDialog({ ...@@ -44,17 +50,34 @@ export function TransferDialog({
transferring, transferring,
}: TransferDialogProps) { }: TransferDialogProps) {
const { t } = useTranslation() const { t } = useTranslation()
const [amount, setAmount] = useState(QUOTA_PER_DOLLAR) const currencyConfig = useSystemConfigStore(
(state) => state.config.currency
)
const minimumQuota = Math.ceil(
currencyConfig.quotaPerUnit > 0
? currencyConfig.quotaPerUnit
: DEFAULT_CURRENCY_CONFIG.quotaPerUnit
)
const minimumAmount = quotaUnitsToDollars(minimumQuota)
const maximumAmount = quotaUnitsToDollars(availableQuota)
const [amount, setAmount] = useState(minimumAmount)
const transferQuota = parseQuotaFromDollars(amount)
const canTransfer =
Number.isFinite(amount) &&
transferQuota >= minimumQuota &&
transferQuota <= availableQuota
useEffect(() => { useEffect(() => {
if (open) { if (open) {
// eslint-disable-next-line react-hooks/set-state-in-effect // eslint-disable-next-line react-hooks/set-state-in-effect
setAmount(QUOTA_PER_DOLLAR) setAmount(minimumAmount)
} }
}, [open]) }, [minimumAmount, open])
const handleConfirm = async () => { const handleConfirm = async () => {
const success = await onConfirm(amount) if (!canTransfer) return
const success = await onConfirm(transferQuota)
if (success) { if (success) {
onOpenChange(false) onOpenChange(false)
} }
...@@ -80,7 +103,10 @@ export function TransferDialog({ ...@@ -80,7 +103,10 @@ export function TransferDialog({
> >
{t('Cancel')} {t('Cancel')}
</Button> </Button>
<Button onClick={handleConfirm} disabled={transferring}> <Button
onClick={handleConfirm}
disabled={transferring || !canTransfer}
>
{transferring && <Loader2 className='mr-2 h-4 w-4 animate-spin' />} {transferring && <Loader2 className='mr-2 h-4 w-4 animate-spin' />}
{t('Transfer')} {t('Transfer')}
</Button> </Button>
...@@ -109,13 +135,13 @@ export function TransferDialog({ ...@@ -109,13 +135,13 @@ export function TransferDialog({
type='number' type='number'
value={amount} value={amount}
onChange={(e) => setAmount(Number(e.target.value))} onChange={(e) => setAmount(Number(e.target.value))}
min={QUOTA_PER_DOLLAR} min={minimumAmount}
max={availableQuota} max={maximumAmount}
step={QUOTA_PER_DOLLAR} step={minimumAmount}
className='font-mono text-lg' className='font-mono text-lg'
/> />
<p className='text-muted-foreground text-xs'> <p className='text-muted-foreground text-xs'>
{t('Minimum:')} {formatQuota(QUOTA_PER_DOLLAR)} {t('Minimum:')} {formatQuota(minimumQuota)}
</p> </p>
</div> </div>
</div> </div>
......
...@@ -56,11 +56,6 @@ export const PAYMENT_ICON_COLORS = { ...@@ -56,11 +56,6 @@ export const PAYMENT_ICON_COLORS = {
} as const } as const
/** /**
* Quota conversion rate: 500,000 units = $1
*/
export const QUOTA_PER_DOLLAR = 500000
/**
* Default discount rate (no discount) * Default discount rate (no discount)
*/ */
export const DEFAULT_DISCOUNT_RATE = 1.0 export const DEFAULT_DISCOUNT_RATE = 1.0
......
...@@ -31,14 +31,14 @@ ...@@ -31,14 +31,14 @@
"extrasCount": 0, "extrasCount": 0,
"untranslatedCount": 0 "untranslatedCount": 0
}, },
"zh": { "zh-TW": {
"file": "zh.json", "file": "zh-TW.json",
"missingCount": 0, "missingCount": 0,
"extrasCount": 0, "extrasCount": 0,
"untranslatedCount": 0 "untranslatedCount": 0
}, },
"zh-TW": { "zh": {
"file": "zh-TW.json", "file": "zh.json",
"missingCount": 0, "missingCount": 0,
"extrasCount": 0, "extrasCount": 0,
"untranslatedCount": 0 "untranslatedCount": 0
......
...@@ -2269,6 +2269,7 @@ ...@@ -2269,6 +2269,7 @@
"Increased user quota by {{quota}}": "Increased user quota by {{quota}}", "Increased user quota by {{quota}}": "Increased user quota by {{quota}}",
"Index": "Index", "Index": "Index",
"Initial quota given to new users": "Initial quota given to new users", "Initial quota given to new users": "Initial quota given to new users",
"Initial quota given to new users ({{formattedQuota}})": "Initial quota given to new users ({{formattedQuota}})",
"Initialization failed, please try again.": "Initialization failed, please try again.", "Initialization failed, please try again.": "Initialization failed, please try again.",
"Initialize": "Initialize", "Initialize": "Initialize",
"Initialize system": "Initialize system", "Initialize system": "Initialize system",
...@@ -3509,7 +3510,9 @@ ...@@ -3509,7 +3510,9 @@
"Quota consumed before charging users": "Quota consumed before charging users", "Quota consumed before charging users": "Quota consumed before charging users",
"Quota Distribution": "Quota Distribution", "Quota Distribution": "Quota Distribution",
"Quota given to invited users": "Quota given to invited users", "Quota given to invited users": "Quota given to invited users",
"Quota given to invited users ({{formattedQuota}})": "Quota given to invited users ({{formattedQuota}})",
"Quota given to users who invite others": "Quota given to users who invite others", "Quota given to users who invite others": "Quota given to users who invite others",
"Quota given to users who invite others ({{formattedQuota}})": "Quota given to users who invite others ({{formattedQuota}})",
"Quota must be a positive number": "Quota must be a positive number", "Quota must be a positive number": "Quota must be a positive number",
"Quota must be zero or greater": "Quota must be zero or greater", "Quota must be zero or greater": "Quota must be zero or greater",
"Quota Per Unit": "Quota Per Unit", "Quota Per Unit": "Quota Per Unit",
......
...@@ -2269,6 +2269,7 @@ ...@@ -2269,6 +2269,7 @@
"Increased user quota by {{quota}}": "Quota de l'utilisateur augmenté de {{quota}}", "Increased user quota by {{quota}}": "Quota de l'utilisateur augmenté de {{quota}}",
"Index": "Index", "Index": "Index",
"Initial quota given to new users": "Quota initial donné aux nouveaux utilisateurs", "Initial quota given to new users": "Quota initial donné aux nouveaux utilisateurs",
"Initial quota given to new users ({{formattedQuota}})": "Quota initial donné aux nouveaux utilisateurs ({{formattedQuota}})",
"Initialization failed, please try again.": "L'initialisation a échoué, veuillez réessayer.", "Initialization failed, please try again.": "L'initialisation a échoué, veuillez réessayer.",
"Initialize": "Initialiser", "Initialize": "Initialiser",
"Initialize system": "Initialiser le système", "Initialize system": "Initialiser le système",
...@@ -3509,7 +3510,9 @@ ...@@ -3509,7 +3510,9 @@
"Quota consumed before charging users": "Quota consommé avant de facturer les utilisateurs", "Quota consumed before charging users": "Quota consommé avant de facturer les utilisateurs",
"Quota Distribution": "Distribution des quotas", "Quota Distribution": "Distribution des quotas",
"Quota given to invited users": "Quota attribué aux utilisateurs invités", "Quota given to invited users": "Quota attribué aux utilisateurs invités",
"Quota given to invited users ({{formattedQuota}})": "Quota attribué aux utilisateurs invités ({{formattedQuota}})",
"Quota given to users who invite others": "Quota attribué aux utilisateurs qui invitent d'autres personnes", "Quota given to users who invite others": "Quota attribué aux utilisateurs qui invitent d'autres personnes",
"Quota given to users who invite others ({{formattedQuota}})": "Quota attribué aux utilisateurs qui invitent d'autres personnes ({{formattedQuota}})",
"Quota must be a positive number": "Le quota doit être un nombre positif", "Quota must be a positive number": "Le quota doit être un nombre positif",
"Quota must be zero or greater": "Le quota ne peut pas être négatif", "Quota must be zero or greater": "Le quota ne peut pas être négatif",
"Quota Per Unit": "Quota par unité", "Quota Per Unit": "Quota par unité",
......
...@@ -2269,6 +2269,7 @@ ...@@ -2269,6 +2269,7 @@
"Increased user quota by {{quota}}": "ユーザーのクォータを {{quota}} 増やしました", "Increased user quota by {{quota}}": "ユーザーのクォータを {{quota}} 増やしました",
"Index": "インデックス", "Index": "インデックス",
"Initial quota given to new users": "新規ユーザーに付与される初期クォータ", "Initial quota given to new users": "新規ユーザーに付与される初期クォータ",
"Initial quota given to new users ({{formattedQuota}})": "新規ユーザーに付与される初期クォータ({{formattedQuota}})",
"Initialization failed, please try again.": "初期化に失敗しました。もう一度お試しください。", "Initialization failed, please try again.": "初期化に失敗しました。もう一度お試しください。",
"Initialize": "初期化", "Initialize": "初期化",
"Initialize system": "システム初期化", "Initialize system": "システム初期化",
...@@ -3509,7 +3510,9 @@ ...@@ -3509,7 +3510,9 @@
"Quota consumed before charging users": "ユーザーに請求する前に消費されるクォータ", "Quota consumed before charging users": "ユーザーに請求する前に消費されるクォータ",
"Quota Distribution": "クォータの分配", "Quota Distribution": "クォータの分配",
"Quota given to invited users": "招待されたユーザーに付与されるクォータ", "Quota given to invited users": "招待されたユーザーに付与されるクォータ",
"Quota given to invited users ({{formattedQuota}})": "招待されたユーザーに付与されるクォータ({{formattedQuota}})",
"Quota given to users who invite others": "他のユーザーを招待したユーザーに付与されるクォータ", "Quota given to users who invite others": "他のユーザーを招待したユーザーに付与されるクォータ",
"Quota given to users who invite others ({{formattedQuota}})": "他のユーザーを招待したユーザーに付与されるクォータ({{formattedQuota}})",
"Quota must be a positive number": "クォータは正の数である必要があります", "Quota must be a positive number": "クォータは正の数である必要があります",
"Quota must be zero or greater": "クォータは負の値にできません", "Quota must be zero or greater": "クォータは負の値にできません",
"Quota Per Unit": "ユニットあたりのクォータ", "Quota Per Unit": "ユニットあたりのクォータ",
......
...@@ -2269,6 +2269,7 @@ ...@@ -2269,6 +2269,7 @@
"Increased user quota by {{quota}}": "Квота пользователя увеличена на {{quota}}", "Increased user quota by {{quota}}": "Квота пользователя увеличена на {{quota}}",
"Index": "Индекс", "Index": "Индекс",
"Initial quota given to new users": "Начальная квота, предоставляемая новым пользователям", "Initial quota given to new users": "Начальная квота, предоставляемая новым пользователям",
"Initial quota given to new users ({{formattedQuota}})": "Начальная квота, предоставляемая новым пользователям ({{formattedQuota}})",
"Initialization failed, please try again.": "Инициализация не удалась, попробуйте ещё раз.", "Initialization failed, please try again.": "Инициализация не удалась, попробуйте ещё раз.",
"Initialize": "Инициализировать", "Initialize": "Инициализировать",
"Initialize system": "Инициализация системы", "Initialize system": "Инициализация системы",
...@@ -3509,7 +3510,9 @@ ...@@ -3509,7 +3510,9 @@
"Quota consumed before charging users": "Квота, потребляемая до взимания платы с пользователей", "Quota consumed before charging users": "Квота, потребляемая до взимания платы с пользователей",
"Quota Distribution": "Распределение квоты", "Quota Distribution": "Распределение квоты",
"Quota given to invited users": "Квота, предоставляемая приглашенным пользователям", "Quota given to invited users": "Квота, предоставляемая приглашенным пользователям",
"Quota given to invited users ({{formattedQuota}})": "Квота, предоставляемая приглашенным пользователям ({{formattedQuota}})",
"Quota given to users who invite others": "Квота, предоставляемая пользователям, которые приглашают других", "Quota given to users who invite others": "Квота, предоставляемая пользователям, которые приглашают других",
"Quota given to users who invite others ({{formattedQuota}})": "Квота, предоставляемая пользователям, которые приглашают других ({{formattedQuota}})",
"Quota must be a positive number": "Квота должна быть положительным числом", "Quota must be a positive number": "Квота должна быть положительным числом",
"Quota must be zero or greater": "Квота не может быть отрицательной", "Quota must be zero or greater": "Квота не может быть отрицательной",
"Quota Per Unit": "Квота на единицу", "Quota Per Unit": "Квота на единицу",
......
...@@ -2269,6 +2269,7 @@ ...@@ -2269,6 +2269,7 @@
"Increased user quota by {{quota}}": "Đã tăng hạn mức người dùng thêm {{quota}}", "Increased user quota by {{quota}}": "Đã tăng hạn mức người dùng thêm {{quota}}",
"Index": "Chỉ mục", "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", "Initial quota given to new users": "Hạn mức ban đầu cấp cho người dùng mới",
"Initial quota given to new users ({{formattedQuota}})": "Hạn mức ban đầu cấp cho người dùng mới ({{formattedQuota}})",
"Initialization failed, please try again.": "Khởi tạo thất bại, vui lòng thử lại.", "Initialization failed, please try again.": "Khởi tạo thất bại, vui lòng thử lại.",
"Initialize": "Khởi tạo", "Initialize": "Khởi tạo",
"Initialize system": "Khởi tạo hệ thống", "Initialize system": "Khởi tạo hệ thống",
...@@ -3509,7 +3510,9 @@ ...@@ -3509,7 +3510,9 @@
"Quota consumed before charging users": "Hạn mức tiêu thụ trước khi tính phí người dùng", "Quota consumed before charging users": "Hạn mức tiêu thụ trước khi tính phí người dùng",
"Quota Distribution": "Phân bổ hạn ngạch", "Quota Distribution": "Phân bổ hạn ngạch",
"Quota given to invited users": "Hạn mức được cấp cho người dùng được mời", "Quota given to invited users": "Hạn mức được cấp cho người dùng được mời",
"Quota given to invited users ({{formattedQuota}})": "Hạn mức cấp cho người dùng được mời ({{formattedQuota}})",
"Quota given to users who invite others": "Limit for users inviting others", "Quota given to users who invite others": "Limit for users inviting others",
"Quota given to users who invite others ({{formattedQuota}})": "Hạn mức cấp cho người dùng mời người khác ({{formattedQuota}})",
"Quota must be a positive number": "Hạn mức phải là một số dương", "Quota must be a positive number": "Hạn mức phải là một số dương",
"Quota must be zero or greater": "Hạn mức không được âm", "Quota must be zero or greater": "Hạn mức không được âm",
"Quota Per Unit": "Định mức mỗi đơn vị", "Quota Per Unit": "Định mức mỗi đơn vị",
......
...@@ -238,6 +238,7 @@ ...@@ -238,6 +238,7 @@
"Administer user accounts and roles.": "管理用戶用戶和角色。", "Administer user accounts and roles.": "管理用戶用戶和角色。",
"Administrator account": "管理員用戶", "Administrator account": "管理員用戶",
"Administrator username": "管理員用戶名", "Administrator username": "管理員用戶名",
"Advance next reset time": "推進下次重置時間",
"Advanced": "進階", "Advanced": "進階",
"Advanced Configuration": "進階設定", "Advanced Configuration": "進階設定",
"Advanced Custom": "進階自訂", "Advanced Custom": "進階自訂",
...@@ -807,6 +808,7 @@ ...@@ -807,6 +808,7 @@
"Choose the default charts, range, and time granularity for model analytics.": "選擇模型呼叫分析的預設圖表、範圍和時間粒度。", "Choose the default charts, range, and time granularity for model analytics.": "選擇模型呼叫分析的預設圖表、範圍和時間粒度。",
"Choose where to fetch upstream metadata.": "選擇從何處獲取上游元數據。", "Choose where to fetch upstream metadata.": "選擇從何處獲取上游元數據。",
"Choose which charts are selected by default when opening model analytics.": "選擇打開模型呼叫分析時預設選中的圖表。", "Choose which charts are selected by default when opening model analytics.": "選擇打開模型呼叫分析時預設選中的圖表。",
"Clamped to": "限制為",
"Classic (Legacy Frontend)": "經典前端", "Classic (Legacy Frontend)": "經典前端",
"Claude": "Claude", "Claude": "Claude",
"Claude CLI Header Passthrough": "Claude CLI 請求頭透傳", "Claude CLI Header Passthrough": "Claude CLI 請求頭透傳",
...@@ -1258,10 +1260,12 @@ ...@@ -1258,10 +1260,12 @@
"Delete": "刪除", "Delete": "刪除",
"Delete (": "刪除 (", "Delete (": "刪除 (",
"Delete {{count}} API key(s)?": "刪除 {{count}} 個 API 金鑰?", "Delete {{count}} API key(s)?": "刪除 {{count}} 個 API 金鑰?",
"Delete {{count}} stale instance records? Online instances will not be deleted.": "刪除 {{count}} 筆失聯實例記錄?線上實例不會被刪除。",
"Delete a runtime request header": "刪除運行期請求頭", "Delete a runtime request header": "刪除運行期請求頭",
"Delete Account": "刪除用戶", "Delete Account": "刪除用戶",
"Delete All Disabled": "刪除所有已停用", "Delete All Disabled": "刪除所有已停用",
"Delete All Disabled Channels?": "刪除所有已停用的渠道?", "Delete All Disabled Channels?": "刪除所有已停用的渠道?",
"Delete all stale": "刪除所有失聯",
"Delete Auto-Disabled": "刪除自動停用", "Delete Auto-Disabled": "刪除自動停用",
"Delete Channel": "刪除渠道", "Delete Channel": "刪除渠道",
"Delete Channels?": "刪除渠道?", "Delete Channels?": "刪除渠道?",
...@@ -1287,10 +1291,14 @@ ...@@ -1287,10 +1291,14 @@
"Delete selected API keys": "刪除選定的 API 金鑰", "Delete selected API keys": "刪除選定的 API 金鑰",
"Delete selected channels": "刪除所選渠道", "Delete selected channels": "刪除所選渠道",
"Delete selected models": "刪除選定的模型", "Delete selected models": "刪除選定的模型",
"Delete stale instance": "刪除失聯實例",
"Delete stale instance \"{{name}}\"? If it has reported again, it will not be deleted.": "刪除失聯實例「{{name}}」?如果它已重新上報,將不會被刪除。",
"Delete stale instances": "刪除失聯實例",
"Deleted": "已註銷", "Deleted": "已註銷",
"Deleted \"{{name}}\"": "已刪除「{{name}}」", "Deleted \"{{name}}\"": "已刪除「{{name}}」",
"Deleted ({{id}})": "已刪除({{id}})", "Deleted ({{id}})": "已刪除({{id}})",
"Deleted {{count}} failed models": "已刪除 {{count}} 個失敗模型", "Deleted {{count}} failed models": "已刪除 {{count}} 個失敗模型",
"Deleted {{count}} stale instances": "已刪除 {{count}} 個失聯實例",
"Deleted a custom OAuth provider": "刪除了一個自訂 OAuth 提供方", "Deleted a custom OAuth provider": "刪除了一個自訂 OAuth 提供方",
"Deleted a deployment": "刪除了一個部署", "Deleted a deployment": "刪除了一個部署",
"Deleted a model": "刪除了一個模型", "Deleted a model": "刪除了一個模型",
...@@ -1301,6 +1309,7 @@ ...@@ -1301,6 +1309,7 @@
"Deleted all disabled channels ({{count}})": "刪除全部停用渠道({{count}})", "Deleted all disabled channels ({{count}})": "刪除全部停用渠道({{count}})",
"Deleted channel {{name}} (ID: {{id}})": "刪除渠道 {{name}}(ID: {{id}})", "Deleted channel {{name}} (ID: {{id}})": "刪除渠道 {{name}}(ID: {{id}})",
"Deleted invalid redemption codes": "刪除無效兌換碼", "Deleted invalid redemption codes": "刪除無效兌換碼",
"Deleted stale instance": "已刪除失聯實例",
"Deleted successfully": "刪除成功", "Deleted successfully": "刪除成功",
"Deleted user {{username}} (ID: {{id}})": "刪除用戶 {{username}}(ID: {{id}})", "Deleted user {{username}} (ID: {{id}})": "刪除用戶 {{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?": "刪除會徹底移除該訂閱記錄(含權益明細)。是否繼續?",
...@@ -1987,7 +1996,7 @@ ...@@ -1987,7 +1996,7 @@
"footer.columns.related.links.oneApi": "One API", "footer.columns.related.links.oneApi": "One API",
"footer.columns.related.title": "相關項目", "footer.columns.related.title": "相關項目",
"footer.defaultCopyright": "版權所有。", "footer.defaultCopyright": "版權所有。",
"footer.newapi.projectAttributionSuffix": "版權所有,由項目貢獻者設計與開發。", "footer.new\u0061pi.projectAttributionSuffix": "版權所有,由項目貢獻者設計與開發。",
"For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "對於 2025 年 5 月 10 日之後新增的渠道,在部署時無需從模型名稱中移除 \".\"", "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "對於 2025 年 5 月 10 日之後新增的渠道,在部署時無需從模型名稱中移除 \".\"",
"For private deployments, format: https://fastgpt.run/api/openapi": "對於私有部署,格式為:https://fastgpt.run/api/openapi", "For private deployments, format: https://fastgpt.run/api/openapi": "對於私有部署,格式為:https://fastgpt.run/api/openapi",
"Force a syntactically valid JSON response": "強制返回語法合法的 JSON", "Force a syntactically valid JSON response": "強制返回語法合法的 JSON",
...@@ -2260,6 +2269,7 @@ ...@@ -2260,6 +2269,7 @@
"Increased user quota by {{quota}}": "增加用戶額度 {{quota}}", "Increased user quota by {{quota}}": "增加用戶額度 {{quota}}",
"Index": "索引", "Index": "索引",
"Initial quota given to new users": "授予新用戶的初始配額", "Initial quota given to new users": "授予新用戶的初始配額",
"Initial quota given to new users ({{formattedQuota}})": "授予新用戶的初始配額({{formattedQuota}})",
"Initialization failed, please try again.": "初始化失敗,請重試。", "Initialization failed, please try again.": "初始化失敗,請重試。",
"Initialize": "初始化", "Initialize": "初始化",
"Initialize system": "初始化系統", "Initialize system": "初始化系統",
...@@ -2284,6 +2294,7 @@ ...@@ -2284,6 +2294,7 @@
"Internal Notes": "內部備註", "Internal Notes": "內部備註",
"Internal notes (not shown to users)": "內部備註(不顯示給用戶)", "Internal notes (not shown to users)": "內部備註(不顯示給用戶)",
"Internal Server Error!": "內部伺服器錯誤!", "Internal Server Error!": "內部伺服器錯誤!",
"Invalid (NaN)": "無效 (NaN)",
"Invalid chat link. Please contact the administrator.": "無效的聊天連結。請聯絡管理員。", "Invalid chat link. Please contact the administrator.": "無效的聊天連結。請聯絡管理員。",
"Invalid chat link. Please contact your administrator.": "無效的聊天連結。請聯絡您的管理員。", "Invalid chat link. Please contact your administrator.": "無效的聊天連結。請聯絡您的管理員。",
"Invalid code": "無效代碼", "Invalid code": "無效代碼",
...@@ -2364,6 +2375,7 @@ ...@@ -2364,6 +2375,7 @@
"Key Summary": "Key 摘要", "Key Summary": "Key 摘要",
"Key Update Mode": "金鑰更新模式", "Key Update Mode": "金鑰更新模式",
"Keys, OAuth credentials, and multi-key update behavior.": "管理金鑰、OAuth 憑證和多金鑰更新行為。", "Keys, OAuth credentials, and multi-key update behavior.": "管理金鑰、OAuth 憑證和多金鑰更新行為。",
"Kind": "類型",
"Kling": "Kling", "Kling": "Kling",
"Knowledge Base ID *": "知識庫 ID *", "Knowledge Base ID *": "知識庫 ID *",
"Knowledge cutoff": "知識截止", "Knowledge cutoff": "知識截止",
...@@ -3089,6 +3101,7 @@ ...@@ -3089,6 +3101,7 @@
"Order Payment Method": "訂單支付方式", "Order Payment Method": "訂單支付方式",
"org-...": "org-...", "org-...": "org-...",
"Original Model": "原始模型", "Original Model": "原始模型",
"Original value": "原始值",
"Other": "其他", "Other": "其他",
"Other channels": "其他渠道", "Other channels": "其他渠道",
"Other groups": "其他分組", "Other groups": "其他分組",
...@@ -3106,6 +3119,7 @@ ...@@ -3106,6 +3119,7 @@
"Output Tokens": "輸出 Token", "Output Tokens": "輸出 Token",
"Overage limited": "超額受限", "Overage limited": "超額受限",
"overall": "總體", "overall": "總體",
"Overflow": "上溢",
"Overflow items": "超出項", "Overflow items": "超出項",
"Overnight range": "跨日範圍", "Overnight range": "跨日範圍",
"override": "覆蓋", "override": "覆蓋",
...@@ -3492,15 +3506,19 @@ ...@@ -3492,15 +3506,19 @@
"Quota": "額度", "Quota": "額度",
"Quota ({{currency}})": "額度 ({{currency}})", "Quota ({{currency}})": "額度 ({{currency}})",
"Quota adjusted successfully": "調整額度成功", "Quota adjusted successfully": "調整額度成功",
"Quota clamped": "額度已限制",
"Quota consumed before charging users": "向用戶收費前消耗的配額", "Quota consumed before charging users": "向用戶收費前消耗的配額",
"Quota Distribution": "消耗分佈", "Quota Distribution": "消耗分佈",
"Quota given to invited users": "授予被邀請用戶的配額", "Quota given to invited users": "授予被邀請用戶的配額",
"Quota given to invited users ({{formattedQuota}})": "授予被邀請用戶的配額({{formattedQuota}})",
"Quota given to users who invite others": "授予邀請其他用戶的配額", "Quota given to users who invite others": "授予邀請其他用戶的配額",
"Quota given to users who invite others ({{formattedQuota}})": "授予邀請其他用戶的配額({{formattedQuota}})",
"Quota must be a positive number": "配額必須是正數", "Quota must be a positive number": "配額必須是正數",
"Quota must be zero or greater": "額度不能為負數", "Quota must be zero or greater": "額度不能為負數",
"Quota Per Unit": "每單位配額", "Quota Per Unit": "每單位配額",
"Quota reminder (tokens)": "配額提醒(token)", "Quota reminder (tokens)": "配額提醒(token)",
"Quota Reset": "額度重置", "Quota Reset": "額度重置",
"Quota saturation protection triggered": "已觸發額度飽和保護",
"Quota Settings": "額度設定", "Quota Settings": "額度設定",
"Quota Types": "配額類型", "Quota Types": "配額類型",
"Quota Warning Threshold": "配額警告閾值", "Quota Warning Threshold": "配額警告閾值",
...@@ -3708,8 +3726,11 @@ ...@@ -3708,8 +3726,11 @@
"Resend ({{seconds}}s)": "重新發送 ({{seconds}}s)", "Resend ({{seconds}}s)": "重新發送 ({{seconds}}s)",
"Reserved for viewing complete channel keys after secure verification.": "預留用於在安全驗證後查看完整渠道金鑰。", "Reserved for viewing complete channel keys after secure verification.": "預留用於在安全驗證後查看完整渠道金鑰。",
"Reset": "重置", "Reset": "重置",
"Reset {{count}} active subscriptions": "已重置 {{count}} 個有效訂閱",
"Reset 2FA": "重置 2FA", "Reset 2FA": "重置 2FA",
"Reset 2FA for {{username}}? The user must set up 2FA again to continue using it.": "要重置 {{username}} 的 2FA 嗎?該用戶必須重新設定 2FA 後才能繼續使用。", "Reset 2FA for {{username}}? The user must set up 2FA again to continue using it.": "要重置 {{username}} 的 2FA 嗎?該用戶必須重新設定 2FA 後才能繼續使用。",
"Reset active {{plan}} subscriptions for this user?": "要重置此用戶的有效 {{plan}} 訂閱嗎?",
"Reset all active subscriptions under {{plan}}?": "要重置 {{plan}} 下的所有有效訂閱嗎?",
"Reset all model prices?": "重置所有模型價格嗎?", "Reset all model prices?": "重置所有模型價格嗎?",
"Reset all model ratios?": "重置所有模型比例嗎?", "Reset all model ratios?": "重置所有模型比例嗎?",
"Reset all settings to default values": "將所有設定重置為預設值", "Reset all settings to default values": "將所有設定重置為預設值",
...@@ -3729,8 +3750,10 @@ ...@@ -3729,8 +3750,10 @@
"Reset password": "重設密碼", "Reset password": "重設密碼",
"Reset Period": "重置週期", "Reset Period": "重置週期",
"Reset prices": "重置價格", "Reset prices": "重置價格",
"Reset quota": "重置額度",
"Reset ratios": "重置比例", "Reset ratios": "重置比例",
"Reset Stats": "重置統計", "Reset Stats": "重置統計",
"Reset subscription quota": "重置訂閱額度",
"Reset the user passkey": "重設了用戶的通行金鑰", "Reset the user passkey": "重設了用戶的通行金鑰",
"Reset to default": "重置為預設", "Reset to default": "重置為預設",
"Reset to Default": "重置為預設", "Reset to Default": "重置為預設",
...@@ -3922,6 +3945,7 @@ ...@@ -3922,6 +3945,7 @@
"Select a timestamp before clearing logs.": "清除日誌前請選擇一個時間戳。", "Select a timestamp before clearing logs.": "清除日誌前請選擇一個時間戳。",
"Select a usage mode to continue": "選擇使用模式以繼續", "Select a usage mode to continue": "選擇使用模式以繼續",
"Select a verification method first": "請先選擇驗證方式", "Select a verification method first": "請先選擇驗證方式",
"Select active subscription plan": "選擇有效訂閱套餐",
"Select all": "全選", "Select all": "全選",
"Select all (filtered)": "全選(篩選結果)", "Select all (filtered)": "全選(篩選結果)",
"Select all models": "選擇所有模型", "Select all models": "選擇所有模型",
...@@ -4411,6 +4435,7 @@ ...@@ -4411,6 +4435,7 @@
"This FAQ entry will be removed from the list.": "此 FAQ 條目將從列表中移除。", "This FAQ entry will be removed from the list.": "此 FAQ 條目將從列表中移除。",
"This feature is experimental. Configuration format and behavior may change.": "此功能為實驗性功能。設定格式和行為可能會發生變化。", "This feature is experimental. Configuration format and behavior may change.": "此功能為實驗性功能。設定格式和行為可能會發生變化。",
"This feature requires server-side WeChat configuration": "此功能需要伺服器端微信設定", "This feature requires server-side WeChat configuration": "此功能需要伺服器端微信設定",
"This historical record predates audit-info tracking and cannot be backfilled. The current instance already records server IP, callback IP, payment method, and system version for new top-ups going forward.": "該條歷史記錄缺少審計欄位。目前版本已支援記錄伺服器 IP、Callback IP、支付方式與系統版本等審計資訊;這些欄位僅會寫入後續新產生的記錄,歷史記錄無法自動補齊。",
"This identifier is sent to the payment backend when creating an order. Use alipay for Alipay, wxpay for WeChat Pay, stripe for Stripe. Custom values must be supported by your payment provider.": "建立訂單時會把這個標識提交給支付後端。支付寶填 alipay,微信填 wxpay,Stripe 填 stripe。自訂值必須是支付服務支援的標識。", "This identifier is sent to the payment backend when creating an order. Use alipay for Alipay, wxpay for WeChat Pay, stripe for Stripe. Custom values must be supported by your payment provider.": "建立訂單時會把這個標識提交給支付後端。支付寶填 alipay,微信填 wxpay,Stripe 填 stripe。自訂值必須是支付服務支援的標識。",
"This instance is using an automatic hostname. Set NODE_NAME to a stable unique value for multi-instance management.": "該實例正在使用自動主機名稱。請設定穩定且唯一的 NODE_NAME,以便進行多實例管理。", "This instance is using an automatic hostname. Set NODE_NAME to a stable unique value for multi-instance management.": "該實例正在使用自動主機名稱。請設定穩定且唯一的 NODE_NAME,以便進行多實例管理。",
"This may cause cache failures.": "這可能導致緩存故障。", "This may cause cache failures.": "這可能導致緩存故障。",
...@@ -4423,7 +4448,6 @@ ...@@ -4423,7 +4448,6 @@
"This page has not been created yet.": "此頁面尚未建立。", "This page has not been created yet.": "此頁面尚未建立。",
"This plan does not allow balance redemption": "該套餐不允許使用餘額兌換", "This plan does not allow balance redemption": "該套餐不允許使用餘額兌換",
"This project must be used in compliance with the": "此項目的使用必須遵守", "This project must be used in compliance with the": "此項目的使用必須遵守",
"This historical record predates audit-info tracking and cannot be backfilled. The current instance already records server IP, callback IP, payment method, and system version for new top-ups going forward.": "該條歷史記錄缺少審計欄位。目前版本已支援記錄伺服器 IP、Callback IP、支付方式與系統版本等審計資訊;這些欄位僅會寫入後續新產生的記錄,歷史記錄無法自動補齊。",
"This removes {{count}} failed models from this channel. This action cannot be undone.": "此操作將從該渠道移除 {{count}} 個測試失敗的模型,且無法撤銷。", "This removes {{count}} failed models from this channel. This action cannot be undone.": "此操作將從該渠道移除 {{count}} 個測試失敗的模型,且無法撤銷。",
"This site currently has {{count}} models enabled": "本站目前已啟用模型,總計 {{count}} 個", "This site currently has {{count}} models enabled": "本站目前已啟用模型,總計 {{count}} 個",
"This tier catches any request that did not match earlier tiers.": "此階梯會兜底處理未匹配前面階梯的請求。", "This tier catches any request that did not match earlier tiers.": "此階梯會兜底處理未匹配前面階梯的請求。",
...@@ -4639,6 +4663,7 @@ ...@@ -4639,6 +4663,7 @@
"Unbind": "解綁", "Unbind": "解綁",
"Unbind failed": "解綁失敗", "Unbind failed": "解綁失敗",
"Unbound {{provider}}": "已解綁 {{provider}}", "Unbound {{provider}}": "已解綁 {{provider}}",
"Underflow": "下溢",
"Underground": "暗夜", "Underground": "暗夜",
"Understand how user groups, token groups, ratios, and special rules work together.": "了解用戶分組、令牌分組、倍率和特殊規則如何共同生效。", "Understand how user groups, token groups, ratios, and special rules work together.": "了解用戶分組、令牌分組、倍率和特殊規則如何共同生效。",
"Understand image inputs alongside text": "在文字之外理解圖像輸入", "Understand image inputs alongside text": "在文字之外理解圖像輸入",
...@@ -5059,4 +5084,4 @@ ...@@ -5059,4 +5084,4 @@
"Zhipu V4": "智譜 V4", "Zhipu V4": "智譜 V4",
"Zoom": "縮放" "Zoom": "縮放"
} }
} }
\ No newline at end of file
...@@ -2269,6 +2269,7 @@ ...@@ -2269,6 +2269,7 @@
"Increased user quota by {{quota}}": "增加用户额度 {{quota}}", "Increased user quota by {{quota}}": "增加用户额度 {{quota}}",
"Index": "索引", "Index": "索引",
"Initial quota given to new users": "授予新用户的初始配额", "Initial quota given to new users": "授予新用户的初始配额",
"Initial quota given to new users ({{formattedQuota}})": "授予新用户的初始配额({{formattedQuota}})",
"Initialization failed, please try again.": "初始化失败,请重试。", "Initialization failed, please try again.": "初始化失败,请重试。",
"Initialize": "初始化", "Initialize": "初始化",
"Initialize system": "初始化系统", "Initialize system": "初始化系统",
...@@ -3509,7 +3510,9 @@ ...@@ -3509,7 +3510,9 @@
"Quota consumed before charging users": "向用户收费前消耗的配额", "Quota consumed before charging users": "向用户收费前消耗的配额",
"Quota Distribution": "消耗分布", "Quota Distribution": "消耗分布",
"Quota given to invited users": "授予被邀请用户的配额", "Quota given to invited users": "授予被邀请用户的配额",
"Quota given to invited users ({{formattedQuota}})": "授予被邀请用户的配额({{formattedQuota}})",
"Quota given to users who invite others": "授予邀请其他用户的配额", "Quota given to users who invite others": "授予邀请其他用户的配额",
"Quota given to users who invite others ({{formattedQuota}})": "授予邀请其他用户的配额({{formattedQuota}})",
"Quota must be a positive number": "配额必须是正数", "Quota must be a positive number": "配额必须是正数",
"Quota must be zero or greater": "额度不能为负数", "Quota must be zero or greater": "额度不能为负数",
"Quota Per Unit": "每单位配额", "Quota Per Unit": "每单位配额",
......
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