Files
sub2api/frontend/src/i18n/locales/en.ts
song 08ce6de4db feat(antigravity): 添加配额窗口显示功能
后端:
- 新增 AntigravityQuotaRefresher 定时刷新配额
- Client 添加 FetchAvailableModels 方法获取模型配额
- 配额数据存入 account.extra.quota 字段

前端:
- AccountUsageCell 支持显示 Antigravity 账户配额
- UsageProgressBar 新增 amber 颜色
- 显示 G3P/G3F/G3I/C4.5 四个配额进度条
2025-12-28 22:29:01 +08:00

1509 lines
58 KiB
TypeScript

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',
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'
},
// 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',
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',
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'
},
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 (requires explicit user access)',
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',
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',
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.',
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'
}
},
// 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',
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',
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}'
}
}