export default {
  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',
    platformBreakdown: 'Per-platform Breakdown',
    platformBreakdownEmpty: 'No platform usage yet',
    platformCount: '{count} platforms',
    platformOther: 'Other',
    platformQuota: {
      title: 'Quota Usage',
      daily: 'Daily',
      weekly: 'Weekly',
      monthly: 'Monthly (30-day rolling)',
      resetsAt: 'Resets {time}',
      noLimit: 'unlimited',
      disabled: 'Disabled',
    },
    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',
    batchImageAgent: 'Batch Image Assistant',
    batchImageAgentDesc: 'Copy instructions for an agent',
    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',
    columnSettings: 'Column Settings',
    columnAlwaysVisible: 'This column is always visible',
    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.",
    id: 'ID',
    apiKey: 'API Key',
    group: 'Group',
    currentConcurrency: 'Current Concurrency',
    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',
    lastUsedIP: 'Last Used IP',
    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.',
      claudeSettingsHint: 'User-level persistent configuration. Do not commit this file containing your API key to a project repository.',
      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.',
        authModeTitle: 'Codex authentication mode',
        authModeDescription: 'Compatibility mode keeps the existing setup for older Codex clients. API Key Mode authorizes the client-side image executor.',
        authModeLegacy: 'Compatibility mode',
        authModeApiKey: 'API Key Mode',
        authModeApiKeyRestartNotice: 'After saving this configuration, completely quit and restart Codex Desktop or CLI, then create a new task so the client can rebuild its tool registry.',
        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)',
        grokCli: 'Grok CLI',
        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.',
      },
      grok: {
        description:
          'Configure Grok CLI, Claude Code, Codex, or OpenCode to send requests through your Sub2API Grok group. Text models use Responses; image/video use Imagine model IDs on media endpoints.',
        claudeDescription: 'Configure Claude Code to send Messages API traffic through your Sub2API Grok group.',
        codexDescription: 'Configure Codex to send Responses API traffic through your Sub2API Grok group.',
        configTomlHint:
          'Official path: ~/.grok/config.toml (or $GROK_HOME). Fill [endpoints] (models_base_url / models_list_url / xai_api_base_url / cli_chat_proxy_base_url), [auth] preferred_method=api_key, [models], [session], and [features] image/video overrides. Prefer env_key over api_key; every text model needs api_backend=responses. Back up before merge, then run grok inspect.',
        codexConfigTomlHint:
          'Official Codex: wire_api = "responses" only; prefer env_key over experimental_bearer_token; supports_websockets = false for non-OpenAI gateways (Sub2API can still accept client WS and bridge to HTTP/SSE). Back up ~/.codex/config.toml before merge.',
        note:
          'Export GROK_MODELS_BASE_URL and XAI_API_KEY, save the full config.toml (endpoints/auth/models/session/features) as ~/.grok/config.toml, run grok inspect, then /model grok-4.5 (or grok-build-0.1 for coding).',
        noteWindows:
          'Set GROK_MODELS_BASE_URL and XAI_API_KEY, save the full config.toml as %USERPROFILE%\\.grok\\config.toml, run grok inspect, then /model grok-4.5 (or grok-build-0.1 for coding).',
        claudeNote:
          'Choose one method: terminal env for this session, or ~/.claude/settings.json for persistence. Do not commit files that contain your API key.',
        codexNote:
          'Export SUB2API_API_KEY, save config.toml under ~/.codex (mkdir -p ~/.codex). Prefer env_key auth; do not commit secrets.',
        codexNoteWindows:
          'Set $env:SUB2API_API_KEY, save config.toml under %USERPROFILE%\\.codex. Prefer env_key auth; do not commit secrets.',
      },
      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',
    cacheTotal: 'Cache',
    cacheBreakdown: 'Cache Token Breakdown',
    cacheCreationTokensLabel: 'Cache Creation',
    cacheReadTokensLabel: 'Cache Read',
    totalCost: 'Total Cost',
    standardCost: 'Standard',
    actualCost: 'Actual',
    accountCost: 'Cost',
    userBilled: 'User billed',
    accountBilled: 'Account billed',
    resetNow: 'Now',
    resetPending: 'Pending refresh',
    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',
	  sentUpstreamModel: 'Sent upstream',
	  upstreamResponseModel: 'Upstream response',
	  upstreamModelMismatch: 'Response model mismatch',
	  modelVariant: 'Possible version variant',
	  modelMismatch: 'Different model',
    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',
    latency: 'Latency',
    latencyFirstToken: 'First',
    latencyDuration: 'Total',
    time: 'Time',
    ws: 'WS',
    stream: 'Stream',
    sync: 'Sync',
    cyber: 'Cyber',
    live: 'Live',
    unknown: 'Unknown',
    in: 'In',
    out: 'Out',
    cacheHit: 'Cache hit',
    cacheCreate: 'Cache create',
    cacheHitRate: 'Cache hit rate',
    inputTokenPrice: 'Input price',
    outputTokenPrice: 'Output price',
    perMillionTokens: '/ 1M tokens',
    unitPrice: 'Per-request price',
    imageUnitPrice: 'Per-image price',
    imageTotalPrice: 'Image total price',
    imageCount: 'Image count',
    imageBillingSize: 'Billing size',
    imageInputSize: 'Input size',
    imageOutputSize: 'Output size',
    imageInputTokens: 'Image Input Tokens',
    imageInputTokenPrice: 'Image Input Price',
    imageInputCost: 'Image Input Cost',
    imageOutputTokens: 'Image Output Tokens',
    imageOutputTokenPrice: 'Image Output Price',
    imageOutputCost: 'Image Output Cost',
    imageSizeSource: 'Size source',
    imageSizeBreakdown: 'Size breakdown',
    imageSizeSourceOutput: 'Upstream output',
    imageSizeSourceInput: 'Request input',
    imageSizeSourceDefault: 'Default billing tier',
    imageSizeSourceLegacy: 'Legacy record',
    imageSizeSourceMissing: 'Not recorded',
    imageSizeNotRecorded: 'not recorded',
    imageSizeLegacyUnstandardized: 'legacy unstandardized',
    imageSizeUnknown: 'unknown',
    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',
    ipGeo: {
      fetch: 'Fetch region',
      fetching: 'Fetching...',
      failed: 'Failed',
      private: 'Private address',
      refreshTitle: 'Refresh region info',
      batchFetch: 'Batch fetch regions',
      batchFetching: 'Fetching...',
      pending: '{count} IPs pending',
      batchFailed: 'Failed to batch fetch IP regions',
      detailOrg: 'ISP',
      detailTimezone: 'Timezone',
      detailAccuracy: 'Accuracy',
      detailCoordinates: 'Coordinates',
    },
    tabs: { usage: 'Usage', errors: 'Error Requests', ranking: 'User Ranking' },
    errors: {
      time: 'Time', model: 'Model', endpoint: 'Endpoint', status: 'Status',
      category: 'Category', platform: 'Platform', message: 'Message',
      keyName: 'Key Name', keyDeleted: 'Deleted', allKeys: 'All keys',
      modelPlaceholder: 'Search model', allCategories: 'All categories', allStatuses: 'All status codes',
      empty: 'No error requests', failedToLoad: 'Failed to load error requests',
      categories: {
        auth: 'Auth failed', rate_limit: 'Rate limited', quota: 'Balance/Subscription',
        invalid_request: 'Invalid request', service_unavailable: 'Service unavailable',
        upstream: 'Upstream error', internal: 'Platform error', other: 'Other', cyber: 'Cyber policy',
      },
      detail: {
        title: 'Error Request Detail',
        responseBody: 'Response Body',
        upstreamStatus: 'Upstream Status',
        loadFailed: 'Failed to load detail, please try again',
      },
    },
  },

  // Shared keys for channel monitor (admin + user views)
  monitorCommon: {
    status: {
      operational: 'Operational',
      degraded: 'Degraded',
      failed: 'Failed',
      error: 'Error',
      unknown: '-'
    },
    providers: {
      openai: 'OpenAI',
      anthropic: 'Anthropic',
      gemini: 'Gemini',
      grok: 'Grok',
      antigravity: 'Antigravity',
      kimi: 'Kimi',
      zhipu: 'Zhipu GLM',
      deepseek: 'DeepSeek'
    },
    // Check modes (how a monitor performs its checks)
    checkMode: {
      probe: 'Probe',
      quota: 'Quota',
      quota_probe: 'Probe + Quota'
    },
    // Quota snapshot rendering (MonitorQuotaView, shared by admin + user views)
    quota: {
      unavailable: 'Quota unavailable',
      resetSoon: 'resetting',
      windows: {
        '5h': '5h',
        '7d': '7d',
        '7dSonnet': '7d Sonnet',
        '7dFable': '7d Fable',
        weekly: 'Weekly',
        daily: 'Daily',
        '30d': '30d',
        total: 'Total'
      },
      labels: {
        requests: 'Requests',
        tokens: 'Tokens',
        shared: 'Shared',
        pro: 'Pro',
        flash: 'Flash'
      }
    },
    extraModelsHeader: 'Extra Models',
    extraModelsEmpty: 'No extra models',
    latencyEmpty: '-',
    availabilityPrefix: 'Availability',
    dialogLatency: 'Dialog Latency',
    endpointPing: 'Endpoint PING',
    history60pts: 'HISTORY ({n} PTS)',
    nextUpdateIn: 'NEXT UPDATE IN {n}s',
    past: 'PAST',
    now: 'NOW',
    maintenancePaused: 'Maintenance · timeline paused',
    extraModelsCount: '+ {n} models',
    pollEvery: '{n}s polling',
    updatedAt: 'Updated {time}',
    relativeSecondsAgo: '{n}s ago',
    relativeMinutesAgo: '{n}m ago',
    relativeHoursAgo: '{n}h ago',
    relativeDaysAgo: '{n}d ago'
  },

  // Channel Status (user-facing read-only view)
  channelStatus: {
    title: 'Channel Status',
    description: 'Inspect channel availability, latency and recent status',
    searchPlaceholder: 'Search channels...',
    allProviders: 'All Providers',
    loadError: 'Failed to load channel status',
    detailLoadError: 'Failed to load channel detail',
    detailTitle: 'Channel Detail',
    closeDetail: 'Close',
    windowTab: {
      '7d': '7 days',
      '15d': '15 days',
      '30d': '30 days'
    },
    overall: {
      operational: 'OPERATIONAL',
      degraded: 'DEGRADED',
      unavailable: 'UNAVAILABLE'
    },
    columns: {
      name: 'Name',
      provider: 'Provider',
      groupName: 'Group',
      primaryModel: 'Primary Model',
      availability7d: '7d Availability',
      latency: 'Latency (ms)'
    },
    detailColumns: {
      model: 'Model',
      latestStatus: 'Latest Status',
      latestLatency: 'Latest Latency (ms)',
      availability7d: '7d Availability',
      availability15d: '15d Availability',
      availability30d: '30d Availability',
      avgLatency7d: '7d Avg Latency (ms)'
    },
    empty: {
      title: 'No channels available',
      description: 'No monitored channels have been configured yet.'
    }
  },

  // Available Channels (user-facing)
  availableChannels: {
    title: 'Available Channels',
    description: 'Channels you can access, along with their supported models and pricing',
    searchPlaceholder: 'Search channels or models...',
    empty: 'No available channels',
    noModels: 'No models configured',
    noPricing: 'Pricing not configured',
    exclusive: 'Exclusive',
    public: 'Public',
    exclusiveTooltip: 'Exclusive groups granted to you by an admin',
    publicTooltip: 'Groups open to all users',
    columns: {
      name: 'Channel',
      description: 'Description',
      platform: 'Platform',
      groups: 'Your Accessible Groups',
      supportedModels: 'Supported Models'
    },
    pricing: {
      billingMode: 'Billing Mode',
      billingModeToken: 'Per Token',
      billingModePerRequest: 'Per Request',
      billingModeImage: 'Per Image',
      billingModeVideo: 'Per Video',
      inputPrice: 'Input',
      outputPrice: 'Output',
      cacheWritePrice: 'Cache Write',
      cacheReadPrice: 'Cache Read',
      imageInputPrice: 'Image Input',
      imageOutputPrice: 'Image Output',
      perRequestPrice: 'Per Request',
      intervals: 'Tiered Pricing',
      unitPerMillion: '/ 1M tokens',
      unitPerRequest: '/ request'
    }
  },

  // Model Plaza (public group/model pricing showcase)
  modelPlaza: {
    title: 'Model Plaza',
    description: 'Browse available models and pricing by group',
    loading: 'Loading...',
    empty: 'No groups to display',
    loadFailed: 'Failed to load model plaza',
    noSearchResult: 'No matching models',
    anonymousHint: 'Sign in to see your exclusive groups and personal rates',
    filters: {
      platformLabel: 'Platform',
      groupLabel: 'Group',
      rateLabel: 'Rate',
      modelLabel: 'Model',
      searchPlaceholder: 'Search models',
      all: 'All'
    },
    badges: {
      exclusive: 'Exclusive',
      subscription: 'Subscription'
    },
    detail: {
      noModels: 'No models configured for this group',
      noPricing: 'Pricing not configured',
      peakNote: 'Peak hours {window}: billing rate ×{multiplier}'
    },
    table: {
      model: 'Model',
      input: 'Input',
      output: 'Output',
      cache: 'Cache',
      cacheWrite: 'Write',
      cacheRead: 'Read',
      paidPrice: 'Your Price (Discounted)',
      officialPrice: 'Official Price',
      rate: 'Rate',
      unitPerMillion: '$ / 1M tokens',
      perUnitRequest: '/ request',
      perUnitImage: '/ image',
      perRequest: 'Per request',
      perImage: 'Per image'
    },
    nav: {
      login: 'Sign In',
      backToDashboard: 'Back to Console'
    }
  },

  affiliate: {
    title: 'Affiliate Rebates',
    description: 'Invite new users and convert your rebate quota into account balance',
    yourCode: 'Your Affiliate Code',
    inviteLink: 'Invite Link',
    copyCode: 'Copy Code',
    copyLink: 'Copy Link',
    codeCopied: 'Affiliate code copied',
    linkCopied: 'Invite link copied',
    loadFailed: 'Failed to load affiliate data',
    transferFailed: 'Failed to transfer affiliate quota',
    stats: {
      rebateRate: 'My Rebate Rate',
      rebateRateHint: 'What you earn each time an invitee recharges',
      invitedUsers: 'Invited Users',
      availableQuota: 'Available Rebate Quota',
      frozenQuota: 'Frozen',
      frozenQuotaHint: 'Recently earned rebates pending release',
      totalQuota: 'Historical Rebate Quota'
    },
    transfer: {
      title: 'Transfer Rebate Quota',
      description: 'Move available rebate quota into your account balance',
      button: 'Transfer to Balance',
      transferring: 'Transferring...',
      empty: 'No available rebate quota',
      success: '{amount} has been transferred to your balance'
    },
    invitees: {
      title: 'Invited Users',
      empty: 'No invited users yet',
      columns: {
        email: 'Email',
        username: 'Username',
        rebate: 'Rebate',
        joinedAt: 'Joined At'
      }
    },
    tips: {
      title: 'How It Works',
      line1: 'Share your affiliate code or invite link with new users.',
      line2: 'When invitees recharge, you receive {rate} of the recharge as rebate quota.',
      line3: 'Transfer rebate quota to balance at any time.',
      line4: 'Newly earned rebates may have a waiting period before they can be transferred.'
    }
  },

  // 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)',
    balanceAddedAffiliate: 'Balance Added (Affiliate Transfer)',
    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',
    rpmLimit: 'RPM Limit',
    rpmUnlimited: 'Unlimited',
    memberSince: 'Member Since',
    overviewTitle: 'Account Overview',
    overviewDescription: 'Check account status, profile sources, and common actions at a glance.',
    basicsTitle: 'Profile & Avatar',
    basicsDescription: 'Keep your public profile details and avatar aligned.',
    linkedProfileSources: 'Profile Sources',
    linkedProfileSourcesDescription: 'Some profile details may stay synced from third-party sign-in methods.',
    securityTitle: 'Security Settings',
    securityDescription: 'Password, two-factor authentication, and alerts live in the right rail.',
    administrator: 'Administrator',
    user: 'User',
    username: 'Username',
    email: 'Email',
    status: 'Status',
    role: 'Role',
    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'
    },
    passkey: {
      title: 'Passkeys',
      description: 'Use Face ID, Touch ID, Windows Hello, or a security key to sign in without a password.',
      add: 'Add passkey',
      continue: 'Create passkey',
      name: 'Passkey name',
      namePlaceholder: 'For example, MacBook Touch ID',
      passwordPlaceholder: 'Enter your current password to confirm',
      empty: 'No passkeys are registered yet.',
      synced: 'Synced',
      createdAt: 'Created {date}',
      lastUsed: 'Last used {date}',
      featureDisabled: 'Passkeys have not been configured by the administrator.',
      unsupported: 'This browser or device does not support passkeys.',
      loadFailed: 'Failed to load passkeys.',
      added: 'Passkey added.',
      addFailed: 'Failed to add passkey.',
      renamePrompt: 'Enter a new name for this passkey',
      renamed: 'Passkey renamed.',
      renameFailed: 'Failed to rename passkey.',
      deleteTitle: 'Delete passkey',
      deleteConfirm: 'Delete “{name}”? You will no longer be able to sign in with it.',
      deleted: 'Passkey deleted.',
      deleteFailed: 'Failed to delete passkey.'
    },
    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',
    },
    avatar: {
      title: 'Profile Avatar',
      description: 'Upload an avatar image. Static uploads are compressed to 20KB before saving.',
      uploadAction: 'Upload image',
      uploadHint: 'Static uploads are compressed to 20KB when possible. GIF uploads must already be within 20KB.',
      uploadRequired: 'Upload an avatar image first',
      saveSuccess: 'Avatar updated',
      deleteSuccess: 'Avatar removed',
      invalidType: 'Please choose an image file',
      gifTooLarge: 'GIF avatars must already be 20KB or smaller',
      compressTooLarge: 'Unable to compress this image below 20KB. Try a smaller image.',
      compressFailed: 'Failed to compress the selected image.',
      readFailed: 'Failed to read the selected image.',
      emptyDeleteHint: 'Avatar is already empty',
    },
    authBindings: {
      title: 'Connected Sign-In Methods',
      description: 'View current bindings and connect another provider to this account.',
      bindAction: 'Bind {providerName}',
      bindSuccess: 'Account linked successfully',
      emailPlaceholder: 'Enter email address',
      codePlaceholder: 'Enter verification code',
      passwordPlaceholder: 'Set a login password',
      replaceEmailPasswordPlaceholder: 'Enter current password',
      sendCodeAction: 'Send code',
      manageEmailAction: 'Manage email',
      hideEmailFormAction: 'Hide email form',
      confirmEmailBindAction: 'Bind email',
      confirmEmailReplaceAction: 'Replace primary email',
      codeSentTo: 'Code sent to {email}',
      replaceSuccess: 'Primary email updated',
      unbindAction: 'Unbind',
      unbindSuccess: '{providerName} unbound',
      boundCount: '{count} linked records',
      status: {
        bound: 'Bound',
        notBound: 'Not bound',
      },
      providers: {
        email: 'Email',
        linuxdo: 'LinuxDo',
        dingtalk: 'DingTalk',
        oidc: '{providerName}',
        wechat: 'WeChat',
      },
      notes: {
        emailManagedFromProfile: 'Primary email is managed in the profile form',
        canUnbind: 'You can unbind this sign-in method',
        bindAnotherBeforeUnbind: 'Bind another sign-in method before unbinding',
      },
      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
}
