fix(web): require confirmation before rotating access token (#6749)

This commit is contained in:
Seefs
2026-08-10 13:12:59 +08:00
committed by GitHub
parent 4cf9107f04
commit 9c97e78ace
9 changed files with 209 additions and 68 deletions
@@ -16,13 +16,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { RefreshCw, Loader2 } from 'lucide-react'
import { useEffect } from 'react'
import { KeyRound, Loader2, RefreshCw } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { CopyButton } from '@/components/copy-button'
import { Dialog } from '@/components/dialog'
import { Button } from '@/components/ui/button'
import {
Empty,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from '@/components/ui/empty'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
@@ -42,77 +50,149 @@ export function AccessTokenDialog({
onOpenChange,
}: AccessTokenDialogProps) {
const { t } = useTranslation()
const { token, generating, generate } = useAccessToken()
const { token, generating, generate, clearToken } = useAccessToken()
const [confirmOpen, setConfirmOpen] = useState(false)
// Auto-generate token when dialog opens if no token exists
useEffect(() => {
if (open && !token) {
generate()
const handleOpenChange = (nextOpen: boolean) => {
if (generating) return
if (!nextOpen) {
setConfirmOpen(false)
clearToken()
}
}, [open, token, generate])
onOpenChange(nextOpen)
}
const handleGenerate = async () => {
if (await generate()) {
setConfirmOpen(false)
}
}
return (
<Dialog
open={open}
onOpenChange={onOpenChange}
title={t('Access Token')}
description={t(
"Your system access token for API authentication. Keep it secure and don't share it with others."
)}
contentClassName='sm:max-w-md'
contentHeight='auto'
bodyClassName='space-y-4'
footer={
<>
<Button
type='button'
variant='outline'
onClick={() => onOpenChange(false)}
>
{t('Close')}
</Button>
<Button
type='button'
onClick={generate}
disabled={generating}
className='gap-2'
>
{generating ? (
<Loader2 className='h-4 w-4 animate-spin' />
) : (
<RefreshCw className='h-4 w-4' />
)}
{generating ? t('Generating...') : t('Regenerate')}
</Button>
</>
}
>
<div className='my-6 space-y-4'>
<div className='space-y-2'>
<Label htmlFor='token'>{t('Token')}</Label>
<div className='flex gap-2'>
<Input
id='token'
type='text'
value={token}
readOnly
className='font-mono text-xs'
placeholder={t('Click "Generate" to create a token')}
/>
<CopyButton
value={token}
<>
<Dialog
open={open}
onOpenChange={handleOpenChange}
title={t('Access Token')}
description={t(
"Your system access token for API authentication. Keep it secure and don't share it with others."
)}
contentClassName='sm:max-w-md'
contentHeight='auto'
bodyClassName='space-y-4'
footer={
<>
<Button
type='button'
variant='outline'
className='size-9'
iconClassName='size-4'
tooltip={t('Copy token')}
aria-label={t('Copy token')}
/>
</div>
<p className='text-muted-foreground text-xs'>
{t('Use this token for API authentication')}
</p>
onClick={() => handleOpenChange(false)}
disabled={generating}
>
{t('Close')}
</Button>
<Button
type='button'
onClick={() => setConfirmOpen(true)}
disabled={generating}
className='gap-2'
>
{generating ? (
<Loader2 className='h-4 w-4 animate-spin' aria-hidden='true' />
) : (
<RefreshCw className='h-4 w-4' aria-hidden='true' />
)}
{generating ? t('Generating...') : t('Regenerate')}
</Button>
</>
}
>
<div className='my-6'>
{token ? (
<div className='space-y-2'>
<Label htmlFor='token'>{t('Token')}</Label>
<div className='flex gap-2'>
<Input
id='token'
type='text'
value={token}
readOnly
className='font-mono text-xs'
/>
<CopyButton
value={token}
variant='outline'
className='size-9'
iconClassName='size-4'
tooltip={t('Copy token')}
aria-label={t('Copy token')}
/>
</div>
<p className='text-muted-foreground text-xs'>
{t(
"Save this token now. You won't be able to view it again after closing this dialog."
)}
</p>
</div>
) : (
<Empty className='border py-8'>
<EmptyHeader>
<EmptyMedia variant='icon'>
<KeyRound aria-hidden='true' />
</EmptyMedia>
<EmptyTitle>
{t('Access tokens are shown only once')}
</EmptyTitle>
<EmptyDescription>
{t(
'For security, existing access tokens cannot be displayed. Regenerate only when you need a new token.'
)}
</EmptyDescription>
<EmptyDescription>
{t(
'Regenerating immediately invalidates any existing token.'
)}
</EmptyDescription>
</EmptyHeader>
</Empty>
)}
</div>
</div>
</Dialog>
</Dialog>
<ConfirmDialog
open={confirmOpen}
onOpenChange={(nextOpen) => {
if (!generating) setConfirmOpen(nextOpen)
}}
title={t('Regenerate access token?')}
desc={
<div className='space-y-2'>
<p>
{t(
'This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.'
)}
</p>
<p>
{t(
'The new token will only be shown once. Copy it and store it securely.'
)}
</p>
</div>
}
confirmText={
generating ? (
<>
<Loader2 className='h-4 w-4 animate-spin' aria-hidden='true' />
{t('Generating...')}
</>
) : (
t('Regenerate token')
)
}
destructive
isLoading={generating}
handleConfirm={handleGenerate}
/>
</>
)
}
@@ -58,9 +58,14 @@ export function useAccessToken() {
}
}, [copyToClipboard])
const clearToken = useCallback(() => {
setToken('')
}, [])
return {
token,
generating,
generate,
clearToken,
}
}
+8
View File
@@ -130,6 +130,7 @@
"Access Policy (JSON)": "Access Policy (JSON)",
"Access previous conversations and start new ones.": "Access previous conversations and start new ones.",
"Access Token": "Access Token",
"Access tokens are shown only once": "Access tokens are shown only once",
"AccessKey / SecretAccessKey": "AccessKey / SecretAccessKey",
"Account Binding Management": "Account Binding Management",
"Account Bindings": "Account Bindings",
@@ -2048,6 +2049,7 @@
"footer.new\u0061pi.projectAttributionSuffix": "All rights reserved. Designed and developed by the project contributors.",
"For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment",
"For private deployments, format: https://fastgpt.run/api/openapi": "For private deployments, format: https://fastgpt.run/api/openapi",
"For security, existing access tokens cannot be displayed. Regenerate only when you need a new token.": "For security, existing access tokens cannot be displayed. Regenerate only when you need a new token.",
"Force a syntactically valid JSON response": "Force a syntactically valid JSON response",
"Force AUTH LOGIN": "Force AUTH LOGIN",
"Force Format": "Force Format",
@@ -3726,7 +3728,10 @@
"Refund": "Refund",
"Refund Details": "Refund Details",
"Regenerate": "Regenerate",
"Regenerate access token?": "Regenerate access token?",
"Regenerate Backup Codes": "Regenerate Backup Codes",
"Regenerate token": "Regenerate token",
"Regenerating immediately invalidates any existing token.": "Regenerating immediately invalidates any existing token.",
"Regex": "Regex",
"Regex Pattern": "Regex Pattern",
"Regex Replace": "Regex Replace",
@@ -4003,6 +4008,7 @@
"Save Stripe settings": "Save Stripe settings",
"Save these backup codes in a safe place. Each code can only be used once.": "Save these backup codes in a safe place. Each code can only be used once.",
"Save these codes in a safe place. Each code can only be used once.": "Save these codes in a safe place. Each code can only be used once.",
"Save this token now. You won't be able to view it again after closing this dialog.": "Save this token now. You won't be able to view it again after closing this dialog.",
"Save token limits": "Save token limits",
"Save tool prices": "Save tool prices",
"Save Waffo Pancake settings": "Save Waffo Pancake settings",
@@ -4528,6 +4534,7 @@
"The model that was requested": "The model that was requested",
"The model you're looking for doesn't exist.": "The model you're looking for doesn't exist.",
"The name displayed across the application": "The name displayed across the application",
"The new token will only be shown once. Copy it and store it securely.": "The new token will only be shown once. Copy it and store it securely.",
"The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations": "The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations",
"The requested chat preset does not exist or has been removed.": "The requested chat preset does not exist or has been removed.",
"The reset request stays disabled until a credit is available.": "The reset request stays disabled until a credit is available.",
@@ -4609,6 +4616,7 @@
"This will delete all channel affinity cache entries still in memory.": "This will delete all channel affinity cache entries still in memory.",
"This will delete temporary cache files that have not been used for more than 10 minutes": "This will delete temporary cache files that have not been used for more than 10 minutes",
"This will extend the deployment by the specified hours.": "This will extend the deployment by the specified hours.",
"This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.": "This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.",
"This will permanently delete all manually and automatically disabled channels. This action cannot be undone.": "This will permanently delete all manually and automatically disabled channels. This action cannot be undone.",
"This will permanently delete API key": "This will permanently delete API key",
"This will permanently delete redemption code": "This will permanently delete redemption code",
+8
View File
@@ -130,6 +130,7 @@
"Access Policy (JSON)": "Politique d'accès (JSON)",
"Access previous conversations and start new ones.": "Accéder aux conversations précédentes et en démarrer de nouvelles.",
"Access Token": "Jeton d'accès",
"Access tokens are shown only once": "Les jetons d'accès ne sont affichés qu'une seule fois",
"AccessKey / SecretAccessKey": "AccessKey / SecretAccessKey",
"Account Binding Management": "Gestion des liaisons de compte",
"Account Bindings": "Associations de compte",
@@ -2048,6 +2049,7 @@
"footer.new\u0061pi.projectAttributionSuffix": "Tous droits réservés. Conçu et développé par les contributeurs du projet.",
"For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "Pour les canaux ajoutés après le 10 mai 2025, pas besoin de supprimer \".\" des noms de modèles lors du déploiement",
"For private deployments, format: https://fastgpt.run/api/openapi": "Pour les déploiements privés, format : https://fastgpt.run/api/openapi",
"For security, existing access tokens cannot be displayed. Regenerate only when you need a new token.": "Pour des raisons de sécurité, les jetons d'accès existants ne peuvent pas être réaffichés. Ne les régénérez que si vous en avez besoin d'un nouveau.",
"Force a syntactically valid JSON response": "Imposer une réponse JSON syntaxiquement valide",
"Force AUTH LOGIN": "Forcer AUTH LOGIN",
"Force Format": "Forcer le format",
@@ -3726,7 +3728,10 @@
"Refund": "Remboursement",
"Refund Details": "Détails du remboursement",
"Regenerate": "Régénérer",
"Regenerate access token?": "Régénérer le jeton d'accès ?",
"Regenerate Backup Codes": "Régénérer les codes de secours",
"Regenerate token": "Régénérer le jeton",
"Regenerating immediately invalidates any existing token.": "La régénération invalide immédiatement tout jeton existant.",
"Regex": "Regex",
"Regex Pattern": "Expression régulière",
"Regex Replace": "Remplacement regex",
@@ -4003,6 +4008,7 @@
"Save Stripe settings": "Enregistrer les paramètres Stripe",
"Save these backup codes in a safe place. Each code can only be used once.": "Enregistrez ces codes de secours dans un endroit sûr. Chaque code ne peut être utilisé qu'une seule fois.",
"Save these codes in a safe place. Each code can only be used once.": "Enregistrez ces codes dans un endroit sûr. Chaque code ne peut être utilisé qu'une seule fois.",
"Save this token now. You won't be able to view it again after closing this dialog.": "Enregistrez ce jeton maintenant. Vous ne pourrez plus le consulter après la fermeture de cette boîte de dialogue.",
"Save token limits": "Enregistrer les limites de jetons",
"Save tool prices": "Enregistrer les prix des outils",
"Save Waffo Pancake settings": "Enregistrer les paramètres Waffo Pancake",
@@ -4528,6 +4534,7 @@
"The model that was requested": "Le modèle qui a été demandé",
"The model you're looking for doesn't exist.": "Le modèle que vous recherchez n'existe pas.",
"The name displayed across the application": "Le nom affiché dans l'application",
"The new token will only be shown once. Copy it and store it securely.": "Le nouveau jeton ne sera affiché quune seule fois. Copiez-le et conservez-le en lieu sûr.",
"The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations": "L'URL publique de votre serveur, utilisée pour les rappels OAuth, les webhooks et autres intégrations externes",
"The requested chat preset does not exist or has been removed.": "Le préréglage de discussion demandé n'existe pas ou a été supprimé.",
"The reset request stays disabled until a credit is available.": "La demande de réinitialisation reste désactivée tant quaucun crédit nest disponible.",
@@ -4609,6 +4616,7 @@
"This will delete all channel affinity cache entries still in memory.": "Cela supprimera toutes les entrées de cache d'affinité de canal encore en mémoire.",
"This will delete temporary cache files that have not been used for more than 10 minutes": "Cela supprimera les fichiers de cache temporaires inutilisés depuis plus de 10 minutes",
"This will extend the deployment by the specified hours.": "Cela prolongera le déploiement du nombre d'heures spécifié.",
"This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.": "Cela invalidera immédiatement votre jeton d'accès actuel. Les applications ou scripts qui l'utilisent cesseront de fonctionner.",
"This will permanently delete all manually and automatically disabled channels. This action cannot be undone.": "Cela supprimera définitivement tous les canaux désactivés manuellement et automatiquement. Cette action ne peut pas être annulée.",
"This will permanently delete API key": "Cela supprimera définitivement la clé API",
"This will permanently delete redemption code": "Cela supprimera définitivement le code d'échange",
+8
View File
@@ -130,6 +130,7 @@
"Access Policy (JSON)": "アクセスポリシー (JSON)",
"Access previous conversations and start new ones.": "以前の会話にアクセスし、新しい会話を開始します。",
"Access Token": "アクセストークン",
"Access tokens are shown only once": "アクセストークンは一度だけ表示されます",
"AccessKey / SecretAccessKey": "AccessKey/SecretAccessKey",
"Account Binding Management": "アカウント連携管理",
"Account Bindings": "アカウントバインディング",
@@ -2048,6 +2049,7 @@
"footer.new\u0061pi.projectAttributionSuffix": "すべての権利を留保します。プロジェクトコントリビューターにより設計・開発されています。",
"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 security, existing access tokens cannot be displayed. Regenerate only when you need a new token.": "セキュリティ上、既存のアクセストークンは再表示できません。新しいトークンが必要な場合のみ再生成してください。",
"Force a syntactically valid JSON response": "構文的に有効な JSON 応答を強制",
"Force AUTH LOGIN": "AUTH LOGINを強制",
"Force Format": "強制フォーマット",
@@ -3726,7 +3728,10 @@
"Refund": "返金",
"Refund Details": "返金詳細",
"Regenerate": "再生成",
"Regenerate access token?": "アクセストークンを再生成しますか?",
"Regenerate Backup Codes": "バックアップコードを再生成",
"Regenerate token": "トークンを再生成",
"Regenerating immediately invalidates any existing token.": "再生成すると、既存のトークンは直ちに無効になります。",
"Regex": "正規表現",
"Regex Pattern": "正規表現パターン",
"Regex Replace": "正規表現置換",
@@ -4003,6 +4008,7 @@
"Save Stripe settings": "Stripe設定を保存",
"Save these backup codes in a safe place. Each code can only be used once.": "これらのバックアップコードを安全な場所に保存してください。各コードは一度だけ使用できます。",
"Save these codes in a safe place. Each code can only be used once.": "これらのコードを安全な場所に保存してください。各コードは一度だけ使用できます。",
"Save this token now. You won't be able to view it again after closing this dialog.": "このトークンを今すぐ保存してください。このダイアログを閉じると、再度表示できません。",
"Save token limits": "トークン制限を保存",
"Save tool prices": "ツール価格を保存",
"Save Waffo Pancake settings": "Waffo Pancake 設定を保存",
@@ -4528,6 +4534,7 @@
"The model that was requested": "リクエストされたモデル",
"The model you're looking for doesn't exist.": "お探しのモデルは存在しません。",
"The name displayed across the application": "アプリケーション全体に表示される名前",
"The new token will only be shown once. Copy it and store it securely.": "新しいトークンは一度だけ表示されます。コピーして安全に保管してください。",
"The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations": "OAuthコールバック、Webhook、その他の外部統合に使用されるサーバーの公開URL",
"The requested chat preset does not exist or has been removed.": "要求されたチャットプリセットは存在しないか、削除されました。",
"The reset request stays disabled until a credit is available.": "リセット回数が利用可能になるまで、リセット要求は無効です。",
@@ -4609,6 +4616,7 @@
"This will delete all channel affinity cache entries still in memory.": "メモリ内のすべてのチャネルアフィニティキャッシュエントリが削除されます。",
"This will delete temporary cache files that have not been used for more than 10 minutes": "10分以上使用されていない一時キャッシュファイルが削除されます",
"This will extend the deployment by the specified hours.": "これにより、デプロイメントを指定された時間分延長します。",
"This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.": "既存のアクセストークンは直ちに無効になります。使用中のアプリケーションやスクリプトは動作しなくなります。",
"This will permanently delete all manually and automatically disabled channels. This action cannot be undone.": "手動および自動で無効化されたすべてのチャネルを完全に削除します。この操作は元に戻せません。",
"This will permanently delete API key": "これによりAPIキーが完全に削除されます",
"This will permanently delete redemption code": "これにより引き換えコードが完全に削除されます",
+8
View File
@@ -130,6 +130,7 @@
"Access Policy (JSON)": "Политика доступа (JSON)",
"Access previous conversations and start new ones.": "Доступ к предыдущим разговорам и начало новых.",
"Access Token": "Токен доступа",
"Access tokens are shown only once": "Токены доступа отображаются только один раз",
"AccessKey / SecretAccessKey": "AccessKey / SecretAccessKey",
"Account Binding Management": "Управление привязкой аккаунта",
"Account Bindings": "Привязки аккаунта",
@@ -2048,6 +2049,7 @@
"footer.new\u0061pi.projectAttributionSuffix": "Все права защищены. Разработано участниками проекта.",
"For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "Для каналов, добавленных после 10 мая 2025 г., не нужно удалять \".\" из имён моделей при развёртывании",
"For private deployments, format: https://fastgpt.run/api/openapi": "Для частных развертываний, формат: https://fastgpt.run/api/openapi",
"For security, existing access tokens cannot be displayed. Regenerate only when you need a new token.": "В целях безопасности существующие токены доступа нельзя просмотреть повторно. Создавайте новый токен только при необходимости.",
"Force a syntactically valid JSON response": "Принудительно возвращать синтаксически корректный JSON",
"Force AUTH LOGIN": "Принудительный AUTH LOGIN",
"Force Format": "Принудительный формат",
@@ -3726,7 +3728,10 @@
"Refund": "Возврат",
"Refund Details": "Детали возврата",
"Regenerate": "Перегенерировать",
"Regenerate access token?": "Перегенерировать токен доступа?",
"Regenerate Backup Codes": "Сгенерировать резервные коды",
"Regenerate token": "Перегенерировать токен",
"Regenerating immediately invalidates any existing token.": "Перегенерация немедленно делает недействительными все существующие токены.",
"Regex": "Регулярное выражение",
"Regex Pattern": "Регулярное выражение",
"Regex Replace": "Замена по regex",
@@ -4003,6 +4008,7 @@
"Save Stripe settings": "Сохранить настройки Stripe",
"Save these backup codes in a safe place. Each code can only be used once.": "Сохраните эти резервные коды в безопасном месте. Каждый код может быть использован только один раз.",
"Save these codes in a safe place. Each code can only be used once.": "Сохраните эти коды в безопасном месте. Каждый код может быть использован только один раз.",
"Save this token now. You won't be able to view it again after closing this dialog.": "Сохраните этот токен сейчас. После закрытия диалогового окна вы не сможете просмотреть его снова.",
"Save token limits": "Сохранить лимиты токенов",
"Save tool prices": "Сохранить цены инструментов",
"Save Waffo Pancake settings": "Сохранить настройки Waffo Pancake",
@@ -4528,6 +4534,7 @@
"The model that was requested": "Запрошенная модель",
"The model you're looking for doesn't exist.": "Модель, которую вы ищете, не существует.",
"The name displayed across the application": "Имя, отображаемое в приложении",
"The new token will only be shown once. Copy it and store it securely.": "Новый токен будет показан только один раз. Скопируйте его и сохраните в безопасном месте.",
"The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations": "Публичный URL вашего сервера, используемый для OAuth-перенаправлений, вебхуков и других внешних интеграций",
"The requested chat preset does not exist or has been removed.": "Запрошенный предустановленный чат не существует или был удален.",
"The reset request stays disabled until a credit is available.": "Запрос сброса недоступен, пока нет доступного сброса.",
@@ -4609,6 +4616,7 @@
"This will delete all channel affinity cache entries still in memory.": "Это удалит все записи кэша привязки каналов из памяти.",
"This will delete temporary cache files that have not been used for more than 10 minutes": "Будут удалены временные файлы кэша, не использовавшиеся более 10 минут",
"This will extend the deployment by the specified hours.": "Это продлит развертывание на указанное количество часов.",
"This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.": "Это немедленно сделает текущий токен доступа недействительным. Использующие его приложения и скрипты перестанут работать.",
"This will permanently delete all manually and automatically disabled channels. This action cannot be undone.": "Это навсегда удалит все каналы, отключённые вручную и автоматически. Это действие нельзя отменить.",
"This will permanently delete API key": "Это безвозвратно удалит ключ API",
"This will permanently delete redemption code": "Это безвозвратно удалит код активации",
+8
View File
@@ -130,6 +130,7 @@
"Access Policy (JSON)": "Chính sách truy cập (JSON)",
"Access previous conversations and start new ones.": "Truy cập các cuộc trò chuyện trước đó và bắt đầu các cuộc trò chuyện mới.",
"Access Token": "Token truy cập",
"Access tokens are shown only once": "Token truy cập chỉ được hiển thị một lần",
"AccessKey / SecretAccessKey": "AccessKey / SecretAccessKey",
"Account Binding Management": "Quản lý liên kết tài khoản",
"Account Bindings": "Liên kết tài khoản",
@@ -2048,6 +2049,7 @@
"footer.new\u0061pi.projectAttributionSuffix": "Bản quyền được bảo lưu. Được thiết kế và phát triển bởi các cộng tác viên dự án.",
"For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "Đối với các kênh được thêm sau ngày 10 tháng 5 năm 2025, không cần loại bỏ \".\" khỏi tên mô hình trong quá trình triển khai",
"For private deployments, format: https://fastgpt.run/api/openapi": "Đối với các triển khai riêng tư, định dạng: https://fastgpt.run/api/openapi",
"For security, existing access tokens cannot be displayed. Regenerate only when you need a new token.": "Vì lý do bảo mật, không thể hiển thị lại token truy cập hiện có. Chỉ tạo lại khi bạn cần token mới.",
"Force a syntactically valid JSON response": "Buộc phản hồi JSON hợp lệ về cú pháp",
"Force AUTH LOGIN": "Bắt buộc AUTH LOGIN",
"Force Format": "Buộc định dạng",
@@ -3726,7 +3728,10 @@
"Refund": "Hoàn tiền",
"Refund Details": "Chi tiết hoàn tiền",
"Regenerate": "Tạo lại",
"Regenerate access token?": "Tạo lại token truy cập?",
"Regenerate Backup Codes": "Tạo lại Mã dự phòng",
"Regenerate token": "Tạo lại token",
"Regenerating immediately invalidates any existing token.": "Việc tạo lại sẽ vô hiệu hóa ngay mọi token hiện có.",
"Regex": "Biểu thức chính quy",
"Regex Pattern": "Mẫu biểu thức chính quy",
"Regex Replace": "Thay thế regex",
@@ -4003,6 +4008,7 @@
"Save Stripe settings": "Lưu cài đặt Stripe",
"Save these backup codes in a safe place. Each code can only be used once.": "Lưu các mã dự phòng này ở nơi an toàn. Mỗi mã chỉ được sử dụng một lần.",
"Save these codes in a safe place. Each code can only be used once.": "Hãy lưu các mã này ở nơi an toàn. Mỗi mã chỉ có thể được sử dụng một lần.",
"Save this token now. You won't be able to view it again after closing this dialog.": "Hãy lưu token này ngay. Bạn sẽ không thể xem lại sau khi đóng hộp thoại.",
"Save token limits": "Lưu giới hạn token",
"Save tool prices": "Lưu giá công cụ",
"Save Waffo Pancake settings": "Lưu cài đặt Waffo Pancake",
@@ -4528,6 +4534,7 @@
"The model that was requested": "Mô hình đã được yêu cầu",
"The model you're looking for doesn't exist.": "Mô hình bạn đang tìm kiếm không tồn tại.",
"The name displayed across the application": "Tên hiển thị trên ứng dụng",
"The new token will only be shown once. Copy it and store it securely.": "Token mới chỉ được hiển thị một lần. Hãy sao chép và lưu trữ an toàn.",
"The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations": "URL công khai của máy chủ, dùng cho callback OAuth, webhook và các tích hợp bên ngoài khác",
"The requested chat preset does not exist or has been removed.": "Cài đặt sẵn cuộc trò chuyện được yêu cầu không tồn tại hoặc đã bị xóa.",
"The reset request stays disabled until a credit is available.": "Yêu cầu đặt lại sẽ bị tắt cho đến khi có lượt khả dụng.",
@@ -4609,6 +4616,7 @@
"This will delete all channel affinity cache entries still in memory.": "Thao tác này sẽ xóa tất cả mục bộ nhớ đệm ưu tiên kênh còn trong bộ nhớ.",
"This will delete temporary cache files that have not been used for more than 10 minutes": "Thao tác này sẽ xóa các tệp bộ nhớ đệm tạm không được sử dụng hơn 10 phút",
"This will extend the deployment by the specified hours.": "Thao tác này sẽ kéo dài triển khai thêm số giờ được chỉ định.",
"This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.": "Thao tác này sẽ vô hiệu hóa ngay token truy cập hiện có. Mọi ứng dụng hoặc tập lệnh đang sử dụng token đó sẽ ngừng hoạt động.",
"This will permanently delete all manually and automatically disabled channels. This action cannot be undone.": "Thao tác này sẽ xóa vĩnh viễn tất cả các kênh bị tắt thủ công và tự động. Hành động này không thể hoàn tác.",
"This will permanently delete API key": "Thao tác này sẽ xóa vĩnh viễn khóa API",
"This will permanently delete redemption code": "Thao tác này sẽ xóa vĩnh viễn mã đổi thưởng.",
+8
View File
@@ -130,6 +130,7 @@
"Access Policy (JSON)": "存取政策 (JSON)",
"Access previous conversations and start new ones.": "存取之前的對話並開始新的對話。",
"Access Token": "存取令牌",
"Access tokens are shown only once": "存取令牌僅顯示一次",
"AccessKey / SecretAccessKey": "AccessKey / SecretAccessKey",
"Account Binding Management": "用戶連結管理",
"Account Bindings": "用戶連結",
@@ -2048,6 +2049,7 @@
"footer.new\u0061pi.projectAttributionSuffix": "版權所有,由項目貢獻者設計與開發。",
"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 security, existing access tokens cannot be displayed. Regenerate only when you need a new token.": "基於安全考量,現有存取令牌無法再次顯示。僅在需要新令牌時重新生成。",
"Force a syntactically valid JSON response": "強制返回語法合法的 JSON",
"Force AUTH LOGIN": "強制 AUTH LOGIN",
"Force Format": "強制格式化",
@@ -3726,7 +3728,10 @@
"Refund": "退款",
"Refund Details": "退款詳情",
"Regenerate": "重新生成",
"Regenerate access token?": "重新生成存取令牌?",
"Regenerate Backup Codes": "重新生成備用代碼",
"Regenerate token": "重新生成令牌",
"Regenerating immediately invalidates any existing token.": "重新生成會立即使所有現有令牌失效。",
"Regex": "正則",
"Regex Pattern": "正則表達式",
"Regex Replace": "正則替換",
@@ -4003,6 +4008,7 @@
"Save Stripe settings": "儲存 Stripe 設定",
"Save these backup codes in a safe place. Each code can only be used once.": "將這些備份代碼儲存在安全的地方。每個代碼只能使用一次。",
"Save these codes in a safe place. Each code can only be used once.": "將這些代碼儲存在安全的地方。每個代碼只能使用一次。",
"Save this token now. You won't be able to view it again after closing this dialog.": "請立即儲存此令牌。關閉此對話框後,您將無法再次查看。",
"Save token limits": "儲存令牌限制",
"Save tool prices": "儲存工具價格",
"Save Waffo Pancake settings": "儲存 Waffo Pancake 設定",
@@ -4528,6 +4534,7 @@
"The model that was requested": "被請求的模型",
"The model you're looking for doesn't exist.": "您查找的模型不存在。",
"The name displayed across the application": "在整個套用程式中顯示的名稱",
"The new token will only be shown once. Copy it and store it securely.": "新令牌僅顯示一次。請複製並妥善保存。",
"The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations": "伺服器的公開URL,用於OAuthCallback、Webhook和其他外部整合",
"The requested chat preset does not exist or has been removed.": "請求的聊天預設不存在或已被刪除。",
"The reset request stays disabled until a credit is available.": "沒有可用次數時,重置請求會保持停用。",
@@ -4609,6 +4616,7 @@
"This will delete all channel affinity cache entries still in memory.": "這將刪除記憶體中所有的渠道親和性緩存條目。",
"This will delete temporary cache files that have not been used for more than 10 minutes": "這將刪除超過 10 分鐘未使用的臨時緩存檔案",
"This will extend the deployment by the specified hours.": "這將透過指定的小時數延長部署。",
"This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.": "這會立即使現有存取令牌失效。任何正在使用它的應用程式或指令碼都將停止運作。",
"This will permanently delete all manually and automatically disabled channels. This action cannot be undone.": "這將永久刪除所有手動停用和自動停用的渠道。此操作無法撤銷。",
"This will permanently delete API key": "這將永久刪除 API 金鑰",
"This will permanently delete redemption code": "這將永久刪除兌換碼",
+8
View File
@@ -130,6 +130,7 @@
"Access Policy (JSON)": "访问策略 (JSON)",
"Access previous conversations and start new ones.": "访问之前的对话并开始新的对话。",
"Access Token": "访问令牌",
"Access tokens are shown only once": "访问令牌仅显示一次",
"AccessKey / SecretAccessKey": "AccessKey / SecretAccessKey",
"Account Binding Management": "账户绑定管理",
"Account Bindings": "账户绑定",
@@ -2048,6 +2049,7 @@
"footer.new\u0061pi.projectAttributionSuffix": "版权所有,由项目贡献者设计与开发。",
"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 security, existing access tokens cannot be displayed. Regenerate only when you need a new token.": "出于安全考虑,现有访问令牌无法再次显示。仅在需要新令牌时重新生成。",
"Force a syntactically valid JSON response": "强制返回语法合法的 JSON",
"Force AUTH LOGIN": "强制 AUTH LOGIN",
"Force Format": "强制格式化",
@@ -3726,7 +3728,10 @@
"Refund": "退款",
"Refund Details": "退款详情",
"Regenerate": "重新生成",
"Regenerate access token?": "重新生成访问令牌?",
"Regenerate Backup Codes": "重新生成备用代码",
"Regenerate token": "重新生成令牌",
"Regenerating immediately invalidates any existing token.": "重新生成会立即使所有现有令牌失效。",
"Regex": "正则",
"Regex Pattern": "正则表达式",
"Regex Replace": "正则替换",
@@ -4003,6 +4008,7 @@
"Save Stripe settings": "保存 Stripe 设置",
"Save these backup codes in a safe place. Each code can only be used once.": "将这些备份代码保存在安全的地方。每个代码只能使用一次。",
"Save these codes in a safe place. Each code can only be used once.": "将这些代码保存在安全的地方。每个代码只能使用一次。",
"Save this token now. You won't be able to view it again after closing this dialog.": "请立即保存此令牌。关闭此对话框后,您将无法再次查看。",
"Save token limits": "保存令牌限制",
"Save tool prices": "保存工具价格",
"Save Waffo Pancake settings": "保存 Waffo Pancake 设置",
@@ -4528,6 +4534,7 @@
"The model that was requested": "被请求的模型",
"The model you're looking for doesn't exist.": "您查找的模型不存在。",
"The name displayed across the application": "在整个应用程序中显示的名称",
"The new token will only be shown once. Copy it and store it securely.": "新令牌仅显示一次。请复制并妥善保存。",
"The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations": "服务器的公开URL,用于OAuth回调、Webhook和其他外部集成",
"The requested chat preset does not exist or has been removed.": "请求的聊天预设不存在或已被删除。",
"The reset request stays disabled until a credit is available.": "没有可用次数时,重置请求会保持禁用。",
@@ -4609,6 +4616,7 @@
"This will delete all channel affinity cache entries still in memory.": "这将删除内存中所有的渠道亲和性缓存条目。",
"This will delete temporary cache files that have not been used for more than 10 minutes": "这将删除超过 10 分钟未使用的临时缓存文件",
"This will extend the deployment by the specified hours.": "这将通过指定的小时数延长部署。",
"This will immediately invalidate your existing access token. Any applications or scripts using it will stop working.": "这会立即使现有访问令牌失效。任何正在使用它的应用程序或脚本都将停止工作。",
"This will permanently delete all manually and automatically disabled channels. This action cannot be undone.": "这将永久删除所有手动禁用和自动禁用的渠道。此操作无法撤销。",
"This will permanently delete API key": "这将永久删除 API 密钥",
"This will permanently delete redemption code": "这将永久删除兑换码",