Files
sub2api/frontend/src/i18n/locales/en.ts
shaw c328b741cb Merge PR #73: feat(antigravity): 添加 Antigravity (Cloud AI Companion) 平台支持
新增功能:
- Antigravity OAuth 授权流程支持
- Claude → Gemini 协议转换(Claude API 请求自动转换为 Gemini 格式)
- 配额刷新和状态显示
- 混合调度功能,支持 Anthropic 和 Antigravity 账户混合使用
- /antigravity 专用路由,支持仅使用 Antigravity 账户
- 前端 Antigravity 服务商标识和账户管理功能

冲突解决:
- CreateAccountModal.vue: 合并 data-tour 属性和 mixed-scheduling 属性
- EditAccountModal.vue: 合并 data-tour 属性和 mixed-scheduling 属性

代码质量改进:
- 修复 antigravity 类型文件的 gofmt 格式问题(struct 字段对齐、interface{} → any)
- 移除 .golangci.yml 中的 gofmt 排除规则
- 修复测试文件的格式问题
2025-12-29 20:32:20 +08:00

1691 lines
79 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export default {
// Home Page
home: {
viewOnGithub: 'View on GitHub',
viewDocs: 'View Documentation',
docs: 'Docs',
switchToLight: 'Switch to Light Mode',
switchToDark: 'Switch to Dark Mode',
dashboard: 'Dashboard',
login: 'Login',
getStarted: 'Get Started',
goToDashboard: 'Go to Dashboard',
tags: {
subscriptionToApi: 'Subscription to API',
stickySession: 'Sticky Session',
realtimeBilling: 'Real-time Billing'
},
features: {
unifiedGateway: 'Unified API Gateway',
unifiedGatewayDesc:
'Convert Claude subscriptions to API endpoints. Access AI capabilities through standard /v1/messages interface.',
multiAccount: 'Multi-Account Pool',
multiAccountDesc:
'Manage multiple upstream accounts with smart load balancing. Support OAuth and API Key authentication.',
balanceQuota: 'Balance & Quota',
balanceQuotaDesc:
'Token-based billing with precise usage tracking. Manage quotas and recharge with redeem codes.'
},
providers: {
title: 'Supported Providers',
description: 'Unified API interface for AI services',
supported: 'Supported',
soon: 'Soon',
claude: 'Claude',
gemini: 'Gemini',
antigravity: 'Antigravity',
more: 'More'
},
footer: {
allRightsReserved: 'All rights reserved.'
}
},
// Setup Wizard
setup: {
title: 'Sub2API Setup',
description: 'Configure your Sub2API instance',
database: {
title: 'Database Configuration',
host: 'Host',
port: 'Port',
username: 'Username',
password: 'Password',
databaseName: 'Database Name',
sslMode: 'SSL Mode',
passwordPlaceholder: 'Password',
ssl: {
disable: 'Disable',
require: 'Require',
verifyCa: 'Verify CA',
verifyFull: 'Verify Full'
}
},
redis: {
title: 'Redis Configuration',
host: 'Host',
port: 'Port',
password: 'Password (optional)',
database: 'Database',
passwordPlaceholder: 'Password'
},
admin: {
title: 'Admin Account',
email: 'Email',
password: 'Password',
confirmPassword: 'Confirm Password',
passwordPlaceholder: 'Min 6 characters',
confirmPasswordPlaceholder: 'Confirm password',
passwordMismatch: 'Passwords do not match'
},
ready: {
title: 'Ready to Install',
database: 'Database',
redis: 'Redis',
adminEmail: 'Admin Email'
}
},
// Common
common: {
loading: 'Loading...',
save: 'Save',
cancel: 'Cancel',
delete: 'Delete',
edit: 'Edit',
create: 'Create',
update: 'Update',
confirm: 'Confirm',
reset: 'Reset',
search: 'Search',
filter: 'Filter',
export: 'Export',
import: 'Import',
actions: 'Actions',
status: 'Status',
name: 'Name',
email: 'Email',
password: 'Password',
submit: 'Submit',
back: 'Back',
next: 'Next',
yes: 'Yes',
no: 'No',
all: 'All',
none: 'None',
noData: 'No data',
success: 'Success',
error: 'Error',
warning: 'Warning',
info: 'Info',
active: 'Active',
inactive: 'Inactive',
more: 'More',
close: 'Close',
enabled: 'Enabled',
disabled: 'Disabled',
total: 'Total',
balance: 'Balance',
available: 'Available',
copiedToClipboard: 'Copied to clipboard',
copyFailed: 'Failed to copy',
contactSupport: 'Contact Support',
selectOption: 'Select an option',
searchPlaceholder: 'Search...',
noOptionsFound: 'No options found',
saving: 'Saving...',
refresh: 'Refresh',
time: {
never: 'Never',
justNow: 'Just now',
minutesAgo: '{n}m ago',
hoursAgo: '{n}h ago',
daysAgo: '{n}d ago'
}
},
// Navigation
nav: {
dashboard: 'Dashboard',
apiKeys: 'API Keys',
usage: 'Usage',
redeem: 'Redeem',
profile: 'Profile',
users: 'Users',
groups: 'Groups',
subscriptions: 'Subscriptions',
accounts: 'Accounts',
proxies: 'Proxies',
redeemCodes: 'Redeem Codes',
settings: 'Settings',
myAccount: 'My Account',
lightMode: 'Light Mode',
darkMode: 'Dark Mode',
collapse: 'Collapse',
expand: 'Expand',
logout: 'Logout',
github: 'GitHub',
mySubscriptions: 'My Subscriptions'
},
// Auth
auth: {
welcomeBack: 'Welcome Back',
signInToAccount: 'Sign in to your account to continue',
signIn: 'Sign In',
signingIn: 'Signing in...',
createAccount: 'Create Account',
signUpToStart: 'Sign up to start using {siteName}',
signUp: 'Sign up',
processing: 'Processing...',
continue: 'Continue',
rememberMe: 'Remember me',
dontHaveAccount: "Don't have an account?",
alreadyHaveAccount: 'Already have an account?',
registrationDisabled: 'Registration is currently disabled. Please contact the administrator.',
emailLabel: 'Email',
emailPlaceholder: 'Enter your email',
passwordLabel: 'Password',
passwordPlaceholder: 'Enter your password',
createPasswordPlaceholder: 'Create a strong password',
passwordHint: 'At least 6 characters',
emailRequired: 'Email is required',
invalidEmail: 'Please enter a valid email address',
passwordRequired: 'Password is required',
passwordMinLength: 'Password must be at least 6 characters',
loginFailed: 'Login failed. Please check your credentials and try again.',
registrationFailed: 'Registration failed. Please try again.',
loginSuccess: 'Login successful! Welcome back.',
accountCreatedSuccess: 'Account created successfully! Welcome to {siteName}.',
turnstileExpired: 'Verification expired, please try again',
turnstileFailed: 'Verification failed, please try again',
completeVerification: 'Please complete the verification',
verifyYourEmail: 'Verify Your Email',
sessionExpired: 'Session expired',
sessionExpiredDesc: 'Please go back to the registration page and start again.',
verificationCode: 'Verification Code',
verificationCodeHint: 'Enter the 6-digit code sent to your email',
sendingCode: 'Sending...',
clickToResend: 'Click to resend code',
resendCode: 'Resend verification code',
oauth: {
code: 'Code',
state: 'State',
fullUrl: 'Full URL'
}
},
// Dashboard
dashboard: {
title: 'Dashboard',
welcomeMessage: "Welcome back! Here's an overview of your account.",
balance: 'Balance',
apiKeys: 'API Keys',
todayRequests: 'Today Requests',
todayCost: 'Today Cost',
todayTokens: 'Today Tokens',
totalTokens: 'Total Tokens',
cacheToday: 'Cache (Today)',
performance: 'Performance',
avgResponse: 'Avg Response',
averageTime: 'Average time',
timeRange: 'Time Range',
granularity: 'Granularity',
day: 'Day',
hour: 'Hour',
modelDistribution: 'Model Distribution',
tokenUsageTrend: 'Token Usage Trend',
noDataAvailable: 'No data available',
model: 'Model',
requests: 'Requests',
tokens: 'Tokens',
actual: 'Actual',
standard: 'Standard',
input: 'Input',
output: 'Output',
cache: 'Cache',
recentUsage: 'Recent Usage',
last7Days: 'Last 7 days',
noUsageRecords: 'No usage records',
startUsingApi: 'Start using the API to see your usage history here.',
viewAllUsage: 'View all usage',
quickActions: 'Quick Actions',
createApiKey: 'Create API Key',
generateNewKey: 'Generate a new API key',
viewUsage: 'View Usage',
checkDetailedLogs: 'Check detailed usage logs',
redeemCode: 'Redeem Code',
addBalanceWithCode: 'Add balance with a code'
},
// Groups (shared)
groups: {
subscription: 'Sub'
},
// API Keys
keys: {
title: 'API Keys',
description: 'Manage your API keys and access tokens',
createKey: 'Create API Key',
editKey: 'Edit API Key',
deleteKey: 'Delete API Key',
deleteConfirmMessage: "Are you sure you want to delete '{name}'? This action cannot be undone.",
apiKey: 'API Key',
group: 'Group',
noGroup: 'No group',
created: 'Created',
copyToClipboard: 'Copy to clipboard',
copied: 'Copied!',
importToCcSwitch: 'Import to CCS',
enable: 'Enable',
disable: 'Disable',
nameLabel: 'Name',
namePlaceholder: 'My API Key',
groupLabel: 'Group',
selectGroup: 'Select a group',
statusLabel: 'Status',
selectStatus: 'Select status',
saving: 'Saving...',
noKeysYet: 'No API keys yet',
createFirstKey: 'Create your first API key to get started with the API.',
keyCreatedSuccess: 'API key created successfully',
keyUpdatedSuccess: 'API key updated successfully',
keyDeletedSuccess: 'API key deleted successfully',
keyEnabledSuccess: 'API key enabled successfully',
keyDisabledSuccess: 'API key disabled successfully',
failedToLoad: 'Failed to load API keys',
failedToSave: 'Failed to save API key',
failedToDelete: 'Failed to delete API key',
failedToUpdateStatus: 'Failed to update API key status',
clickToChangeGroup: 'Click to change group',
groupChangedSuccess: 'Group changed successfully',
failedToChangeGroup: 'Failed to change group',
groupRequired: 'Please select a group',
usage: 'Usage',
today: 'Today',
total: 'Total',
useKey: 'Use Key',
useKeyModal: {
title: 'Use API Key',
description:
'Add the following environment variables to your terminal profile or run directly in terminal to configure API access.',
copy: 'Copy',
copied: 'Copied',
note: 'These environment variables will be active in the current terminal session. For permanent configuration, add them to ~/.bashrc, ~/.zshrc, or the appropriate configuration file.',
noGroupTitle: 'Please assign a group first',
noGroupDescription: 'This API key has not been assigned to a group. Please click the group column in the key list to assign one before viewing the configuration.',
openai: {
description: 'Add the following configuration files to your Codex CLI config directory.',
configTomlHint: 'Make sure the following content is at the beginning of the config.toml file',
note: 'Make sure the config directory exists. macOS/Linux users can run mkdir -p ~/.codex to create it.',
noteWindows: 'Press Win+R and enter %userprofile%\\.codex to open the config directory. Create it manually if it does not exist.',
},
},
customKeyLabel: 'Custom Key',
customKeyPlaceholder: 'Enter your custom key (min 16 chars)',
customKeyHint: 'Only letters, numbers, underscores and hyphens allowed. Minimum 16 characters.',
customKeyTooShort: 'Custom key must be at least 16 characters',
customKeyInvalidChars: 'Custom key can only contain letters, numbers, underscores, and hyphens',
customKeyRequired: 'Please enter a custom key',
ccSwitchNotInstalled: 'CC-Switch is not installed or the protocol handler is not registered. Please install CC-Switch first or manually copy the API key.'
},
// Usage
usage: {
title: 'Usage Records',
description: 'View and analyze your API usage history',
totalRequests: 'Total Requests',
totalTokens: 'Total Tokens',
totalCost: 'Total Cost',
standardCost: 'Standard',
actualCost: 'Actual',
avgDuration: 'Avg Duration',
inSelectedRange: 'in selected range',
perRequest: 'per request',
apiKeyFilter: 'API Key',
allApiKeys: 'All API Keys',
timeRange: 'Time Range',
exportCsv: 'Export CSV',
exportExcel: 'Export Excel',
exportingProgress: 'Exporting data...',
exportedCount: 'Exported {current}/{total} records',
estimatedTime: 'Estimated time remaining: {time}',
cancelExport: 'Cancel Export',
exportCancelled: 'Export cancelled',
exporting: 'Exporting...',
preparingExport: 'Preparing export...',
model: 'Model',
type: 'Type',
tokens: 'Tokens',
cost: 'Cost',
firstToken: 'First Token',
duration: 'Duration',
time: 'Time',
stream: 'Stream',
sync: 'Sync',
in: 'In',
out: 'Out',
cacheRead: 'Read',
cacheWrite: 'Write',
rate: 'Rate',
original: 'Original',
billed: 'Billed',
noRecords: 'No usage records found. Try adjusting your filters.',
failedToLoad: 'Failed to load usage logs',
noDataToExport: 'No data to export',
exportSuccess: 'Usage data exported successfully',
exportFailed: 'Failed to export usage data',
exportExcelSuccess: 'Usage data exported successfully (Excel format)',
exportExcelFailed: 'Failed to export usage data',
billingType: 'Billing',
balance: 'Balance',
subscription: 'Subscription'
},
// Redeem
redeem: {
title: 'Redeem Code',
description: 'Enter your redeem code to add balance or increase concurrency',
currentBalance: 'Current Balance',
concurrency: 'Concurrency',
requests: 'requests',
redeemCodeLabel: 'Redeem Code',
redeemCodePlaceholder: 'Enter your redeem code',
redeemCodeHint: 'Redeem codes are case-sensitive',
redeeming: 'Redeeming...',
redeemButton: 'Redeem Code',
redeemSuccess: 'Code Redeemed Successfully!',
redeemFailed: 'Redemption Failed',
added: 'Added',
concurrentRequests: 'concurrent requests',
newBalance: 'New Balance',
newConcurrency: 'New Concurrency',
aboutCodes: 'About Redeem Codes',
codeRule1: 'Each code can only be used once',
codeRule2: 'Codes may add balance, increase concurrency, or grant trial access',
codeRule3: 'Contact support if you have issues redeeming a code',
codeRule4: 'Balance and concurrency updates are immediate',
recentActivity: 'Recent Activity',
historyWillAppear: 'Your redemption history will appear here',
balanceAddedRedeem: 'Balance Added (Redeem)',
balanceAddedAdmin: 'Balance Added (Admin)',
balanceDeductedAdmin: 'Balance Deducted (Admin)',
concurrencyAddedRedeem: 'Concurrency Added (Redeem)',
concurrencyAddedAdmin: 'Concurrency Added (Admin)',
concurrencyReducedAdmin: 'Concurrency Reduced (Admin)',
adminAdjustment: 'Admin Adjustment',
subscriptionAssigned: 'Subscription Assigned',
subscriptionAssignedDesc: 'You have been granted access to {groupName}',
subscriptionDays: '{days} days',
days: ' days',
codeRedeemSuccess: 'Code redeemed successfully!',
failedToRedeem: 'Failed to redeem code. Please check the code and try again.',
subscriptionRefreshFailed: 'Redeemed successfully, but failed to refresh subscription status.'
},
// Profile
profile: {
title: 'Profile Settings',
description: 'Manage your account information and settings',
accountBalance: 'Account Balance',
concurrencyLimit: 'Concurrency Limit',
memberSince: 'Member Since',
administrator: 'Administrator',
user: 'User',
username: 'Username',
wechat: 'WeChat ID',
enterUsername: 'Enter username',
enterWechat: 'Enter WeChat ID',
editProfile: 'Edit Profile',
updateProfile: 'Update Profile',
updating: 'Updating...',
updateSuccess: 'Profile updated successfully',
updateFailed: 'Failed to update profile',
usernameRequired: 'Username is required',
changePassword: 'Change Password',
currentPassword: 'Current Password',
newPassword: 'New Password',
confirmNewPassword: 'Confirm New Password',
passwordHint: 'Password must be at least 8 characters long',
changingPassword: 'Changing...',
changePasswordButton: 'Change Password',
passwordsNotMatch: 'New passwords do not match',
passwordTooShort: 'Password must be at least 8 characters long',
passwordChangeSuccess: 'Password changed successfully',
passwordChangeFailed: 'Failed to change password'
},
// Empty States
empty: {
noData: 'No data found'
},
// Table
table: {
expandActions: 'Expand More Actions',
collapseActions: 'Collapse Actions'
},
// Pagination
pagination: {
showing: 'Showing',
to: 'to',
of: 'of',
results: 'results',
page: 'Page',
pageOf: 'Page {page} of {total}',
previous: 'Previous',
next: 'Next',
perPage: 'Per page',
goToPage: 'Go to page {page}'
},
// Errors
errors: {
somethingWentWrong: 'Something went wrong',
pageNotFound: 'Page not found',
unauthorized: 'Unauthorized',
forbidden: 'Forbidden',
serverError: 'Server error',
networkError: 'Network error',
timeout: 'Request timeout',
tryAgain: 'Please try again'
},
// Dates
dates: {
today: 'Today',
yesterday: 'Yesterday',
thisWeek: 'This Week',
lastWeek: 'Last Week',
thisMonth: 'This Month',
lastMonth: 'Last Month',
last7Days: 'Last 7 Days',
last14Days: 'Last 14 Days',
last30Days: 'Last 30 Days',
custom: 'Custom',
startDate: 'Start Date',
endDate: 'End Date',
apply: 'Apply',
selectDateRange: 'Select date range'
},
// Admin
admin: {
// Dashboard
dashboard: {
title: 'Admin Dashboard',
description: 'System overview and real-time statistics',
apiKeys: 'API Keys',
accounts: 'Accounts',
users: 'Users',
todayRequests: 'Today Requests',
newUsersToday: 'New Users Today',
todayTokens: 'Today Tokens',
totalTokens: 'Total Tokens',
cacheToday: 'Cache (Today)',
performance: 'Performance',
avgResponse: 'Avg Response',
active: 'active',
ok: 'ok',
err: 'err',
activeUsers: 'active users',
create: 'Create',
timeRange: 'Time Range',
granularity: 'Granularity',
day: 'Day',
hour: 'Hour',
modelDistribution: 'Model Distribution',
tokenUsageTrend: 'Token Usage Trend',
userUsageTrend: 'User Usage Trend (Top 12)',
model: 'Model',
requests: 'Requests',
tokens: 'Tokens',
actual: 'Actual',
standard: 'Standard',
noDataAvailable: 'No data available',
recentUsage: 'Recent Usage',
failedToLoad: 'Failed to load dashboard statistics'
},
// Users
users: {
title: 'User Management',
description: 'Manage users and their permissions',
createUser: 'Create User',
editUser: 'Edit User',
deleteUser: 'Delete User',
searchUsers: 'Search users...',
allRoles: 'All Roles',
allStatus: 'All Status',
admin: 'Admin',
user: 'User',
disabled: 'Disabled',
email: 'Email',
password: 'Password',
username: 'Username',
wechat: 'WeChat ID',
notes: 'Notes',
enterEmail: 'Enter email',
enterPassword: 'Enter password',
enterUsername: 'Enter username (optional)',
enterWechat: 'Enter WeChat ID (optional)',
enterNotes: 'Enter notes (admin only)',
notesHint: 'This note is only visible to administrators',
enterNewPassword: 'Enter new password (optional)',
leaveEmptyToKeep: 'Leave empty to keep current password',
generatePassword: 'Generate random password',
copyPassword: 'Copy password',
creating: 'Creating...',
updating: 'Updating...',
columns: {
user: 'User',
username: 'Username',
wechat: 'WeChat ID',
notes: 'Notes',
role: 'Role',
subscriptions: 'Subscriptions',
balance: 'Balance',
usage: 'Usage',
concurrency: 'Concurrency',
status: 'Status',
created: 'Created',
actions: 'Actions'
},
today: 'Today',
total: 'Total',
noSubscription: 'No subscription',
daysRemaining: '{days}d',
expired: 'Expired',
disable: 'Disable',
enable: 'Enable',
disableUser: 'Disable User',
enableUser: 'Enable User',
viewApiKeys: 'View API Keys',
groups: 'Groups',
apiKeys: 'API Keys',
userApiKeys: 'User API Keys',
noApiKeys: 'This user has no API keys',
group: 'Group',
none: 'None',
noUsersYet: 'No users yet',
createFirstUser: 'Create your first user to get started.',
userCreated: 'User created successfully',
userUpdated: 'User updated successfully',
userDeleted: 'User deleted successfully',
userEnabled: 'User enabled successfully',
userDisabled: 'User disabled successfully',
failedToLoad: 'Failed to load users',
failedToCreate: 'Failed to create user',
failedToUpdate: 'Failed to update user',
failedToDelete: 'Failed to delete user',
failedToToggle: 'Failed to update user status',
failedToLoadApiKeys: 'Failed to load user API keys',
deleteConfirm: "Are you sure you want to delete '{email}'? This action cannot be undone.",
setAllowedGroups: 'Set Allowed Groups',
allowedGroupsHint:
'Select which standard groups this user can use. Subscription groups are managed separately.',
noStandardGroups: 'No standard groups available',
allowAllGroups: 'Allow All Groups',
allowAllGroupsHint: 'User can use any non-exclusive group',
allowedGroupsUpdated: 'Allowed groups updated successfully',
failedToLoadGroups: 'Failed to load groups',
failedToUpdateAllowedGroups: 'Failed to update allowed groups',
deposit: 'Deposit',
withdraw: 'Withdraw',
depositAmount: 'Deposit Amount',
withdrawAmount: 'Withdraw Amount',
currentBalance: 'Current Balance',
depositNotesPlaceholder:
'e.g., New user registration bonus, promotional credit, compensation, etc.',
withdrawNotesPlaceholder:
'e.g., Service issue refund, incorrect charge reversal, account closure refund, etc.',
notesOptional: 'Notes are optional but helpful for record keeping',
amountHint: 'Please enter a positive amount',
newBalance: 'New Balance',
depositing: 'Depositing...',
withdrawing: 'Withdrawing...',
confirmDeposit: 'Confirm Deposit',
confirmWithdraw: 'Confirm Withdraw',
depositSuccess: 'Deposit successful',
withdrawSuccess: 'Withdraw successful',
failedToDeposit: 'Failed to deposit',
failedToWithdraw: 'Failed to withdraw',
useDepositWithdrawButtons: 'Please use deposit/withdraw buttons to adjust balance',
insufficientBalance: 'Insufficient balance, balance cannot be negative after withdrawal'
},
// Groups
groups: {
title: 'Group Management',
description: 'Manage API key groups and rate multipliers',
createGroup: 'Create Group',
editGroup: 'Edit Group',
deleteGroup: 'Delete Group',
allPlatforms: 'All Platforms',
allStatus: 'All Status',
allGroups: 'All Groups',
exclusive: 'Exclusive',
nonExclusive: 'Non-Exclusive',
public: 'Public',
columns: {
name: 'Name',
platform: 'Platform',
rateMultiplier: 'Rate Multiplier',
type: 'Type',
accounts: 'Accounts',
status: 'Status',
actions: 'Actions',
billingType: 'Billing Type'
},
rateAndAccounts: '{rate}x rate · {count} accounts',
accountsCount: '{count} accounts',
form: {
name: 'Name',
description: 'Description',
platform: 'Platform',
rateMultiplier: 'Rate Multiplier',
status: 'Status',
exclusive: 'Exclusive Group'
},
enterGroupName: 'Enter group name',
optionalDescription: 'Optional description',
platformHint: 'Select the platform this group is associated with',
platformNotEditable: 'Platform cannot be changed after creation',
rateMultiplierHint: 'Cost multiplier for this group (e.g., 1.5 = 150% of base cost)',
exclusiveHint: 'Exclusive group, manually assign to specific users',
exclusiveTooltip: {
title: 'What is an exclusive group?',
description: 'When enabled, users cannot see this group when creating API Keys. Only after an admin manually assigns a user to this group can they use it.',
example: 'Use case:',
exampleContent: 'Public group rate is 0.8. Create an exclusive group with 0.7 rate, manually assign VIP users to give them better pricing.'
},
noGroupsYet: 'No groups yet',
createFirstGroup: 'Create your first group to organize API keys.',
creating: 'Creating...',
updating: 'Updating...',
limitDay: 'd',
limitWeek: 'w',
limitMonth: 'mo',
groupCreated: 'Group created successfully',
groupUpdated: 'Group updated successfully',
groupDeleted: 'Group deleted successfully',
failedToLoad: 'Failed to load groups',
failedToCreate: 'Failed to create group',
failedToUpdate: 'Failed to update group',
failedToDelete: 'Failed to delete group',
deleteConfirm:
"Are you sure you want to delete '{name}'? All associated API keys will no longer belong to any group.",
deleteConfirmSubscription:
"Are you sure you want to delete subscription group '{name}'? This will invalidate all API keys bound to this subscription and delete all related subscription records. This action cannot be undone.",
subscription: {
title: 'Subscription Settings',
type: 'Billing Type',
typeHint:
'Standard billing deducts from user balance. Subscription mode uses quota limits instead.',
typeNotEditable: 'Billing type cannot be changed after group creation.',
standard: 'Standard (Balance)',
subscription: 'Subscription (Quota)',
dailyLimit: 'Daily Limit (USD)',
weeklyLimit: 'Weekly Limit (USD)',
monthlyLimit: 'Monthly Limit (USD)',
defaultValidityDays: 'Default Validity (Days)',
validityHint: 'Number of days the subscription is valid when assigned to a user',
noLimit: 'No limit'
}
},
// Subscriptions
subscriptions: {
title: 'Subscription Management',
description: 'Manage user subscriptions and quota limits',
assignSubscription: 'Assign Subscription',
extendSubscription: 'Extend Subscription',
revokeSubscription: 'Revoke Subscription',
allStatus: 'All Status',
allGroups: 'All Groups',
daily: 'Daily',
weekly: 'Weekly',
monthly: 'Monthly',
noLimits: 'No limits configured',
resetNow: 'Resetting soon',
windowNotActive: 'Window not active',
resetInMinutes: 'Resets in {minutes}m',
resetInHoursMinutes: 'Resets in {hours}h {minutes}m',
resetInDaysHours: 'Resets in {days}d {hours}h',
daysRemaining: 'days remaining',
noExpiration: 'No expiration',
status: {
active: 'Active',
expired: 'Expired',
revoked: 'Revoked'
},
columns: {
user: 'User',
group: 'Group',
usage: 'Usage',
expires: 'Expires',
status: 'Status',
actions: 'Actions'
},
form: {
user: 'User',
group: 'Subscription Group',
validityDays: 'Validity (Days)',
extendDays: 'Extend by (Days)'
},
selectUser: 'Select a user',
selectGroup: 'Select a subscription group',
groupHint: 'Only groups with subscription billing type are shown',
validityHint: 'Number of days the subscription will be valid',
extendingFor: 'Extending subscription for',
currentExpiration: 'Current expiration',
assign: 'Assign',
assigning: 'Assigning...',
extend: 'Extend',
extending: 'Extending...',
revoke: 'Revoke',
noSubscriptionsYet: 'No subscriptions yet',
assignFirstSubscription: 'Assign a subscription to get started.',
subscriptionAssigned: 'Subscription assigned successfully',
subscriptionExtended: 'Subscription extended successfully',
subscriptionRevoked: 'Subscription revoked successfully',
failedToLoad: 'Failed to load subscriptions',
failedToAssign: 'Failed to assign subscription',
failedToExtend: 'Failed to extend subscription',
failedToRevoke: 'Failed to revoke subscription',
revokeConfirm:
"Are you sure you want to revoke the subscription for '{user}'? This action cannot be undone."
},
// Accounts
accounts: {
title: 'Account Management',
description: 'Manage AI platform accounts and credentials',
createAccount: 'Create Account',
syncFromCrs: 'Sync from CRS',
syncFromCrsTitle: 'Sync Accounts from CRS',
syncFromCrsDesc:
'Sync accounts from claude-relay-service (CRS) into this system (CRS is called server-to-server).',
crsVersionRequirement: '⚠️ Note: CRS version must be ≥ v1.1.240 to support this feature',
crsBaseUrl: 'CRS Base URL',
crsBaseUrlPlaceholder: 'e.g. http://127.0.0.1:3000',
crsUsername: 'Username',
crsPassword: 'Password',
syncProxies: 'Also sync proxies (match by host/port/auth or create)',
syncNow: 'Sync Now',
syncing: 'Syncing...',
syncMissingFields: 'Please fill base URL, username and password',
syncResult: 'Sync Result',
syncResultSummary: 'Created {created}, updated {updated}, skipped {skipped}, failed {failed}',
syncErrors: 'Errors / Skipped Details',
syncCompleted: 'Sync completed: created {created}, updated {updated}',
syncCompletedWithErrors:
'Sync completed with errors: failed {failed} (created {created}, updated {updated})',
syncFailed: 'Sync failed',
editAccount: 'Edit Account',
deleteAccount: 'Delete Account',
searchAccounts: 'Search accounts...',
allPlatforms: 'All Platforms',
allTypes: 'All Types',
allStatus: 'All Status',
oauthType: 'OAuth',
setupToken: 'Setup Token',
apiKey: 'API Key',
// Schedulable toggle
schedulable: 'Schedulable',
schedulableHint: 'Enable to include this account in API request scheduling',
schedulableEnabled: 'Scheduling enabled',
schedulableDisabled: 'Scheduling disabled',
failedToToggleSchedulable: 'Failed to toggle scheduling status',
platforms: {
anthropic: 'Anthropic',
claude: 'Claude',
openai: 'OpenAI',
gemini: 'Gemini',
antigravity: 'Antigravity'
},
types: {
oauth: 'OAuth',
chatgptOauth: 'ChatGPT OAuth',
responsesApi: 'Responses API',
googleOauth: 'Google OAuth',
codeAssist: 'Code Assist',
antigravityOauth: 'Antigravity OAuth'
},
columns: {
name: 'Name',
platformType: 'Platform/Type',
platform: 'Platform',
type: 'Type',
concurrencyStatus: 'Concurrency',
status: 'Status',
schedulable: 'Schedule',
todayStats: "Today's Stats",
groups: 'Groups',
usageWindows: 'Usage Windows',
priority: 'Priority',
lastUsed: 'Last Used',
actions: 'Actions'
},
clearRateLimit: 'Clear Rate Limit',
testConnection: 'Test Connection',
reAuthorize: 'Re-Authorize',
refreshToken: 'Refresh Token',
noAccountsYet: 'No accounts yet',
createFirstAccount: 'Create your first account to start using AI services.',
tokenRefreshed: 'Token refreshed successfully',
accountDeleted: 'Account deleted successfully',
rateLimitCleared: 'Rate limit cleared successfully',
bulkActions: {
selected: '{count} account(s) selected',
selectCurrentPage: 'Select this page',
clear: 'Clear selection',
edit: 'Bulk Edit',
delete: 'Bulk Delete'
},
bulkEdit: {
title: 'Bulk Edit Accounts',
selectionInfo:
'{count} account(s) selected. Only checked or filled fields will be updated; others stay unchanged.',
baseUrlPlaceholder: 'https://api.anthropic.com or https://api.openai.com',
baseUrlNotice: 'Applies to API Key accounts only; leave empty to keep existing value',
submit: 'Update Accounts',
updating: 'Updating...',
success: 'Updated {count} account(s)',
partialSuccess: 'Partially updated: {success} succeeded, {failed} failed',
failed: 'Bulk update failed',
noSelection: 'Please select accounts to edit',
noFieldsSelected: 'Select at least one field to update'
},
bulkDeleteTitle: 'Bulk Delete Accounts',
bulkDeleteConfirm: 'Delete the selected {count} account(s)? This action cannot be undone.',
bulkDeleteSuccess: 'Deleted {count} account(s)',
bulkDeletePartial: 'Partially deleted: {success} succeeded, {failed} failed',
bulkDeleteFailed: 'Bulk delete failed',
resetStatus: 'Reset Status',
statusReset: 'Account status reset successfully',
failedToResetStatus: 'Failed to reset account status',
failedToLoad: 'Failed to load accounts',
failedToRefresh: 'Failed to refresh token',
failedToDelete: 'Failed to delete account',
failedToClearRateLimit: 'Failed to clear rate limit',
deleteConfirm: "Are you sure you want to delete '{name}'? This action cannot be undone.",
// Create/Edit Account Modal
platform: 'Platform',
accountName: 'Account Name',
enterAccountName: 'Enter account name',
accountType: 'Account Type',
claudeCode: 'Claude Code',
claudeConsole: 'Claude Console',
oauthSetupToken: 'OAuth / Setup Token',
addMethod: 'Add Method',
setupTokenLongLived: 'Setup Token (Long-lived)',
baseUrl: 'Base URL',
baseUrlHint: 'Leave default for official Anthropic API',
apiKeyRequired: 'API Key *',
apiKeyPlaceholder: 'sk-ant-api03-...',
apiKeyHint: 'Your Claude Console API Key',
// OpenAI specific hints
openai: {
baseUrlHint: 'Leave default for official OpenAI API',
apiKeyHint: 'Your OpenAI API Key'
},
modelRestriction: 'Model Restriction (Optional)',
modelWhitelist: 'Model Whitelist',
modelMapping: 'Model Mapping',
selectAllowedModels: 'Select allowed models. Leave empty to support all models.',
mapRequestModels:
'Map request models to actual models. Left is the requested model, right is the actual model sent to API.',
selectedModels: 'Selected {count} model(s)',
supportsAllModels: '(supports all models)',
requestModel: 'Request model',
actualModel: 'Actual model',
addMapping: 'Add Mapping',
mappingExists: 'Mapping for {model} already exists',
customErrorCodes: 'Custom Error Codes',
customErrorCodesHint: 'Only stop scheduling for selected error codes',
customErrorCodesWarning:
'Only selected error codes will stop scheduling. Other errors will return 500.',
selectedErrorCodes: 'Selected',
noneSelectedUsesDefault: 'None selected (uses default policy)',
enterErrorCode: 'Enter error code (100-599)',
invalidErrorCode: 'Please enter a valid HTTP error code (100-599)',
errorCodeExists: 'This error code is already selected',
interceptWarmupRequests: 'Intercept Warmup Requests',
interceptWarmupRequestsDesc:
'When enabled, warmup requests like title generation will return mock responses without consuming upstream tokens',
proxy: 'Proxy',
noProxy: 'No Proxy',
concurrency: 'Concurrency',
priority: 'Priority',
priorityHint: 'Higher priority accounts are used first',
higherPriorityFirst: 'Higher value means higher priority',
mixedScheduling: 'Mixed Scheduling',
mixedSchedulingHint: 'Enable to participate in Anthropic/Gemini group scheduling',
mixedSchedulingTooltip:
'When enabled, this account can be scheduled by /v1/messages and /v1beta endpoints. Otherwise, it will only be scheduled by /antigravity. Note: Anthropic Claude and Antigravity Claude cannot be mixed in the same context. Please manage groups carefully when enabled.',
creating: 'Creating...',
updating: 'Updating...',
accountCreated: 'Account created successfully',
accountUpdated: 'Account updated successfully',
failedToCreate: 'Failed to create account',
failedToUpdate: 'Failed to update account',
pleaseEnterAccountName: 'Please enter account name',
pleaseEnterApiKey: 'Please enter API Key',
apiKeyIsRequired: 'API Key is required',
leaveEmptyToKeep: 'Leave empty to keep current key',
// OAuth flow
oauth: {
title: 'Claude Account Authorization',
authMethod: 'Authorization Method',
manualAuth: 'Manual Authorization',
cookieAutoAuth: 'Cookie Auto-Auth',
cookieAutoAuthDesc:
'Use claude.ai sessionKey to automatically complete OAuth authorization without manually opening browser.',
sessionKey: 'sessionKey',
keysCount: '{count} keys',
batchCreateAccounts: 'Will batch create {count} accounts',
sessionKeyPlaceholder:
'One sessionKey per line, e.g.:\nsk-ant-sid01-xxxxx...\nsk-ant-sid01-yyyyy...',
sessionKeyPlaceholderSingle: 'sk-ant-sid01-xxxxx...',
howToGetSessionKey: 'How to get sessionKey',
step1: 'Login to <strong>claude.ai</strong> in your browser',
step2: 'Press <kbd>F12</kbd> to open Developer Tools',
step3: 'Go to <strong>Application</strong> tab',
step4: 'Find <strong>Cookies</strong> → <strong>https://claude.ai</strong>',
step5: 'Find the row with key <strong>sessionKey</strong>',
step6: 'Copy the <strong>Value</strong>',
sessionKeyFormat: 'sessionKey usually starts with <code>sk-ant-sid01-</code>',
startAutoAuth: 'Start Auto-Auth',
authorizing: 'Authorizing...',
followSteps: 'Follow these steps to authorize your Claude account:',
step1GenerateUrl: 'Click the button below to generate the authorization URL',
generateAuthUrl: 'Generate Auth URL',
generating: 'Generating...',
regenerate: 'Regenerate',
step2OpenUrl: 'Open the URL in your browser and complete authorization',
openUrlDesc:
'Open the authorization URL in a new tab, log in to your Claude account and authorize.',
proxyWarning:
'<strong>Note:</strong> If you configured a proxy, make sure your browser uses the same proxy to access the authorization page.',
step3EnterCode: 'Enter the Authorization Code',
authCodeDesc:
'After authorization is complete, the page will display an <strong>Authorization Code</strong>. Copy and paste it below:',
authCode: 'Authorization Code',
authCodePlaceholder: 'Paste the Authorization Code from Claude page...',
authCodeHint: 'Paste the Authorization Code copied from the Claude page',
completeAuth: 'Complete Authorization',
verifying: 'Verifying...',
pleaseEnterSessionKey: 'Please enter at least one valid sessionKey',
authFailed: 'Authorization failed',
cookieAuthFailed: 'Cookie authorization failed',
keyAuthFailed: 'Key {index}: {error}',
successCreated: 'Successfully created {count} account(s)',
// OpenAI specific
openai: {
title: 'OpenAI Account Authorization',
followSteps: 'Follow these steps to complete OpenAI account authorization:',
step1GenerateUrl: 'Click the button below to generate the authorization URL',
generateAuthUrl: 'Generate Auth URL',
step2OpenUrl: 'Open the URL in your browser and complete authorization',
openUrlDesc:
'Open the authorization URL in a new tab, log in to your OpenAI account and authorize.',
importantNotice:
'<strong>Important:</strong> The page may take a while to load after authorization. Please wait patiently. When the browser address bar changes to <code>http://localhost...</code>, the authorization is complete.',
step3EnterCode: 'Enter Authorization URL or Code',
authCodeDesc:
'After authorization is complete, when the page URL becomes <code>http://localhost:xxx/auth/callback?code=...</code>:',
authCode: 'Authorization URL or Code',
authCodePlaceholder:
'Option 1: Copy the complete URL\n(http://localhost:xxx/auth/callback?code=...)\nOption 2: Copy only the code parameter value',
authCodeHint:
'You can copy the entire URL or just the code parameter value, the system will auto-detect'
},
// Gemini specific
gemini: {
title: 'Gemini Account Authorization',
followSteps: 'Follow these steps to authorize your Gemini account:',
step1GenerateUrl: 'Generate the authorization URL',
generateAuthUrl: 'Generate Auth URL',
projectIdLabel: 'Project ID (optional)',
projectIdPlaceholder: 'e.g. my-gcp-project or cloud-ai-companion-xxxxx',
projectIdHint:
'Leave empty to auto-detect after code exchange. If auto-detection fails, fill it in and re-generate the auth URL to try again.',
howToGetProjectId: 'How to get',
step2OpenUrl: 'Open the URL in your browser and complete authorization',
openUrlDesc:
'Open the authorization URL in a new tab, log in to your Google account and authorize.',
step3EnterCode: 'Enter Authorization URL or Code',
authCodeDesc:
'After authorization, copy the callback URL (recommended) or just the <code>code</code> and paste it below.',
authCode: 'Callback URL or Code',
authCodePlaceholder:
'Option 1 (recommended): Paste the callback URL\nOption 2: Paste only the code value',
authCodeHint: 'The system will auto-extract code/state from the URL.',
redirectUri: 'Redirect URI',
redirectUriHint:
'This must be configured in your Google OAuth client and must match exactly.',
confirmRedirectUri:
'I have configured this Redirect URI in the Google OAuth client (must match exactly)',
invalidRedirectUri: 'Redirect URI must be a valid http(s) URL',
redirectUriNotConfirmed: 'Please confirm the Redirect URI is configured correctly',
missingRedirectUri: 'Missing redirect URI',
failedToGenerateUrl: 'Failed to generate Gemini auth URL',
missingExchangeParams: 'Missing auth code, session ID, or state',
failedToExchangeCode: 'Failed to exchange Gemini auth code',
modelPassthrough: 'Gemini Model Passthrough',
modelPassthroughDesc:
'All model requests are forwarded directly to the Gemini API without model restrictions or mappings.',
stateWarningTitle: 'Note',
stateWarningDesc: 'Recommended: paste the full callback URL (includes code & state).',
oauthTypeLabel: 'OAuth Type',
needsProjectId: 'For GCP Developers',
needsProjectIdDesc: 'Requires GCP project',
noProjectIdNeeded: 'For Regular Users',
noProjectIdNeededDesc: 'Requires admin-configured OAuth client',
aiStudioNotConfiguredShort: 'Not configured',
aiStudioNotConfiguredTip:
'AI Studio OAuth is not configured: set GEMINI_OAUTH_CLIENT_ID / GEMINI_OAUTH_CLIENT_SECRET and add Redirect URI: http://localhost:1455/auth/callback (Consent screen scopes must include https://www.googleapis.com/auth/generative-language.retriever)',
aiStudioNotConfigured:
'AI Studio OAuth is not configured: set GEMINI_OAUTH_CLIENT_ID / GEMINI_OAUTH_CLIENT_SECRET and add Redirect URI: http://localhost:1455/auth/callback'
},
// Antigravity specific
antigravity: {
title: 'Antigravity Account Authorization',
followSteps: 'Follow these steps to authorize your Antigravity account:',
step1GenerateUrl: 'Generate the authorization URL',
generateAuthUrl: 'Generate Auth URL',
step2OpenUrl: 'Open the URL in your browser and complete authorization',
openUrlDesc: 'Open the authorization URL in a new tab, log in to your Google account and authorize.',
importantNotice:
'<strong>Important:</strong> The page may take a while to load after authorization. Please wait patiently. When the browser address bar shows <code>http://localhost...</code>, authorization is complete.',
step3EnterCode: 'Enter Authorization URL or Code',
authCodeDesc:
'After authorization, when the page URL becomes <code>http://localhost:xxx/auth/callback?code=...</code>:',
authCode: 'Authorization URL or Code',
authCodePlaceholder:
'Option 1: Copy the complete URL\n(http://localhost:xxx/auth/callback?code=...)\nOption 2: Copy only the code parameter value',
authCodeHint: 'You can copy the entire URL or just the code parameter value, the system will auto-detect',
failedToGenerateUrl: 'Failed to generate Antigravity auth URL',
missingExchangeParams: 'Missing code, session ID, or state',
failedToExchangeCode: 'Failed to exchange Antigravity auth code'
}
},
// Gemini specific (platform-wide)
gemini: {
modelPassthrough: 'Gemini Model Passthrough',
modelPassthroughDesc:
'All model requests are forwarded directly to the Gemini API without model restrictions or mappings.',
baseUrlHint: 'Leave default for official Gemini API',
apiKeyHint: 'Your Gemini API Key (starts with AIza)'
},
// Re-Auth Modal
reAuthorizeAccount: 'Re-Authorize Account',
claudeCodeAccount: 'Claude Code Account',
openaiAccount: 'OpenAI Account',
geminiAccount: 'Gemini Account',
antigravityAccount: 'Antigravity Account',
inputMethod: 'Input Method',
reAuthorizedSuccess: 'Account re-authorized successfully',
// Test Modal
testAccountConnection: 'Test Account Connection',
account: 'Account',
readyToTest: 'Ready to test. Click "Start Test" to begin...',
connectingToApi: 'Connecting to API...',
testCompleted: 'Test completed successfully!',
testFailed: 'Test failed',
connectedToApi: 'Connected to API',
usingModel: 'Using model: {model}',
sendingTestMessage: 'Sending test message: "hi"',
response: 'Response:',
startTest: 'Start Test',
testing: 'Testing...',
retry: 'Retry',
copyOutput: 'Copy output',
startingTestForAccount: 'Starting test for account: {name}',
testAccountTypeLabel: 'Account type: {type}',
selectTestModel: 'Select Test Model',
testModel: 'Test model',
testPrompt: 'Prompt: "hi"',
// Stats Modal
viewStats: 'View Stats',
usageStatistics: 'Usage Statistics',
last30DaysUsage: 'Last 30 days usage statistics (based on actual usage days)',
stats: {
totalCost: '30-Day Total Cost',
accumulatedCost: 'Accumulated cost',
standardCost: 'Standard',
totalRequests: '30-Day Total Requests',
totalCalls: 'Total API calls',
avgDailyCost: 'Daily Avg Cost',
basedOnActualDays: 'Based on {days} actual usage days',
avgDailyRequests: 'Daily Avg Requests',
avgDailyUsage: 'Average daily usage',
todayOverview: 'Today Overview',
cost: 'Cost',
requests: 'Requests',
tokens: 'Tokens',
highestCostDay: 'Highest Cost Day',
highestRequestDay: 'Highest Request Day',
date: 'Date',
accumulatedTokens: 'Accumulated Tokens',
totalTokens: '30-Day Total',
dailyAvgTokens: 'Daily Average',
performance: 'Performance',
avgResponseTime: 'Avg Response',
daysActive: 'Days Active',
recentActivity: 'Recent Activity',
todayRequests: 'Today Requests',
todayTokens: 'Today Tokens',
todayCost: 'Today Cost',
usageTrend: '30-Day Cost & Request Trend',
noData: 'No usage data available for this account'
},
usageWindow: {
statsTitle: '5-Hour Window Usage Statistics',
gemini3Pro: 'G3P',
gemini3Flash: 'G3F',
gemini3Image: 'G3I',
claude45: 'C4.5'
},
tier: {
free: 'Free',
pro: 'Pro',
ultra: 'Ultra'
}
},
// Proxies
proxies: {
title: 'Proxy Management',
description: 'Manage proxy servers for accounts',
createProxy: 'Create Proxy',
editProxy: 'Edit Proxy',
deleteProxy: 'Delete Proxy',
searchProxies: 'Search proxies...',
allProtocols: 'All Protocols',
allStatus: 'All Status',
columns: {
name: 'Name',
protocol: 'Protocol',
address: 'Address',
status: 'Status',
actions: 'Actions'
},
testConnection: 'Test Connection',
batchTest: 'Test All Proxies',
testFailed: 'Failed',
name: 'Name',
protocol: 'Protocol',
host: 'Host',
port: 'Port',
username: 'Username (Optional)',
password: 'Password (Optional)',
status: 'Status',
enterProxyName: 'Enter proxy name',
leaveEmptyToKeep: 'Leave empty to keep current',
optionalAuth: 'Optional authentication',
form: {
hostPlaceholder: 'proxy.example.com',
portPlaceholder: '8080'
},
noProxiesYet: 'No proxies yet',
createFirstProxy: 'Create your first proxy to route traffic through it.',
// Batch import
standardAdd: 'Standard Add',
batchAdd: 'Quick Add',
batchInput: 'Proxy List',
batchInputPlaceholder:
"Enter one proxy per line in the following formats:\nsocks5://user:pass{'@'}192.168.1.1:1080\nhttp://192.168.1.1:8080\nhttps://user:pass{'@'}proxy.example.com:443",
batchInputHint:
"Supports http, https, socks5 protocols. Format: protocol://[user:pass{'@'}]host:port",
parsedCount: '{count} valid',
invalidCount: '{count} invalid',
duplicateCount: '{count} duplicate',
importing: 'Importing...',
importProxies: 'Import {count} proxies',
batchImportSuccess: 'Successfully imported {created} proxies, skipped {skipped} duplicates',
batchImportAllSkipped: 'All {skipped} proxies already exist, skipped import',
failedToImport: 'Failed to batch import',
// Other messages
creating: 'Creating...',
updating: 'Updating...',
proxyCreated: 'Proxy created successfully',
proxyUpdated: 'Proxy updated successfully',
proxyDeleted: 'Proxy deleted successfully',
proxyWorking: 'Proxy is working!',
proxyWorkingWithLatency: 'Proxy is working! Latency: {latency}ms',
proxyTestFailed: 'Proxy test failed',
failedToLoad: 'Failed to load proxies',
failedToCreate: 'Failed to create proxy',
failedToUpdate: 'Failed to update proxy',
failedToDelete: 'Failed to delete proxy',
failedToTest: 'Failed to test proxy',
deleteConfirm:
"Are you sure you want to delete '{name}'? Accounts using this proxy will have their proxy removed."
},
// Redeem Codes
redeem: {
title: 'Redeem Code Management',
description: 'Generate and manage redeem codes',
generateCodes: 'Generate Codes',
searchCodes: 'Search codes...',
allTypes: 'All Types',
allStatus: 'All Status',
balance: 'Balance',
concurrency: 'Concurrency',
subscription: 'Subscription',
unused: 'Unused',
used: 'Used',
columns: {
code: 'Code',
type: 'Type',
value: 'Value',
status: 'Status',
usedBy: 'Used By',
usedAt: 'Used At',
actions: 'Actions'
},
userPrefix: 'User #{id}',
exportCsv: 'Export CSV',
deleteAllUnused: 'Delete All Unused Codes',
deleteCode: 'Delete Redeem Code',
deleteCodeConfirm:
'Are you sure you want to delete this redeem code? This action cannot be undone.',
deleteAllUnusedConfirm:
'Are you sure you want to delete all unused (active) redeem codes? This action cannot be undone.',
deleteAll: 'Delete All',
generateCodesTitle: 'Generate Redeem Codes',
generatedSuccessfully: 'Generated Successfully',
codesCreated: '{count} redeem code(s) created',
codeType: 'Code Type',
amount: 'Amount ($)',
value: 'Value',
count: 'Count',
generating: 'Generating...',
generate: 'Generate',
copyAll: 'Copy All',
copied: 'Copied!',
download: 'Download',
codesExported: 'Codes exported successfully',
codeDeleted: 'Redeem code deleted successfully',
codesDeleted: 'Successfully deleted {count} unused code(s)',
noUnusedCodes: 'No unused codes to delete',
failedToLoad: 'Failed to load redeem codes',
failedToGenerate: 'Failed to generate codes',
failedToExport: 'Failed to export codes',
failedToDelete: 'Failed to delete code',
failedToDeleteUnused: 'Failed to delete unused codes',
failedToCopy: 'Failed to copy codes',
selectGroup: 'Select Group',
selectGroupPlaceholder: 'Choose a subscription group',
validityDays: 'Validity Days',
groupRequired: 'Please select a subscription group',
days: ' days'
},
// Usage Records
usage: {
title: 'Usage Records',
description: 'View and manage all user usage records',
userFilter: 'User',
searchUserPlaceholder: 'Search user by email...',
selectedUser: 'Selected',
user: 'User',
account: 'Account',
group: 'Group',
requestId: 'Request ID',
requestIdCopied: 'Request ID copied',
allModels: 'All Models',
allAccounts: 'All Accounts',
allGroups: 'All Groups',
allTypes: 'All Types',
allBillingTypes: 'All Billing',
inputCost: 'Input Cost',
outputCost: 'Output Cost',
cacheCreationCost: 'Cache Creation Cost',
cacheReadCost: 'Cache Read Cost',
inputTokens: 'Input Tokens',
outputTokens: 'Output Tokens',
cacheCreationTokens: 'Cache Creation Tokens',
cacheReadTokens: 'Cache Read Tokens',
failedToLoad: 'Failed to load usage records'
},
// Settings
settings: {
title: 'System Settings',
description: 'Manage registration, email verification, default values, and SMTP settings',
registration: {
title: 'Registration Settings',
description: 'Control user registration and verification',
enableRegistration: 'Enable Registration',
enableRegistrationHint: 'Allow new users to register',
emailVerification: 'Email Verification',
emailVerificationHint: 'Require email verification for new registrations'
},
turnstile: {
title: 'Cloudflare Turnstile',
description: 'Bot protection for login and registration',
enableTurnstile: 'Enable Turnstile',
enableTurnstileHint: 'Require Cloudflare Turnstile verification',
siteKey: 'Site Key',
secretKey: 'Secret Key',
siteKeyHint: 'Get this from your Cloudflare Dashboard',
secretKeyHint: 'Server-side verification key (keep this secret)'
},
defaults: {
title: 'Default User Settings',
description: 'Default values for new users',
defaultBalance: 'Default Balance',
defaultBalanceHint: 'Initial balance for new users',
defaultConcurrency: 'Default Concurrency',
defaultConcurrencyHint: 'Maximum concurrent requests for new users'
},
site: {
title: 'Site Settings',
description: 'Customize site branding',
siteName: 'Site Name',
siteNamePlaceholder: 'Sub2API',
siteNameHint: 'Displayed in emails and page titles',
siteSubtitle: 'Site Subtitle',
siteSubtitlePlaceholder: 'Subscription to API Conversion Platform',
siteSubtitleHint: 'Displayed on login and register pages',
apiBaseUrl: 'API Base URL',
apiBaseUrlPlaceholder: 'https://api.example.com',
apiBaseUrlHint:
'Used for "Use Key" and "Import to CC Switch" features. Leave empty to use current site URL.',
contactInfo: 'Contact Info',
contactInfoPlaceholder: 'e.g., QQ: 123456789',
contactInfoHint: 'Customer support contact info, displayed on redeem page, profile, etc.',
docUrl: 'Documentation URL',
docUrlPlaceholder: 'https://docs.example.com',
docUrlHint: 'Link to your documentation site. Leave empty to hide the documentation link.',
siteLogo: 'Site Logo',
uploadImage: 'Upload Image',
remove: 'Remove',
logoHint: 'PNG, JPG, or SVG. Max 300KB. Recommended: 80x80px square image.',
logoSizeError: 'Image size exceeds 300KB limit ({size}KB)',
logoTypeError: 'Please select an image file',
logoReadError: 'Failed to read the image file'
},
smtp: {
title: 'SMTP Settings',
description: 'Configure email sending for verification codes',
testConnection: 'Test Connection',
testing: 'Testing...',
host: 'SMTP Host',
hostPlaceholder: 'smtp.gmail.com',
port: 'SMTP Port',
portPlaceholder: '587',
username: 'SMTP Username',
usernamePlaceholder: "your-email{'@'}gmail.com",
password: 'SMTP Password',
passwordPlaceholder: '********',
passwordHint: 'Leave empty to keep existing password',
fromEmail: 'From Email',
fromEmailPlaceholder: "noreply{'@'}example.com",
fromName: 'From Name',
fromNamePlaceholder: 'Sub2API',
useTls: 'Use TLS',
useTlsHint: 'Enable TLS encryption for SMTP connection'
},
testEmail: {
title: 'Send Test Email',
description: 'Send a test email to verify your SMTP configuration',
recipientEmail: 'Recipient Email',
recipientEmailPlaceholder: "test{'@'}example.com",
sendTestEmail: 'Send Test Email',
sending: 'Sending...',
enterRecipientHint: 'Please enter a recipient email address'
},
adminApiKey: {
title: 'Admin API Key',
description: 'Global API key for external system integration with full admin access',
notConfigured: 'Admin API key not configured',
configured: 'Admin API key is active',
currentKey: 'Current Key',
regenerate: 'Regenerate',
regenerating: 'Regenerating...',
delete: 'Delete',
deleting: 'Deleting...',
create: 'Create Key',
creating: 'Creating...',
regenerateConfirm: 'Are you sure? The current key will be immediately invalidated.',
deleteConfirm:
'Are you sure you want to delete the admin API key? External integrations will stop working.',
keyGenerated: 'New admin API key generated',
keyDeleted: 'Admin API key deleted',
copyKey: 'Copy Key',
keyCopied: 'Key copied to clipboard',
keyWarning: 'This key will only be shown once. Please copy it now.',
securityWarning: 'Warning: This key provides full admin access. Keep it secure.',
usage: 'Usage: Add to request header - x-api-key: <your-admin-api-key>'
},
saveSettings: 'Save Settings',
saving: 'Saving...',
settingsSaved: 'Settings saved successfully',
smtpConnectionSuccess: 'SMTP connection successful',
testEmailSent: 'Test email sent successfully',
failedToLoad: 'Failed to load settings',
failedToSave: 'Failed to save settings',
failedToTestSmtp: 'SMTP connection test failed',
failedToSendTestEmail: 'Failed to send test email'
}
},
// Subscription Progress (Header component)
subscriptionProgress: {
title: 'My Subscriptions',
viewDetails: 'View subscription details',
activeCount: '{count} active subscription(s)',
daily: 'Daily',
weekly: 'Weekly',
monthly: 'Monthly',
daysRemaining: '{days} days left',
expired: 'Expired',
expiresToday: 'Expires today',
expiresTomorrow: 'Expires tomorrow',
viewAll: 'View all subscriptions',
noSubscriptions: 'No active subscriptions'
},
// Version Badge
version: {
currentVersion: 'Current Version',
latestVersion: 'Latest Version',
upToDate: "You're running the latest version.",
updateAvailable: 'A new version is available!',
releaseNotes: 'Release Notes',
noReleaseNotes: 'No release notes',
viewUpdate: 'View Update',
viewRelease: 'View Release',
viewChangelog: 'View Changelog',
refresh: 'Refresh',
sourceMode: 'Source Build',
sourceModeHint: 'Source build, use git pull to update',
updateNow: 'Update Now',
updating: 'Updating...',
updateComplete: 'Update Complete',
updateFailed: 'Update Failed',
restartRequired: 'Please restart the service to apply the update',
restartNow: 'Restart Now',
restarting: 'Restarting...',
retry: 'Retry'
},
// User Subscriptions Page
userSubscriptions: {
title: 'My Subscriptions',
description: 'View your subscription plans and usage',
noActiveSubscriptions: 'No Active Subscriptions',
noActiveSubscriptionsDesc:
"You don't have any active subscriptions. Contact administrator to get one.",
status: {
active: 'Active',
expired: 'Expired',
revoked: 'Revoked'
},
usage: 'Usage',
expires: 'Expires',
noExpiration: 'No expiration',
unlimited: 'Unlimited',
daily: 'Daily',
weekly: 'Weekly',
monthly: 'Monthly',
daysRemaining: '{days} days remaining',
expiresOn: 'Expires on {date}',
resetIn: 'Resets in {time}',
windowNotActive: 'Awaiting first use',
usageOf: '{used} of {limit}'
},
// Onboarding Tour
onboarding: {
restartTour: 'Restart Onboarding Tour',
dontShowAgain: "Don't show again",
dontShowAgainTitle: 'Permanently close onboarding guide',
confirmDontShow: "Are you sure you don't want to see the onboarding guide again?\n\nYou can restart it anytime from the user menu in the top right corner.",
confirmExit: 'Are you sure you want to exit the onboarding guide? You can restart it anytime from the top right menu.',
interactiveHint: 'Press Enter or Click to continue',
navigation: {
flipPage: 'Flip Page',
exit: 'Exit'
},
// Admin tour steps
admin: {
welcome: {
title: '👋 Welcome to Sub2API',
description: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">Sub2API is a powerful AI service gateway platform that helps you easily manage and distribute AI services.</p><p style="margin-bottom: 12px;"><b>🎯 Core Features:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>📦 <b>Group Management</b> - Create service tiers (VIP, Free Trial, etc.)</li><li>🔗 <b>Account Pool</b> - Connect multiple upstream AI service accounts</li><li>🔑 <b>Key Distribution</b> - Generate independent API Keys for users</li><li>💰 <b>Billing Control</b> - Flexible rate and quota management</li></ul><p style="color: #10b981; font-weight: 600;">Let\'s complete the initial setup in 3 minutes →</p></div>',
nextBtn: 'Start Setup 🚀',
prevBtn: 'Skip'
},
groupManage: {
title: '📦 Step 1: Group Management',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;"><b>What is a Group?</b></p><p style="margin-bottom: 12px;">Groups are the core concept of Sub2API, like a "service package":</p><ul style="margin-left: 20px; margin-bottom: 12px; font-size: 13px;"><li>🎯 Each group can contain multiple upstream accounts</li><li>💰 Each group has independent billing multiplier</li><li>👥 Can be set as public or exclusive</li></ul><p style="margin-top: 12px; padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Example:</b> You can create "VIP Premium" (high rate) and "Free Trial" (low rate) groups</p><p style="margin-top: 16px; color: #10b981; font-weight: 600;">👉 Click "Group Management" on the left sidebar</p></div>'
},
createGroup: {
title: ' Create New Group',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Let\'s create your first group.</p><p style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>📝 Tip:</b> Recommend creating a test group first to familiarize yourself with the process</p><p style="color: #10b981; font-weight: 600;">👉 Click the "Create Group" button</p></div>'
},
groupName: {
title: '✏️ 1. Group Name',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Give your group an easy-to-identify name.</p><div style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>💡 Naming Suggestions:</b><ul style="margin: 8px 0 0 16px;"><li>"Test Group" - For testing</li><li>"VIP Premium" - High-quality service</li><li>"Free Trial" - Trial version</li></ul></div><p style="font-size: 13px; color: #6b7280;">Click "Next" when done</p></div>',
nextBtn: 'Next'
},
groupPlatform: {
title: '🤖 2. Select Platform',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Choose the AI platform this group supports.</p><div style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>📌 Platform Guide:</b><ul style="margin: 8px 0 0 16px;"><li><b>Anthropic</b> - Claude models</li><li><b>OpenAI</b> - GPT models</li><li><b>Google</b> - Gemini models</li></ul></div><p style="font-size: 13px; color: #6b7280;">One group can only have one platform</p></div>',
nextBtn: 'Next'
},
groupMultiplier: {
title: '💰 3. Rate Multiplier',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Set the billing multiplier to control user charges.</p><div style="padding: 8px 12px; background: #fef3c7; border-left: 3px solid #f59e0b; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>⚙️ Billing Rules:</b><ul style="margin: 8px 0 0 16px;"><li><b>1.0</b> - Original price (cost price)</li><li><b>1.5</b> - User consumes $1, charged $1.5</li><li><b>2.0</b> - User consumes $1, charged $2</li><li><b>0.8</b> - Subsidy mode (loss-making)</li></ul></div><p style="font-size: 13px; color: #6b7280;">Recommend setting test group to 1.0</p></div>',
nextBtn: 'Next'
},
groupExclusive: {
title: '🔒 4. Exclusive Group (Optional)',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Control group visibility and access permissions.</p><div style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>🔐 Permission Guide:</b><ul style="margin: 8px 0 0 16px;"><li><b>Off</b> - Public group, visible to all users</li><li><b>On</b> - Exclusive group, only for specified users</li></ul></div><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Use Cases:</b> VIP exclusive, internal testing, special customers</p></div>',
nextBtn: 'Next'
},
groupSubmit: {
title: '✅ Save Group',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Confirm the information and click create to save the group.</p><p style="padding: 8px 12px; background: #fef3c7; border-left: 3px solid #f59e0b; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>⚠️ Note:</b> Platform type cannot be changed after creation, but other settings can be edited anytime</p><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>📌 Next Step:</b> After creation, we\'ll add upstream accounts to this group</p><p style="margin-top: 12px; color: #10b981; font-weight: 600;">👉 Click "Create" button</p></div>'
},
accountManage: {
title: '🔗 Step 2: Add Account',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;"><b>Great! Group created successfully 🎉</b></p><p style="margin-bottom: 12px;">Now add upstream AI service accounts to enable actual service delivery.</p><div style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>🔑 Account Purpose:</b><ul style="margin: 8px 0 0 16px;"><li>Connect to upstream AI services (Claude, GPT, etc.)</li><li>One group can contain multiple accounts (load balancing)</li><li>Supports OAuth and Session Key methods</li></ul></div><p style="margin-top: 16px; color: #10b981; font-weight: 600;">👉 Click "Account Management" on the left sidebar</p></div>'
},
createAccount: {
title: ' Add New Account',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Click the button to start adding your first upstream account.</p><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Tip:</b> Recommend using OAuth method - more secure and no manual key extraction needed</p><p style="margin-top: 12px; color: #10b981; font-weight: 600;">👉 Click "Add Account" button</p></div>'
},
accountName: {
title: '✏️ 1. Account Name',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Set an easy-to-identify name for the account.</p><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Naming Suggestions:</b> "Claude Main", "GPT Backup 1", "Test Account", etc.</p></div>',
nextBtn: 'Next'
},
accountPlatform: {
title: '🤖 2. Select Platform',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Choose the service provider platform for this account.</p><p style="padding: 8px 12px; background: #fef3c7; border-left: 3px solid #f59e0b; border-radius: 4px; font-size: 13px;"><b>⚠️ Important:</b> Platform must match the group you just created</p></div>',
nextBtn: 'Next'
},
accountType: {
title: '🔐 3. Authorization Method',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Choose the account authorization method.</p><div style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>✅ Recommended: OAuth Method</b><ul style="margin: 8px 0 0 16px;"><li>No manual key extraction needed</li><li>More secure with auto-refresh support</li><li>Works with Claude Code, ChatGPT OAuth</li></ul></div><div style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px;"><b>📌 Session Key Method</b><ul style="margin: 8px 0 0 16px;"><li>Requires manual extraction from browser</li><li>May need periodic updates</li><li>For platforms without OAuth support</li></ul></div></div>',
nextBtn: 'Next'
},
accountPriority: {
title: '⚖️ 4. Priority (Optional)',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Set the account call priority.</p><div style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>📊 Priority Rules:</b><ul style="margin: 8px 0 0 16px;"><li>Higher number = higher priority</li><li>System uses high-priority accounts first</li><li>Same priority = random selection</li></ul></div><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Use Case:</b> Set main account to high priority, backup accounts to low priority</p></div>',
nextBtn: 'Next'
},
accountGroups: {
title: '🎯 5. Assign Groups',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;"><b>Key Step!</b> Assign the account to the group you just created.</p><div style="padding: 8px 12px; background: #fee2e2; border-left: 3px solid #ef4444; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>⚠️ Important Reminder:</b><ul style="margin: 8px 0 0 16px;"><li>Must select at least one group</li><li>Unassigned accounts cannot be used</li><li>One account can be assigned to multiple groups</li></ul></div><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Tip:</b> Select the test group you just created</p></div>',
nextBtn: 'Next'
},
accountSubmit: {
title: '✅ Save Account',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Confirm the information and click save.</p><div style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>📌 OAuth Flow:</b><ul style="margin: 8px 0 0 16px;"><li>Will redirect to service provider page after clicking save</li><li>Complete login and authorization on provider page</li><li>Auto-return after successful authorization</li></ul></div><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>📌 Next Step:</b> After adding account, we\'ll create an API key</p><p style="margin-top: 12px; color: #10b981; font-weight: 600;">👉 Click "Save" button</p></div>'
},
keyManage: {
title: '🔑 Step 3: Generate Key',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;"><b>Congratulations! Account setup complete 🎉</b></p><p style="margin-bottom: 12px;">Final step: generate an API Key to test if the service works properly.</p><div style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>🔑 API Key Purpose:</b><ul style="margin: 8px 0 0 16px;"><li>Credential for calling AI services</li><li>Each key is bound to one group</li><li>Can set quota and expiration</li><li>Supports independent usage statistics</li></ul></div><p style="margin-top: 16px; color: #10b981; font-weight: 600;">👉 Click "API Keys" on the left sidebar</p></div>'
},
createKey: {
title: ' Create Key',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Click the button to create your first API Key.</p><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Tip:</b> Copy and save immediately after creation - key is only shown once</p><p style="margin-top: 12px; color: #10b981; font-weight: 600;">👉 Click "Create Key" button</p></div>'
},
keyName: {
title: '✏️ 1. Key Name',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Set an easy-to-manage name for the key.</p><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Naming Suggestions:</b> "Test Key", "Production", "Mobile", etc.</p></div>',
nextBtn: 'Next'
},
keyGroup: {
title: '🎯 2. Select Group',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Select the group you just configured.</p><div style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>📌 Group Determines:</b><ul style="margin: 8px 0 0 16px;"><li>Which accounts this key can use</li><li>What billing multiplier applies</li><li>Whether it\'s an exclusive key</li></ul></div><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Tip:</b> Select the test group you just created</p></div>',
nextBtn: 'Next'
},
keySubmit: {
title: '🎉 Generate and Copy',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">System will generate a complete API Key after clicking create.</p><div style="padding: 8px 12px; background: #fee2e2; border-left: 3px solid #ef4444; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>⚠️ Important Reminder:</b><ul style="margin: 8px 0 0 16px;"><li>Key is only shown once, copy immediately</li><li>Need to regenerate if lost</li><li>Keep it safe, don\'t share with others</li></ul></div><div style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>🚀 Next Steps:</b><ul style="margin: 8px 0 0 16px;"><li>Copy the generated sk-xxx key</li><li>Use in any OpenAI-compatible client</li><li>Start experiencing AI services!</li></ul></div><p style="margin-top: 12px; color: #10b981; font-weight: 600;">👉 Click "Create" button</p></div>'
}
},
// User tour steps
user: {
welcome: {
title: '👋 Welcome to Sub2API',
description: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">Hello! Welcome to the Sub2API AI service platform.</p><p style="margin-bottom: 12px;"><b>🎯 Quick Start:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>🔑 Create API Key</li><li>📋 Copy key to your application</li><li>🚀 Start using AI services</li></ul><p style="color: #10b981; font-weight: 600;">Just 1 minute, let\'s get started →</p></div>',
nextBtn: 'Start 🚀',
prevBtn: 'Skip'
},
keyManage: {
title: '🔑 API Key Management',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Manage all your API access keys here.</p><p style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px;"><b>📌 What is an API Key?</b><br/>An API key is your credential for accessing AI services, like a key that allows your application to call AI capabilities.</p><p style="margin-top: 12px; color: #10b981; font-weight: 600;">👉 Click to enter key page</p></div>'
},
createKey: {
title: ' Create New Key',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Click the button to create your first API key.</p><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Tip:</b> Key is only shown once after creation, make sure to copy and save</p><p style="margin-top: 12px; color: #10b981; font-weight: 600;">👉 Click "Create Key"</p></div>'
},
keyName: {
title: '✏️ Key Name',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Give your key an easy-to-identify name.</p><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Examples:</b> "My First Key", "For Testing", etc.</p></div>',
nextBtn: 'Next'
},
keyGroup: {
title: '🎯 Select Group',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Select the service group assigned by the administrator.</p><p style="padding: 8px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 13px;"><b>📌 Group Info:</b><br/>Different groups may have different service quality and billing rates, choose according to your needs.</p></div>',
nextBtn: 'Next'
},
keySubmit: {
title: '🎉 Complete Creation',
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;">Click to confirm and create your API key.</p><div style="padding: 8px 12px; background: #fee2e2; border-left: 3px solid #ef4444; border-radius: 4px; font-size: 13px; margin-bottom: 12px;"><b>⚠️ Important:</b><ul style="margin: 8px 0 0 16px;"><li>Copy the key (sk-xxx) immediately after creation</li><li>Key is only shown once, need to regenerate if lost</li></ul></div><p style="padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>🚀 How to Use:</b><br/>Configure the key in any OpenAI-compatible client (like ChatBox, OpenCat, etc.) and start using!</p><p style="margin-top: 12px; color: #10b981; font-weight: 600;">👉 Click "Create" button</p></div>'
}
}
}
}