{
  "title": "Settings",
  "subtitle": "Manage pricing, notifications, data, and hooks",
  "exportData": "Export Data",
  "acrossSessions": "Across all tracked sessions",
  "basedOnUsage": "Based on per-model token usage",
  "tabby": {
    "title": "Tabby companion",
    "description": "A floating cat that reacts to your live sessions.",
    "enable": "Show Tabby",
    "enableDesc": "Display the corner companion across the dashboard (⌘B to open)"
  },
  "pricing": {
    "title": "Model Pricing",
    "description": "Rates per million tokens (USD). Use % as wildcard in patterns. Some models have a time-limited introductory rate (shown in violet); usage on or before its cutoff date is billed at that rate, and usage after it at the standard rate.",
    "introNote": "Intro ${{input}}/${{output}} through {{until}}",
    "introRatesTitle": "Introductory rates",
    "introRatesHint": "Leave the date empty for no promo",
    "introUntil": "Through (date)",
    "introUntilInvalid": "Introductory cutoff must be a YYYY-MM-DD date",
    "resetConfirm": "Confirm Reset",
    "resetDefaults": "Reset Defaults",
    "resetResult": "Reset to {{count}} default rules",
    "addModel": "Add Model",
    "pattern": "Pattern",
    "patternPlaceholder": "claude-opus-4%",
    "namePlaceholder": "Claude Opus 4",
    "validationRequired": "Pattern and display name are required",
    "lastUpdated": "Last updated: ",
    "tooltip": {
      "title": "How model pricing works",
      "howItWorks": "How it works",
      "howItWorksBody": "When a session reports usage, the dashboard finds the first pricing rule whose pattern matches the model id and multiplies (input tokens / 1M) and (output tokens / 1M) by the rates below to compute cost. Rules are evaluated top-to-bottom - the first match wins.",
      "patternsTitle": "Pattern syntax",
      "patternsBody": "Patterns are SQL-style globs. % is a wildcard that matches any characters. For example: claude-opus-4-7% matches every model id that starts with claude-opus-4-7 (e.g. claude-opus-4-7, claude-opus-4-7-20260101). claude-%-haiku matches any haiku variant. An exact id like claude-sonnet-4-6 only matches itself.",
      "manualUpdates": "You must update prices manually",
      "manualUpdatesBody": "Anthropic publishes pricing changes on their website - there is no live feed. When a new model launches or rates change, edit the matching rule (or add a new one above the catch-all) so newly recorded sessions are costed correctly. Already-stored sessions keep the price that was applied at ingest time.",
      "apiPricing": "Reference only - API rates",
      "apiPricingBody": "These are pay-as-you-go API rates. If you use Claude Code on a subscription plan (Pro, Max, Team, or Enterprise), your actual cost is a flat monthly fee, not per-token - so these figures will usually be higher than what you really pay. Treat the costs here as a usage estimate for reference, not a bill."
    },
    "cacheWrite5m": "Cache Write (5m)",
    "cacheWrite1h": "Cache Write (1h)",
    "fastInput": "Fast Input",
    "fastOutput": "Fast Output"
  },
  "claudeHome": {
    "title": "CLAUDE_HOME",
    "description": "Root directory for Claude Code session data. Changing this updates the scan path for transcripts and imports immediately.",
    "save": "Save",
    "saving": "Saving...",
    "current": "Current:",
    "placeholder": "/path/to/claude-home",
    "saveFailed": "Failed to update CLAUDE_HOME"
  },
  "hooks": {
    "title": "Hook Configuration",
    "description": "Claude Code hooks forward events to the dashboard in real time.",
    "allInstalled": "All hooks installed",
    "incomplete": "Hooks incomplete",
    "reinstall": "Reinstall Hooks",
    "success": "Hooks installed successfully",
    "failed": "Hook installation failed"
  },
  "notifications": {
    "title": "Notifications",
    "description": "Browser notifications for important events. Requires permission.",
    "enable": "Enable Browser Notifications",
    "granted": "Permission granted",
    "blocked": "Permission blocked",
    "required": "Permission required",
    "notifyWhen": "Notify me when...",
    "newSession": "New session starts",
    "sessionComplete": "Session completes",
    "sessionError": "Session errors",
    "subagentSpawned": "Subagent spawned",
    "testTitle": "Agent Monitor",
    "testBody": "Notifications are working!",
    "sendTest": "Send Test Notification",
    "disabledInfo": "Notifications are disabled - enable to get alerts for session events"
  },
  "import": {
    "title": "Import History",
    "description": "Bring existing Claude Code sessions into the dashboard. Token counts, per-model cost, compactions, subagents, tool uses, and turn durations are reconstructed from the original JSONL transcripts - identical to how live sessions are captured.",
    "accuracyNote": "Re-running is safe. Sessions are deduplicated by session ID, and compaction baselines ensure token totals never double-count.",
    "supportedFiles": "Supported inputs: .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz",
    "instructions": "How to gather your history",
    "stepLocate": "1. Locate your Claude Code history",
    "stepLocateBody": "Every Claude Code session is stored as a JSONL transcript under the projects folder. Each subfolder is named after the working directory where the session started (slashes replaced with dashes).",
    "stepArchive": "2. Bundle it for transfer (optional)",
    "stepArchiveBody": "To move history from another machine, archive the whole folder first, then copy it over (AirDrop, scp, USB, cloud storage):",
    "stepChoose": "3. Pick an import mode below",
    "stepChooseBody": "Rescan the default location, point at any folder you've extracted history into, or upload files/archives directly.",
    "stepVerify": "4. Verify tokens and cost",
    "stepVerifyBody": "After import, open Analytics → Cost to confirm the breakdown. Re-importing the same session is always safe.",
    "defaultLocation": "Default location on this machine",
    "locationFound": "Folder found",
    "locationMissing": "Folder not found",
    "projectsLabel": "projects",
    "jsonlLabel": "JSONL files",
    "modeRescan": "Rescan default folder",
    "modeRescanDesc": "Re-read ~/.claude/projects and import anything new.",
    "modeFolder": "Scan a folder",
    "modeFolderDesc": "Scan any directory on this machine for JSONL transcripts (walks subfolders).",
    "modeUpload": "Upload files",
    "modeUploadDesc": "Drop JSONL files or an archive (.zip / .tar.gz) directly into the browser.",
    "modeBackup": "Restore backup",
    "modeBackupDesc": "Import a dashboard export (.json) from Export data — merge another machine's history in.",
    "backupHint": "Drop an export .json here or click to select",
    "backupSub": "The file produced by the Export data button (top of Settings)",
    "runRestore": "Restore",
    "backupResult": {
      "title": "Restore complete",
      "sessionsImported": "Sessions added: {{count}}",
      "sessionsSkipped": "Already present: {{count}}",
      "events": "Events: {{count}}",
      "pricing": "Pricing rules: {{count}}",
      "detail": "{{agents}} agents · {{workflows}} workflows · {{runs}} runs · {{rules}} alert rules"
    },
    "folderPlaceholder": "/absolute/path/to/claude-history",
    "folderHelper": "Absolute path. Tilde (~) is expanded. Subfolders are scanned recursively.",
    "runRescan": "Rescan Now",
    "runScan": "Scan Folder",
    "runUpload": "Upload & Import",
    "dropzoneHint": "Drag files here or click to select",
    "dropzoneSub": "Accepts .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz",
    "filesSelected": "{{count}} file(s) selected",
    "clearSelection": "Clear",
    "copy": "Copy",
    "copied": "Copied",
    "progress": {
      "scan": "Scanning directory...",
      "extract": "Extracting archives ({{processed}}/{{total}})...",
      "parse": "Parsing transcripts ({{processed}}/{{total}})...",
      "complete": "Import complete",
      "error": "Import failed"
    },
    "result": {
      "imported": "Imported: {{count}}",
      "backfilled": "Enriched existing: {{count}}",
      "skipped": "Already up to date: {{count}}",
      "errors": "Errors: {{count}}",
      "filesScanned": "Files scanned: {{count}}",
      "title": "Last import result"
    },
    "errors": {
      "noFiles": "No files selected",
      "noJsonl": "No .jsonl files were found in the uploaded content",
      "pathRequired": "Path is required",
      "pathInvalid": "Path must be absolute",
      "pathNotFound": "Path does not exist",
      "pathNotDir": "Path is not a directory",
      "generic": "Import failed: {{message}}"
    }
  },
  "data": {
    "title": "Data Management",
    "description": "Database info, import/export, and cleanup.",
    "dbOverview": "Database Overview",
    "dbSize": "DB Size",
    "loadingDb": "Loading database info...",
    "sessionCleanup": "Session Cleanup",
    "cleanupDesc": "Abandon stale sessions and purge old data",
    "abandonAfter": "Abandon stale active sessions older than",
    "purgeAfter": "Purge completed/errored sessions older than",
    "confirmCleanup": "Confirm Cleanup",
    "runCleanup": "Run Cleanup",
    "nothingToClean": "Nothing to clean up",
    "abandonedResult": " sessions abandoned",
    "purgedResult": " sessions purged ({{events}} events, {{agents}} agents)"
  },
  "danger": {
    "title": "Danger Zone",
    "description": "Irreversible actions that delete data permanently",
    "warning": "This will delete all sessions, agents, events, and token data. Are you sure?",
    "yesClearAll": "Yes, Clear All",
    "clearAllData": "Clear All Data",
    "clearedResult": "Cleared {{count}} rows"
  },
  "about": {
    "title": "About",
    "description": "Server runtime information.",
    "release": "Release",
    "uiBuild": "UI build v{{version}} (rebuild client to match)",
    "uptime": "Uptime",
    "nodejs": "Node.js",
    "platform": "Platform",
    "wsClients": "WS Clients",
    "loadingInfo": "Loading server info..."
  },
  "tables": {
    "sessions": "sessions",
    "agents": "agents",
    "events": "events",
    "sessionsWithCost": "sessions with cost",
    "pricingRules": "pricing rules"
  },
  "messages": {
    "failedLoad": "Failed to load",
    "failedSave": "Failed to save",
    "failedDelete": "Failed to delete",
    "unknownError": "Unknown",
    "actionFailed": "Error: {{message}}"
  },
  "webhooks": {
    "title": "Webhook Notifications",
    "description": "Forward fired alerts to Slack, Discord, Microsoft Teams, or any HTTP endpoint. Delivery is automatic, retried on failure, and never blocks monitoring.",
    "count_one": "{{count}} target",
    "count_other": "{{count}} targets",
    "add": "Add Webhook",
    "loading": "Loading webhooks…",
    "empty": "No webhooks configured. Add one to forward alerts to Slack, Discord, Teams, or a custom endpoint.",
    "scopedTo_one": "{{count}} rule",
    "scopedTo_other": "{{count}} rules",
    "enabled": "Enabled",
    "test": "Test",
    "edit": "Edit",
    "delete": "Delete",
    "confirmDelete": "Confirm",
    "testOk": "Delivered (HTTP {{status}})",
    "testFail": "Failed: {{error}}",
    "addTitle": "New Webhook",
    "editTitle": "Edit Webhook",
    "fieldName": "Name",
    "fieldNamePlaceholder": "e.g. Team Slack #alerts",
    "fieldType": "Type",
    "type": {
      "slack": "Slack",
      "discord": "Discord",
      "teams": "Microsoft Teams",
      "generic": "Generic (custom JSON)"
    },
    "fieldUrl": "Webhook URL",
    "urlKeepHint": "leave blank to keep current",
    "urlKeepPlaceholder": "•••••••• (unchanged)",
    "urlPlaceholder": {
      "slack": "https://hooks.slack.com/services/…",
      "discord": "https://discord.com/api/webhooks/…",
      "teams": "https://outlook.office.com/webhook/…",
      "generic": "https://example.com/webhook"
    },
    "fieldSecret": "Signing secret (optional)",
    "secretPlaceholder": "HMAC-SHA256 secret",
    "secretKeepPlaceholder": "•••••••• (leave blank to keep)",
    "secretHint": "When set, requests are signed with an X-Webhook-Signature header.",
    "fieldHeaders": "Custom headers (optional)",
    "replaceHeaders": "Replace headers",
    "headerKey": "Header",
    "headerValue": "Value",
    "addHeader": "Add header",
    "scopeAll": "Receive alerts from all rules",
    "enabledOnSave": "Enabled",
    "save": "Save",
    "create": "Create",
    "cancel": "Cancel",
    "urlOptional": "optional override",
    "urlAuto": "URL is set automatically from the credentials below.",
    "deleteTitle": "Delete webhook?",
    "deleteMessage": "Delete \"{{name}}\"? Fired alerts will stop being delivered to this target. This cannot be undone.",
    "guideToggle": "How to set up {{provider}}",
    "guideDocs": "Official {{provider}} docs",
    "guideStaleNote": "Provider setup screens change often, so these steps may be out of date - always confirm against the official docs."
  },
  "alertsHub": {
    "title": "Alerts",
    "description": "Define alert rules, route them to webhook channels, and review what has fired - all in one place.",
    "tabRules": "Rules",
    "tabChannels": "Channels",
    "tabActivity": "Activity",
    "rulesHint": "Conditions that trigger an alert. Evaluated server-side against the live event stream.",
    "rulesEmptyHint": "Add a rule to start alerting on errors, inactivity, stuck agents, or token thresholds."
  },
  "jumpTo": "Jump to",
  "webhookGuides": {
    "slack": {
      "steps": [
        "Create or open a Slack app at api.slack.com/apps.",
        "Turn on 'Incoming Webhooks', then click 'Add New Webhook to Workspace'.",
        "Choose the channel to post to and authorize.",
        "Copy the generated URL (https://hooks.slack.com/services/…) and paste it above."
      ]
    },
    "discord": {
      "steps": [
        "Open your server → Server Settings → Integrations → Webhooks.",
        "Click 'New Webhook', pick a channel, optionally rename it.",
        "Click 'Copy Webhook URL' and paste it above."
      ]
    },
    "teams": {
      "steps": [
        "In the target Teams channel, click ⋯ → 'Workflows'.",
        "Pick the template 'Post to a channel when a webhook request is received'.",
        "Finish the flow and copy the generated HTTP POST URL.",
        "Paste it above. (Classic Office 365 connectors were retired in 2025 - use Workflows.)"
      ]
    },
    "google_chat": {
      "steps": [
        "Open the Google Chat space → space title → 'Apps & integrations'.",
        "Click 'Webhooks' → 'Add webhook' and give it a name.",
        "Copy the webhook URL and paste it above."
      ]
    },
    "mattermost": {
      "steps": [
        "Main Menu → Integrations → Incoming Webhooks (an admin must enable webhooks first).",
        "Click 'Add Incoming Webhook' and choose a channel.",
        "Save, then copy the webhook URL and paste it above."
      ]
    },
    "rocketchat": {
      "steps": [
        "Administration → Integrations → New → Incoming.",
        "Enable it, pick a channel, and save.",
        "Copy the 'Webhook URL' and paste it above."
      ]
    },
    "telegram": {
      "steps": [
        "Message @BotFather, run /newbot, and copy the bot token.",
        "Add the bot to your group/channel (or just DM it).",
        "Find the chat ID: send a message, open https://api.telegram.org/bot<token>/getUpdates, read result[].message.chat.id.",
        "Enter the Bot token and Chat ID above - no URL needed."
      ]
    },
    "pagerduty": {
      "steps": [
        "Open the target Service → Integrations → 'Add integration'.",
        "Choose 'Events API v2'.",
        "Copy the Integration Key (the routing key).",
        "Enter it as the Routing key above - the Events API URL is prefilled."
      ]
    },
    "opsgenie": {
      "steps": [
        "Settings → Integrations → add an 'API' integration.",
        "Copy the generated API key.",
        "Note your account region (US or EU).",
        "Enter the API key and region above - the alerts URL is derived from the region."
      ]
    },
    "splunk_oncall": {
      "steps": [
        "Integrations → REST Endpoint, and enable it.",
        "Copy the REST URL - it already contains your API key.",
        "Replace the trailing '$routing_key' with one of your routing keys.",
        "Paste the full URL above."
      ]
    },
    "zapier": {
      "steps": [
        "Create a Zap with the trigger 'Webhooks by Zapier' → 'Catch Hook'.",
        "Copy the custom webhook URL it gives you.",
        "Paste it above. The alert arrives as JSON: { event, alert }."
      ]
    },
    "make": {
      "steps": [
        "Add a 'Webhooks' → 'Custom webhook' module as the first step of a scenario.",
        "Click 'Add', create the hook, and copy its URL.",
        "Paste it above, then run once so Make learns the payload shape."
      ]
    },
    "n8n": {
      "steps": [
        "Add a 'Webhook' node to your workflow; set the method to POST.",
        "Copy the Production URL.",
        "Activate the workflow and paste the URL above (http is allowed for self-hosted)."
      ]
    },
    "pipedream": {
      "steps": [
        "Create a workflow with an 'HTTP / Webhook' trigger.",
        "Copy the unique endpoint URL.",
        "Paste it above; inspect deliveries in the Pipedream event inspector."
      ]
    },
    "generic": {
      "steps": [
        "Point this at any endpoint that accepts a JSON POST (https, or http for local testing).",
        "Body shape: { event: 'alert.triggered', source, sent_at, alert: { … } }.",
        "Optional: set a signing secret (HMAC-SHA256 over the body → X-Webhook-Signature header) and custom headers.",
        "Tip: use a free inspector like webhook.site to see the exact payload."
      ]
    }
  },
  "remoteSources": {
    "title": "Remote Data Sources",
    "description": "Collect Claude Code usage from other machines over SSH - e.g. a dev box or cloud VM you drive over SSH while running this dashboard locally. Authentication uses your own SSH setup (~/.ssh/config, keys, agent); no passwords are stored here.",
    "scopeTitle": "Data scope",
    "scopeDesc": "Choose which machines' data the whole dashboard shows. Changes apply immediately across every page — sessions, analytics, and cost.",
    "scopeAll": "All sources",
    "scopeAllDesc": "This machine plus every configured remote source, combined.",
    "scopeLocal": "This machine only",
    "scopeLocalDesc": "Only sessions collected locally — hides all remote-source data.",
    "scopeSelected": "Selected sources",
    "scopeSelectedDesc": "Pick exactly which machines to include, below.",
    "scopeSelectedCount": "{{n}} of {{total}} selected",
    "scopePickMachines": "Machines to include",
    "thisMachine": "This machine",
    "listTitle": "Configured sources",
    "add": "Add source",
    "addTitle": "Add a remote source",
    "editTitle": "Edit source",
    "fieldLabel": "Label",
    "fieldHost": "SSH host",
    "fieldPort": "Port (optional)",
    "fieldIdentity": "Identity file (optional)",
    "fieldRemoteHome": "Remote Claude home (optional)",
    "fieldRemoteHomeHint": "Linux/macOS: default ~/.claude (or an absolute path like /home/you/.claude). Windows SSH + Claude in WSL: leave blank (auto-detect) or use wsl:~/.claude. Native Windows: C:/Users/you/.claude.",
    "fieldEnabled": "Sync automatically in the background",
    "empty": "No remote sources yet.",
    "emptyHint": "Add a machine you reach over SSH to pull its Claude Code usage in.",
    "paused": "Auto-sync off",
    "sessionCount": "{{n}} sessions",
    "sessionCountLinked": "{{n}} linked",
    "sessionCountHint": "Sessions linked to this source (not every session visible when data scope is All)",
    "lastSync": "Last sync: {{when}}",
    "neverSynced": "Never synced",
    "imported": "{{n}} imported",
    "syncNew": "{{n}} new",
    "syncOnRemote": "{{n}} on remote",
    "test": "Test",
    "syncNow": "Sync",
    "syncAll": "Sync all",
    "enable": "Enable",
    "disable": "Disable",
    "confirmDelete": "Remove this source?",
    "purgeData": "Also delete the sessions imported from this source (cannot be undone)",
    "deleteAndPurge": "Remove + delete data",
    "removeKeep": "Remove (keep data)",
    "remoteSourceBadgeTitle": "Collected from a remote machine"
  },
  "cursorPathsNote": "Informational: Cursor sessions count here too — Cursor happens to use the same ~/.claude paths as Claude Code (locally and on synced remotes)."
}
