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',
    // User-focused value proposition
    heroSubtitle: 'One Key, All AI Models',
    heroDescription: 'No need to manage multiple subscriptions. Access Claude, GPT, Gemini and more with a single API key',
    tags: {
      subscriptionToApi: 'Subscription to API',
      stickySession: 'Session Persistence',
      realtimeBilling: 'Pay As You Go'
    },
    // Pain points section
    painPoints: {
      title: 'Sound Familiar?',
      items: {
        expensive: {
          title: 'High Subscription Costs',
          desc: 'Paying for multiple AI subscriptions that add up every month'
        },
        complex: {
          title: 'Account Chaos',
          desc: 'Managing scattered accounts and API keys across different platforms'
        },
        unstable: {
          title: 'Service Interruptions',
          desc: 'Single accounts hitting rate limits and disrupting your workflow'
        },
        noControl: {
          title: 'No Usage Control',
          desc: "Can't track where your money goes or limit team member usage"
        }
      }
    },
    // Solutions section
    solutions: {
      title: 'We Solve These Problems',
      subtitle: 'Three simple steps to stress-free AI access'
    },
    features: {
      unifiedGateway: 'One-Click Access',
      unifiedGatewayDesc: 'Get a single API key to call all connected AI models. No separate applications needed.',
      multiAccount: 'Always Reliable',
      multiAccountDesc: 'Smart routing across multiple upstream accounts with automatic failover. Say goodbye to errors.',
      balanceQuota: 'Pay What You Use',
      balanceQuotaDesc: 'Usage-based billing with quota limits. Full visibility into team consumption.'
    },
    // Comparison section
    comparison: {
      title: 'Why Choose Us?',
      headers: {
        feature: 'Comparison',
        official: 'Official Subscriptions',
        us: 'Our Platform'
      },
      items: {
        pricing: {
          feature: 'Pricing',
          official: 'Fixed monthly fee, pay even if unused',
          us: 'Pay only for what you use'
        },
        models: {
          feature: 'Model Selection',
          official: 'Single provider only',
          us: 'Switch between models freely'
        },
        management: {
          feature: 'Account Management',
          official: 'Manage each service separately',
          us: 'Unified key, one dashboard'
        },
        stability: {
          feature: 'Stability',
          official: 'Single account rate limits',
          us: 'Multi-account pool, auto-failover'
        },
        control: {
          feature: 'Usage Control',
          official: 'Not available',
          us: 'Quotas & detailed analytics'
        }
      }
    },
    providers: {
      title: 'Supported AI Models',
      description: 'One API, Multiple Choices',
      supported: 'Supported',
      soon: 'Soon',
      claude: 'Claude',
      gemini: 'Gemini',
      antigravity: 'Antigravity',
      more: 'More'
    },
    // CTA section
    cta: {
      title: 'Ready to Get Started?',
      description: 'Sign up now and get free trial credits to experience seamless AI access',
      button: 'Sign Up Free'
    },
    footer: {
      allRightsReserved: 'All rights reserved.'
    }
  },

  // Key Usage Query Page
  keyUsage: {
    title: 'API Key Usage',
    subtitle: 'Enter your API Key to view real-time spending and usage status',
    placeholder: 'sk-ant-mirror-xxxxxxxxxxxx',
    query: 'Query',
    querying: 'Querying...',
    privacyNote: 'Your Key is processed locally in the browser and will not be stored',
    dateRange: 'Date Range:',
    dateRangeToday: 'Today',
    dateRange7d: '7 Days',
    dateRange30d: '30 Days',
    dateRangeCustom: 'Custom',
    apply: 'Apply',
    used: 'Used',
    detailInfo: 'Detail Information',
    tokenStats: 'Token Statistics',
    modelStats: 'Model Usage Statistics',
    // Table headers
    model: 'Model',
    requests: 'Requests',
    inputTokens: 'Input Tokens',
    outputTokens: 'Output Tokens',
    cacheCreationTokens: 'Cache Creation',
    cacheReadTokens: 'Cache Read',
    totalTokens: 'Total Tokens',
    cost: 'Cost',
    // Status
    quotaMode: 'Key Quota Mode',
    walletBalance: 'Wallet Balance',
    // Ring card titles
    totalQuota: 'Total Quota',
    limit5h: '5-Hour Limit',
    limitDaily: 'Daily Limit',
    limit7d: '7-Day Limit',
    limitWeekly: 'Weekly Limit',
    limitMonthly: 'Monthly Limit',
    // Detail rows
    remainingQuota: 'Remaining Quota',
    expiresAt: 'Expires At',
    todayExpires: '(expires today)',
    daysLeft: '({days} days)',
    usedQuota: 'Used Quota',
    resetNow: 'Resetting soon',
    subscriptionType: 'Subscription Type',
    subscriptionExpires: 'Subscription Expires',
    // Usage stat cells
    todayRequests: 'Today Requests',
    todayInputTokens: 'Today Input',
    todayOutputTokens: 'Today Output',
    todayTokens: 'Today Tokens',
    todayCacheCreation: 'Today Cache Creation',
    todayCacheRead: 'Today Cache Read',
    todayCost: 'Today Cost',
    rpmTpm: 'RPM / TPM',
    totalRequests: 'Total Requests',
    totalInputTokens: 'Total Input',
    totalOutputTokens: 'Total Output',
    totalTokensLabel: 'Total Tokens',
    totalCacheCreation: 'Total Cache Creation',
    totalCacheRead: 'Total Cache Read',
    totalCost: 'Total Cost',
    avgDuration: 'Avg Duration',
    // Messages
    enterApiKey: 'Please enter an API Key',
    querySuccess: 'Query successful',
    queryFailed: 'Query failed',
    queryFailedRetry: 'Query failed, please try again later',
  },

  // Setup Wizard
  setup: {
    title: 'Sub2API Setup',
    description: 'Configure your Sub2API instance',
    database: {
      title: 'Database Configuration',
      description: 'Connect to your PostgreSQL database',
      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',
      description: 'Connect to your Redis server',
      host: 'Host',
      port: 'Port',
      password: 'Password (optional)',
      database: 'Database',
      passwordPlaceholder: 'Password',
      enableTls: 'Enable TLS',
      enableTlsHint: 'Use TLS when connecting to Redis (public CA certs)'
    },
    admin: {
      title: 'Admin Account',
      description: 'Create your administrator account',
      email: 'Email',
      password: 'Password',
      confirmPassword: 'Confirm Password',
      passwordPlaceholder: 'Min 8 characters',
      confirmPasswordPlaceholder: 'Confirm password',
      passwordMismatch: 'Passwords do not match'
    },
    ready: {
      title: 'Ready to Install',
      description: 'Review your configuration and complete setup',
      database: 'Database',
      redis: 'Redis',
      adminEmail: 'Admin Email'
    },
    status: {
      testing: 'Testing...',
      success: 'Connection Successful',
      testConnection: 'Test Connection',
      installing: 'Installing...',
      completeInstallation: 'Complete Installation',
      completed: 'Installation completed!',
      redirecting: 'Redirecting to login page...',
      restarting: 'Service is restarting, please wait...',
      timeout: 'Service restart is taking longer than expected. Please refresh the page manually.'
    }
  },

  // Common
  common: {
    loading: 'Loading...',
    justNow: 'just now',
    save: 'Save',
    saved: 'Saved successfully',
    deleted: 'Deleted successfully',
    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',
    expand: 'Expand',
    collapse: 'Collapse',
    success: 'Success',
    error: 'Error',
    critical: 'Critical',
    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',
    copied: 'Copied',
    copyFailed: 'Failed to copy',
    verifying: 'Verifying...',
    processing: 'Processing...',
    contactSupport: 'Contact Support',
    add: 'Add',
    invalidEmail: 'Please enter a valid email address',
    optional: 'optional',
    selectOption: 'Select an option',
    searchPlaceholder: 'Search...',
    noOptionsFound: 'No options found',
    noGroupsAvailable: 'No groups available',
    unknownError: 'Unknown error occurred',
    saving: 'Saving...',
    selectedCount: '({count} selected)',
    refresh: 'Refresh',
    view: 'View',
    settings: 'Settings',
    chooseFile: 'Choose File',
    notAvailable: 'N/A',
    now: 'Now',
    today: 'Today',
    tomorrow: 'Tomorrow',
    unknown: 'Unknown',
    minutes: 'min',
    time: {
      never: 'Never',
      justNow: 'Just now',
      minutesAgo: '{n}m ago',
      hoursAgo: '{n}h ago',
      daysAgo: '{n}d ago',
      countdown: {
        daysHours: '{d}d {h}h',
        hoursMinutes: '{h}h {m}m',
        minutes: '{m}m',
        withSuffix: '{time} to lift'
      }
    }
  },

  // Navigation
  nav: {
    dashboard: 'Dashboard',
    announcements: 'Announcements',
    apiKeys: 'API Keys',
    usage: 'Usage',
    redeem: 'Redeem',
    profile: 'Profile',
    users: 'Users',
    groups: 'Groups',
    channels: 'Channels',
    subscriptions: 'Subscriptions',
    accounts: 'Accounts',
    proxies: 'Proxies',
    redeemCodes: 'Redeem Codes',
    ops: 'Ops',
    promoCodes: 'Promo Codes',
    settings: 'Settings',
    myAccount: 'My Account',
    lightMode: 'Light Mode',
    darkMode: 'Dark Mode',
    collapse: 'Collapse',
    expand: 'Expand',
    logout: 'Logout',
    github: 'GitHub',
    mySubscriptions: 'My Subscriptions',
    buySubscription: 'Recharge / Subscription',
    docs: 'Docs',
    myOrders: 'My Orders',
    orderManagement: 'Orders',
    paymentDashboard: 'Payment Dashboard',
    paymentConfig: 'Payment Config',
    paymentPlans: 'Plans'
  },

  // 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.',
    emailSuffixNotAllowed: 'This email domain is not allowed for registration.',
    emailSuffixNotAllowedWithAllowed:
      'This email domain is not allowed. Allowed domains: {suffixes}',
    loginSuccess: 'Login successful! Welcome back.',
    accountCreatedSuccess: 'Account created successfully! Welcome to {siteName}.',
    reloginRequired: 'Session expired. Please log in again.',
    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',
    sendCodeDesc: "We'll send a verification code to",
    codeSentSuccess: 'Verification code sent! Please check your inbox.',
    verifying: 'Verifying...',
    verifyAndCreate: 'Verify & Create Account',
    resendCountdown: 'Resend code in {countdown}s',
    backToRegistration: 'Back to registration',
    sendCodeFailed: 'Failed to send verification code. Please try again.',
    verifyFailed: 'Verification failed. Please try again.',
    codeRequired: 'Verification code is required',
    invalidCode: 'Please enter a valid 6-digit code',
    promoCodeLabel: 'Promo Code',
    promoCodePlaceholder: 'Enter promo code (optional)',
    promoCodeValid: 'Valid! You will receive ${amount} bonus balance',
    promoCodeInvalid: 'Invalid promo code',
    promoCodeNotFound: 'Promo code not found',
    promoCodeExpired: 'This promo code has expired',
    promoCodeDisabled: 'This promo code is disabled',
    promoCodeMaxUsed: 'This promo code has reached its usage limit',
    promoCodeAlreadyUsed: 'You have already used this promo code',
    promoCodeValidating: 'Promo code is being validated, please wait',
    promoCodeInvalidCannotRegister: 'Invalid promo code. Please check and try again or clear the promo code field',
    invitationCodeLabel: 'Invitation Code',
    invitationCodePlaceholder: 'Enter invitation code',
    invitationCodeRequired: 'Invitation code is required',
    invitationCodeValid: 'Invitation code is valid',
    invitationCodeInvalid: 'Invalid or used invitation code',
    invitationCodeValidating: 'Validating invitation code...',
    invitationCodeInvalidCannotRegister: 'Invalid invitation code. Please check and try again',
    oauthOrContinue: 'or continue with email',
    linuxdo: {
      signIn: 'Continue with Linux.do',
      orContinue: 'or continue with email',
      callbackTitle: 'Signing you in',
      callbackProcessing: 'Completing login, please wait...',
      callbackHint: 'If you are not redirected automatically, go back to the login page and try again.',
      callbackMissingToken: 'Missing login token, please try again.',
      backToLogin: 'Back to Login',
      invitationRequired: 'This Linux.do account is not yet registered. The site requires an invitation code — please enter one to complete registration.',
      invalidPendingToken: 'The registration token has expired. Please sign in with Linux.do again.',
      completeRegistration: 'Complete Registration',
      completing: 'Completing registration…',
      completeRegistrationFailed: 'Registration failed. Please check your invitation code and try again.'
    },
    oidc: {
      signIn: 'Continue with {providerName}',
      callbackTitle: 'Signing you in with {providerName}',
      callbackProcessing: 'Completing login with {providerName}, please wait...',
      callbackHint: 'If you are not redirected automatically, go back to the login page and try again.',
      callbackMissingToken: 'Missing login token, please try again.',
      backToLogin: 'Back to Login',
      invitationRequired:
        'This {providerName} account is not yet registered. The site requires an invitation code — please enter one to complete registration.',
      invalidPendingToken: 'The registration token has expired. Please sign in again.',
      completeRegistration: 'Complete Registration',
      completing: 'Completing registration…',
      completeRegistrationFailed: 'Registration failed. Please check your invitation code and try again.'
    },
    oauth: {
      code: 'Code',
      state: 'State',
      fullUrl: 'Full URL'
    },
    // Forgot password
    forgotPassword: 'Forgot password?',
    forgotPasswordTitle: 'Reset Your Password',
    forgotPasswordHint: 'Enter your email address and we will send you a link to reset your password.',
    sendResetLink: 'Send Reset Link',
    sendingResetLink: 'Sending...',
    sendResetLinkFailed: 'Failed to send reset link. Please try again.',
    resetEmailSent: 'Reset Link Sent',
    resetEmailSentHint: 'If an account exists with this email, you will receive a password reset link shortly. Please check your inbox and spam folder.',
    backToLogin: 'Back to Login',
    rememberedPassword: 'Remembered your password?',
    // Reset password
    resetPasswordTitle: 'Set New Password',
    resetPasswordHint: 'Enter your new password below.',
    newPassword: 'New Password',
    newPasswordPlaceholder: 'Enter your new password',
    confirmPassword: 'Confirm Password',
    confirmPasswordPlaceholder: 'Confirm your new password',
    confirmPasswordRequired: 'Please confirm your password',
    passwordsDoNotMatch: 'Passwords do not match',
    resetPassword: 'Reset Password',
    resettingPassword: 'Resetting...',
    resetPasswordFailed: 'Failed to reset password. Please try again.',
    passwordResetSuccess: 'Password Reset Successful',
    passwordResetSuccessHint: 'Your password has been reset. You can now sign in with your new password.',
    invalidResetLink: 'Invalid Reset Link',
    invalidResetLinkHint: 'This password reset link is invalid or has expired. Please request a new one.',
    requestNewResetLink: 'Request New Reset Link',
    invalidOrExpiredToken: 'The password reset link is invalid or has expired. Please request a new one.'
  },

  // 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',
    groupDistribution: 'Group Usage Distribution',
    tokenUsageTrend: 'Token Usage Trend',
    noDataAvailable: 'No data available',
    model: 'Model',
    group: 'Group',
    noGroup: 'No Group',
    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',
    searchPlaceholder: 'Search name or key...',
    endpoints: {
      title: 'API Endpoints',
      default: 'Default',
      copied: 'Copied',
      copiedHint: 'Copied to clipboard',
      clickToCopy: 'Click to copy this endpoint',
      speedTest: 'Speed Test',
    },
    allGroups: 'All Groups',
    allStatus: 'All Status',
    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',
    searchGroup: 'Search groups...',
    noGroupFound: 'No groups found',
    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: 'Last 30d',
    quota: 'Quota',
    lastUsedAt: 'Last Used',
    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.',
      },
      cliTabs: {
        claudeCode: 'Claude Code',
        geminiCli: 'Gemini CLI',
        codexCli: 'Codex CLI',
        codexCliWs: 'Codex CLI (WebSocket)',
        opencode: 'OpenCode',
      },
      antigravity: {
        description: 'Configure API access for Antigravity group. Select the configuration method based on your client.',
        claudeCode: 'Claude Code',
        geminiCli: 'Gemini CLI',
        claudeNote: 'These environment variables will be active in the current terminal session. For permanent configuration, add them to ~/.bashrc, ~/.zshrc, or the appropriate configuration file.',
        geminiNote: 'These environment variables will be active in the current terminal session. For permanent configuration, add them to ~/.bashrc, ~/.zshrc, or the appropriate configuration file.',
      },
      gemini: {
        description: 'Add the following environment variables to your terminal profile or run directly in terminal to configure Gemini CLI access.',
        modelComment: 'If you have Gemini 3 access, you can use: gemini-3-pro-preview',
        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.',
      },
      opencode: {
        title: 'OpenCode Example',
        subtitle: 'opencode.json',
        hint: 'Config path: ~/.config/opencode/opencode.json (or opencode.jsonc), create if not exists. Use default providers (openai/anthropic/google) or custom provider_id. API Key can be configured directly or via /connect command. This is an example, adjust models and options as needed.',
      },
    },
    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',
    ipRestriction: 'IP Restriction',
    ipWhitelist: 'IP Whitelist',
    ipWhitelistPlaceholder: '192.168.1.100\n10.0.0.0/8',
    ipWhitelistHint: 'One IP or CIDR per line. Only these IPs can use this key when set.',
    ipBlacklist: 'IP Blacklist',
    ipBlacklistPlaceholder: '1.2.3.4\n5.6.0.0/16',
    ipBlacklistHint: 'One IP or CIDR per line. These IPs will be blocked from using this key.',
    ipRestrictionEnabled: 'IP restriction enabled',
    ccSwitchNotInstalled: 'CC-Switch is not installed or the protocol handler is not registered. Please install CC-Switch first or manually copy the API key.',
    ccsClientSelect: {
      title: 'Select Client',
      description: 'Please select the client type to import to CC-Switch:',
      claudeCode: 'Claude Code',
      claudeCodeDesc: 'Import as Claude Code configuration',
      geminiCli: 'Gemini CLI',
      geminiCliDesc: 'Import as Gemini CLI configuration',
    },
    // Quota and expiration
    quotaLimit: 'Quota Limit',
    quotaAmount: 'Quota Amount (USD)',
    quotaAmountPlaceholder: 'Enter quota limit in USD',
    quotaAmountHint: 'Set the maximum amount this key can spend. 0 = unlimited.',
    quotaUsed: 'Quota Used',
    reset: 'Reset',
    resetQuotaUsed: 'Reset used quota to 0',
    resetQuotaTitle: 'Confirm Reset Quota',
    resetQuotaConfirmMessage: 'Are you sure you want to reset the used quota (${used}) for key "{name}" to 0? This action cannot be undone.',
    quotaResetSuccess: 'Quota reset successfully',
    failedToResetQuota: 'Failed to reset quota',
    rateLimitColumn: 'Rate Limit',
    rateLimitSection: 'Rate Limit',
    resetUsage: 'Reset',
    rateLimit5h: '5-Hour Limit (USD)',
    rateLimit1d: 'Daily Limit (USD)',
    rateLimit7d: '7-Day Limit (USD)',
    rateLimitHint: 'Set the maximum spending for this key within each time window. 0 = unlimited.',
    rateLimitUsage: 'Rate Limit Usage',
    resetRateLimitUsage: 'Reset Rate Limit Usage',
    resetRateLimitTitle: 'Confirm Reset Rate Limit',
    resetRateLimitConfirmMessage: 'Are you sure you want to reset the rate limit usage for key "{name}"? All time window usage will be reset to zero. This action cannot be undone.',
    rateLimitResetSuccess: 'Rate limit usage reset successfully',
    failedToResetRateLimit: 'Failed to reset rate limit usage',
    resetNow: 'Resetting soon',
    expiration: 'Expiration',
    expiresInDays: '{days} days',
    extendDays: '+{days} days',
    customDate: 'Custom',
    expirationDate: 'Expiration Date',
    expirationDateHint: 'Select when this API key should expire.',
    currentExpiration: 'Current expiration',
    expiresAt: 'Expires',
    noExpiration: 'Never',
    status: {
      active: 'Active',
      inactive: 'Inactive',
      quota_exhausted: 'Quota Exhausted',
      expired: 'Expired',
    },
  },

  // Usage
  usage: {
    title: 'Usage Records',
    description: 'View and analyze your API usage history',
    costDetails: 'Cost Breakdown',
    tokenDetails: 'Token Breakdown',
    cacheTtlOverriddenHint: 'Cache TTL Override enabled',
    cacheTtlOverriddenLabel: 'TTL Override',
    cacheTtlOverridden5m: 'Billed as 5m',
    cacheTtlOverridden1h: 'Billed as 1h',
    totalRequests: 'Total Requests',
    totalTokens: 'Total Tokens',
    totalCost: 'Total Cost',
    standardCost: 'Standard',
    actualCost: 'Actual',
    accountCost: 'Cost',
    userBilled: 'User billed',
    accountBilled: 'Account billed',
    accountMultiplier: 'Account rate',
    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',
    requestedModel: 'Requested',
    upstreamModel: 'Upstream',
    reasoningEffort: 'Reasoning Effort',
    endpoint: 'Endpoint',
    endpointDistribution: 'Endpoint Distribution',
    inbound: 'Inbound',
    upstream: 'Upstream',
    mapping: 'Mapping',
    path: 'Path',
    inboundEndpoint: 'Inbound Endpoint',
    upstreamEndpoint: 'Upstream Endpoint',
    type: 'Type',
    tokens: 'Tokens',
    cost: 'Cost',
    firstToken: 'First Token',
    duration: 'Duration',
    time: 'Time',
    ws: 'WS',
    stream: 'Stream',
    sync: 'Sync',
    unknown: 'Unknown',
    in: 'In',
    out: 'Out',
    inputTokenPrice: 'Input price',
    outputTokenPrice: 'Output price',
    perMillionTokens: '/ 1M tokens',
    unitPrice: 'Per-request price',
    imageUnitPrice: 'Per-image price',
    cacheRead: 'Read',
    cacheWrite: 'Write',
    serviceTier: 'Service tier',
    serviceTierPriority: 'Fast',
    serviceTierFlex: 'Flex',
    serviceTierStandard: 'Standard',
    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',
    imageUnit: ' images',
    userAgent: 'User-Agent'
  },

  // 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.',
    pleaseEnterCode: 'Please enter a redeem code'
  },

  // 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',
    enterUsername: 'Enter username',
    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',
    // TOTP 2FA
    totp: {
      title: 'Two-Factor Authentication (2FA)',
      description: 'Enhance account security with Google Authenticator or similar apps',
      enabled: 'Enabled',
      enabledAt: 'Enabled at',
      notEnabled: 'Not Enabled',
      notEnabledHint: 'Enable two-factor authentication to enhance account security',
      enable: 'Enable',
      disable: 'Disable',
      featureDisabled: 'Feature Unavailable',
      featureDisabledHint: 'Two-factor authentication has not been enabled by the administrator',
      setupTitle: 'Set Up Two-Factor Authentication',
      setupStep1: 'Scan the QR code below with your authenticator app',
      setupStep2: 'Enter the 6-digit code from your app',
      manualEntry: "Can't scan? Enter the key manually:",
      enterCode: 'Enter 6-digit code',
      verify: 'Verify',
      setupFailed: 'Failed to get setup information',
      verifyFailed: 'Invalid code, please try again',
      enableSuccess: 'Two-factor authentication enabled',
      disableTitle: 'Disable Two-Factor Authentication',
      disableWarning: 'After disabling, you will no longer need a verification code to log in. This may reduce your account security.',
      enterPassword: 'Enter your current password to confirm',
      confirmDisable: 'Confirm Disable',
      disableSuccess: 'Two-factor authentication disabled',
      disableFailed: 'Failed to disable, please check your password',
      loginTitle: 'Two-Factor Authentication',
      loginHint: 'Enter the 6-digit code from your authenticator app',
      loginFailed: 'Verification failed, please try again',
      // New translations for email verification
      verifyEmailFirst: 'Please verify your email first',
      verifyPasswordFirst: 'Please verify your identity first',
      emailCode: 'Email Verification Code',
      enterEmailCode: 'Enter 6-digit code',
      sendCode: 'Send Code',
      codeSent: 'Verification code sent to your email',
      sendCodeFailed: 'Failed to send verification code'
    },
    balanceNotify: {
      title: 'Balance Low Notification',
      description: 'Send email alert when account balance falls below threshold',
      enabled: 'Enable Balance Low Notification',
      threshold: 'Custom Threshold',
      thresholdHint: 'Leave empty to use system default',
      thresholdPlaceholder: 'Enter amount',
      systemDefault: 'System Default',
      extraEmails: 'Notification Emails',
      extraEmailsHint: 'You must add and verify an email address to receive low balance alerts',
      primaryEmail: 'Primary',
      noExtraEmails: 'No extra notification emails',
      enterEmail: 'Enter email address',
      addEmail: 'Add Email',
      emailPlaceholder: 'Enter email address',
      sendCode: 'Send Code',
      resend: 'Resend',
      codeSent: 'Verification code sent',
      codeSentTo: 'Code sent to {email}',
      enterCode: 'Enter verification code',
      codePlaceholder: '6-digit code',
      verify: 'Verify',
      emailAdded: 'Email added',
      emailRemoved: 'Email removed',
      verifySuccess: 'Email added successfully',
      removeEmail: 'Remove',
      removeSuccess: 'Email removed',
      emailDuplicate: 'This email already exists',
      maxEmailsReached: 'Maximum number of notification emails reached',
      unverified: 'Unverified',
      verified: 'Verified',
    },
    authBindings: {
      title: 'Connected Sign-In Methods',
      description: 'View current bindings and connect another provider to this account.',
      bindAction: 'Bind {providerName}',
      bindSuccess: 'Account linked successfully',
      status: {
        bound: 'Bound',
        notBound: 'Not bound',
      },
      providers: {
        email: 'Email',
        linuxdo: 'LinuxDo',
        oidc: '{providerName}',
        wechat: 'WeChat',
      },
      source: {
        avatar: 'Avatar is currently synced from {providerName}',
        username: 'Nickname is currently synced from {providerName}',
      },
    }
  },

  // 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}',
    jumpTo: 'Jump to',
    jumpPlaceholder: 'Page',
    jumpAction: 'Go'
  },

  // 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',
    last24Hours: 'Last 24 Hours',
    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',
      groupDistribution: 'Group Usage Distribution',
      metricTokens: 'By Tokens',
      metricActualCost: 'By Actual Cost',
      tokenUsageTrend: 'Token Usage Trend',
      userUsageTrend: 'User Usage Trend (Top 12)',
      model: 'Model',
      group: 'Group',
      noGroup: 'No Group',
      requests: 'Requests',
      tokens: 'Tokens',
      actual: 'Actual',
      standard: 'Standard',
      accountCost: 'Cost',
      noDataAvailable: 'No data available',
      recentUsage: 'Recent Usage',
      viewModelDistribution: 'Model Distribution',
      viewSpendingRanking: 'User Spending Ranking',
      spendingRankingTitle: 'User Spending Ranking',
      spendingRankingUser: 'User',
      spendingRankingRequests: 'Requests',
      spendingRankingTokens: 'Tokens',
      spendingRankingSpend: 'Spend',
      spendingRankingOther: 'Others',
      spendingRankingUsage: 'Usage',
      spendShort: 'Spend',
      requestsShort: 'Req',
      tokensShort: 'Tok',
      failedToLoad: 'Failed to load dashboard statistics'
    },

    backup: {
      title: 'Database Backup',
      description: 'Full database backup to S3-compatible storage with scheduled backup and restore',
      s3: {
        title: 'S3 Storage Configuration',
        description: 'Configure S3-compatible storage (supports Cloudflare R2)',
        descriptionPrefix: 'Configure S3-compatible storage (supports',
        descriptionSuffix: ')',
        enabled: 'Enable S3 Storage',
        endpoint: 'Endpoint',
        region: 'Region',
        bucket: 'Bucket',
        prefix: 'Key Prefix',
        accessKeyId: 'Access Key ID',
        secretAccessKey: 'Secret Access Key',
        secretConfigured: 'Already configured, leave empty to keep',
        forcePathStyle: 'Force Path Style',
        testConnection: 'Test Connection',
        testSuccess: 'S3 connection test successful',
        testFailed: 'S3 connection test failed',
        saved: 'S3 configuration saved'
      },
      schedule: {
        title: 'Scheduled Backup',
        description: 'Configure automatic scheduled backups',
        enabled: 'Enable Scheduled Backup',
        cronExpr: 'Cron Expression',
        cronHint: 'e.g. "0 2 * * *" means every day at 2:00 AM',
        retainDays: 'Backup Expire Days',
        retainDaysHint: 'Backup files auto-delete after this many days, 0 = never expire',
        retainCount: 'Max Retain Count',
        retainCountHint: 'Maximum number of backups to keep, 0 = unlimited',
        saved: 'Schedule configuration saved'
      },
      operations: {
        title: 'Backup Records',
        description: 'Create manual backups and manage existing backup records',
        createBackup: 'Create Backup',
        backing: 'Backing up...',
        backupCreated: 'Backup created successfully',
        expireDays: 'Expire Days',
        alreadyInProgress: 'A backup is already in progress',
        backupRunning: 'Backup in progress...',
        backupFailed: 'Backup failed',
        restoreRunning: 'Restore in progress...',
        restoreFailed: 'Restore failed',
      },
      columns: {
        status: 'Status',
        fileName: 'File Name',
        size: 'Size',
        expiresAt: 'Expires At',
        triggeredBy: 'Triggered By',
        startedAt: 'Started At',
        actions: 'Actions'
      },
      status: {
        pending: 'Pending',
        running: 'Running',
        completed: 'Completed',
        failed: 'Failed'
      },
      progress: {
        pending: 'Preparing',
        dumping: 'Dumping database',
        uploading: 'Uploading',
      },
      trigger: {
        manual: 'Manual',
        scheduled: 'Scheduled'
      },
      neverExpire: 'Never',
      empty: 'No backup records',
      actions: {
        download: 'Download',
        restore: 'Restore',
        restoreConfirm: 'Are you sure you want to restore from this backup? This will overwrite the current database!',
        restorePasswordPrompt: 'Please enter your admin password to confirm the restore operation',
        restoreSuccess: 'Database restored successfully',
        deleteConfirm: 'Are you sure you want to delete this backup?',
        deleted: 'Backup deleted'
      },
      r2Guide: {
        title: 'Cloudflare R2 Setup Guide',
        intro: 'Cloudflare R2 provides S3-compatible object storage with a free tier of 10GB storage + 1M Class A requests/month, ideal for database backups.',
        step1: {
          title: 'Create an R2 Bucket',
          line1: 'Log in to the Cloudflare Dashboard (dash.cloudflare.com), select "R2 Object Storage" from the sidebar',
          line2: 'Click "Create bucket", enter a name (e.g. sub2api-backups), choose a region',
          line3: 'Click create to finish'
        },
        step2: {
          title: 'Create an API Token',
          line1: 'On the R2 page, click "Manage R2 API Tokens" in the top right',
          line2: 'Click "Create API token", set permission to "Object Read & Write"',
          line3: 'Recommended: restrict to specific bucket for better security',
          line4: 'After creation, you will see the Access Key ID and Secret Access Key',
          warning: 'The Secret Access Key is only shown once — copy and save it immediately!'
        },
        step3: {
          title: 'Get the S3 Endpoint',
          desc: 'Find your Account ID on the R2 overview page (in the URL or the right panel). The endpoint format is:',
          accountId: 'your_account_id'
        },
        step4: {
          title: 'Fill in the Configuration',
          checkEnabled: 'Checked',
          bucketValue: 'Your bucket name',
          fromStep2: 'Value from Step 2',
          unchecked: 'Unchecked'
        },
        freeTier: 'R2 Free Tier: 10GB storage + 1M Class A requests + 10M Class B requests per month — more than enough for database backups.'
      }
    },

    dataManagement: {
      title: 'Data Management',
      description: 'Manage data management agent status, object storage settings, and backup jobs in one place',
      agent: {
        title: 'Data Management Agent Status',
        description: 'The system probes a fixed Unix socket and enables data management only when reachable.',
        enabled: 'Data management agent is ready. Data management operations are available.',
        disabled: 'Data management agent is unavailable. Only diagnostic information is available now.',
        socketPath: 'Socket Path',
        version: 'Version',
        status: 'Status',
        uptime: 'Uptime',
        reasonLabel: 'Unavailable Reason',
        reason: {
          DATA_MANAGEMENT_AGENT_SOCKET_MISSING: 'Data management socket file is missing',
          DATA_MANAGEMENT_AGENT_UNAVAILABLE: 'Data management agent is unreachable',
          BACKUP_AGENT_SOCKET_MISSING: 'Backup socket file is missing',
          BACKUP_AGENT_UNAVAILABLE: 'Backup agent is unreachable',
          UNKNOWN: 'Unknown reason'
        }
      },
      sections: {
        config: {
          title: 'Backup Configuration',
          description: 'Configure backup source, retention policy, and S3 settings.'
        },
        s3: {
          title: 'S3 Object Storage',
          description: 'Configure and test uploads of backup artifacts to a standard S3-compatible storage.'
        },
        backup: {
          title: 'Backup Operations',
          description: 'Trigger PostgreSQL, Redis, and full backup jobs.'
        },
        history: {
          title: 'Backup History',
          description: 'Review backup job status, errors, and artifact metadata.'
        }
      },
      form: {
        sourceMode: 'Source Mode',
        backupRoot: 'Backup Root',
        activePostgresProfile: 'Active PostgreSQL Profile',
        activeRedisProfile: 'Active Redis Profile',
        activeS3Profile: 'Active S3 Profile',
        retentionDays: 'Retention Days',
        keepLast: 'Keep Last Jobs',
        uploadToS3: 'Upload to S3',
        useActivePostgresProfile: 'Use Active PostgreSQL Profile',
        useActiveRedisProfile: 'Use Active Redis Profile',
        useActiveS3Profile: 'Use Active Profile',
        idempotencyKey: 'Idempotency Key (Optional)',
        secretConfigured: 'Configured already, leave empty to keep unchanged',
        source: {
          profileID: 'Profile ID (Unique)',
          profileName: 'Profile Name',
          setActive: 'Set as active after creation'
        },
        postgres: {
          title: 'PostgreSQL',
          host: 'Host',
          port: 'Port',
          user: 'User',
          password: 'Password',
          database: 'Database',
          sslMode: 'SSL Mode',
          containerName: 'Container Name (docker_exec mode)'
        },
        redis: {
          title: 'Redis',
          addr: 'Address (host:port)',
          username: 'Username',
          password: 'Password',
          db: 'Database Index',
          containerName: 'Container Name (docker_exec mode)'
        },
        s3: {
          enabled: 'Enable S3 Upload',
          profileID: 'Profile ID (Unique)',
          profileName: 'Profile Name',
          endpoint: 'Endpoint (Optional)',
          region: 'Region',
          bucket: 'Bucket',
          accessKeyID: 'Access Key ID',
          secretAccessKey: 'Secret Access Key',
          prefix: 'Object Prefix',
          forcePathStyle: 'Force Path Style',
          useSSL: 'Use SSL',
          setActive: 'Set as active after creation'
        }
      },
      sourceProfiles: {
        createTitle: 'Create Source Profile',
        editTitle: 'Edit Source Profile',
        empty: 'No source profiles yet, create one first',
        deleteConfirm: 'Delete source profile {profileID}?',
        columns: {
          profile: 'Profile',
          active: 'Active',
          connection: 'Connection',
          database: 'Database',
          updatedAt: 'Updated At',
          actions: 'Actions'
        }
      },
      s3Profiles: {
        createTitle: 'Create S3 Profile',
        editTitle: 'Edit S3 Profile',
        empty: 'No S3 profiles yet, create one first',
        editHint: 'Click "Edit" to modify profile details in the right drawer.',
        deleteConfirm: 'Delete S3 profile {profileID}?',
        columns: {
          profile: 'Profile',
          active: 'Active',
          storage: 'Storage',
          updatedAt: 'Updated At',
          actions: 'Actions'
        }
      },
      history: {
        total: '{count} jobs',
        empty: 'No backup jobs yet',
        columns: {
          jobID: 'Job ID',
          type: 'Type',
          status: 'Status',
          triggeredBy: 'Triggered By',
          pgProfile: 'PostgreSQL Profile',
          redisProfile: 'Redis Profile',
          s3Profile: 'S3 Profile',
          finishedAt: 'Finished At',
          artifact: 'Artifact',
          error: 'Error'
        },
        status: {
          queued: 'Queued',
          running: 'Running',
          succeeded: 'Succeeded',
          failed: 'Failed',
          partial_succeeded: 'Partial Succeeded'
        }
      },
      actions: {
        refresh: 'Refresh Status',
        disabledHint: 'Start datamanagementd first and ensure the socket is reachable.',
        reloadConfig: 'Reload Config',
        reloadSourceProfiles: 'Reload Source Profiles',
        reloadProfiles: 'Reload Profiles',
        newSourceProfile: 'New Source Profile',
        saveConfig: 'Save Config',
        configSaved: 'Configuration saved',
        testS3: 'Test S3 Connection',
        s3TestOK: 'S3 connection test succeeded',
        s3TestFailed: 'S3 connection test failed',
        newProfile: 'New Profile',
        saveProfile: 'Save Profile',
        activateProfile: 'Activate',
        profileIDRequired: 'Profile ID is required',
        profileNameRequired: 'Profile name is required',
        profileSelectRequired: 'Select a profile to edit first',
        profileCreated: 'S3 profile created',
        profileSaved: 'S3 profile saved',
        profileActivated: 'S3 profile activated',
        profileDeleted: 'S3 profile deleted',
        sourceProfileCreated: 'Source profile created',
        sourceProfileSaved: 'Source profile saved',
        sourceProfileActivated: 'Source profile activated',
        sourceProfileDeleted: 'Source profile deleted',
        createBackup: 'Create Backup Job',
        jobCreated: 'Backup job created: {jobID} ({status})',
        refreshJobs: 'Refresh Jobs',
        loadMore: 'Load More'
      }
    },

    // Users
    users: {
      title: 'User Management',
      description: 'Manage users and their permissions',
      createUser: 'Create User',
      editUser: 'Edit User',
      deleteUser: 'Delete User',
      searchUsers: 'Search by email, username, notes, or API key...',
      allRoles: 'All Roles',
      allStatus: 'All Status',
      allGroups: 'All Groups',
      searchGroups: 'Search groups...',
      fuzzySearch: 'Fuzzy search',
      admin: 'Admin',
      user: 'User',
      disabled: 'Disabled',
      email: 'Email',
      password: 'Password',
      username: 'Username',
      notes: 'Notes',
      enterEmail: 'Enter email',
      enterPassword: 'Enter password',
      enterUsername: 'Enter username (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',
        email: 'Email',
        username: 'Username',
        notes: 'Notes',
        role: 'Role',
        groups: 'Groups',
        subscriptions: 'Subscriptions',
        balance: 'Balance',
        usage: 'Usage',
        concurrency: 'Concurrency',
        status: 'Status',
        lastLogin: 'Last Login',
        lastActive: 'Last Active',
        created: 'Created',
        actions: 'Actions'
      },
      today: 'Today',
      total: 'Last 30d',
      noSubscription: 'No subscription',
      publicGroupCount: '+{count} public',
      exclusiveLabel: 'exclusive',
      publicLabel: 'public',
      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',
      groupChangedSuccess: 'Group updated successfully',
      groupChangedWithGrant: 'Group updated. User auto-granted access to "{group}"',
      groupChangeFailed: 'Failed to update group',
      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',
      emailRequired: 'Please enter email',
      concurrencyMin: 'Concurrency must be at least 1',
      soraStorageQuota: 'Sora Storage Quota',
      soraStorageQuotaHint: 'In GB, 0 means use group or system default quota',
      amountRequired: 'Please enter a valid amount',
      insufficientBalance: 'Insufficient balance',
      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',
      // User Group Configuration
      groupConfig: 'User Group Configuration',
      groupConfigHint: 'Configure custom rate multipliers for user {email} (overrides group defaults)',
      exclusiveGroups: 'Exclusive Groups',
      publicGroups: 'Public Groups (Default Available)',
      defaultRate: 'Default Rate',
      customRate: 'Custom Rate',
      useDefaultRate: 'Use Default',
      customRatePlaceholder: 'Leave empty for default',
      groupConfigUpdated: 'Group configuration updated successfully',
      replaceGroup: 'Replace Group',
      clickToReplace: 'Click to replace',
      replaceGroupTitle: 'Replace Exclusive Group',
      replaceGroupHint: 'Select a new group to replace "{old}". Keys will be migrated and permissions updated automatically.',
      replaceGroupConfirm: 'Confirm Replace',
      replaceGroupSuccess: 'Group replaced successfully, {count} key(s) migrated',
      selectNewGroup: 'Select target group',
      noOtherGroups: 'No other exclusive groups available',
      deposit: 'Deposit',
      withdraw: 'Withdraw',
      depositAmount: 'Deposit Amount',
      withdrawAmount: 'Withdraw Amount',
      withdrawAll: 'All',
      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',
      // Balance History
      balanceHistory: 'Recharge History',
      balanceHistoryTip: 'Click to open recharge history',
      balanceHistoryTitle: 'User Recharge & Concurrency History',
      noBalanceHistory: 'No records found for this user',
      allTypes: 'All Types',
      typeBalance: 'Balance (Redeem)',
      typeAdminBalance: 'Balance (Admin)',
      typeConcurrency: 'Concurrency (Redeem)',
      typeAdminConcurrency: 'Concurrency (Admin)',
      typeSubscription: 'Subscription',
      failedToLoadBalanceHistory: 'Failed to load balance history',
      createdAt: 'Created',
      totalRecharged: 'Total Recharged',
      roles: {
        admin: 'Admin',
        user: 'User'
      },
      // Settings Dropdowns
      filterSettings: 'Filter Settings',
      columnSettings: 'Column Settings',
      filterValue: 'Enter value',
      // User Attributes
      attributes: {
        title: 'User Attributes',
        description: 'Configure custom user attribute fields',
        configButton: 'Attributes',
        addAttribute: 'Add Attribute',
        editAttribute: 'Edit Attribute',
        deleteAttribute: 'Delete Attribute',
        deleteConfirm: "Are you sure you want to delete attribute '{name}'? All user values for this attribute will be deleted.",
        noAttributes: 'No custom attributes',
        noAttributesHint: 'Click the button above to add custom attributes',
        key: 'Attribute Key',
        keyHint: 'For programmatic reference, only letters, numbers and underscores',
        name: 'Display Name',
        nameHint: 'Name shown in forms',
        type: 'Attribute Type',
        fieldDescription: 'Description',
        fieldDescriptionHint: 'Description text for the attribute',
        placeholder: 'Placeholder',
        placeholderHint: 'Placeholder text for input field',
        required: 'Required',
        enabled: 'Enabled',
        options: 'Options',
        optionsHint: 'For select/multi-select types',
        addOption: 'Add Option',
        optionValue: 'Option Value',
        optionLabel: 'Display Text',
        validation: 'Validation Rules',
        minLength: 'Min Length',
        maxLength: 'Max Length',
        min: 'Min Value',
        max: 'Max Value',
        pattern: 'Regex Pattern',
        patternMessage: 'Validation Error Message',
        types: {
          text: 'Text',
          textarea: 'Textarea',
          number: 'Number',
          email: 'Email',
          url: 'URL',
          date: 'Date',
          select: 'Select',
          multi_select: 'Multi-Select'
        },
        created: 'Attribute created successfully',
        updated: 'Attribute updated successfully',
        deleted: 'Attribute deleted successfully',
        reordered: 'Attribute order updated successfully',
        failedToLoad: 'Failed to load attributes',
        failedToCreate: 'Failed to create attribute',
        failedToUpdate: 'Failed to update attribute',
        keyRequired: 'Please enter attribute key',
        nameRequired: 'Please enter display name',
        optionsRequired: 'Please add at least one option',
        failedToDelete: 'Failed to delete attribute',
        failedToReorder: 'Failed to update order',
        keyExists: 'Attribute key already exists',
        dragToReorder: 'Drag to reorder'
      }
    },

    // Groups
    groups: {
      title: 'Group Management',
      description: 'Manage API key groups and rate multipliers',
      searchGroups: 'Search groups...',
      createGroup: 'Create Group',
      editGroup: 'Edit Group',
      deleteGroup: 'Delete Group',
      sortOrder: 'Sort',
      sortOrderHint: 'Drag groups to adjust display order, groups at the top will be displayed first',
      sortOrderUpdated: 'Sort order updated',
      failedToUpdateSortOrder: 'Failed to update sort order',
      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',
        capacity: 'Capacity',
        usage: 'Usage',
        status: 'Status',
        actions: 'Actions',
        billingType: 'Billing Type',
        userName: 'Username',
        userEmail: 'Email',
        userNotes: 'Notes',
        userStatus: 'Status'
      },
      usageToday: 'Today',
      usageTotal: 'Total',
      accountsAvailable: 'Avail:',
      accountsRateLimited: 'Limited:',
      accountsTotal: 'Total:',
      accountsUnit: '',
      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',
      nameRequired: 'Please enter group name',
      rateMultipliers: 'Rate Multipliers',
      rateMultipliersTitle: 'Group Rate Multipliers',
      addUserRate: 'Add User Rate Multiplier',
      searchUserPlaceholder: 'Search user email...',
      noRateMultipliers: 'No user rate multipliers configured',
      rateUpdated: 'Rate multiplier updated',
      rateDeleted: 'Rate multiplier removed',
      rateAdded: 'Rate multiplier added',
      clearAll: 'Clear All',
      confirmClearAll: 'Are you sure you want to clear all rate multiplier settings for this group? This cannot be undone.',
      rateCleared: 'All rate multipliers cleared',
      batchAdjust: 'Batch Adjust Rates',
      multiplierFactor: 'Factor',
      applyMultiplier: 'Apply',
      rateAdjusted: 'Rates adjusted successfully',
      rateSaved: 'Rate multipliers saved',
      finalRate: 'Final Rate',
      unsavedChanges: 'Unsaved changes',
      revertChanges: 'Revert',
      userInfo: 'User Info',
      platforms: {
        all: 'All Platforms',
        anthropic: 'Anthropic',
        openai: 'OpenAI',
        gemini: 'Gemini',
        antigravity: 'Antigravity',
      },
      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'
      },
      imagePricing: {
        title: 'Image Generation Pricing',
        description: 'Configure pricing for image generation models. Leave empty to use default prices.'
      },
      claudeCode: {
        title: 'Claude Code Client Restriction',
        tooltip: 'When enabled, this group only allows official Claude Code clients. Non-Claude Code requests will be rejected or fallback to the specified group.',
        enabled: 'Claude Code Only',
        disabled: 'Allow All Clients',
        fallbackGroup: 'Fallback Group',
        fallbackHint: 'Non-Claude Code requests will use this group. Leave empty to reject directly.',
        noFallback: 'No Fallback (Reject)'
      },
      openaiMessages: {
        title: 'OpenAI Messages Dispatch',
        allowDispatch: 'Allow /v1/messages dispatch',
        allowDispatchHint: 'When enabled, API keys in this OpenAI group can dispatch requests through /v1/messages endpoint',
        familyMappingTitle: 'Family Default Mapping',
        familyMappingHint: 'Requests that match the Opus, Sonnet, or Haiku families will prefer the target model configured here.',
        opusModel: 'Opus Target Model',
        opusModelPlaceholder: 'e.g., gpt-5.4',
        sonnetModel: 'Sonnet Target Model',
        sonnetModelPlaceholder: 'e.g., gpt-5.3-codex',
        haikuModel: 'Haiku Target Model',
        haikuModelPlaceholder: 'e.g., gpt-5.4-mini',
        exactMappingTitle: 'Exact Model Overrides',
        exactMappingHint: 'Exact Claude model overrides take priority over the family defaults and can route a specific Claude model to a different target model.',
        noExactMappings: 'No exact model overrides yet',
        addExactMapping: 'Add Exact Mapping',
        claudeModel: 'Claude Model',
        claudeModelPlaceholder: 'e.g., claude-sonnet-4-5-20250929',
        targetModel: 'Target Model',
        targetModelPlaceholder: 'e.g., gpt-5.4',
        removeExactMapping: 'Remove Exact Mapping'
      },
      invalidRequestFallback: {
        title: 'Invalid Request Fallback Group',
        hint: 'Triggered only when upstream explicitly returns prompt too long. Leave empty to disable fallback.',
        noFallback: 'No Fallback'
      },
      copyAccounts: {
        title: 'Copy Accounts from Groups',
        tooltip: 'Select one or more groups of the same platform. After creation, all accounts from these groups will be automatically bound to the new group (deduplicated).',
        tooltipEdit: 'Select one or more groups of the same platform. After saving, current group accounts will be replaced with accounts from these groups (deduplicated).',
        selectPlaceholder: 'Select groups to copy accounts from...',
        hint: 'Multiple groups can be selected, accounts will be deduplicated',
        hintEdit: '⚠️ Warning: This will replace all existing account bindings'
      },
      modelRouting: {
        title: 'Model Routing',
        tooltip: 'Configure specific model requests to be routed to designated accounts. Supports wildcard matching, e.g., claude-opus-* matches all opus models.',
        enabled: 'Enabled',
        disabled: 'Disabled',
        disabledHint: 'Routing rules will only take effect when enabled',
        addRule: 'Add Routing Rule',
        modelPattern: 'Model Pattern',
        modelPatternPlaceholder: 'claude-opus-*',
        modelPatternHint: 'Supports * wildcard, e.g., claude-opus-* matches all opus models',
        accounts: 'Priority Accounts',
        selectAccounts: 'Select accounts',
        noAccounts: 'No accounts in this group',
        loadingAccounts: 'Loading accounts...',
        removeRule: 'Remove Rule',
        noRules: 'No routing rules',
        noRulesHint: 'Add routing rules to route specific model requests to designated accounts',
        searchAccountPlaceholder: 'Search accounts...',
        accountsHint: 'Select accounts to prioritize for this model pattern'
      },
      mcpXml: {
        title: 'MCP XML Protocol Injection',
        tooltip: 'When enabled, if the request contains MCP tools, an XML format call protocol prompt will be injected into the system prompt. Disable this to avoid interference with certain clients.',
        enabled: 'Enabled',
        disabled: 'Disabled'
      },
      claudeMaxSimulation: {
        title: 'Claude Max Usage Simulation',
        tooltip:
          'When enabled, for Claude models without upstream cache-write usage, the system deterministically maps tokens to a small input plus 1h cache creation while keeping total tokens unchanged.',
        enabled: 'Enabled (simulate 1h cache)',
        disabled: 'Disabled',
        hint: 'Only token categories in usage billing logs are adjusted. No per-request mapping state is persisted.'
      },
      supportedScopes: {
        title: 'Supported Model Families',
        tooltip: 'Select the model families this group supports. Unchecked families will not be routed to this group.',
        claude: 'Claude',
        geminiText: 'Gemini Text',
        geminiImage: 'Gemini Image',
        hint: 'Select at least one model family'
      }
    },

    // Channel Management
    channels: {
      title: 'Channel Management',
      description: 'Manage channels and custom model pricing',
      searchChannels: 'Search channels...',
      createChannel: 'Create Channel',
      editChannel: 'Edit Channel',
      deleteChannel: 'Delete Channel',
      statusActive: 'Active',
      statusDisabled: 'Disabled',
      allStatus: 'All Status',
      groupsUnit: 'groups',
      pricingUnit: 'pricing rules',
      noChannelsYet: 'No Channels Yet',
      createFirstChannel: 'Create your first channel to manage model pricing',
      loadError: 'Failed to load channels',
      createSuccess: 'Channel created',
      updateSuccess: 'Channel updated',
      deleteSuccess: 'Channel deleted',
      createError: 'Failed to create channel',
      updateError: 'Failed to update channel',
      deleteError: 'Failed to delete channel',
      nameRequired: 'Please enter a channel name',
      duplicateModels: 'Model "{0}" appears in multiple pricing entries',
      modelConflict: "Model patterns '{model1}' and '{model2}' conflict: overlapping match range",
      mappingConflict: "Mapping source patterns '{model1}' and '{model2}' conflict: overlapping match range",
      deleteConfirm: 'Are you sure you want to delete channel "{name}"? This cannot be undone.',
      columns: {
        name: 'Name',
        description: 'Description',
        status: 'Status',
        groups: 'Groups',
        pricing: 'Pricing',
        createdAt: 'Created',
        actions: 'Actions'
      },
      billingMode: {
        token: 'Token',
        perRequest: 'Per Request',
        image: 'Image (Per Request)'
      },
      form: {
        name: 'Name',
        namePlaceholder: 'Enter channel name',
        description: 'Description',
        descriptionPlaceholder: 'Optional description',
        status: 'Status',
        groups: 'Associated Groups',
        noGroupsAvailable: 'No groups available',
        inOtherChannel: 'In "{name}"',
        modelPricing: 'Model Pricing',
        models: 'Models',
        modelsPlaceholder: 'Type full model name and press Enter',
        modelInputHint: 'Press Enter to add, supports paste for batch import.',
        billingMode: 'Billing Mode',
        defaultPrices: 'Default prices (fallback when no interval matches)',
        inputPrice: 'Input',
        outputPrice: 'Output',
        cacheWritePrice: 'Cache Write',
        cacheReadPrice: 'Cache Read',
        imageTokenPrice: 'Image Output',
        imageOutputPrice: 'Image Output Price',
        pricePlaceholder: 'Default',
        intervals: 'Context Intervals (optional)',
        addInterval: 'Add Interval',
        requestTiers: 'Request Tiers',
        imageTiers: 'Image Tiers (Per Request)',
        addTier: 'Add Tier',
        noTiersYet: 'No tiers yet. Click add to configure per-request pricing.',
        noPricingRules: 'No pricing rules yet. Click "Add" to create one.',
        perRequestPrice: 'Price per Request',
        perRequestPriceRequired: 'Per-request price or billing tiers required for per-request/image billing mode',
        tierLabel: 'Tier',
        resolution: 'Resolution',
        modelMapping: 'Model Mapping',
        modelMappingHint: 'Map request model names to actual model names. Runs before account-level mapping.',
        noMappingRules: 'No mapping rules. Click "Add" to create one.',
        mappingSource: 'Source model',
        mappingTarget: 'Target model',
        billingModelSource: 'Billing Model',
        billingModelSourceChannelMapped: 'Bill by channel-mapped model',
        billingModelSourceRequested: 'Bill by requested model',
        billingModelSourceUpstream: 'Bill by final upstream model',
        billingModelSourceHint: 'Controls which model name is used for pricing lookup',
        selectedCount: '{count} selected',
        searchGroups: 'Search groups...',
        noGroupsMatch: 'No groups match your search',
        restrictModels: 'Restrict Models',
        restrictModelsHint: 'When enabled, only models in the pricing list are allowed. Others will be rejected.',
        defaultPerRequestPrice: 'Default per-request price (fallback when no tier matches)',
        defaultImagePrice: 'Default image price (fallback when no tier matches)',
        platformConfig: 'Platform Configuration',
        webSearchEmulation: 'Web Search Emulation',
        webSearchEmulationHint: '⚠️ When enabled, all accounts in this channel\'s Anthropic groups will intercept web_search requests. Use with caution.',
        webSearchEmulationGlobalDisabled: 'Please enable the global switch first in Settings → Gateway → Web Search Emulation',
        basicSettings: 'Basic Settings',
        addPlatform: 'Add Platform',
        noPlatforms: 'Click "Add Platform" to start configuring the channel',
        mappingCount: 'mappings',
        pricingEntry: 'Pricing Entry',
        noModels: 'No models added',
        applyPricingToAccountStats: 'Apply Pricing to Account Stats',
        applyPricingToAccountStatsDesc: 'When enabled, requests not matched by custom rules will use standard model pricing for account stats calculation',
        accountStatsPricingRules: 'Custom Account Stats Pricing Rules',
        addRule: 'Add Rule',
        noRulesConfigured: 'No custom rules configured. Channel model pricing above will be used.',
        ruleName: 'Rule name (optional)',
        ruleGroups: 'Groups',
        ruleAccounts: 'Accounts',
        searchAccountPlaceholder: 'Search accounts...',
        ruleAccountsHint: 'Leave empty to match all accounts',
        ruleModelPricing: 'Model Pricing',
        noGroupsInChannel: 'No groups selected in platform tabs above',
        unnamed: 'Unnamed'
      }
    },

    // Subscriptions
    subscriptions: {
      title: 'Subscription Management',
      description: 'Manage user subscriptions and quota limits',
      assignSubscription: 'Assign Subscription',
      adjustSubscription: 'Adjust Subscription',
      revokeSubscription: 'Revoke Subscription',
      allStatus: 'All Status',
      allGroups: 'All Groups',
      allPlatforms: 'All Platforms',
      daily: 'Daily',
      weekly: 'Weekly',
      monthly: 'Monthly',
      noLimits: 'No limits configured',
      unlimited: 'Unlimited',
      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',
      remainingDays: 'Remaining days',
      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)',
        adjustDays: 'Adjust 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',
      adjustingFor: 'Adjusting subscription for',
      currentExpiration: 'Current expiration',
      adjustDaysPlaceholder: 'Positive to extend, negative to shorten',
      adjustHint: 'Enter positive number to extend, negative to shorten (remaining days must be > 0)',
      assign: 'Assign',
      assigning: 'Assigning...',
      adjust: 'Adjust',
      adjusting: 'Adjusting...',
      revoke: 'Revoke',
      resetQuota: 'Reset Quota',
      resetQuotaTitle: 'Reset Usage Quota',
      resetQuotaConfirm: "Reset the daily, weekly, and monthly usage quota for '{user}'? Usage will be zeroed and windows restarted from today.",
      quotaResetSuccess: 'Quota reset successfully',
      failedToResetQuota: 'Failed to reset quota',
      noSubscriptionsYet: 'No subscriptions yet',
      assignFirstSubscription: 'Assign a subscription to get started.',
      subscriptionAssigned: 'Subscription assigned successfully',
      subscriptionAdjusted: 'Subscription adjusted successfully',
      subscriptionRevoked: 'Subscription revoked successfully',
      failedToLoad: 'Failed to load subscriptions',
      failedToAssign: 'Failed to assign subscription',
      failedToAdjust: 'Failed to adjust subscription',
      failedToRevoke: 'Failed to revoke subscription',
      adjustWouldExpire: 'Remaining days after adjustment must be greater than 0',
      adjustOutOfRange: 'Adjustment days must be between -36500 and 36500',
      pleaseSelectUser: 'Please select a user',
      pleaseSelectGroup: 'Please select a group',
      validityDaysRequired: 'Please enter a valid number of days (at least 1)',
      revokeConfirm:
        "Are you sure you want to revoke the subscription for '{user}'? This action cannot be undone.",
      guide: {
        title: 'Subscription Management Guide',
        subtitle: 'Subscription mode lets you assign time-based usage quotas to users, with daily/weekly/monthly limits. Follow these steps to get started.',
        showGuide: 'Usage Guide',
        step1: {
          title: 'Create a Subscription Group',
          line1: 'Go to "Group Management" page, click "Create Group"',
          line2: 'Set billing type to "Subscription", configure daily/weekly/monthly quota limits',
          line3: 'Save the group and ensure its status is "Active"',
          link: 'Go to Group Management'
        },
        step2: {
          title: 'Assign Subscription to User',
          line1: 'Click the "Assign Subscription" button in the top right',
          line2: 'Search for a user by email and select them',
          line3: 'Choose a subscription group, set validity days, then click "Assign"'
        },
        step3: {
          title: 'Manage Existing Subscriptions'
        },
        actions: {
          adjust: 'Adjust',
          adjustDesc: 'Extend or shorten the subscription validity period',
          resetQuota: 'Reset Quota',
          resetQuotaDesc: 'Reset daily/weekly/monthly usage to zero',
          revoke: 'Revoke',
          revokeDesc: 'Immediately terminate the subscription (irreversible)'
        },
        tip: 'Tip: Only groups with billing type "Subscription" and status "Active" appear in the group dropdown. If no options are available, create one in Group Management first.'
      }
    },

    // Accounts
    accounts: {
      title: 'Account Management',
      description: 'Manage AI platform accounts and credentials',
      createAccount: 'Create Account',
      autoRefresh: 'Auto Refresh',
      enableAutoRefresh: 'Enable auto refresh',
      refreshInterval5s: '5 seconds',
      refreshInterval10s: '10 seconds',
      refreshInterval15s: '15 seconds',
      refreshInterval30s: '30 seconds',
      autoRefreshCountdown: 'Auto refresh: {seconds}s',
      listPendingSyncHint: 'List changes are pending sync. Click sync to load latest rows.',
      listPendingSyncAction: 'Sync now',
      syncFromCrs: 'Sync from CRS',
      dataExport: 'Export',
      dataExportSelected: 'Export Selected',
      dataExportIncludeProxies: 'Include proxies linked to the exported accounts',
      dataImport: 'Import',
      dataExportConfirmMessage: 'The exported data contains sensitive account and proxy information. Store it securely.',
      dataExportConfirm: 'Confirm Export',
      dataExported: 'Data exported successfully',
      dataExportFailed: 'Failed to export data',
      dataImportTitle: 'Import Data',
      dataImportHint: 'Upload the exported JSON file to import accounts and proxies.',
      dataImportWarning: 'Import will create new accounts/proxies; groups must be bound manually. Ensure existing data does not conflict.',
      dataImportFile: 'Data file',
      dataImportButton: 'Start Import',
      dataImporting: 'Importing...',
      dataImportSelectFile: 'Please select a data file',
      dataImportParseFailed: 'Failed to parse data file',
      dataImportFailed: 'Data import failed',
      dataImportResult: 'Import Result',
      dataImportResultSummary: 'Proxies created {proxy_created}, reused {proxy_reused}, failed {proxy_failed}; Accounts created {account_created}, failed {account_failed}',
      dataImportErrors: 'Error Details',
      dataImportSuccess: 'Import completed: accounts {account_created}, failed {account_failed}',
      dataImportCompletedWithErrors: 'Import completed with errors: account failed {account_failed}, proxy failed {proxy_failed}',
      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}, skipped {skipped}',
      syncCompletedWithErrors:
        'Sync completed with errors: failed {failed} (created {created}, updated {updated}, skipped {skipped})',
      syncFailed: 'Sync failed',
      crsPreview: 'Preview',
      crsPreviewing: 'Previewing...',
      crsPreviewFailed: 'Preview failed',
      crsExistingAccounts: 'Existing accounts (will be updated)',
      crsNewAccounts: 'New accounts (select to sync)',
      crsSelectAll: 'Select all',
      crsSelectNone: 'Select none',
      crsNoNewAccounts: 'All CRS accounts are already synced.',
      crsWillUpdate: 'Will update {count} existing accounts.',
      crsSelectedCount: '{count} new accounts selected',
      crsUpdateBehaviorNote:
        'Existing accounts only sync fields returned by CRS; missing fields keep their current values. Credentials are merged by key — keys not returned by CRS are preserved. Proxies are kept when "Sync proxies" is unchecked.',
      crsBack: 'Back',
      editAccount: 'Edit Account',
      deleteAccount: 'Delete Account',
      searchAccounts: 'Search accounts...',
      notes: 'Notes',
      notesPlaceholder: 'Enter notes',
      notesHint: 'Notes are optional',
      allPlatforms: 'All Platforms',
      allTypes: 'All Types',
      allStatus: 'All Status',
      allGroups: 'All Groups',
      ungroupedGroup: 'Ungrouped',
      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',
      groupCountTotal: '{count} groups total',
      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',
        antigravityApikey: 'Connect via Base URL + API Key',
        upstream: 'Upstream',
        upstreamDesc: 'Connect via Base URL + API Key'
      },
      status: {
        active: 'Active',
        inactive: 'Inactive',
        error: 'Error',
        cooldown: 'Cooldown',
        paused: 'Paused',
        limited: 'Limited',
        rateLimited: 'Rate Limited',
        overloaded: 'Overloaded',
        tempUnschedulable: 'Temp Unschedulable',
        unschedulable: 'Unschedulable',
        rateLimitedUntil: 'Rate limited and removed from scheduling. Auto resumes at {time}',
        rateLimitedAutoResume: 'Auto resumes in {time}',
        modelRateLimitedUntil: '{model} rate limited until {time}',
        modelCreditOveragesUntil: '{model} using AI Credits until {time}',
        creditsExhausted: 'Credits Exhausted',
        creditsExhaustedUntil: 'AI Credits exhausted, expected recovery at {time}',
        overloadedUntil: 'Overloaded until {time}',
        viewTempUnschedDetails: 'View temp unschedulable details'
      },
      columns: {
        name: 'Name',
        platformType: 'Platform/Type',
        platform: 'Platform',
        type: 'Type',
        capacity: 'Capacity',
        notes: 'Notes',
        priority: 'Priority',
        billingRateMultiplier: 'Billing Rate',
        weight: 'Weight',
        status: 'Status',
        schedulable: 'Schedulable',
        todayStats: 'Today Stats',
        groups: 'Groups',
        usageWindows: 'Usage Windows',
        proxy: 'Proxy',
        lastUsed: 'Last Used',
        expiresAt: 'Expires At',
        actions: 'Actions'
      },
      allPrivacyModes: 'All Privacy States',
      privacyUnset: 'Unset',
      privacyTrainingOff: 'Training data sharing disabled',
      privacyCfBlocked: 'Blocked by Cloudflare, training may still be on',
      privacyFailed: 'Failed to disable training',
      privacyAntigravitySet: 'Telemetry and marketing emails disabled',
      privacyAntigravityFailed: 'Privacy setting failed',
      setPrivacy: 'Set Privacy',
      subscriptionAbnormal: 'Abnormal',
      subscriptionExpires: 'Expires',
      // Capacity status tooltips
      capacity: {
        windowCost: {
          blocked: '5h window cost exceeded, account scheduling paused',
          stickyOnly: '5h window cost at threshold, only sticky sessions allowed',
          normal: '5h window cost normal'
        },
        sessions: {
          full: 'Active sessions full, new sessions must wait (idle timeout: {idle} min)',
          normal: 'Active sessions normal (idle timeout: {idle} min)'
        },
        rpm: {
          full: 'RPM limit reached',
          warning: 'RPM approaching limit',
          normal: 'RPM normal',
          tieredNormal: 'RPM limit (Tiered) - Normal',
          tieredWarning: 'RPM limit (Tiered) - Approaching limit',
          tieredStickyOnly: 'RPM limit (Tiered) - Sticky only | Buffer: {buffer}',
          tieredBlocked: 'RPM limit (Tiered) - Blocked | Buffer: {buffer}',
          stickyExemptNormal: 'RPM limit (Sticky Exempt) - Normal',
          stickyExemptWarning: 'RPM limit (Sticky Exempt) - Approaching limit',
          stickyExemptOver: 'RPM limit (Sticky Exempt) - Over limit, sticky only'
        },
        quota: {
          exceeded: 'Quota exceeded, account paused',
          normal: 'Quota normal'
        },
      },
      tempUnschedulable: {
        title: 'Temp Unschedulable',
        statusTitle: 'Temp Unschedulable Status',
        hint: 'Disable accounts temporarily when error code and keyword both match.',
        notice: 'Rules are evaluated in order and require both error code and keyword match.',
        addRule: 'Add Rule',
        ruleOrder: 'Rule Order',
        ruleIndex: 'Rule #{index}',
        errorCode: 'Error Code',
        errorCodePlaceholder: 'e.g. 429',
        durationMinutes: 'Duration (minutes)',
        durationPlaceholder: 'e.g. 30',
        keywords: 'Keywords',
        keywordsPlaceholder: 'e.g. overloaded, too many requests',
        keywordsHint: 'Separate keywords with commas; any keyword match will trigger.',
        description: 'Description',
        descriptionPlaceholder: 'Optional note for this rule',
        rulesInvalid: 'Add at least one rule with error code, keywords, and duration.',
        viewDetails: 'View temp unschedulable details',
        accountName: 'Account',
        triggeredAt: 'Triggered At',
        until: 'Until',
        remaining: 'Remaining',
        matchedKeyword: 'Matched Keyword',
        errorMessage: 'Error Details',
        reset: 'Recover State',
        resetSuccess: 'Account state recovered successfully',
        resetFailed: 'Failed to recover account state',
        failedToLoad: 'Failed to load temp unschedulable status',
        notActive: 'This account is not temporarily unschedulable.',
        expired: 'Expired',
        remainingMinutes: 'About {minutes} minutes',
        remainingHours: 'About {hours} hours',
        remainingHoursMinutes: 'About {hours} hours {minutes} minutes',
        presets: {
          overloadLabel: '529 Overloaded',
          overloadDesc: 'Overloaded - pause 60 minutes',
          rateLimitLabel: '429 Rate Limit',
          rateLimitDesc: 'Rate limited - pause 10 minutes',
          unavailableLabel: '503 Unavailable',
          unavailableDesc: 'Unavailable - pause 30 minutes'
        }
      },
      clearRateLimit: 'Clear Rate Limit',
      resetQuota: 'Reset Quota',
      quotaLimit: 'Quota Limit',
      quotaLimitPlaceholder: '0 means unlimited',
      quotaLimitHint: 'Set daily/weekly/total spending limits (USD). Anthropic API key accounts can also configure client affinity. Changing limits won\'t reset usage.',
      quotaLimitToggle: 'Enable Quota Limit',
      quotaLimitToggleHint: 'When enabled, account will be paused when usage reaches the set limit',
      quotaDailyLimit: 'Daily Limit',
      quotaDailyLimitHint: 'Automatically resets every 24 hours from first usage.',
      quotaWeeklyLimit: 'Weekly Limit',
      quotaWeeklyLimitHint: 'Automatically resets every 7 days from first usage.',
      quotaTotalLimit: 'Total Limit',
      quotaTotalLimitHint: 'Cumulative spending limit. Does not auto-reset — use "Reset Quota" to clear.',
      quotaResetMode: 'Reset Mode',
      quotaResetModeRolling: 'Rolling Window',
      quotaResetModeFixed: 'Fixed Time',
      quotaResetHour: 'Reset Hour',
      quotaWeeklyResetDay: 'Reset Day',
      quotaResetTimezone: 'Reset Timezone',
      quotaDailyLimitHintFixed: 'Resets daily at {hour}:00 ({timezone}).',
      quotaWeeklyLimitHintFixed: 'Resets every {day} at {hour}:00 ({timezone}).',
      dayOfWeek: {
        monday: 'Monday',
        tuesday: 'Tuesday',
        wednesday: 'Wednesday',
        thursday: 'Thursday',
        friday: 'Friday',
        saturday: 'Saturday',
        sunday: 'Sunday',
      },
      quotaLimitAmount: 'Total Limit',
      quotaLimitAmountHint: 'Cumulative spending limit. Does not auto-reset.',
      quotaNotify: {
        alert: 'Alert',
        enabled: 'Enable Alert',
        threshold: 'Alert Amount',
        thresholdPlaceholder: 'Enter percentage',
      },
      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',
      bulkSchedulableEnabled: 'Successfully enabled scheduling for {count} account(s)',
      bulkSchedulableDisabled: 'Successfully disabled scheduling for {count} account(s)',
      bulkSchedulablePartial: 'Scheduling updated partially: {success} succeeded, {failed} failed',
      bulkSchedulableResultUnknown: 'Bulk scheduling result incomplete. Please retry or refresh.',
      bulkActions: {
        selected: '{count} account(s) selected',
        selectCurrentPage: 'Select this page',
        clear: 'Clear selection',
        edit: 'Bulk Edit',
        delete: 'Bulk Delete',
        enableScheduling: 'Enable Scheduling',
        disableScheduling: 'Disable Scheduling',
        resetStatus: 'Reset Status',
        refreshToken: 'Refresh Token',
        resetStatusSuccess: 'Successfully reset {count} account(s) status',
        refreshTokenSuccess: 'Successfully refreshed {count} account(s) token',
        partialSuccess: 'Partially completed: {success} succeeded, {failed} failed'
      },
      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',
        mixedPlatformWarning: 'Selected accounts span multiple platforms ({platforms}). Model mapping presets shown are combined — ensure mappings are appropriate for each platform.'
      },
      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',
      recoverState: 'Recover State',
      recoverStateHint: 'Used to recover error, rate-limit, and temporary unschedulable runtime state.',
      recoverStateSuccess: 'Account state recovered successfully',
      recoverStateFailed: 'Failed to recover account state',
      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',
      bedrockLabel: 'AWS Bedrock',
      bedrockDesc: 'SigV4 / API Key',
      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',
        oauthPassthrough: 'Auto passthrough (auth only)',
        oauthPassthroughDesc:
          'When enabled, this OpenAI account uses automatic passthrough: the gateway forwards request/response as-is and only swaps auth, while keeping billing/concurrency/audit and necessary safety filtering.',
        responsesWebsocketsV2: 'Responses WebSocket v2',
        responsesWebsocketsV2Desc:
          'Disabled by default. Enable to allow responses_websockets_v2 capability (still gated by global and account-type switches).',
        wsMode: 'WS mode',
        wsModeDesc: 'Only applies to the current OpenAI account type.',
        wsModeOff: 'Off (off)',
        wsModeCtxPool: 'Context Pool (ctx_pool)',
        wsModePassthrough: 'Passthrough (passthrough)',
        wsModeShared: 'Shared (shared)',
        wsModeDedicated: 'Dedicated (dedicated)',
        wsModeConcurrencyHint:
          'When WS mode is enabled, account concurrency becomes the WS connection pool limit for this account.',
        wsModePassthroughHint: 'Passthrough mode does not use the WS connection pool.',
        oauthResponsesWebsocketsV2: 'OAuth WebSocket Mode',
        oauthResponsesWebsocketsV2Desc:
          'Only applies to OpenAI OAuth. This account can use OpenAI WebSocket Mode only when enabled.',
        apiKeyResponsesWebsocketsV2: 'API Key WebSocket Mode',
        apiKeyResponsesWebsocketsV2Desc:
          'Only applies to OpenAI API Key. This account can use OpenAI WebSocket Mode only when enabled.',
        responsesWebsocketsV2PassthroughHint:
          'Automatic passthrough is currently enabled: it only affects HTTP passthrough and does not disable WS mode.',
        codexCLIOnly: 'Codex official clients only',
        codexCLIOnlyDesc:
          'Only applies to OpenAI OAuth. When enabled, only Codex official client families are allowed; when disabled, the gateway bypasses this restriction and keeps existing behavior.',
        modelRestrictionDisabledByPassthrough: 'Automatic passthrough is enabled: model whitelist/mapping will not take effect.',
      },
      anthropic: {
        apiKeyPassthrough: 'Auto passthrough (auth only)',
        apiKeyPassthroughDesc:
          'Only applies to Anthropic API Key accounts. When enabled, messages/count_tokens are forwarded in passthrough mode with auth replacement only, while billing/concurrency/audit and safety filtering are preserved. Disable to roll back immediately.',
        webSearchEmulation: 'Web Search Emulation',
        webSearchEmulationDesc:
          'Enable web search emulation for this API Key account. When a pure web_search request is detected, the gateway calls a third-party search API and constructs the response locally. Default follows channel config.',
        webSearchDefault: 'Default',
        webSearchEnabled: 'Enabled',
        webSearchDisabled: 'Disabled',
      },
      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',
      wildcardOnlyAtEnd: 'Wildcard * can only be at the end',
      targetNoWildcard: 'Target model cannot contain wildcard *',
      searchModels: 'Search models...',
      noMatchingModels: 'No matching models',
      fillRelatedModels: 'Fill related models',
      clearAllModels: 'Clear all models',
      customModelName: 'Custom model name',
      enterCustomModelName: 'Enter custom model name',
      addModel: 'Add',
      modelExists: 'Model already exists',
      modelCount: '{count} models',
      poolMode: 'Pool Mode',
      poolModeHint: 'Enable when upstream is an account pool; errors won\'t mark local account status',
      poolModeInfo:
        'When enabled, upstream 429/403/401 errors will auto-retry without marking the account as rate-limited or errored. Suitable for upstream pointing to another sub2api instance.',
      poolModeRetryCount: 'Same-Account Retries',
      poolModeRetryCountHint:
        'Only applies in pool mode. Use 0 to disable in-place retry. Default {default}, maximum {max}.',
      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.',
      customErrorCodes429Warning:
        '429 already has built-in rate limit handling. Adding it to custom error codes will disable the account instead of temporary rate limiting. Are you sure?',
      customErrorCodes529Warning:
        '529 already has built-in overload handling. Adding it to custom error codes will disable the account instead of temporary overload marking. Are you sure?',
      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',
      autoPauseOnExpired: 'Auto Pause On Expired',
      autoPauseOnExpiredDesc: 'When enabled, the account will auto pause scheduling after it expires',
      // Quota control (Anthropic OAuth/SetupToken only)
      quotaControl: {
        title: 'Quota Control',
        hint: 'Configure cost window, session limits, client affinity and other scheduling controls.',
        windowCost: {
          label: '5h Window Cost Limit',
          hint: 'Limit account cost usage within the 5-hour window',
          limit: 'Cost Threshold',
          limitPlaceholder: '50',
          limitHint: 'Account will not participate in new scheduling after reaching threshold',
          stickyReserve: 'Sticky Reserve',
          stickyReservePlaceholder: '10',
          stickyReserveHint: 'Additional reserve for sticky sessions'
        },
        sessionLimit: {
          label: 'Session Count Limit',
          hint: 'Limit the number of active concurrent sessions',
          maxSessions: 'Max Sessions',
          maxSessionsPlaceholder: '3',
          maxSessionsHint: 'Maximum number of active concurrent sessions',
          idleTimeout: 'Idle Timeout',
          idleTimeoutPlaceholder: '5',
          idleTimeoutHint: 'Sessions will be released after idle timeout'
        },
        rpmLimit: {
          label: 'RPM Limit',
          hint: 'Limit requests per minute to protect upstream accounts',
          baseRpm: 'Base RPM',
          baseRpmPlaceholder: '15',
          baseRpmHint: 'Max requests per minute, 0 or empty means no limit',
          strategy: 'RPM Strategy',
          strategyTiered: 'Tiered Model',
          strategyStickyExempt: 'Sticky Exempt',
          strategyTieredHint: 'Green → Yellow → Sticky only → Blocked, progressive throttling',
          strategyStickyExemptHint: 'Only sticky sessions allowed when over limit',
          strategyHint: 'Tiered: gradually restrict when exceeded; Sticky Exempt: existing sessions unrestricted',
          stickyBuffer: 'Sticky Buffer',
          stickyBufferPlaceholder: 'Default: 20% of base RPM',
          stickyBufferHint: 'Extra requests allowed for sticky sessions after exceeding base RPM. Leave empty to use default (20% of base RPM, min 1)',
          userMsgQueue: 'User Message Rate Control',
          userMsgQueueHint: 'Rate-limit user messages to avoid triggering upstream RPM limits',
          umqModeOff: 'Off',
          umqModeThrottle: 'Throttle',
          umqModeSerialize: 'Serialize',
        },
        tlsFingerprint: {
          label: 'TLS Fingerprint Simulation',
          hint: 'Simulate Node.js/Claude Code client TLS fingerprint',
          defaultProfile: 'Built-in Default',
          randomProfile: 'Random'
        },
        sessionIdMasking: {
          label: 'Session ID Masking',
          hint: 'When enabled, fixes the session ID in metadata.user_id for 15 minutes, making upstream think requests come from the same session'
        },
        cacheTTLOverride: {
          label: 'Cache TTL Override',
          hint: 'Force all cache creation tokens to be billed as the selected TTL tier (5m or 1h)',
          target: 'Target TTL',
          targetHint: 'Select the TTL tier for billing'
        },
        customBaseUrl: {
          label: 'Custom Relay URL',
          hint: 'Forward requests to a custom relay service. Proxy URL will be passed as a query parameter.',
          urlHint: 'Relay service URL (e.g., https://relay.example.com)',
        },
        clientAffinity: {
          label: 'Client Affinity Scheduling',
          hint: 'When enabled, new sessions prefer accounts previously used by this client to reduce account switching'
        }
      },
      affinityNoClients: 'No affinity clients',
      affinityClients: '{count} affinity clients:',
      affinitySection: 'Client Affinity',
      affinitySectionHint: 'Control how clients are distributed across accounts. Configure zone thresholds to balance load.',
      affinityToggle: 'Enable Client Affinity',
      affinityToggleHint: 'New sessions prefer accounts previously used by this client',
      affinityBase: 'Base Limit (Green Zone)',
      affinityBasePlaceholder: 'Empty = no limit',
      affinityBaseHint: 'Max clients in green zone (full priority scheduling)',
      affinityBaseOffHint: 'No green zone limit. All clients receive full priority scheduling.',
      affinityBuffer: 'Buffer (Yellow Zone)',
      affinityBufferPlaceholder: 'e.g. 3',
      affinityBufferHint: 'Additional clients allowed in the yellow zone (degraded priority)',
      affinityBufferInfinite: 'Unlimited',
      expired: 'Expired',
      proxy: 'Proxy',
      noProxy: 'No Proxy',
      concurrency: 'Concurrency',
      loadFactor: 'Load Factor',
      loadFactorHint: 'Higher load factor increases scheduling frequency',
      priority: 'Priority',
      priorityHint: 'Lower value accounts are used first',
      billingRateMultiplier: 'Billing Rate Multiplier',
      billingRateMultiplierHint: '0 = free, affects account billing only',
      expiresAt: 'Expires At',
      expiresAtHint: 'Leave empty for no expiration',
      higherPriorityFirst: 'Lower value means higher priority',
      mixedScheduling: 'Use in /v1/messages',
      mixedSchedulingHint: 'Enable to participate in Anthropic/Gemini group scheduling',
      mixedSchedulingTooltip:
        '!! WARNING !! Antigravity Claude and Anthropic Claude cannot be used in the same context. If you have both Anthropic and Antigravity accounts, enabling this option will cause frequent 400 errors. When enabled, please use the group feature to isolate Antigravity accounts from Anthropic accounts. Make sure you understand this before enabling!!',
      aiCreditsBalance: 'AI Credits',
      allowOverages: 'Allow Overages (AI Credits)',
      allowOveragesTooltip:
        'Only use AI Credits after free quota is explicitly exhausted. Ordinary concurrent 429 rate limits will not switch to overages.',
      creating: 'Creating...',
      updating: 'Updating...',
      accountCreated: 'Account created successfully',
      accountUpdated: 'Account updated successfully',
      failedToCreate: 'Failed to create account',
      failedToUpdate: 'Failed to update account',
      pleaseSelectStatus: 'Please select a valid account status',
      mixedChannelWarningTitle: 'Mixed Channel Warning',
      mixedChannelWarning: 'Warning: Group "{groupName}" contains both {currentPlatform} and {otherPlatform} accounts. Mixing different channels may cause thinking block signature validation issues, which will fallback to non-thinking mode. Are you sure you want to continue?',
      pleaseEnterAccountName: 'Please enter account name',
      pleaseEnterApiKey: 'Please enter API Key',
      bedrockAccessKeyId: 'AWS Access Key ID',
      bedrockSecretAccessKey: 'AWS Secret Access Key',
      bedrockSessionToken: 'AWS Session Token',
      bedrockRegion: 'AWS Region',
      bedrockRegionHint: 'e.g. us-east-1, us-west-2, eu-west-1',
      bedrockForceGlobal: 'Force Global cross-region inference',
      bedrockForceGlobalHint: 'When enabled, model IDs use the global. prefix (e.g. global.anthropic.claude-...), routing requests to any supported region worldwide for higher availability',
      bedrockAccessKeyIdRequired: 'Please enter AWS Access Key ID',
      bedrockSecretAccessKeyRequired: 'Please enter AWS Secret Access Key',
      bedrockRegionRequired: 'Please select AWS Region',
      bedrockSessionTokenHint: 'Optional, for temporary credentials',
      bedrockSecretKeyLeaveEmpty: 'Leave empty to keep current key',
      bedrockAuthMode: 'Authentication Mode',
      bedrockAuthModeSigv4: 'SigV4 Signing',
      bedrockAuthModeApikey: 'Bedrock API Key',
      bedrockApiKeyLabel: 'Bedrock API Key',
      bedrockApiKeyDesc: 'Bearer Token',
      bedrockApiKeyInput: 'API Key',
      bedrockApiKeyRequired: 'Please enter Bedrock API Key',
      bedrockApiKeyLeaveEmpty: 'Leave empty to keep current key',
      apiKeyIsRequired: 'API Key is required',
      leaveEmptyToKeep: 'Leave empty to keep current key',
      // Upstream type
      upstream: {
        baseUrl: 'Upstream Base URL',
        baseUrlHint: 'The address of the upstream Antigravity service, e.g., https://cloudcode-pa.googleapis.com',
        apiKey: 'Upstream API Key',
        apiKeyHint: 'API Key for the upstream service',
        pleaseEnterBaseUrl: 'Please enter upstream Base URL',
        pleaseEnterApiKey: 'Please enter upstream API 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 claude.ai in your browser',
        step2: 'Press F12 to open Developer Tools',
        step3: 'Go to Application tab',
        step4: 'Find Cookies → https://claude.ai',
        step5: 'Find the row with key sessionKey',
        step6: 'Copy the Value',
        sessionKeyFormat: 'sessionKey usually starts with sk-ant-sid01-',
        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:
          'Note: 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 Authorization Code. 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)',
        batchSuccess: 'Successfully created {count} account(s)',
        batchPartialSuccess: 'Partial success: {success} succeeded, {failed} failed',
        batchFailed: 'Batch creation failed',
        // 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:
            'Important: The page may take a while to load after authorization. Please wait patiently. When the browser address bar changes to http://localhost..., the authorization is complete.',
          step3EnterCode: 'Enter Authorization URL or Code',
          authCodeDesc:
            'After authorization is complete, when the page URL becomes http://localhost:xxx/auth/callback?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',
          // Refresh Token auth
          refreshTokenAuth: 'Manual RT Input',
          refreshTokenDesc: 'Enter your existing OpenAI Refresh Token(s). Supports batch input (one per line). The system will automatically validate and create accounts.',
          refreshTokenPlaceholder: 'Paste your OpenAI Refresh Token...\nSupports multiple, one per line',
          sessionTokenAuth: 'Manual ST Input',
          sessionTokenDesc: 'Enter your existing Session Token(s). Supports batch input (one per line). The system will automatically validate and create accounts.',
          sessionTokenPlaceholder: 'Paste your Session Token...\nSupports multiple, one per line',
          sessionTokenRawLabel: 'Raw Input',
          sessionTokenRawPlaceholder: 'Paste /api/auth/session raw payload or Session Token...',
          sessionTokenRawHint: 'You can paste full JSON. The system will auto-parse ST and AT.',
          openSessionUrl: 'Open Fetch URL',
          copySessionUrl: 'Copy URL',
          sessionUrlHint: 'This URL usually returns AT. If sessionToken is absent, copy __Secure-next-auth.session-token from browser cookies as ST.',
          parsedSessionTokensLabel: 'Parsed ST',
          parsedSessionTokensEmpty: 'No ST parsed. Please check your input.',
          parsedAccessTokensLabel: 'Parsed AT',
          validating: 'Validating...',
          validateAndCreate: 'Validate & Create Account',
          pleaseEnterRefreshToken: 'Please enter Refresh Token',
          pleaseEnterSessionToken: 'Please enter Session Token'
        },
        // 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 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',
	          missingProjectId: 'GCP Project ID retrieval failed: Your Google account is not linked to an active GCP project. Please activate GCP and bind a credit card in Google Cloud Console, or manually enter the Project ID during authorization.',
	          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: 'Built-in OAuth (Code Assist)',
          needsProjectIdDesc: 'Requires GCP project and Project ID',
          noProjectIdNeeded: 'Custom OAuth (AI Studio)',
          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:
            'Important: The page may take a while to load after authorization. Please wait patiently. When the browser address bar shows http://localhost..., authorization is complete.',
          step3EnterCode: 'Enter Authorization URL or Code',
          authCodeDesc:
            'After authorization, when the page URL becomes http://localhost:xxx/auth/callback?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',
                    // Refresh Token auth
                    refreshTokenAuth: 'Manual RT',
                    refreshTokenDesc: 'Enter your existing Antigravity Refresh Token. Supports batch input (one per line). The system will automatically validate and create accounts.',
                    refreshTokenPlaceholder: 'Paste your Antigravity Refresh Token...\nSupports multiple tokens, one per line',
                    validating: 'Validating...',
                    validateAndCreate: 'Validate & Create',
                    pleaseEnterRefreshToken: 'Please enter Refresh Token',
                    failedToValidateRT: 'Failed to validate Refresh Token'
                  }
                },      // Gemini specific (platform-wide)
      gemini: {
        helpButton: 'Help',
        helpDialog: {
          title: 'Gemini Usage Guide',
          apiKeySection: 'API Key Links'
        },
        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)',
        tier: {
          label: 'Account Tier',
          hint: 'Tip: The system will try to auto-detect the tier first; if auto-detection is unavailable or fails, your selected tier is used as a fallback (simulated quota).',
          aiStudioHint:
            'AI Studio quotas are per-model (Pro/Flash are limited independently). If billing is enabled, choose Pay-as-you-go.',
          googleOne: {
            free: 'Google One Free',
            pro: 'Google One Pro',
            ultra: 'Google One Ultra'
          },
          gcp: {
            standard: 'GCP Standard',
            enterprise: 'GCP Enterprise'
          },
          aiStudio: {
            free: 'Google AI Free',
            paid: 'Google AI Pay-as-you-go'
          }
        },
        accountType: {
          oauthTitle: 'OAuth (Gemini)',
          oauthDesc: 'Authorize with your Google account and choose an OAuth type.',
          apiKeyTitle: 'API Key (AI Studio)',
          apiKeyDesc: 'Fastest setup. Use an AIza API key.',
          apiKeyNote:
            'Best for light testing. Free tier has strict rate limits and data may be used for training.',
          apiKeyLink: 'Get API Key',
          quotaLink: 'Quota guide'
        },
        oauthType: {
          builtInTitle: 'Built-in OAuth (Gemini CLI / Code Assist)',
          builtInDesc: 'Uses Google built-in client ID. No admin configuration required.',
          builtInRequirement: 'Requires a GCP project and Project ID.',
          gcpProjectLink: 'Create project',
          customTitle: 'Custom OAuth (AI Studio OAuth)',
          customDesc: 'Uses admin-configured OAuth client for org management.',
          customRequirement: 'Admin must configure Client ID and add you as a test user.',
          badges: {
            recommended: 'Recommended',
            highConcurrency: 'High concurrency',
            noAdmin: 'No admin setup',
            orgManaged: 'Org managed',
            adminRequired: 'Admin required'
          }
        },
        setupGuide: {
          title: 'Gemini Setup Checklist',
          checklistTitle: 'Checklist',
          checklistItems: {
            usIp: 'Use a US IP and ensure your account country is set to US.',
            age: 'Account must be 18+.'
          },
          activationTitle: 'One-click Activation',
          activationItems: {
            geminiWeb: 'Activate Gemini Web to avoid User not initialized.',
            gcpProject: 'Activate a GCP project and get the Project ID for Code Assist.'
          },
          links: {
            countryCheck: 'Check country association',
            geminiWebActivation: 'Activate Gemini Web',
            gcpProject: 'Open GCP Console'
          }
        },
        quotaPolicy: {
          title: 'Gemini Quota & Limit Policy (Reference)',
          note: 'Note: Gemini does not provide an official quota inquiry API. The "Daily Quota" shown here is an estimate simulated by the system based on account tiers for scheduling reference only. Please refer to official Google errors for actual limits.',
          columns: {
            channel: 'Auth Channel',
            account: 'Account Status',
            limits: 'Limit Policy',
            docs: 'Official Docs'
          },
          docs: {
            codeAssist: 'Code Assist Quotas',
            aiStudio: 'AI Studio Pricing',
            vertex: 'Vertex AI Quotas'
          },
          simulatedNote: 'Simulated quota, for reference only',
          rows: {
            googleOne: {
              channel: 'Google One OAuth (Individuals / Code Assist for Individuals)',
              limitsFree: 'Shared pool: 1000 RPD / 60 RPM',
              limitsPro: 'Shared pool: 1500 RPD / 120 RPM',
              limitsUltra: 'Shared pool: 2000 RPD / 120 RPM'
            },
            gcp: {
              channel: 'GCP Code Assist OAuth (Enterprise)',
              limitsStandard: 'Shared pool: 1500 RPD / 120 RPM',
              limitsEnterprise: 'Shared pool: 2000 RPD / 120 RPM'
            },
            cli: {
              channel: 'Gemini CLI (Official Google Login / Code Assist)',
              free: 'Free Google Account',
              premium: 'Google One AI Premium',
              limitsFree: 'RPD ~1000; RPM ~60 (soft)',
              limitsPremium: 'RPD ~1500+; RPM ~60+ (priority queue)'
            },
            gcloud: {
              channel: 'GCP Code Assist (gcloud auth)',
              account: 'No Code Assist subscription',
              limits: 'RPD ~1000; RPM ~60 (preview)'
            },
            aiStudio: {
              channel: 'AI Studio API Key / OAuth',
              free: 'No billing (free tier)',
              paid: 'Billing enabled (pay-as-you-go)',
              limitsFree: 'RPD 50; RPM 2 (Pro) / 15 (Flash)',
              limitsPaid: 'RPD unlimited; RPM 1000 (Pro) / 2000 (Flash) (per model)'
            },
            customOAuth: {
              channel: 'Custom OAuth Client (GCP)',
              free: 'Project not billed',
              paid: 'Project billed',
              limitsFree: 'RPD 50; RPM 2 (project quota)',
              limitsPaid: 'RPD unlimited; RPM 1000+ (project quota)'
            }
          }
        },
        rateLimit: {
          ok: 'Not rate limited',
          unlimited: 'Unlimited',
          limited: 'Rate limited {time}',
          now: 'now'
        }
      },
      // 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"',
      sendingGeminiImageRequest: 'Sending Gemini image generation test request...',
      response: 'Response:',
      startTest: 'Start Test',
      testing: 'Testing...',
      retry: 'Retry',
      copyOutput: 'Copy output',
      outputCopied: 'Output copied',
      startingTestForAccount: 'Starting test for account: {name}',
      testAccountTypeLabel: 'Account type: {type}',
      selectTestModel: 'Select Test Model',
      testModel: 'Test model',
      testPrompt: 'Prompt: "hi"',
      geminiImagePromptLabel: 'Image prompt',
      geminiImagePromptPlaceholder: 'Example: Generate an orange cat astronaut sticker in pixel-art style on a solid background.',
      geminiImagePromptDefault: 'Generate a cute orange cat astronaut sticker on a clean pastel background.',
      geminiImageTestHint: 'When a Gemini image model is selected, this test sends a real image-generation request and previews the returned image below.',
      geminiImageTestMode: 'Mode: Gemini image generation test',
      geminiImagePreview: 'Generated images:',
      geminiImageReceived: 'Received test image #{count}',
      // 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',
        statsTitleDaily: 'Daily Usage Statistics',
        geminiProDaily: 'Pro',
        geminiFlashDaily: 'Flash',
        gemini3Pro: 'G3P',
        gemini3Flash: 'G3F',
        gemini3Image: 'G31FI',
        claude: 'Claude',
        passiveSampled: 'Passive',
        activeQuery: 'Query'
      },
      tier: {
        free: 'Free',
        pro: 'Pro',
        ultra: 'Ultra',
        aiPremium: 'AI Premium',
        standard: 'Standard',
        basic: 'Basic',
        personal: 'Personal',
        unlimited: 'Unlimited'
      },
      ineligibleWarning:
        'This account is not eligible for Antigravity, but API forwarding still works. Use at your own risk.',
      forbidden: 'Forbidden',
      forbiddenValidation: 'Verification Required',
      forbiddenViolation: 'Violation Ban',
      openVerification: 'Open Verification Link',
      copyLink: 'Copy Link',
      linkCopied: 'Link Copied',
      needsReauth: 'Re-auth Required',
      rateLimited: 'Rate Limited',
      usageError: 'Fetch Error'
    },

    // Scheduled Tests
    scheduledTests: {
      title: 'Scheduled Tests',
      addPlan: 'Add Plan',
      editPlan: 'Edit Plan',
      deletePlan: 'Delete Plan',
      model: 'Model',
      cronExpression: 'Cron Expression',
      enabled: 'Enabled',
      lastRun: 'Last Run',
      nextRun: 'Next Run',
      maxResults: 'Max Results',
      noPlans: 'No scheduled test plans',
      confirmDelete: 'Are you sure you want to delete this plan?',
      createSuccess: 'Plan created successfully',
      updateSuccess: 'Plan updated successfully',
      deleteSuccess: 'Plan deleted successfully',
      results: 'Test Results',
      noResults: 'No test results yet',
      responseText: 'Response',
      errorMessage: 'Error',
      success: 'Success',
      failed: 'Failed',
      running: 'Running',
      schedule: 'Schedule',
      cronHelp: 'Standard 5-field cron expression (e.g., */30 * * * *)',
      cronTooltipTitle: 'Cron expression examples:',
      cronTooltipMeaning: 'Defines when the test runs automatically. The 5 fields are: minute, hour, day, month, and weekday.',
      cronTooltipExampleEvery30Min: '*/30 * * * *: run every 30 minutes',
      cronTooltipExampleHourly: '0 * * * *: run at the start of every hour',
      cronTooltipExampleDaily: '0 9 * * *: run every day at 09:00',
      cronTooltipExampleWeekly: '0 9 * * 1: run every Monday at 09:00',
      cronTooltipRange: 'Recommended range: use standard 5-field cron. For health checks, start with a moderate frequency such as every 30 minutes, every hour, or once a day instead of running too often.',
      maxResultsTooltipTitle: 'What Max Results means:',
      maxResultsTooltipMeaning: 'Sets how many historical test results are kept for a single plan so the result list does not grow without limit.',
      maxResultsTooltipBody: 'Only the newest test results are kept. Once the number of saved results exceeds this value, older records are pruned automatically so the history list and storage stay under control.',
      maxResultsTooltipExample: 'For example, 100 means keeping at most the latest 100 test results. When the 101st result is saved, the oldest one is removed.',
      maxResultsTooltipRange: 'Recommended range: usually 20 to 200. Use 20-50 when you only care about recent health status, or 100-200 if you want a longer trend history.',
      autoRecover: 'Auto Recover',
      autoRecoverHelp: 'Automatically recover account from error/rate-limited state on successful test'
    },

    // Proxies
    proxies: {
      title: 'Proxy Management',
      description: 'Manage proxy servers for accounts',
      createProxy: 'Create Proxy',
      editProxy: 'Edit Proxy',
      deleteProxy: 'Delete Proxy',
      dataImport: 'Import',
      dataExportSelected: 'Export Selected',
      dataImportTitle: 'Import Proxies',
      dataImportHint: 'Upload the exported proxy JSON file to import proxies in bulk.',
      dataImportWarning: 'Import will create or reuse proxies, keep their status, and trigger latency checks after completion.',
      dataImportFile: 'Data File',
      dataImportButton: 'Start Import',
      dataImporting: 'Importing...',
      dataImportSelectFile: 'Please select a data file',
      dataImportParseFailed: 'Failed to parse data',
      dataImportFailed: 'Failed to import data',
      dataImportResult: 'Import Result',
      dataImportResultSummary: 'Created {proxy_created}, reused {proxy_reused}, failed {proxy_failed}',
      dataImportErrors: 'Failure Details',
      dataImportSuccess: 'Import completed: created {proxy_created}, reused {proxy_reused}',
      dataImportCompletedWithErrors: 'Import completed with errors: failed {proxy_failed}',
      dataExport: 'Export',
      dataExportConfirmMessage: 'The exported data contains sensitive proxy information. Store it securely.',
      dataExportConfirm: 'Confirm Export',
      dataExported: 'Data exported successfully',
      dataExportFailed: 'Failed to export data',
      copyProxyUrl: 'Copy Proxy URL',
      urlCopied: 'Proxy URL copied',
      searchProxies: 'Search proxies...',
      allProtocols: 'All Protocols',
      allStatus: 'All Status',
      protocols: {
        http: 'HTTP',
        https: 'HTTPS',
        socks5: 'SOCKS5',
        socks5h: 'SOCKS5H (Remote DNS)'
      },
      columns: {
        name: 'Name',
        protocol: 'Protocol',
        address: 'Address',
        auth: 'Auth',
        location: 'Location',
        status: 'Status',
        accounts: 'Accounts',
        latency: 'Latency',
        actions: 'Actions'
      },
      testConnection: 'Test Connection',
      qualityCheck: 'Quality Check',
      batchQualityCheck: 'Batch Quality Check',
      batchTest: 'Test All Proxies',
      testFailed: 'Failed',
      latencyFailed: 'Connection failed',
      batchTestEmpty: 'No proxies available for testing',
      batchTestDone: 'Batch test completed for {count} proxies',
      batchTestFailed: 'Batch test failed',
      batchDeleteAction: 'Delete',
      batchDelete: 'Batch delete',
      batchDeleteConfirm: 'Delete {count} selected proxies? In-use ones will be skipped.',
      batchDeleteDone: 'Deleted {deleted} proxies, skipped {skipped}',
      batchDeleteSkipped: 'Skipped {skipped} proxies',
      batchDeleteFailed: 'Batch delete failed',
      deleteBlockedInUse: 'This proxy is in use and cannot be deleted',
      accountsTitle: 'Accounts using this IP',
      accountsEmpty: 'No accounts are using this proxy',
      accountsFailed: 'Failed to load accounts list',
      accountName: 'Account',
      accountPlatform: 'Platform',
      accountNotes: 'Notes',
      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',
      qualityCheckDone: 'Quality check completed: score {score} ({grade})',
      qualityCheckFailed: 'Failed to run proxy quality check',
      batchQualityDone:
        'Batch quality check completed for {count} proxies: healthy {healthy}, warn {warn}, challenge {challenge}, abnormal {failed}',
      batchQualityFailed: 'Batch quality check failed',
      batchQualityEmpty: 'No proxies available for quality check',
      qualityReportTitle: 'Proxy Quality Report',
      qualityGrade: 'Grade {grade}',
      qualityExitIP: 'Exit IP',
      qualityCountry: 'Exit Region',
      qualityBaseLatency: 'Base Latency',
      qualityCheckedAt: 'Checked At',
      qualityTableTarget: 'Target',
      qualityTableStatus: 'Status',
      qualityTableLatency: 'Latency',
      qualityTableMessage: 'Message',
      qualityInline: 'Quality {grade}/{score}',
      qualityStatusHealthy: 'Healthy',
      qualityStatusPass: 'Pass',
      qualityStatusWarn: 'Warn',
      qualityStatusFail: 'Fail',
      qualityStatusChallenge: 'Challenge',
      qualityTargetBase: 'Base Connectivity',
      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',
      nameRequired: 'Please enter proxy name',
      hostRequired: 'Please enter host address',
      portInvalid: 'Port must be between 1-65535',
      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 or email...',
      allTypes: 'All Types',
      allStatus: 'All Status',
      balance: 'Balance',
      concurrency: 'Concurrency',
      subscription: 'Subscription',
      invitation: 'Invitation',
      invitationHint: 'Invitation codes are used to restrict user registration. They are automatically marked as used after use.',
      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',
      types: {
        balance: 'Balance',
        concurrency: 'Concurrency',
        subscription: 'Subscription',
        invitation: 'Invitation',
        // Admin adjustment types (created when admin modifies user balance/concurrency)
        admin_balance: 'Balance (Admin)',
        admin_concurrency: 'Concurrency (Admin)'
      },
      selectGroup: 'Select Group',
      selectGroupPlaceholder: 'Choose a subscription group',
      validityDays: 'Validity Days',
      groupRequired: 'Please select a subscription group',
      days: ' days',
      status: {
        unused: 'Unused',
        used: 'Used',
        expired: 'Expired',
        disabled: 'Disabled'
      }
    },

    // Announcements
    announcements: {
      title: 'Announcements',
      description: 'Create announcements and target by conditions',
      createAnnouncement: 'Create Announcement',
      editAnnouncement: 'Edit Announcement',
      deleteAnnouncement: 'Delete Announcement',
      searchAnnouncements: 'Search announcements...',
      status: 'Status',
      allStatus: 'All Status',
      columns: {
        title: 'Title',
        status: 'Status',
        notifyMode: 'Notify Mode',
        targeting: 'Targeting',
        timeRange: 'Schedule',
        createdAt: 'Created At',
        actions: 'Actions'
      },
      statusLabels: {
        draft: 'Draft',
        active: 'Active',
        archived: 'Archived'
      },
      notifyModeLabels: {
        silent: 'Silent',
        popup: 'Popup'
      },
      form: {
        title: 'Title',
        content: 'Content (Markdown supported)',
        status: 'Status',
        notifyMode: 'Notify Mode',
        notifyModeHint: 'Popup mode will show a popup notification to users',
        startsAt: 'Starts At',
        endsAt: 'Ends At',
        startsAtHint: 'Leave empty to start immediately',
        endsAtHint: 'Leave empty to never expire',
        targetingMode: 'Targeting',
        targetingAll: 'All users',
        targetingCustom: 'Custom rules',
        addOrGroup: 'Add OR group',
        addAndCondition: 'Add AND condition',
        conditionType: 'Condition type',
        conditionSubscription: 'Subscription',
        conditionBalance: 'Balance',
        operator: 'Operator',
        balanceValue: 'Balance threshold',
        selectPackages: 'Select packages'
      },
      operators: {
        gt: '>',
        gte: '≥',
        lt: '<',
        lte: '≤',
        eq: '='
      },
      targetingSummaryAll: 'All users',
      targetingSummaryCustom: 'Custom ({groups} groups)',
      timeImmediate: 'Immediate',
      timeNever: 'Never',
      readStatus: 'Read Status',
      eligible: 'Eligible',
      readAt: 'Read at',
      unread: 'Unread',
      searchUsers: 'Search users...',
      failedToLoad: 'Failed to load announcements',
      failedToCreate: 'Failed to create announcement',
      failedToUpdate: 'Failed to update announcement',
      failedToDelete: 'Failed to delete announcement',
      failedToLoadReadStatus: 'Failed to load read status',
      deleteConfirm: 'Are you sure you want to delete this announcement? This action cannot be undone.'
    },

    // Promo Codes
    promo: {
      title: 'Promo Code Management',
      description: 'Create and manage registration promo codes',
      createCode: 'Create Promo Code',
      editCode: 'Edit Promo Code',
      deleteCode: 'Delete Promo Code',
      searchCodes: 'Search codes...',
      allStatus: 'All Status',
      columns: {
        code: 'Code',
        bonusAmount: 'Bonus Amount',
        maxUses: 'Max Uses',
        usedCount: 'Used',
        usage: 'Usage',
        status: 'Status',
        expiresAt: 'Expires At',
        createdAt: 'Created At',
        actions: 'Actions'
      },
      // Form labels (flat structure for template usage)
      code: 'Promo Code',
      autoGenerate: 'auto-generate if empty',
      codePlaceholder: 'Enter promo code or leave empty',
      bonusAmount: 'Bonus Amount ($)',
      maxUses: 'Max Uses',
      zeroUnlimited: '0 = unlimited',
      expiresAt: 'Expires At',
      notes: 'Notes',
      notesPlaceholder: 'Optional notes for this code',
      status: 'Status',
      neverExpires: 'Never expires',
      // Status labels
      statusActive: 'Active',
      statusDisabled: 'Disabled',
      statusExpired: 'Expired',
      statusMaxUsed: 'Used Up',
      // Usage records
      usageRecords: 'Usage Records',
      viewUsages: 'View Usages',
      noUsages: 'No usage records yet',
      userPrefix: 'User #{id}',
      copied: 'Copied!',
      // Messages
      noCodesYet: 'No promo codes yet',
      createFirstCode: 'Create your first promo code to offer registration bonuses.',
      codeCreated: 'Promo code created successfully',
      codeUpdated: 'Promo code updated successfully',
      codeDeleted: 'Promo code deleted successfully',
      deleteCodeConfirm: 'Are you sure you want to delete this promo code? This action cannot be undone.',
      copyRegisterLink: 'Copy register link',
      registerLinkCopied: 'Register link copied to clipboard',
      failedToLoad: 'Failed to load promo codes',
      failedToCreate: 'Failed to create promo code',
      failedToUpdate: 'Failed to update promo code',
      failedToDelete: 'Failed to delete promo code',
      failedToLoadUsages: 'Failed to load usage records'
    },

    // Usage Records
    usage: {
      title: 'Usage Records',
      description: 'View and manage all user usage records',
      userFilter: 'User',
      searchUserPlaceholder: 'Search user by email...',
      searchApiKeyPlaceholder: 'Search API key by name...',
      searchAccountPlaceholder: 'Search account by name...',
      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',
      inputCost: 'Input Cost',
      outputCost: 'Output Cost',
      cacheCreationCost: 'Cache Creation Cost',
      cacheReadCost: 'Cache Read Cost',
      inputTokens: 'Input Tokens',
      outputTokens: 'Output Tokens',
      cacheCreationTokens: 'Cache Creation Tokens',
      cacheCreation5mTokens: 'Cache Write',
      cacheCreation1hTokens: 'Cache Write',
      cacheReadTokens: 'Cache Read Tokens',
      failedToLoad: 'Failed to load usage records',
      billingType: 'Billing Type',
      allBillingTypes: 'All Billing Types',
      billingTypeBalance: 'Balance',
      billingTypeSubscription: 'Subscription',
      billingMode: 'Billing Mode',
      billingModeToken: 'Token',
      billingModePerRequest: 'Per Request',
      billingModeImage: 'Image',
      allBillingModes: 'All Billing Modes',
      ipAddress: 'IP',
      clickToViewBalance: 'Click to view balance history',
      failedToLoadUser: 'Failed to load user info',
      cleanup: {
        button: 'Cleanup',
        title: 'Cleanup Usage Records',
        warning: 'Cleanup is irreversible and will affect historical stats.',
        submit: 'Submit Cleanup',
        submitting: 'Submitting...',
        confirmTitle: 'Confirm Cleanup',
        confirmMessage: 'Are you sure you want to submit this cleanup task? This action cannot be undone.',
        confirmSubmit: 'Confirm Cleanup',
        cancel: 'Cancel',
        cancelConfirmTitle: 'Confirm Cancel',
        cancelConfirmMessage: 'Are you sure you want to cancel this cleanup task?',
        cancelConfirm: 'Confirm Cancel',
        cancelSuccess: 'Cleanup task canceled',
        cancelFailed: 'Failed to cancel cleanup task',
        recentTasks: 'Recent Cleanup Tasks',
        loadingTasks: 'Loading tasks...',
        noTasks: 'No cleanup tasks yet',
        range: 'Range',
        deletedRows: 'Deleted',
        missingRange: 'Please select a date range',
        submitSuccess: 'Cleanup task created',
        submitFailed: 'Failed to create cleanup task',
        loadFailed: 'Failed to load cleanup tasks',
        status: {
          pending: 'Pending',
          running: 'Running',
          succeeded: 'Succeeded',
          failed: 'Failed',
          canceled: 'Canceled'
        }
      }
    },

    // Ops Monitoring
    ops: {
      title: 'Ops Monitoring',
      description: 'Operational monitoring and troubleshooting',
      // Dashboard
      systemHealth: 'System Health',
      overview: 'Overview',
      noSystemMetrics: 'No system metrics collected yet.',
      collectedAt: 'Collected at:',
      window: 'window',
      memory: 'Memory',
      db: 'DB',
      goroutines: 'Goroutines',
      jobs: 'Jobs',
      jobsHelp: 'Click “Details” to view job heartbeats and recent errors',
      active: 'active',
      idle: 'idle',
      waiting: 'waiting',
      conns: 'conns',
      queue: 'queue',
      accountSwitches: 'Account switches',
      ok: 'ok',
      lastRun: 'last_run:',
      lastSuccess: 'last_success:',
      lastError: 'last_error:',
      noData: 'No data.',
      loadingText: 'loading',
      ready: 'ready',
      requestsTotal: 'Requests (total)',
      slaScope: 'SLA scope:',
      tokens: 'Tokens',
      tps: 'TPS:',
      current: 'current',
      peak: 'peak',
      average: 'average',
      totalRequests: 'Total Requests',
      avgQps: 'Avg QPS',
      avgTps: 'Avg TPS',
      avgLatency: 'Avg Request Duration',
      avgTtft: 'Avg TTFT',
      exceptions: 'Exceptions',
      requestErrors: 'Request Errors',
      errorCount: 'Error Count',
      upstreamErrors: 'Upstream Errors',
      errorCountExcl429529: 'Error Count (excl 429/529)',
      sla: 'SLA (excl business limits)',
      businessLimited: 'business_limited:',
      errors: 'Errors',
      errorRate: 'error_rate:',
      upstreamRate: 'upstream_rate:',
      latencyDuration: 'Request Duration',
      ttftLabel: 'TTFT (first_token_ms)',
      p50: 'p50:',
      p90: 'p90:',
      p95: 'p95:',
      p99: 'p99:',
      avg: 'avg:',
      max: 'max:',
      requests: 'Requests',
      requestsTitle: 'Requests',
      upstream: 'Upstream',
      client: 'Client',
      system: 'System',
      other: 'Other',
      errorsSla: 'Errors (SLA scope)',
      upstreamExcl429529: 'Upstream (excl 429/529)',
      failedToLoadData: 'Failed to load ops data.',
      failedToLoadOverview: 'Failed to load overview',
      failedToLoadThroughputTrend: 'Failed to load throughput trend',
      failedToLoadSwitchTrend: 'Failed to load avg account switches trend',
      failedToLoadLatencyHistogram: 'Failed to load request duration histogram',
      failedToLoadErrorTrend: 'Failed to load error trend',
      failedToLoadErrorDistribution: 'Failed to load error distribution',
      failedToLoadErrorDetail: 'Failed to load error detail',
      retryFailed: 'Retry failed',
      tpsK: 'TPS (K)',
      top: 'Top:',
      throughputTrend: 'Throughput Trend',
      switchRateTrend: 'Avg Account Switches',
      latencyHistogram: 'Request Duration Histogram',
      errorTrend: 'Error Trend',
      errorDistribution: 'Error Distribution',
      switchRate: 'Avg switches',
      // Health Score & Diagnosis
      health: 'Health',
      healthCondition: 'Health Condition',
      healthHelp: 'Overall system health score based on SLA, error rate, and resource usage',
      healthyStatus: 'Healthy',
      riskyStatus: 'At Risk',
      idleStatus: 'Idle',
      timeRange: {
        '5m': 'Last 5 minutes',
        '30m': 'Last 30 minutes',
        '1h': 'Last 1 hour',
        '1d': 'Last 1 day',
        '15d': 'Last 15 days',
        '6h': 'Last 6 hours',
        '24h': 'Last 24 hours',
        '7d': 'Last 7 days',
        '30d': 'Last 30 days'
      },
      openaiTokenStats: {
        title: 'OpenAI Token Request Stats',
        viewModeTopN: 'TopN',
        viewModePagination: 'Pagination',
        prevPage: 'Previous',
        nextPage: 'Next',
        pageInfo: 'Page {page}/{total}',
        totalModels: 'Total models: {total}',
        failedToLoad: 'Failed to load OpenAI token stats',
        empty: 'No OpenAI token stats for the current filters',
        table: {
          model: 'Model',
          requestCount: 'Requests',
          avgTokensPerSec: 'Avg Tokens/sec',
          avgFirstTokenMs: 'Avg First Token Latency (ms)',
          totalOutputTokens: 'Total Output Tokens',
          avgDurationMs: 'Avg Duration (ms)',
          requestsWithFirstToken: 'Requests With First Token'
        }
      },
      fullscreen: {
        enter: 'Enter Fullscreen'
      },
      diagnosis: {
        title: 'Smart Diagnosis',
        footer: 'Automated diagnostic suggestions based on current metrics',
        idle: 'System is currently idle',
        idleImpact: 'No active traffic',
        // Resource diagnostics
        dbDown: 'Database connection failed',
        dbDownImpact: 'All database operations will fail',
        dbDownAction: 'Check database service status, network connectivity, and connection configuration',
        redisDown: 'Redis connection failed',
        redisDownImpact: 'Cache functionality degraded, performance may decline',
        redisDownAction: 'Check Redis service status and network connectivity',
        cpuCritical: 'CPU usage critically high ({usage}%)',
        cpuCriticalImpact: 'System response slowing, may affect all requests',
        cpuCriticalAction: 'Check CPU-intensive tasks, consider scaling or code optimization',
        cpuHigh: 'CPU usage elevated ({usage}%)',
        cpuHighImpact: 'System load is high, needs attention',
        cpuHighAction: 'Monitor CPU trends, prepare scaling plan',
        memoryCritical: 'Memory usage critically high ({usage}%)',
        memoryCriticalImpact: 'May trigger OOM, system stability threatened',
        memoryCriticalAction: 'Check for memory leaks, consider increasing memory or optimizing usage',
        memoryHigh: 'Memory usage elevated ({usage}%)',
        memoryHighImpact: 'Memory pressure is high, needs attention',
        memoryHighAction: 'Monitor memory trends, check for memory leaks',
        ttftHigh: 'Time to first token elevated ({ttft}ms)',
        ttftHighImpact: 'User perceived latency increased',
        ttftHighAction: 'Optimize request processing flow, reduce pre-processing time',
        // Error rate diagnostics
        upstreamCritical: 'Upstream error rate critically high ({rate}%)',
        upstreamCriticalImpact: 'May affect many user requests',
        upstreamCriticalAction: 'Check upstream service health, enable fallback strategies',
        upstreamHigh: 'Upstream error rate elevated ({rate}%)',
        upstreamHighImpact: 'Recommend checking upstream service status',
        upstreamHighAction: 'Contact upstream service team, prepare fallback plan',
        errorHigh: 'Error rate too high ({rate}%)',
        errorHighImpact: 'Many requests failing',
        errorHighAction: 'Check error logs, identify root cause, urgent fix required',
        errorElevated: 'Error rate elevated ({rate}%)',
        errorElevatedImpact: 'Recommend checking error logs',
        errorElevatedAction: 'Analyze error types and distribution, create fix plan',
        // SLA diagnostics
        slaCritical: 'SLA critically below target ({sla}%)',
        slaCriticalImpact: 'User experience severely degraded',
        slaCriticalAction: 'Urgently investigate errors and latency, consider rate limiting',
        slaLow: 'SLA below target ({sla}%)',
        slaLowImpact: 'Service quality needs attention',
        slaLowAction: 'Analyze SLA decline causes, optimize system performance',
        // Health score diagnostics
        healthCritical: 'Overall health score critically low ({score})',
        healthCriticalImpact: 'Multiple metrics may be degraded; prioritize error rate and latency investigation',
        healthCriticalAction: 'Comprehensive system check, prioritize critical-level issues',
        healthLow: 'Overall health score low ({score})',
        healthLowImpact: 'May indicate minor instability; monitor SLA and error rates',
        healthLowAction: 'Monitor metric trends, prevent issue escalation',
        healthy: 'All system metrics normal',
        healthyImpact: 'Service running stable'
      },
      // Error Log
      errorLog: {
        timeId: 'Time / ID',
        commonErrors: {
          contextDeadlineExceeded: 'context deadline exceeded',
          connectionRefused: 'connection refused',
          rateLimit: 'rate limit'
        },
        time: 'Time',
        type: 'Type',
        context: 'Context',
        platform: 'Platform',
        model: 'Model',
        group: 'Group',
        user: 'User',
        userId: 'User ID',
        account: 'Account',
        accountId: 'Account ID',
        status: 'Status',
        message: 'Message',
        latency: 'Request Duration',
        action: 'Action',
        noErrors: 'No errors in this window.',
        grp: 'GRP:',
        acc: 'ACC:',
        details: 'Details',
        phase: 'Phase',
        id: 'ID:',
        typeUpstream: 'Upstream',
        typeRequest: 'Request',
        typeAuth: 'Auth',
        typeRouting: 'Routing',
        typeInternal: 'Internal',
        endpoint: 'Endpoint',
        requestType: 'Type',
        requestTypeSync: 'Sync',
        requestTypeStream: 'Stream',
        requestTypeWs: 'WS'
      },
      // Error Details Modal
      errorDetails: {
        upstreamErrors: 'Upstream Errors',
        requestErrors: 'Request Errors',
        unresolved: 'Unresolved',
        resolved: 'Resolved',
        viewErrors: 'Errors',
        viewExcluded: 'Excluded',
        statusCodeOther: 'Other',
        owner: {
          provider: 'Provider',
          client: 'Client',
          platform: 'Platform'
        },
        phase: {
          request: 'Request',
          auth: 'Auth',
          routing: 'Routing',
          upstream: 'Upstream',
          network: 'Network',
          internal: 'Internal'
        },
        total: 'Total:',
        searchPlaceholder: 'Search request_id / client_request_id / message',
      },
      // Error Detail Modal
      errorDetail: {
        title: 'Error Detail',
        titleWithId: 'Error #{id}',
        noErrorSelected: 'No error selected.',
        resolution: 'Resolved:',
        pinnedToOriginalAccountId: 'Pinned to original account_id',
        missingUpstreamRequestBody: 'Missing upstream request body',
        failedToLoadRetryHistory: 'Failed to load retry history',
        failedToUpdateResolvedStatus: 'Failed to update resolved status',
        unsupportedRetryMode: 'Unsupported retry mode',
        classificationKeys: {
          phase: 'Phase',
          owner: 'Owner',
          source: 'Source',
          retryable: 'Retryable',
          resolvedAt: 'Resolved At',
          resolvedBy: 'Resolved By',
          resolvedRetryId: 'Resolved Retry',
          retryCount: 'Retry Count'
        },
        source: {
          upstream_http: 'Upstream HTTP'
        },
        upstreamKeys: {
          status: 'Status',
          message: 'Message',
          detail: 'Detail',
          upstreamErrors: 'Upstream Errors'
        },
        upstreamEvent: {
          account: 'Account',
          status: 'Status',
          requestId: 'Request ID'
        },
        responsePreview: {
          expand: 'Response (click to expand)',
          collapse: 'Response (click to collapse)'
        },
        retryMeta: {
          used: 'Used',
          success: 'Success',
          pinned: 'Pinned'
        },
        loading: 'Loading…',
        requestId: 'Request ID',
        time: 'Time',
        phase: 'Phase',
        status: 'Status',
        message: 'Message',
        basicInfo: 'Basic Info',
        platform: 'Platform',
        model: 'Model',
        group: 'Group',
        user: 'User',
        account: 'Account',
        latency: 'Request Duration',
        businessLimited: 'Business Limited',
        requestPath: 'Request Path',
        inboundEndpoint: 'Inbound Endpoint',
        upstreamEndpoint: 'Upstream Endpoint',
        requestedModel: 'Requested Model',
        upstreamModel: 'Upstream Model',
        requestType: 'Request Type',
        requestTypeUnknown: 'Unknown',
        requestTypeSync: 'Sync',
        requestTypeStream: 'Stream',
        requestTypeWs: 'WebSocket',
        modelMapping: 'Model Mapping',
        timings: 'Timings',
        auth: 'Auth',
        routing: 'Routing',
        upstream: 'Upstream',
        response: 'Response',
        classification: 'Classification',
        notRetryable: 'Not recommended to retry',
        retry: 'Retry',
        retryClient: 'Retry (Client)',
        retryUpstream: 'Retry (Upstream pinned)',
        pinnedAccountId: 'Pinned account_id',
        retryNotes: 'Retry Notes',
        requestBody: 'Request Body',
        errorBody: 'Error Body',
        trimmed: 'trimmed',
        confirmRetry: 'Confirm Retry',
        retrySuccess: 'Retry succeeded',
        retryFailed: 'Retry failed',
        retryHint: 'Retry will resend the request with the same parameters',
        retryClientHint: 'Use client retry (no account pinning)',
        retryUpstreamHint: 'Use upstream pinned retry (pin to the error account)',
        pinnedAccountIdHint: '(auto from error log)',
        retryNote1: 'Retry will use the same request body and parameters',
        retryNote2: 'If the original request failed due to account issues, pinned retry may still fail',
        retryNote3: 'Client retry will reselect an account',
        retryNote4: 'You can force retry for non-retryable errors, but it is not recommended',
        confirmRetryMessage: 'Confirm retry this request?',
        confirmRetryHint: 'Will resend with the same request parameters',
        forceRetry: 'I understand and want to force retry',
        forceRetryHint: 'This error usually cannot be fixed by retry; check to proceed',
        forceRetryNeedAck: 'Please check to force retry',
        markResolved: 'Mark resolved',
        markUnresolved: 'Mark unresolved',
        viewRetries: 'Retry history',
        retryHistory: 'Retry History',
        tabOverview: 'Overview',
        tabRetries: 'Retries',
        tabRequest: 'Request',
        tabResponse: 'Response',
        responseBody: 'Response',
        compareA: 'Compare A',
        compareB: 'Compare B',
        retrySummary: 'Retry Summary',
        responseHintSucceeded: 'Showing succeeded retry response_preview (#{id})',
        responseHintFallback: 'No succeeded retry found; showing stored error_body',
        suggestion: 'Suggestion',
        suggestUpstreamResolved: '✓ Upstream error resolved by retry; no action needed',
        suggestUpstream: 'Upstream instability: check account status, consider switching accounts, or retry',
        suggestRequest: 'Client request error: ask customer to fix request parameters',
        suggestAuth: 'Auth failed: verify API key/credentials',
        suggestPlatform: 'Platform error: prioritize investigation and fix',
        suggestGeneric: 'See details for more context'
      },
      requestDetails: {
        title: 'Request Details',
        details: 'Details',
        rangeLabel: 'Window: {range}',
        rangeMinutes: '{n} minutes',
        rangeHours: '{n} hours',
        empty: 'No requests in this window.',
        emptyHint: 'Try a different time range or remove filters.',
        failedToLoad: 'Failed to load request details',
        requestIdCopied: 'Request ID copied',
        copyFailed: 'Copy failed',
        copy: 'Copy',
        viewError: 'View Error',
        kind: {
          success: 'SUCCESS',
          error: 'ERROR'
        },
        table: {
          time: 'Time',
          kind: 'Kind',
          platform: 'Platform',
          model: 'Model',
          duration: 'Duration',
          status: 'Status',
          requestId: 'Request ID',
          actions: 'Actions'
        }
      },
      alertEvents: {
        title: 'Alert Events',
        description: 'Recent alert firing/resolution records (email-only)',
        loading: 'Loading...',
        empty: 'No alert events',
        loadFailed: 'Failed to load alert events',
        status: {
          firing: 'FIRING',
          resolved: 'RESOLVED',
          manualResolved: 'MANUAL RESOLVED'
        },
        detail: {
          title: 'Alert Detail',
          loading: 'Loading detail...',
          empty: 'No detail',
          loadFailed: 'Failed to load alert detail',
          manualResolve: 'Mark as Resolved',
          manualResolvedSuccess: 'Marked as manually resolved',
          manualResolvedFailed: 'Failed to mark as manually resolved',
          silence: 'Ignore Alert',
          silenceSuccess: 'Alert silenced',
          silenceFailed: 'Failed to silence alert',
          viewRule: 'View Rule',
          viewLogs: 'View Logs',
          firedAt: 'Fired At',
          resolvedAt: 'Resolved At',
          ruleId: 'Rule ID',
          dimensions: 'Dimensions',
          historyTitle: 'History',
          historyHint: 'Recent events with same rule + dimensions',
          historyLoading: 'Loading history...',
          historyEmpty: 'No history'
        },
        table: {
          time: 'Time',
          status: 'Status',
          severity: 'Severity',
          platform: 'Platform',
          ruleId: 'Rule ID',
          title: 'Title',
          duration: 'Duration',
          metric: 'Metric / Threshold',
          dimensions: 'Dimensions',
          email: 'Email Sent',
          emailSent: 'Sent',
          emailIgnored: 'Ignored'
        }
      },
      alertRules: {
        title: 'Alert Rules',
        description: 'Create and manage threshold-based system alerts (email-only)',
        loading: 'Loading...',
        empty: 'No alert rules',
        loadFailed: 'Failed to load alert rules',
        saveFailed: 'Failed to save alert rule',
        saveSuccess: 'Alert rule saved successfully',
        deleteFailed: 'Failed to delete alert rule',
        deleteSuccess: 'Alert rule deleted successfully',
        manage: 'Manage Alert Rules',
        create: 'Create Rule',
        createTitle: 'Create Alert Rule',
        editTitle: 'Edit Alert Rule',
        deleteConfirmTitle: 'Delete this rule?',
        deleteConfirmMessage: 'This will remove the rule and its related events. Continue?',
        metricGroups: {
          system: 'System Metrics',
          group: 'Group-level Metrics (requires group_id)',
          account: 'Account-level Metrics'
        },
        metrics: {
          successRate: 'Success Rate (%)',
          errorRate: 'Error Rate (%)',
          upstreamErrorRate: 'Upstream Error Rate (%)',
          p95: 'P95 Latency (ms)',
          p99: 'P99 Latency (ms)',
          cpu: 'CPU Usage (%)',
          memory: 'Memory Usage (%)',
          queueDepth: 'Concurrency Queue Depth',
          groupAvailableAccounts: 'Group Available Accounts',
          groupAvailableRatio: 'Group Available Ratio (%)',
          groupRateLimitRatio: 'Group Rate Limit Ratio (%)',
          accountRateLimitedCount: 'Rate-limited Accounts',
          accountErrorCount: 'Error Accounts (excluding temporarily unschedulable)',
          accountErrorRatio: 'Error Account Ratio (%)',
          overloadAccountCount: 'Overloaded Accounts'
        },
        metricDescriptions: {
          successRate: 'Percentage of successful requests in the window (0-100).',
          errorRate: 'Percentage of failed requests in the window (0-100).',
          upstreamErrorRate: 'Percentage of upstream failures in the window (0-100).',
          p95: 'P95 request latency within the window (ms).',
          p99: 'P99 request latency within the window (ms).',
          cpu: 'Current instance CPU usage (0-100).',
          memory: 'Current instance memory usage (0-100).',
          queueDepth: 'Concurrency queue depth within the window (queued requests).',
          groupAvailableAccounts: 'Number of available accounts in the selected group (requires group_id).',
          groupAvailableRatio: 'Available account ratio in the selected group (0-100, requires group_id).',
          groupRateLimitRatio: 'Rate-limited account ratio in the selected group (0-100, requires group_id).',
          accountRateLimitedCount: 'Number of rate-limited accounts within the window.',
          accountErrorCount: 'Number of error accounts within the window (excluding temporarily unschedulable).',
          accountErrorRatio: 'Error account ratio within the window (0-100).',
          overloadAccountCount: 'Number of overloaded accounts within the window.'
        },
        hints: {
          recommended: 'Recommended: operator {operator}, threshold {threshold}{unit}',
          groupRequired: 'This is a group-level metric; selecting a group (group_id) is required.',
          groupOptional: 'Optional: limit the rule to a specific group via group_id.'
        },
        table: {
          name: 'Name',
          metric: 'Metric',
          severity: 'Severity',
          enabled: 'Enabled',
          actions: 'Actions'
        },
        form: {
          name: 'Name',
          description: 'Description',
          metric: 'Metric',
          operator: 'Operator',
          groupId: 'Group (group_id)',
          groupPlaceholder: 'Select a group',
          allGroups: 'All groups',
          threshold: 'Threshold',
          severity: 'Severity',
          window: 'Window (minutes)',
          sustained: 'Sustained (samples)',
          cooldown: 'Cooldown (minutes)',
          enabled: 'Enabled',
          notifyEmail: 'Send email notifications'
        },
        validation: {
          title: 'Please fix the following issues',
          invalid: 'Invalid rule',
          nameRequired: 'Name is required',
          metricRequired: 'Metric is required',
          groupIdRequired: 'group_id is required for group-level metrics',
          operatorRequired: 'Operator is required',
          thresholdRequired: 'Threshold must be a number',
          windowRange: 'Window must be one of: 1, 5, 60 minutes',
          sustainedRange: 'Sustained must be between 1 and 1440 samples',
          cooldownRange: 'Cooldown must be between 0 and 1440 minutes'
        }
      },
      runtime: {
        title: 'Ops Runtime Settings',
        description: 'Stored in database; changes take effect without editing config files.',
        loading: 'Loading...',
        noData: 'No runtime settings available',
        loadFailed: 'Failed to load runtime settings',
        saveSuccess: 'Runtime settings saved',
        saveFailed: 'Failed to save runtime settings',
        alertTitle: 'Alert Evaluator',
        groupAvailabilityTitle: 'Group Availability Monitor',
        evalIntervalSeconds: 'Evaluation Interval (seconds)',
        silencing: {
          title: 'Alert Silencing (Maintenance Mode)',
          enabled: 'Enable silencing',
          globalUntil: 'Silence until (RFC3339)',
          untilHint: 'Leave empty to only toggle silencing without an expiry (not recommended).',
          reason: 'Reason',
          reasonPlaceholder: 'e.g., planned maintenance',
          entries: {
            title: 'Advanced: targeted silencing',
            hint: 'Optional: silence only certain rules or severities. Leave fields empty to match all.',
            add: 'Add Entry',
            empty: 'No targeted entries',
            entryTitle: 'Entry #{n}',
            ruleId: 'Rule ID (optional)',
            ruleIdPlaceholder: 'e.g., 1',
            severities: 'Severities (optional)',
            severitiesPlaceholder: 'e.g., P0,P1 (empty = all)',
            until: 'Until (RFC3339)',
            reason: 'Reason',
            validation: {
              untilRequired: 'Entry until time is required',
              untilFormat: 'Entry until time must be a valid RFC3339 timestamp',
              ruleIdPositive: 'Entry rule_id must be a positive integer',
              severitiesFormat: 'Entry severities must be a comma-separated list of P0..P3'
            }
          },
          validation: {
            timeFormat: 'Silence time must be a valid RFC3339 timestamp'
          }
        },
        lockEnabled: 'Distributed Lock Enabled',
        lockKey: 'Distributed Lock Key',
        lockTTLSeconds: 'Distributed Lock TTL (seconds)',
        showAdvancedDeveloperSettings: 'Show advanced developer settings (Distributed Lock)',
        advancedSettingsSummary: 'Advanced settings (Distributed Lock)',
        evalIntervalHint: 'How often the evaluator runs. Keeping the default is recommended.',
        validation: {
          title: 'Please fix the following issues',
          invalid: 'Invalid settings',
          evalIntervalRange: 'Evaluation interval must be between 1 and 86400 seconds',
          lockKeyRequired: 'Distributed lock key is required when lock is enabled',
          lockKeyPrefix: 'Distributed lock key must start with "{prefix}"',
          lockKeyHint: 'Recommended: start with "{prefix}" to avoid conflicts',
          lockTtlRange: 'Distributed lock TTL must be between 1 and 86400 seconds',
          slaMinPercentRange: 'SLA minimum percentage must be between 0 and 100',
          ttftP99MaxRange: 'TTFT P99 maximum must be a number ≥ 0',
          requestErrorRateMaxRange: 'Request error rate maximum must be between 0 and 100',
          upstreamErrorRateMaxRange: 'Upstream error rate maximum must be between 0 and 100'
        }
      },
      email: {
        title: 'Email Notification',
        description: 'Configure alert/report email notifications (stored in database).',
        loading: 'Loading...',
        noData: 'No email notification config',
        loadFailed: 'Failed to load email notification config',
        saveSuccess: 'Email notification config saved',
        saveFailed: 'Failed to save email notification config',
        alertTitle: 'Alert Emails',
        reportTitle: 'Report Emails',
        recipients: 'Recipients',
        recipientsHint: 'If empty, the system may fallback to the first admin email.',
        minSeverity: 'Min Severity',
        minSeverityAll: 'All severities',
        rateLimitPerHour: 'Rate limit per hour',
        batchWindowSeconds: 'Batch window (seconds)',
        includeResolved: 'Include resolved alerts',
        dailySummary: 'Daily summary',
        weeklySummary: 'Weekly summary',
        errorDigest: 'Error digest',
        errorDigestMinCount: 'Min errors for digest',
        accountHealth: 'Account health',
        accountHealthThreshold: 'Error rate threshold (%)',
        cronPlaceholder: 'Cron expression',
        reportHint: 'Schedules use cron syntax; leave empty to use defaults.',
        validation: {
          title: 'Please fix the following issues',
          invalid: 'Invalid email notification config',
          alertRecipientsRequired: 'Alert emails are enabled but no recipients are configured',
          reportRecipientsRequired: 'Report emails are enabled but no recipients are configured',
          invalidRecipients: 'One or more recipient emails are invalid',
          rateLimitRange: 'Rate limit per hour must be a number ≥ 0',
          batchWindowRange: 'Batch window must be between 0 and 86400 seconds',
          cronRequired: 'A cron expression is required when schedule is enabled',
          cronFormat: 'Cron expression format looks invalid (expected at least 5 parts)',
          digestMinCountRange: 'Min errors for digest must be a number ≥ 0',
          accountHealthThresholdRange: 'Account health threshold must be between 0 and 100'
        }
      },
      settings: {
        title: 'Ops Monitoring Settings',
        loadFailed: 'Failed to load settings',
        saveSuccess: 'Ops monitoring settings saved successfully',
        saveFailed: 'Failed to save settings',
        dataCollection: 'Data Collection',
        evaluationInterval: 'Evaluation Interval (seconds)',
        evaluationIntervalHint: 'Frequency of detection tasks, recommended to keep default',
        alertConfig: 'Alert Configuration',
        enableAlert: 'Enable Alerts',
        alertRecipients: 'Alert Recipient Emails',
        emailPlaceholder: 'Enter email address',
        recipientsHint: 'If empty, the system will use the first admin email as default recipient',
        minSeverity: 'Minimum Severity',
        reportConfig: 'Report Configuration',
        enableReport: 'Enable Reports',
        reportRecipients: 'Report Recipient Emails',
        dailySummary: 'Daily Summary',
        weeklySummary: 'Weekly Summary',
        metricThresholds: 'Metric Thresholds',
        metricThresholdsHint: 'Configure alert thresholds for metrics, values exceeding thresholds will be displayed in red',
        slaMinPercent: 'SLA Minimum Percentage',
        slaMinPercentHint: 'SLA below this value will be displayed in red (default: 99.5%)',
        ttftP99MaxMs: 'TTFT P99 Maximum (ms)',
        ttftP99MaxMsHint: 'TTFT P99 above this value will be displayed in red (default: 500ms)',
        requestErrorRateMaxPercent: 'Request Error Rate Maximum (%)',
        requestErrorRateMaxPercentHint: 'Request error rate above this value will be displayed in red (default: 5%)',
        upstreamErrorRateMaxPercent: 'Upstream Error Rate Maximum (%)',
        upstreamErrorRateMaxPercentHint: 'Upstream error rate above this value will be displayed in red (default: 5%)',
        advancedSettings: 'Advanced Settings',
        dataRetention: 'Data Retention Policy',
        enableCleanup: 'Enable Data Cleanup',
        cleanupSchedule: 'Cleanup Schedule (Cron)',
        cleanupScheduleHint: 'Example: 0 2 * * * means 2 AM daily',
        errorLogRetentionDays: 'Error Log Retention Days',
        minuteMetricsRetentionDays: 'Minute Metrics Retention Days',
        hourlyMetricsRetentionDays: 'Hourly Metrics Retention Days',
        retentionDaysHint: 'Recommended 7-90 days, longer periods will consume more storage',
        aggregation: 'Pre-aggregation Tasks',
        enableAggregation: 'Enable Pre-aggregation',
        aggregationHint: 'Pre-aggregation improves query performance for long time windows',
        errorFiltering: 'Error Filtering',
        ignoreCountTokensErrors: 'Ignore count_tokens errors',
        ignoreCountTokensErrorsHint: 'When enabled, errors from count_tokens requests will not be written to the error log.',
        ignoreContextCanceled: 'Ignore client disconnect errors',
        ignoreContextCanceledHint: 'When enabled, client disconnect (context canceled) errors will not be written to the error log.',
        ignoreNoAvailableAccounts: 'Ignore no available accounts errors',
        ignoreNoAvailableAccountsHint: 'When enabled, "No available accounts" errors will not be written to the error log (not recommended; usually a config issue).',
        ignoreInvalidApiKeyErrors: 'Ignore invalid API key errors',
        ignoreInvalidApiKeyErrorsHint: 'When enabled, invalid or missing API key errors (INVALID_API_KEY, API_KEY_REQUIRED) will not be written to the error log.',
        ignoreInsufficientBalanceErrors: 'Ignore Insufficient Balance Errors',
        ignoreInsufficientBalanceErrorsHint: 'When enabled, insufficient account balance errors will not be written to the error log.',
        autoRefresh: 'Auto Refresh',
        enableAutoRefresh: 'Enable auto refresh',
        enableAutoRefreshHint: 'Automatically refresh dashboard data at a fixed interval.',
        refreshInterval: 'Refresh Interval',
        refreshInterval15s: '15 seconds',
        refreshInterval30s: '30 seconds',
        refreshInterval60s: '60 seconds',
        dashboardCards: 'Dashboard Cards',
        displayAlertEvents: 'Display alert events',
        displayAlertEventsHint: 'Show or hide the recent alert events card on the ops dashboard. Enabled by default.',
        displayOpenAITokenStats: 'Display OpenAI token request stats',
        displayOpenAITokenStatsHint: 'Show or hide the OpenAI token request stats card on the ops dashboard. Hidden by default.',
        autoRefreshCountdown: 'Auto refresh: {seconds}s',
        validation: {
          title: 'Please fix the following issues',
          retentionDaysRange: 'Retention days must be between 1-365 days',
          slaMinPercentRange: 'SLA minimum percentage must be between 0 and 100',
          ttftP99MaxRange: 'TTFT P99 maximum must be a number ≥ 0',
          requestErrorRateMaxRange: 'Request error rate maximum must be between 0 and 100',
          upstreamErrorRateMaxRange: 'Upstream error rate maximum must be between 0 and 100'
        }
      },
      concurrency: {
        title: 'Concurrency / Queue',
        byPlatform: 'By Platform',
        byGroup: 'By Group',
        byAccount: 'By Account',
        byUser: 'By User',
        showByUserTooltip: 'Switch to user view to see concurrency usage per user',
        switchToUser: 'Switch to user view',
        switchToPlatform: 'Switch to platform view',
        totalRows: '{count} rows',
        disabledHint: 'Realtime monitoring is disabled in settings.',
        empty: 'No data',
        queued: 'Queue {count}',
        rateLimited: 'Rate-limited {count}',
        errorAccounts: 'Errors {count}',
        loadFailed: 'Failed to load concurrency data'
      },
      realtime: {
        title: 'Realtime',
        connected: 'Realtime connected',
        connecting: 'Realtime connecting',
        reconnecting: 'Realtime reconnecting',
        offline: 'Realtime offline',
        closed: 'Realtime closed',
        reconnectIn: 'retry in {seconds}s'
      },
      queryMode: {
        auto: 'Auto',
        raw: 'Raw',
        preagg: 'Preagg'
      },
      accountAvailability: {
        available: 'Available',
        unavailable: 'Unavailable',
        accountError: 'Error'
      },
      tooltips: {
        totalRequests: 'Total number of requests (including both successful and failed requests) in the selected time window.',
        throughputTrend: 'Requests/QPS + Tokens/TPS in the selected window.',
        switchRateTrend: 'Trend of account switches / total requests over the last 5 hours (avg switches).',
        latencyHistogram: 'Request duration distribution (ms) for successful requests.',
        errorTrend: 'Error counts over time (SLA scope excludes business limits; upstream excludes 429/529).',
        errorDistribution: 'Error distribution by status code.',
        goroutines:
          'Number of Go runtime goroutines (lightweight threads). There is no absolute "safe" number—use your historical baseline. Heuristic: <2k is common; 2k–8k watch; >8k plus rising queue/latency often suggests blocking/leaks.',
        cpu: 'CPU usage percentage, showing system processor load.',
        memory: 'Memory usage, including used and total available memory.',
        db: 'Database connection pool status, including active, idle, and waiting connections.',
        redis: 'Redis connection pool status, showing active and idle connections.',
        jobs: 'Background job execution status, including last run time, success time, and error information.',
        qps: 'Queries Per Second (QPS) and Tokens Per Second (TPS), real-time system throughput.',
        tokens: 'Total number of tokens processed in the current time window.',
        sla: 'Service Level Agreement success rate, excluding business limits (e.g., insufficient balance, quota exceeded).',
        errors: 'Error statistics, including total errors, error rate, and upstream error rate.',
        upstreamErrors: 'Upstream error statistics, excluding rate limit errors (429/529).',
        latency: 'Request duration statistics, including p50, p90, p95, p99 percentiles.',
        ttft: 'Time To First Token, measuring the speed of first token return in streaming responses.',
        health: 'System health score (0-100), considering SLA, error rate, and resource usage.'
      },
      charts: {
        emptyRequest: 'No requests in this window.',
        emptyError: 'No errors in this window.',
        resetZoom: 'Reset',
        resetZoomHint: 'Reset zoom (if enabled)',
        downloadChart: 'Download',
        downloadChartHint: 'Download chart as image'
      }
    },

    // Settings
    settings: {
      title: 'System Settings',
      description: 'Manage registration, email verification, default values, and SMTP settings',
      tabs: {
        general: 'General',
        security: 'Security',
        users: 'Users',
        gateway: 'Gateway',
        email: 'Email',
        backup: 'Backup',
        payment: 'Payment',
      },
      emailTabDisabledTitle: 'Email Verification Not Enabled',
      emailTabDisabledHint: 'Enable email verification in the Security tab to configure 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',
        emailSuffixWhitelist: 'Email Domain Whitelist',
        emailSuffixWhitelistHint:
          "Only email addresses from the specified domains can register (for example, {'@'}qq.com, {'@'}gmail.com)",
        emailSuffixWhitelistPlaceholder: 'example.com',
        emailSuffixWhitelistInputHint: 'Leave empty for no restriction',
        promoCode: 'Promo Code',
        promoCodeHint: 'Allow users to use promo codes during registration',
        invitationCode: 'Invitation Code Registration',
        invitationCodeHint: 'When enabled, users must enter a valid invitation code to register',
        passwordReset: 'Password Reset',
        passwordResetHint: 'Allow users to reset their password via email',
        frontendUrl: 'Frontend URL',
        frontendUrlPlaceholder: 'https://example.com',
        frontendUrlHint: 'Used to generate password reset links in emails. Example: https://example.com',
        totp: 'Two-Factor Authentication (2FA)',
        totpHint: 'Allow users to use authenticator apps like Google Authenticator',
        totpKeyNotConfigured:
          'Please configure TOTP_ENCRYPTION_KEY in environment variables first. Generate a key with: openssl rand -hex 32'
      },
      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',
        cloudflareDashboard: 'Cloudflare Dashboard',
        secretKeyHint: 'Server-side verification key (keep this secret)',
        secretKeyConfiguredHint: 'Secret key configured. Leave empty to keep the current value.'      },
      linuxdo: {
        title: 'LinuxDo Connect Login',
        description: 'Configure LinuxDo Connect OAuth for Sub2API end-user login',
        enable: 'Enable LinuxDo Login',
        enableHint: 'Show LinuxDo login on the login/register pages',
        clientId: 'Client ID',
        clientIdPlaceholder: 'e.g., hprJ5pC3...',
        clientIdHint: 'Get this from Connect.Linux.Do',
        clientSecret: 'Client Secret',
        clientSecretPlaceholder: '********',
        clientSecretHint: 'Used by backend to exchange tokens (keep it secret)',
        clientSecretConfiguredPlaceholder: '********',
        clientSecretConfiguredHint: 'Secret configured. Leave empty to keep the current value.',
        redirectUrl: 'Redirect URL',
        redirectUrlPlaceholder: 'https://your-domain.com/api/v1/auth/oauth/linuxdo/callback',
        redirectUrlHint:
          'Must match the redirect URL configured in Connect.Linux.Do (must be an absolute http(s) URL)',
        quickSetCopy: 'Generate & Copy (current site)',
        redirectUrlSetAndCopied: 'Redirect URL generated and copied to clipboard'
      },
      oidc: {
        title: 'OIDC Login',
        description: 'Configure a standard OIDC provider (for example Keycloak)',
        enable: 'Enable OIDC Login',
        enableHint: 'Show OIDC login on the login/register pages',
        providerName: 'Provider Name',
        providerNamePlaceholder: 'for example Keycloak',
        clientId: 'Client ID',
        clientIdPlaceholder: 'OIDC client id',
        clientSecret: 'Client Secret',
        clientSecretPlaceholder: '********',
        clientSecretHint: 'Used by backend to exchange tokens (keep it secret)',
        clientSecretConfiguredPlaceholder: '********',
        clientSecretConfiguredHint: 'Secret configured. Leave empty to keep the current value.',
        issuerUrl: 'Issuer URL',
        issuerUrlPlaceholder: 'https://id.example.com/realms/main',
        discoveryUrl: 'Discovery URL',
        discoveryUrlPlaceholder: 'Optional, leave empty to auto-derive from issuer',
        authorizeUrl: 'Authorize URL',
        authorizeUrlPlaceholder: 'Optional, can be discovered automatically',
        tokenUrl: 'Token URL',
        tokenUrlPlaceholder: 'Optional, can be discovered automatically',
        userinfoUrl: 'UserInfo URL',
        userinfoUrlPlaceholder: 'Optional, can be discovered automatically',
        jwksUrl: 'JWKS URL',
        jwksUrlPlaceholder: 'Optional, required when strict ID token validation is enabled',
        scopes: 'Scopes',
        scopesPlaceholder: 'openid email profile',
        scopesHint: 'Must include openid',
        redirectUrl: 'Backend Redirect URL',
        redirectUrlPlaceholder: 'https://your-domain.com/api/v1/auth/oauth/oidc/callback',
        redirectUrlHint: 'Must match the callback URL configured in the OIDC provider',
        quickSetCopy: 'Generate & Copy (current site)',
        redirectUrlSetAndCopied: 'Redirect URL generated and copied to clipboard',
        frontendRedirectUrl: 'Frontend Callback Path',
        frontendRedirectUrlPlaceholder: '/auth/oidc/callback',
        frontendRedirectUrlHint: 'Frontend route used after backend callback',
        tokenAuthMethod: 'Token Auth Method',
        clockSkewSeconds: 'Clock Skew (seconds)',
        allowedSigningAlgs: 'Allowed Signing Algs',
        allowedSigningAlgsPlaceholder: 'RS256,ES256,PS256',
        usePkce: 'Use PKCE',
        validateIdToken: 'Validate ID Token',
        requireEmailVerified: 'Require Email Verified',
        userinfoEmailPath: 'UserInfo Email Path',
        userinfoEmailPathPlaceholder: 'for example data.email',
        userinfoIdPath: 'UserInfo ID Path',
        userinfoIdPathPlaceholder: 'for example data.id',
        userinfoUsernamePath: 'UserInfo Username Path',
        userinfoUsernamePathPlaceholder: 'for example data.username'
      },
      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',
        defaultSubscriptions: 'Default Subscriptions',
        defaultSubscriptionsHint: 'Auto-assign these subscriptions when a new user is created or registered',
        addDefaultSubscription: 'Add Default Subscription',
        defaultSubscriptionsEmpty: 'No default subscriptions configured.',
        defaultSubscriptionsDuplicate:
          'Duplicate subscription group: {groupId}. Each group can only appear once.',
        subscriptionGroup: 'Subscription Group',
        subscriptionValidityDays: 'Validity (days)'
      },
      claudeCode: {
        title: 'Claude Code Settings',
        description: 'Control Claude Code client access requirements',
        minVersion: 'Minimum Version',
        minVersionPlaceholder: 'e.g. 2.1.63',
        minVersionHint:
          'Reject Claude Code clients below this version (semver format). Leave empty to disable version check.',
        maxVersion: 'Maximum Version',
        maxVersionPlaceholder: 'e.g. 2.5.0',
        maxVersionHint:
          'Reject Claude Code clients above this version (semver format). Leave empty to allow any version.'
      },
      scheduling: {
        title: 'Gateway Scheduling Settings',
        description: 'Control API Key scheduling behavior',
        allowUngroupedKey: 'Allow Ungrouped Key Scheduling',
        allowUngroupedKeyHint: 'When disabled, API Keys not assigned to any group cannot make requests (403 Forbidden). Keep disabled to ensure all Keys belong to a specific group.'
      },
      gatewayForwarding: {
        title: 'Request Forwarding',
        description: 'Control how requests are forwarded to upstream OAuth accounts',
        fingerprintUnification: 'Fingerprint Unification',
        fingerprintUnificationHint: 'Unify X-Stainless-* headers across users sharing the same OAuth account. Disabling passes through each client\'s original headers.',
        metadataPassthrough: 'Metadata Passthrough',
        metadataPassthroughHint: 'Pass through client\'s original metadata.user_id without rewriting. May improve upstream cache hit rates.',
        cchSigning: 'CCH Signing',
        cchSigningHint: 'Sign the billing header in forwarded requests with CCH hash. When disabled, the placeholder is preserved.',
      },
      webSearchEmulation: {
        title: 'Web Search Emulation',
        description: 'Inject web search capability for Anthropic API Key accounts that don\'t natively support it',
        enabled: 'Enable Web Search Emulation',
        enabledHint: 'Global switch. When disabled, web search emulation is inactive for all channels and accounts.',
        providers: 'Search Providers',
        addProvider: 'Add Provider',
        providerType: 'Provider Type',
        apiKey: 'API Key',
        apiKeyPlaceholder: 'Enter API Key',
        apiKeyConfigured: 'Configured',
        showApiKey: 'Show',
        hideApiKey: 'Hide',
        copyApiKey: 'Copy',
        copied: 'Copied',
        quotaLimit: 'Quota Limit',
        quotaLimitHint: 'Leave empty for unlimited; must be > 0 if set',
        quotaLimitMustBePositive: 'Quota limit must be greater than 0',
        subscribedAt: 'Subscribed At',
        subscribedAtHint: 'Quota resets monthly from this date; leave empty to disable auto-reset',
        quotaUsage: 'Usage',
        resetUsage: 'Reset',
        resetUsageConfirm: 'Reset usage counter for this provider?',
        resetUsageSuccess: 'Usage counter reset',
        proxy: 'Proxy',
        removeProvider: 'Remove',
        noProviders: 'No search providers configured',
        test: 'Test',
        testDefaultQuery: 'Major world events this year',
        testing: 'Searching...',
        testResultTitle: 'Search Results',
        testResultProvider: 'Provider',
        testNoResults: 'No results found',
      },
      site: {
        title: 'Site Settings',
        description: 'Customize site branding',
        backendMode: 'Backend Mode',
        backendModeDescription:
          'Disables user registration, public site, and self-service features. Only admin can log in and manage the platform.',
        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.',
        tablePreferencesTitle: 'Global Table Preferences',
        tablePreferencesDescription: 'Configure default pagination behavior for shared table components',
        tableDefaultPageSize: 'Default Rows Per Page',
        tableDefaultPageSizeHint: 'Must be an integer between 5 and 1000',
        tablePageSizeOptions: 'Rows Per Page Options',
        tablePageSizeOptionsPlaceholder: '10, 20, 50, 100',
        tablePageSizeOptionsHint: 'Use commas to separate integers between 5 and 1000; values are deduplicated and sorted on save',
        tableDefaultPageSizeRangeError: 'Default rows per page must be between {min} and {max}',
        tablePageSizeOptionsFormatError: 'Invalid options format. Enter comma-separated integers between {min} and {max}',
        customEndpoints: {
          title: 'Custom Endpoints',
          description: 'Add additional API endpoint URLs for users to quickly copy on the API Keys page',
          itemLabel: 'Endpoint #{n}',
          name: 'Name',
          namePlaceholder: 'e.g., OpenAI Compatible',
          endpointUrl: 'Endpoint URL',
          endpointUrlPlaceholder: 'https://api2.example.com',
          descriptionLabel: 'Description',
          descriptionPlaceholder: 'e.g., Supports OpenAI format requests',
          add: 'Add Endpoint',
        },
        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',
        homeContent: 'Home Page Content',
        homeContentPlaceholder: 'Enter custom content for the home page. Supports Markdown & HTML. If a URL is entered, it will be displayed as an iframe.',
        homeContentHint: 'Customize the home page content. Supports Markdown/HTML. If you enter a URL (starting with http:// or https://), it will be used as an iframe src to embed an external page. When set, the default status information will no longer be displayed.',
        homeContentIframeWarning: '⚠️ iframe mode note: Some websites have X-Frame-Options or CSP security policies that prevent embedding in iframes. If the page appears blank or shows an error, please verify the target website allows embedding, or consider using HTML mode to build your own content.',
        hideCcsImportButton: 'Hide CCS Import Button',
        hideCcsImportButtonHint: 'When enabled, the "Import to CCS" button will be hidden on the API Keys page'
      },
      purchase: {
        title: 'Recharge / Subscription Page',
        description: 'Show a "Recharge / Subscription" entry in the sidebar and open the configured URL in an iframe',
        enabled: 'Show Recharge / Subscription Entry',
        enabledHint: 'Only shown in standard mode (not simple mode)',
        url: 'Recharge / Subscription URL',
        urlPlaceholder: 'https://example.com/purchase',
        urlHint: 'Must be an absolute http(s) URL',
        iframeWarning:
          '⚠️ iframe note: Some websites block embedding via X-Frame-Options or CSP (frame-ancestors). If the page is blank, provide an "Open in new tab" alternative.',
        integrationDoc: 'Payment Integration Docs',
        integrationDocHint: 'Covers endpoint specs, idempotency semantics, and code samples'
      },
      soraClient: {
        title: 'Sora Client',
        description: 'Control whether to show the Sora client entry in the sidebar',
        enabled: 'Enable Sora Client',
        enabledHint: 'When enabled, the Sora entry will be shown in the sidebar for users to access Sora features'
      },
      customMenu: {
        title: 'Custom Menu Pages',
        description: 'Add custom iframe pages to the sidebar navigation. Each page can be visible to regular users or administrators.',
        itemLabel: 'Menu Item #{n}',
        name: 'Menu Name',
        namePlaceholder: 'e.g. Help Center',
        url: 'Page URL',
        urlPlaceholder: 'https://example.com/page',
        iconSvg: 'SVG Icon',
        iconSvgPlaceholder: '<svg>...</svg>',
        iconPreview: 'Icon Preview',
        uploadSvg: 'Upload SVG',
        removeSvg: 'Remove',
        visibility: 'Visible To',
        visibilityUser: 'Regular Users',
        visibilityAdmin: 'Administrators',
        add: 'Add Menu Item',
        remove: 'Remove',
        moveUp: 'Move Up',
        moveDown: 'Move Down',
      },
      payment: {
        title: 'Payment Settings',
        description: 'Configure payment system options',
        configGuide: 'Configuration Guide',
        enabled: 'Enable Payment',
        enabledHint: 'Enable or disable the payment system',
        enabledPaymentTypes: 'Enabled Providers',
        enabledPaymentTypesHint: 'Disabling a provider will also disable its instances.',
        findProvider: 'Looking for a suitable EasyPay provider?',
        minAmount: 'Minimum Amount',
        maxAmount: 'Maximum Amount',
        dailyLimit: 'Daily Limit',
        balanceRechargeMultiplier: 'Balance Recharge Multiplier',
        balanceRechargeMultiplierHint: 'How many USD balance the user receives for each 1 CNY paid',
        balanceRechargePreview: 'Preview: 1 CNY = {usd} USD',
        rechargeFeeRate: 'Recharge Fee Rate',
        rechargeFeeRateHint: 'Percentage of service fee charged on top of recharge amount, 0 means no fee',
        rechargeFeePreview: 'Preview: Recharge 100, fee {fee}',
        orderTimeout: 'Order Timeout',
        orderTimeoutHint: 'In minutes, minimum 1',
        maxPendingOrders: 'Max Pending Orders',
        cancelRateLimit: 'Limit Cancel Rate',
        cancelRateLimitHint: 'When enabled, users who exceed the cancel limit within the time window cannot create new orders',
        cancelRateLimitEvery: 'Every',
        cancelRateLimitAllowMax: 'allow max',
        cancelRateLimitTimes: 'cancels',
        cancelRateLimitWindow: 'Window',
        cancelRateLimitUnit: 'Unit',
        cancelRateLimitMax: 'Max Cancels',
        cancelRateLimitUnitMinute: 'Minutes',
        cancelRateLimitUnitHour: 'Hours',
        cancelRateLimitUnitDay: 'Days',
        cancelRateLimitWindowMode: 'Window Mode',
        cancelRateLimitWindowModeRolling: 'Rolling',
        cancelRateLimitWindowModeFixed: 'Fixed',
        helpText: 'Help Text',
        helpImageUrl: 'Help Image URL',
        manageProviders: 'Manage Providers',
        balancePaymentDisabled: 'Disable Balance Recharge',
        noLimit: 'Empty = no limit',
        helpImage: 'Help Image',
        helpImagePlaceholder: 'Upload or enter image URL',
        helpTextPlaceholder: 'Enter help text...',
        providerEasypay: 'EasyPay',
        providerAlipay: 'Alipay (Direct)',
        providerWxpay: 'WeChat Pay (Direct)',
        providerStripe: 'Stripe',
        typeDisabled: 'type disabled',
        enableTypesFirst: 'Enable at least one payment type above first',
        easypayRedirect: 'Redirect',
        paymentMode: 'Payment Mode',
        modeRedirect: 'Redirect',
        modeQRCode: 'QR Code',
        modePopup: 'Popup',
        validationNameRequired: 'Provider name is required',
        validationTypesRequired: 'Please select at least one supported payment type',
        validationFieldRequired: '{field} is required',
        field_apiBase: 'API Base URL',
        field_notifyUrl: 'Notify URL',
        field_returnUrl: 'Return URL',
        callbackBaseUrl: 'Callback Base URL',
        field_privateKey: 'Private Key',
        field_publicKey: 'Public Key',
        field_mchId: 'Merchant ID',
        field_apiV3Key: 'API v3 Key',
        field_publicKeyId: 'Public Key ID',
        field_certSerial: 'Certificate Serial',
        field_secretKey: 'Secret Key',
        field_publishableKey: 'Publishable Key',
        field_webhookSecret: 'Webhook Secret',
        field_cid: 'Channel ID',
        field_cidAlipay: 'Alipay Channel ID',
        field_cidWxpay: 'WeChat Channel ID',
        stripeWebhookHint: 'Configure the following URL as a Webhook endpoint in Stripe Dashboard:',
        limitsTitle: 'Limits',
        limitSingleMin: 'Min per order',
        limitSingleMax: 'Max per order',
        limitDaily: 'Daily limit',
        limitsHint: 'All empty = use global config; partially filled = empty means no limit',
        limitsUseGlobal: 'Use global',
        limitsNoLimit: 'No limit',
        productNamePrefix: 'Product Name Prefix',
        productNameSuffix: 'Product Name Suffix',
        preview: 'Preview',
        loadBalanceStrategy: 'Load Balance Strategy',
        strategyRoundRobin: 'Round Robin',
        strategyLeastAmount: 'Least Daily Amount',
        providerManagement: 'Provider Management',
        providerManagementDesc: 'Manage payment provider instances',
        createProvider: 'Add Provider',
        editProvider: 'Edit Provider',
        deleteProvider: 'Delete Provider',
        deleteProviderConfirm: 'Are you sure you want to delete this provider?',
        providerName: 'Provider Name',
        providerKey: 'Provider Type',
        selectProviderKey: 'Select Provider Type',
        providerConfig: 'Credentials',
        noProviders: 'No provider instances configured',
        supportedTypes: 'Supported Payment Types',
        supportedTypesHint: 'Comma-separated, e.g. alipay,wxpay',
        refundEnabled: 'Allow Refund',
        allowUserRefund: 'Allow User Refund',
      },
      balanceNotify: {
        title: 'Balance Low Notification',
        description: 'Send email notification when user balance falls below threshold',
        enabled: 'Enable Balance Low Notification',
        threshold: 'Default Threshold',
        thresholdHint: 'Used when user has not set a custom value',
        thresholdPlaceholder: 'Enter amount',
        rechargeUrl: 'Recharge Page URL',
        rechargeUrlPlaceholder: 'https://example.com/payment',
        rechargeUrlHint: 'A top-up button will appear in the email when set',
      },
      quotaNotify: {
        title: 'Account Quota Notification',
        description: 'Notify admins when account quota usage reaches alert threshold',
        enabled: 'Enable Account Quota Notification',
        emails: 'Notification Emails',
        emailsHint: 'Leave empty to disable notifications',
        addEmail: 'Add Email',
        emailPlaceholder: 'Enter email address',
      },
      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',
        passwordConfiguredPlaceholder: '********',
        passwordConfiguredHint: 'Password configured. Leave empty to keep the current value.',
        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'
      },
      opsMonitoring: {
        title: 'Ops Monitoring',
        description: 'Enable ops monitoring for troubleshooting and health visibility',
        disabled: 'Ops monitoring is disabled',
        enabled: 'Enable Ops Monitoring',
        enabledHint: 'Enable the ops monitoring module (admin only)',
        realtimeEnabled: 'Enable Realtime Monitoring',
        realtimeEnabledHint: 'Enable realtime QPS/metrics push (WebSocket)',
        queryMode: 'Default Query Mode',
        queryModeHint: 'Default query mode for Ops Dashboard (auto/raw/preagg)',
        queryModeAuto: 'Auto (recommended)',
        queryModeRaw: 'Raw (most accurate, slower)',
        queryModePreagg: 'Preagg (fastest, requires aggregation)',
        metricsInterval: 'Metrics Collection Interval (seconds)',
        metricsIntervalHint: 'How often to collect system/request metrics (60-3600 seconds)'
      },
      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>'
      },
      soraS3: {
        title: 'Sora Storage',
        description: 'Manage Sora media storage profiles with S3 and Google Drive support',
        newProfile: 'New Profile',
        reloadProfiles: 'Reload Profiles',
        empty: 'No storage profiles yet, create one first',
        createTitle: 'Create Storage Profile',
        editTitle: 'Edit Storage Profile',
        selectProvider: 'Select Storage Type',
        providerS3Desc: 'S3-compatible object storage',
        providerGDriveDesc: 'Google Drive cloud storage',
        profileID: 'Profile ID',
        profileName: 'Profile Name',
        setActive: 'Set as active after creation',
        saveProfile: 'Save Profile',
        activateProfile: 'Activate',
        profileCreated: 'Storage profile created',
        profileSaved: 'Storage profile saved',
        profileDeleted: 'Storage profile deleted',
        profileActivated: 'Active storage profile switched',
        profileIDRequired: 'Profile ID is required',
        profileNameRequired: 'Profile name is required',
        profileSelectRequired: 'Please select a profile first',
        endpointRequired: 'S3 endpoint is required when enabled',
        bucketRequired: 'Bucket is required when enabled',
        accessKeyRequired: 'Access Key ID is required when enabled',
        deleteConfirm: 'Delete storage profile {profileID}?',
        columns: {
          profile: 'Profile',
          profileId: 'Profile ID',
          name: 'Name',
          provider: 'Type',
          active: 'Active',
          endpoint: 'Endpoint',
          bucket: 'Bucket',
          storagePath: 'Storage Path',
          capacityUsage: 'Capacity / Used',
          capacityUnlimited: 'Unlimited',
          videoCount: 'Videos',
          videoCompleted: 'completed',
          videoInProgress: 'in progress',
          quota: 'Default Quota',
          updatedAt: 'Updated At',
          actions: 'Actions',
          rootFolder: 'Root folder',
          testInTable: 'Test',
          testingInTable: 'Testing...',
          testTimeout: 'Test timed out (15s)'
        },
        enabled: 'Enable Storage',
        enabledHint: 'When enabled, Sora generated media files will be automatically uploaded',
        endpoint: 'S3 Endpoint',
        region: 'Region',
        bucket: 'Bucket',
        prefix: 'Object Prefix',
        accessKeyId: 'Access Key ID',
        secretAccessKey: 'Secret Access Key',
        secretConfigured: '(Configured, leave blank to keep)',
        cdnUrl: 'CDN URL',
        cdnUrlHint: 'Optional. When configured, files are accessed via CDN URL',
        forcePathStyle: 'Force Path Style',
        defaultQuota: 'Default Storage Quota',
        defaultQuotaHint: 'Default quota when not specified at user or group level. 0 means unlimited',
        testConnection: 'Test Connection',
        testing: 'Testing...',
        testSuccess: 'Connection test successful',
        testFailed: 'Connection test failed',
        saved: 'Storage settings saved successfully',
        saveFailed: 'Failed to save storage settings',
        gdrive: {
          authType: 'Authentication Method',
          serviceAccount: 'Service Account',
          clientId: 'Client ID',
          clientSecret: 'Client Secret',
          clientSecretConfigured: '(Configured, leave blank to keep)',
          refreshToken: 'Refresh Token',
          refreshTokenConfigured: '(Configured, leave blank to keep)',
          serviceAccountJson: 'Service Account JSON',
          serviceAccountConfigured: '(Configured, leave blank to keep)',
          folderId: 'Folder ID (optional)',
          authorize: 'Authorize Google Drive',
          authorizeHint: 'Get Refresh Token via OAuth2',
          oauthFieldsRequired: 'Please fill in Client ID and Client Secret first',
          oauthSuccess: 'Google Drive authorization successful',
          oauthFailed: 'Google Drive authorization failed',
          closeWindow: 'This window will close automatically',
          processing: 'Processing authorization...',
          testStorage: 'Test Storage',
          testSuccess: 'Google Drive storage test passed (upload, access, delete all OK)',
          testFailed: 'Google Drive storage test failed'
        }
      },
      overloadCooldown: {
        title: '529 Overload Cooldown',
        description: 'Configure account scheduling pause strategy when upstream returns 529 (overloaded)',
        enabled: 'Enable Overload Cooldown',
        enabledHint: 'Pause account scheduling on 529 errors, auto-recover after cooldown',
        cooldownMinutes: 'Cooldown Duration (minutes)',
        cooldownMinutesHint: 'Duration to pause account scheduling (1-120 minutes)',
        saved: 'Overload cooldown settings saved',
        saveFailed: 'Failed to save overload cooldown settings'
      },
      streamTimeout: {
        title: 'Stream Timeout Handling',
        description: 'Configure account handling strategy when upstream response times out',
        enabled: 'Enable Stream Timeout Handling',
        enabledHint: 'Automatically handle problematic accounts when upstream times out',
        timeoutSeconds: 'Timeout Threshold (seconds)',
        timeoutSecondsHint: 'Stream data interval exceeding this time is considered timeout (30-300s)',
        action: 'Action',
        actionTempUnsched: 'Temporarily Unschedulable',
        actionError: 'Mark as Error',
        actionNone: 'No Action',
        actionHint: 'Action to take on the account after timeout',
        tempUnschedMinutes: 'Pause Duration (minutes)',
        tempUnschedMinutesHint: 'Duration of temporary unschedulable state (1-60 minutes)',
        thresholdCount: 'Trigger Threshold (count)',
        thresholdCountHint: 'Number of timeouts before triggering action (1-10)',
        thresholdWindowMinutes: 'Threshold Window (minutes)',
        thresholdWindowMinutesHint: 'Time window for counting timeouts (1-60 minutes)',
        saved: 'Stream timeout settings saved',
        saveFailed: 'Failed to save stream timeout settings'
      },
      rectifier: {
        title: 'Request Rectifier',
        description: 'Automatically fix request parameters and retry when upstream returns specific errors',
        enabled: 'Enable Request Rectifier',
        enabledHint: 'Master switch - disabling turns off all rectification features',
        thinkingSignature: 'Thinking Signature Rectifier',
        thinkingSignatureHint: 'Automatically strip signatures and retry when upstream returns thinking block signature validation errors',
        thinkingBudget: 'Thinking Budget Rectifier',
        thinkingBudgetHint: 'Automatically set budget to 32000 and retry when upstream returns budget_tokens constraint error (≥1024)',
        apikeySignature: 'API Key Signature Rectifier',
        apikeySignatureHint:
          'Automatically strip signatures and retry when API Key accounts receive signature-related errors (built-in patterns always apply)',
        apikeyPatterns: 'Custom Match Patterns',
        apikeyPatternsHint:
          'Additional keywords matched against the response body (case-insensitive). Built-in patterns always apply; use these for supplementary matching.',
        apikeyPatternPlaceholder: 'e.g., thinking_error',
        addPattern: 'Add Pattern',
        saved: 'Rectifier settings saved',
        saveFailed: 'Failed to save rectifier settings'
      },
      betaPolicy: {
        title: 'Beta Policy',
        description: 'How to handle Beta features when configuring the forwarding of Anthropic API requests. Applicable only to the /v1/messages endpoint.',
        action: 'Action',
        actionPass: 'Pass (transparent)',
        actionFilter: 'Filter (remove)',
        actionBlock: 'Block (reject)',
        scope: 'Scope',
        scopeAll: 'All accounts',
        scopeOAuth: 'OAuth only',
        scopeAPIKey: 'API Key only',
        scopeBedrock: 'Bedrock only',
        errorMessage: 'Error message',
        errorMessagePlaceholder: 'Custom error message when blocked',
        errorMessageHint: 'Leave empty for default message',
        saved: 'Beta policy settings saved',
        saveFailed: 'Failed to save beta policy settings',
        modelWhitelist: 'Model Whitelist',
        modelWhitelistHint: 'Leave empty to apply to all models. Supports exact match and wildcard prefix (e.g., claude-opus-*)',
        modelPatternPlaceholder: 'e.g., claude-opus-* or claude-opus-4-6',
        addModelPattern: 'Add model pattern',
        removePattern: 'Remove',
        fallbackAction: 'Fallback Action',
        fallbackActionHint: 'Action for models not matching the whitelist',
        fallbackErrorMessagePlaceholder: 'Custom error message when non-whitelisted models are blocked',
        quickPresets: 'Quick Presets',
        presetOpusOnly: 'Opus only for 1M',
        presetOpusOnlyDesc: 'Pass for Opus, filter others',
        commonPatterns: 'Common patterns'
      },
      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'
    },

    // Error Passthrough Rules
    errorPassthrough: {
      title: 'Error Passthrough Rules',
      description: 'Configure how upstream errors are returned to clients',
      createRule: 'Create Rule',
      editRule: 'Edit Rule',
      deleteRule: 'Delete Rule',
      noRules: 'No rules configured',
      createFirstRule: 'Create your first error passthrough rule',
      allPlatforms: 'All Platforms',
      passthrough: 'Passthrough',
      custom: 'Custom',
      code: 'Code',
      body: 'Body',
      skipMonitoring: 'Skip Monitoring',

      // Columns
      columns: {
        priority: 'Priority',
        name: 'Name',
        conditions: 'Conditions',
        platforms: 'Platforms',
        behavior: 'Behavior',
        status: 'Status',
        actions: 'Actions'
      },

      // Match Mode
      matchMode: {
        any: 'Code OR Keyword',
        all: 'Code AND Keyword',
        anyHint: 'Status code matches any error code, OR message contains any keyword',
        allHint: 'Status code matches any error code, AND message contains any keyword'
      },

      // Form
      form: {
        name: 'Rule Name',
        namePlaceholder: 'e.g., Context Limit Passthrough',
        priority: 'Priority',
        priorityHint: 'Lower values have higher priority',
        description: 'Description',
        descriptionPlaceholder: 'Describe the purpose of this rule...',
        matchConditions: 'Match Conditions',
        errorCodes: 'Error Codes',
        errorCodesPlaceholder: '422, 400, 429',
        errorCodesHint: 'Separate multiple codes with commas',
        keywords: 'Keywords',
        keywordsPlaceholder: 'One keyword per line\ncontext limit\nmodel not supported',
        keywordsHint: 'One keyword per line, case-insensitive',
        matchMode: 'Match Mode',
        platforms: 'Platforms',
        platformsHint: 'Leave empty to apply to all platforms',
        responseBehavior: 'Response Behavior',
        passthroughCode: 'Passthrough upstream status code',
        responseCode: 'Custom status code',
        passthroughBody: 'Passthrough upstream error message',
        customMessage: 'Custom error message',
        customMessagePlaceholder: 'Error message to return to client...',
        skipMonitoring: 'Skip monitoring',
        skipMonitoringHint: 'When enabled, errors matching this rule will not be recorded in ops monitoring',
        enabled: 'Enable this rule'
      },

      // Messages
      nameRequired: 'Please enter rule name',
      conditionsRequired: 'Please configure at least one error code or keyword',
      ruleCreated: 'Rule created successfully',
      ruleUpdated: 'Rule updated successfully',
      ruleDeleted: 'Rule deleted successfully',
      deleteConfirm: 'Are you sure you want to delete rule "{name}"?',
      failedToLoad: 'Failed to load rules',
      failedToSave: 'Failed to save rule',
      failedToDelete: 'Failed to delete rule',
      failedToToggle: 'Failed to toggle status'
    },

    // TLS Fingerprint Profiles
    tlsFingerprintProfiles: {
      title: 'TLS Fingerprint Profiles',
      description: 'Manage TLS fingerprint profiles for simulating specific client TLS handshake characteristics',
      createProfile: 'Create Profile',
      editProfile: 'Edit Profile',
      deleteProfile: 'Delete Profile',
      noProfiles: 'No profiles configured',
      createFirstProfile: 'Create your first TLS fingerprint profile',

      columns: {
        name: 'Name',
        description: 'Description',
        grease: 'GREASE',
        alpn: 'ALPN',
        actions: 'Actions'
      },

      form: {
        pasteYaml: 'Paste YAML Configuration',
        pasteYamlPlaceholder: 'Paste YAML output from TLS Fingerprint Collector here...',
        pasteYamlHint: 'Paste the YAML copied from TLS Fingerprint Collector to auto-fill all fields.',
        openCollector: 'Open Collector',
        parseYaml: 'Parse YAML',
        yamlParsed: 'YAML parsed successfully, fields auto-filled',
        yamlParseFailed: 'Failed to parse YAML: name field not found',
        name: 'Profile Name',
        namePlaceholder: 'e.g. macOS Node.js v24',
        description: 'Description',
        descriptionPlaceholder: 'Optional description for this profile',
        enableGrease: 'Enable GREASE',
        enableGreaseHint: 'Insert GREASE values in TLS ClientHello extensions',
        cipherSuites: 'Cipher Suites',
        cipherSuitesHint: 'Comma-separated hex values, e.g. 0x1301, 0x1302, 0xc02c',
        curves: 'Elliptic Curves',
        curvesHint: 'Comma-separated curve IDs',
        pointFormats: 'Point Formats',
        signatureAlgorithms: 'Signature Algorithms',
        alpnProtocols: 'ALPN Protocols',
        alpnProtocolsHint: 'Comma-separated, e.g. h2, http/1.1',
        supportedVersions: 'Supported TLS Versions',
        keyShareGroups: 'Key Share Groups',
        pskModes: 'PSK Modes',
        extensions: 'Extensions'
      },

      deleteConfirm: 'Delete Profile',
      deleteConfirmMessage: 'Are you sure you want to delete profile "{name}"? Accounts using this profile will fall back to the built-in default.',
      createSuccess: 'Profile created successfully',
      updateSuccess: 'Profile updated successfully',
      deleteSuccess: 'Profile deleted successfully',
      loadFailed: 'Failed to load profiles',
      saveFailed: 'Failed to save profile',
      deleteFailed: 'Failed to delete profile'
    }
  },

  // 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',
    unlimited: 'Unlimited'
  },

  // 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'
  },

  // Recharge / Subscription Page
  purchase: {
    title: 'Recharge / Subscription',
    description: 'Recharge balance or purchase subscription via the embedded page',
    openInNewTab: 'Open in new tab',
    notEnabledTitle: 'Feature not enabled',
    notEnabledDesc: 'The administrator has not enabled the recharge/subscription entry. Please contact admin.',
    notConfiguredTitle: 'Recharge / Subscription URL not configured',
    notConfiguredDesc:
      'The administrator enabled the entry but has not configured a recharge/subscription URL. Please contact admin.'
  },

  // Custom Page (iframe embed)
  customPage: {
    title: 'Custom Page',
    openInNewTab: 'Open in new tab',
    notFoundTitle: 'Page not found',
    notFoundDesc: 'This custom page does not exist or has been removed.',
    notConfiguredTitle: 'Page URL not configured',
    notConfiguredDesc: 'The URL for this custom page has not been properly configured.',
  },

  // Announcements Page
  announcements: {
    title: 'Announcements',
    description: 'View system announcements',
    unreadOnly: 'Show unread only',
    markRead: 'Mark as read',
    markAllRead: 'Mark all as read',
    viewAll: 'View all announcements',
    markedAsRead: 'Marked as read',
    allMarkedAsRead: 'All announcements marked as read',
    newCount: '{count} new announcement | {count} new announcements',
    readAt: 'Read at',
    read: 'Read',
    unread: 'Unread',
    startsAt: 'Starts at',
    endsAt: 'Ends at',
    empty: 'No announcements',
    emptyUnread: 'No unread announcements',
    total: 'announcements',
    emptyDescription: 'There are no system announcements at this time',
    readStatus: 'You have read this announcement',
    markReadHint: 'Click "Mark as read" to mark this announcement'
  },

  // 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.",
    failedToLoad: 'Failed to load subscriptions',
    status: {
      active: 'Active',
      expired: 'Expired',
      revoked: 'Revoked'
    },
    usage: 'Usage',
    expires: 'Expires',
    noExpiration: 'No expiration',
    unlimited: 'Unlimited',
    unlimitedDesc: 'No usage limits on this subscription',
    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>Lower number = higher priority</li><li>System uses low-value 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 lower value, backup accounts to higher value</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>'
      }
    }
  },

  // Payment System
  payment: {
    title: 'Recharge / Subscription',
    amountLabel: 'Amount',
    paymentAmount: 'Payment Amount',
    creditedBalance: 'Credited Balance',
    quickAmounts: 'Quick Amounts',
    customAmount: 'Custom Amount',
    enterAmount: 'Enter amount',
    paymentMethod: 'Payment Method',
    fee: 'Fee',
    actualPay: 'Actual Payment',
    createOrder: 'Confirm Payment',
    methods: {
      easypay: 'EasyPay',
      alipay: 'Alipay',
      wxpay: 'WeChat Pay',
      stripe: 'Stripe',
      card: 'Card',
      link: 'Link',
      alipay_direct: 'Alipay (Direct)',
      wxpay_direct: 'WeChat Pay (Direct)',
    },
    status: {
      pending: 'Pending',
      paid: 'Paid',
      recharging: 'Recharging',
      completed: 'Completed',
      expired: 'Expired',
      cancelled: 'Cancelled',
      failed: 'Failed',
      refund_requested: 'Refund Requested',
      refunding: 'Refunding',
      refunded: 'Refunded',
      partially_refunded: 'Partially Refunded',
      refund_failed: 'Refund Failed',
    },
    qr: {
      scanToPay: 'Scan to Pay',
      scanAlipay: 'Alipay QR Payment',
      scanWxpay: 'WeChat QR Payment',
      scanAlipayHint: 'Open Alipay on your phone and scan the QR code to pay',
      scanWxpayHint: 'Open WeChat on your phone and scan the QR code to pay',
      payInNewWindow: 'Complete Payment in New Window',
      payInNewWindowHint: 'The payment page has opened in a new window. Please complete the payment there and return to this page.',
      openPayWindow: 'Reopen Payment Page',
      expiresIn: 'Expires in',
      expired: 'Order Expired',
      expiredDesc: 'This order has expired. Please create a new one.',
      cancelled: 'Order Cancelled',
      cancelledDesc: 'You have cancelled this payment.',
      waitingPayment: 'Waiting for payment...',
      cancelOrder: 'Cancel Order',
    },
    orders: {
      title: 'My Orders',
      empty: 'No orders yet',
      orderId: 'Order ID',
      orderNo: 'Order No.',
      amount: 'Amount',
      payAmount: 'Paid',
      creditedAmount: 'Credited Amount',
      fee: 'Fee',
      baseAmount: 'Base Amount',
      includedInPayAmount: 'included in paid amount',
      status: 'Status',
      paymentMethod: 'Payment Method',
      createdAt: 'Created',
      cancel: 'Cancel Order',
      userId: 'User ID',
      orderType: 'Order Type',
      actions: 'Actions',
      requestRefund: 'Request Refund',
    },
    result: {
      success: 'Payment Successful',
      subscriptionSuccess: 'Subscription Successful',
      failed: 'Payment Failed',
      backToRecharge: 'Back to Recharge',
      viewOrders: 'View Orders',
    },
    currentBalance: 'Current Balance',
    rechargeAccount: 'Recharge Account',
    activeSubscription: 'Active Subscription',
    noActiveSubscription: 'No active subscription',
    tabTopUp: 'Top Up',
    tabSubscribe: 'Subscribe',
    noPlans: 'No subscription plans available',
    notAvailable: 'Top-up is currently unavailable',
    confirmSubscription: 'Confirm Subscription',
    confirmCancel: 'Are you sure you want to cancel this order?',
    amountTooLow: 'Minimum amount is {min}',
    amountTooHigh: 'Maximum amount is {max}',
    amountNoMethod: 'No payment method available for this amount',
    rechargeRatePreview: 'Current rate: 1 CNY = {usd} USD',
    refundReason: 'Refund Reason',
    refundReasonPlaceholder: 'Please describe your refund reason',
    stripeLoadFailed: 'Failed to load payment component. Please refresh and try again.',
    stripeMissingParams: 'Missing order ID or client secret',
    stripeNotConfigured: 'Stripe is not configured',
    errors: {
      tooManyPending: 'Too many pending orders (max {max}). Please complete or cancel existing orders first.',
      cancelRateLimited: 'Too many cancellations. Please try again later.',
      PENDING_ORDERS: 'This provider has pending orders. Please wait for them to complete before making changes.',
    },
    stripePay: 'Pay Now',
    stripeSuccessProcessing: 'Payment successful, processing your order...',
    stripePopup: {
      redirecting: 'Redirecting to payment page...',
      loadingQr: 'Loading WeChat Pay QR code...',
      timeout: 'Timed out waiting for payment credentials, please retry',
      qrFailed: 'Failed to get WeChat Pay QR code',
    },
    subscribeNow: 'Subscribe Now',
    renewNow: 'Renew',
    selectPlan: 'Select Plan',
    planFeatures: 'Features',
    planCard: {
      rate: 'Rate',
      dailyLimit: 'Daily',
      weeklyLimit: 'Weekly',
      monthlyLimit: 'Monthly',
      quota: 'Quota',
      unlimited: 'Unlimited',
      models: 'Models',
    },
    days: 'days',
    months: 'months',
    years: 'years',
    oneMonth: '1 Month',
    oneYear: '1 Year',
    perMonth: 'month',
    perYear: 'year',
    admin: {
      tabs: {
        overview: 'Overview',
        orders: 'Orders',
        channels: 'Channels',
        plans: 'Plans',
      },
      todayRevenue: 'Today Revenue',
      totalRevenue: 'Total Revenue',
      todayOrders: 'Today Orders',
      orderCount: 'Order Count',
      avgAmount: 'Average Amount',
      revenue: 'Revenue',
      dailyRevenue: 'Daily Revenue',
      paymentDistribution: 'Payment Distribution',
      colUser: 'User',
      topUsers: 'Top Users',
      noData: 'No data',
      days: 'days',
      weeks: 'weeks',
      months: 'months',
      searchOrders: 'Search orders...',
      allStatuses: 'All Statuses',
      allPaymentTypes: 'All Payment Types',
      allOrderTypes: 'All Order Types',
      orderDetail: 'Order Detail',
      orderType: 'Order Type',
      orders: 'Orders',
      balanceOrder: 'Balance Top-Up',
      subscriptionOrder: 'Subscription',
      paidAt: 'Paid At',
      completedAt: 'Completed At',
      expiresAt: 'Expires At',
      feeRate: 'Fee Rate',
      refund: 'Refund',
      refundOrder: 'Refund Order',
      refundAmount: 'Refund Amount',
      maxRefundable: 'Max Refundable',
      refundReason: 'Refund Reason',
      refundReasonPlaceholder: 'Please enter refund reason',
      confirmRefund: 'Confirm Refund',
      refundSuccess: 'Refund successful',
      refundInfo: 'Refund Info',
      refundEnabled: 'Refund Enabled',
      allowUserRefund: 'Allow User Refund',
      alreadyRefunded: 'Already Refunded',
      deductBalance: 'Deduct Balance',
      deductBalanceHint: 'Subtract recharged amount from user balance',
      userBalance: 'User Balance',
      orderAmount: 'Order Amount',
      insufficientBalance: 'Insufficient balance — will deduct to $0',
      noDeduction: 'Will NOT deduct user balance',
      forceRefund: 'Force refund (ignore balance check)',
      orderCancelled: 'Order Cancelled',
      retry: 'Retry',
      retrySuccess: 'Retry successful',
      approveRefund: 'Approve Refund',
      retryRefund: 'Retry Refund',
      refundRequestInfo: 'Refund Request Info',
      refundRequestedAt: 'Requested At',
      refundRequestedBy: 'Requested By',
      refundRequestReason: 'Request Reason',
      auditLogs: 'Audit Logs',
      operator: 'Operator',
      channelName: 'Channel Name',
      channelDescription: 'Channel Description',
      createChannel: 'Create Channel',
      editChannel: 'Edit Channel',
      deleteChannel: 'Delete Channel',
      deleteChannelConfirm: 'Are you sure you want to delete this channel?',
      planName: 'Plan Name',
      planDescription: 'Plan Description',
      createPlan: 'Create Plan',
      editPlan: 'Edit Plan',
      deletePlan: 'Delete Plan',
      deletePlanConfirm: 'Are you sure you want to delete this plan?',
      originalPrice: 'Original Price',
      price: 'Price',
      validityDays: 'Validity (days)',
      validityUnit: 'Validity Unit',
      sortOrder: 'Sort Order',
      forSale: 'For Sale',
      onSale: 'On Sale',
      offSale: 'Off Sale',
      group: 'Group',
      groupId: 'Group ID',
      features: 'Features',
      featuresHint: 'One feature per line',
      featuresPlaceholder: 'Enter plan features...',
      providerManagement: 'Provider Management',
      providerManagementDesc: 'Manage payment provider instances',
      createProvider: 'Create Provider',
      editProvider: 'Edit Provider',
      deleteProvider: 'Delete Provider',
      deleteProviderConfirm: 'Are you sure you want to delete this provider?',
      providerName: 'Provider Name',
      providerKey: 'Provider Key',
      selectProviderKey: 'Select Provider Key',
      providerConfig: 'Provider Config',
      noProviders: 'No providers configured',
      noProvidersHint: 'Create a provider instance to start accepting payments',
      supportedTypes: 'Supported Payment Types',
      supportedTypesHint: 'Select the payment types this provider supports',
      rateMultiplier: 'Rate Multiplier',
      dashboardTitle: 'Payment Dashboard',
      dashboardDesc: 'Recharge order analytics and insights',
      daySuffix: 'd',
      paymentConfigTitle: 'Payment Config',
      paymentConfigDesc: 'Configure payment providers and settings',
      plansPageTitle: 'Subscription Plans',
      plansPageDesc: 'Manage subscription plan configuration',
      tabPlanConfig: 'Plan Configuration',
      tabUserSubs: 'User Subscriptions',
      selectGroup: 'Select a group',
      groupRequired: 'Please select a subscription group',
      priceRequired: 'Price must be greater than 0',
      validityDaysRequired: 'Validity days must be greater than 0',
      groupMissing: 'Missing',
      groupInfo: 'Group Info',
      platform: 'Platform',
      rateMultiplierLabel: 'Rate',
      dailyLimit: 'Daily Limit',
      weeklyLimit: 'Weekly Limit',
      monthlyLimit: 'Monthly Limit',
      unlimited: 'Unlimited',
      searchUserSubs: 'Search user subscriptions...',
      daily: 'D',
      weekly: 'W',
      monthly: 'M',
      subsStatus: {
        active: 'Active',
        expired: 'Expired',
        revoked: 'Revoked',
      },
    },
  },

}
