import type { WizardTranslationMap } from "../types.js";

export const en = {
  common: {
    back: "Back",
    done: "Done",
    docs: "Docs:",
    finished: "Finished",
    noAuth: "No auth",
    password: "Password",
    required: "Required",
    minute: "{count} minute",
    minutes: "{count} minutes",
    second: "{count} second",
    seconds: "{count} seconds",
    skip: "Skip",
    skipForNow: "Skip for now",
    tokenRecommended: "Token (recommended)",
  },
  wizard: {
    customProvider: {
      apiBaseUrl: "API Base URL",
      apiKeyPrompt: "API Key (leave blank if not required)",
      changeBaseUrl: "Change base URL",
      changeBaseUrlAndModel: "Change base URL and model",
      changeModel: "Change model",
      compatibility: "Endpoint compatibility",
      compatibilityAnthropic: "Anthropic-compatible",
      compatibilityAnthropicHint: "Uses /messages",
      compatibilityOpenAi: "OpenAI-compatible",
      compatibilityOpenAiHint: "Uses /chat/completions",
      compatibilityUnknown: "Unknown (detect automatically)",
      compatibilityUnknownHint: "Probes OpenAI then Anthropic endpoints",
      detectionFailed: "Could not detect endpoint type.",
      detectionFailedNote: "This endpoint did not respond to OpenAI or Anthropic style requests.",
      detectionNoteTitle: "Endpoint detection",
      detectionProgress: "Detecting endpoint type...",
      detectedAnthropic: "Detected Anthropic-compatible endpoint.",
      detectedOpenAi: "Detected OpenAI-compatible endpoint.",
      endpointId: "Endpoint ID",
      endpointIdRequired: "Endpoint ID is required.",
      endpointIdRenamed:
        'Endpoint ID "{from}" already exists for a different base URL. Using "{to}".',
      endpointIdTitle: "Endpoint ID",
      imageInput: "Does this model support image input?",
      modelAlias: "Model alias (optional)",
      modelAliasPlaceholder: "e.g. local, ollama",
      modelId: "Model ID",
      modelIdPlaceholder: "e.g. llama3, claude-3-7-sonnet",
      modelIdRequired: "Model ID is required",
      retryChoice: "What would you like to change?",
      verifying: "Verifying...",
      verificationFailedError: "Verification failed: {error}",
      verificationFailedStatus: "Verification failed: status {status}",
      verificationSuccessful: "Verification successful.",
      validUrl: "Please enter a valid URL (e.g. http://...)",
    },
    gateway: {
      accessProtection: "Gateway access protection",
      auth: "Gateway auth",
      authPasswordStoredMessage: "Where is this gateway password stored?",
      authPasswordMode: "How do you want to provide the gateway password?",
      authTokenMode: "How do you want to provide the gateway token?",
      authTokenStoredMessage: "Where is this gateway token stored?",
      bindAddress: "Gateway bind address",
      bindAuto: "Auto (Loopback -> LAN)",
      bindAutoHint: "Try loopback first",
      bindCustom: "Custom IP",
      bindCustomHint: "Bind to one local address",
      bindCustomIp: "Custom IP address",
      bindLan: "LAN (0.0.0.0)",
      bindLanHint: "Reachable on your local network",
      bindLoopback: "Loopback (127.0.0.1)",
      bindLoopbackHint: "This machine only",
      bindTailnet: "Tailnet (Tailscale IP)",
      bindTailnetHint: "Reachable over Tailscale",
      existingPasswordConfirm: "Use existing gateway password ({password})?",
      existingTokenConfirm: "Use existing gateway token ({token})?",
      passwordPrompt: "Gateway password",
      plaintextPasswordHint: "Stores the password directly in OpenClaw config",
      plaintextPasswordLabel: "Enter password now",
      plaintextTokenHint: "Default",
      plaintextTokenLabel: "Generate/store plaintext token",
      port: "Gateway port",
      refHint: "Store a reference instead of plaintext",
      refLabel: "Use SecretRef",
      remotePasswordMode: "How do you want to provide this gateway password?",
      remoteTokenMode: "How do you want to provide this gateway token?",
      tailscaleExposure: "Tailscale exposure",
      tailscaleReset: "Reset Tailscale serve/funnel on exit?",
      tokenPlaceholder: "Needed for multi-machine or non-loopback access",
      tokenPrompt: "Gateway token",
      tokenPromptGenerate: "Gateway token (blank to generate)",
      websocketUrl: "Gateway WebSocket URL",
    },
    gatewayTailscale: {
      docsNote: "Docs:\nhttps://docs.openclaw.ai/gateway/tailscale\nhttps://docs.openclaw.ai/web",
      funnel: "Funnel",
      funnelHint: "Public HTTPS via Tailscale Funnel (internet)",
      missingBinNote:
        "Tailscale binary not found in PATH or /Applications.\nEnsure Tailscale is installed from:\n  https://tailscale.com/download/mac\n\nYou can continue setup, but serve/funnel will fail at runtime.",
      off: "Off",
      offHint: "No Tailscale exposure",
      serve: "Serve",
      serveHint: "Private HTTPS for your tailnet (devices on Tailscale)",
      warningTitle: "Tailscale Warning",
    },
    hooks: {
      configuredTitle: "Hooks Configured",
      enable: "Enable hooks?",
      introTitle: "Hooks",
      noHooksMessage: "No eligible hooks found. You can configure hooks later in your config.",
      noHooksTitle: "No Hooks Available",
    },
    completion: {
      cacheFailed: "Failed to generate completion cache. Run `{command}` later.",
      enable: "Enable {shell} shell completion for {cli}?",
      installed: "Shell completion installed. {reloadHint}",
      reloadPowerShell: "Restart your shell or run: {command}",
      reloadShell: "Restart your shell or run: source {profile}",
      title: "Shell completion",
    },
    migration: {
      apply: "Apply this migration now?",
      appliedTitle: "Migration applied",
      cancelled: "migration cancelled",
      complete: "Migration complete. Run `openclaw doctor` next.",
      previewTitle: "Migration preview",
      source: "Migration source",
      sourceAgentHome: "Source agent home",
      sourcePathHint: "Enter a source path next",
      targetWorkspace: "Target workspace directory",
    },
    plugins: {
      configureBackHint: "Return to section menu",
      configureEmpty: "No plugins with configurable fields found.",
      configureEmptyTitle: "Plugins",
      configureFieldsTitle: "Plugin setup",
      configurePlugin: "Configure {plugin}",
      configureSelect: "Select plugin to configure",
      configureSelectOnboard: "Configure plugins (select to set up now, or skip)",
      configuredCount: "{configured}/{total} configured",
      currentValue: "Keep current ({value})",
      downloadFromClawHub: "Download from ClawHub ({spec})",
      downloadFromNpm: "Download from npm ({spec})",
      enableFailed: "Cannot enable {plugin}: {reason}.",
      fieldsCount: "{count} field{plural}",
      installFailed: "Failed to install {spec}: {error}",
      installFailedShort: "Install failed: {plugin}",
      installPluginPrompt: "Install {plugin} plugin?",
      installTimedOut: "Installing {spec} timed out after {duration}.",
      installTimedOutShort: "Install timed out: {plugin}",
      installedPlugin: "Installed {plugin} plugin",
      installingPlugin: "Installing {plugin} plugin…",
      installTitle: "Plugin install",
      noRemoteInstallSource:
        "No remote install source is available for {plugin}. Returning to selection.",
      officialInstall: "Install optional plugins",
      officialSkipHint: "Continue without installing optional plugins",
      preparingInstall: "Preparing",
      returningToSelection: "Returning to selection.",
      arrayPromptSuffix: " (comma-separated, empty to clear)",
      arrayPlaceholder: "value1, value2",
      sensitiveField:
        '"{label}" is sensitive. Set it via:\n  openclaw config set plugins.entries.{plugin}.config.{field} <value>\nor use the Web UI Settings page.',
      sensitiveTitle: "Sensitive field",
      skipConfigHint: "Continue without configuring plugins",
      useLocalPluginPath: "Use local plugin path",
      useLocalPluginPathInstead: "Use local plugin path instead? ({path})",
      useNpmPackageInstead: "Use npm package instead? ({spec})",
    },
    model: {
      allProviders: "All providers",
      browseAll: "Browse all models",
      configuredTitle: "Model configured",
      current: "current",
      currentNotInCatalog: "current (not in catalog)",
      allowed: "allowed",
      allowedNotInCatalog: "allowed (not in catalog)",
      allowlistPicker: "Models in /model picker (multi-select)",
      allowlistText: "Allowlist models (comma-separated provider/model; blank to keep current)",
      clearAllowlist: "Clear the model allowlist? (shows all models)",
      configured: "configured",
      configuredNotInCatalog: "configured (not in catalog)",
      defaultModel: "Default model",
      defaultModelBlankToKeep: "Default model (blank to keep)",
      defaultSet: "Default model set to {model}",
      defaultSetForAgent: 'Default model set to {model} for agent "{agent}".',
      enterManually: "Enter model manually",
      filterByProvider: "Filter models by provider",
      keepCurrent: "Keep current ({value})",
      keepCurrentDefault: "Keep current (default: {value})",
      keptExistingDefault: "Kept existing default model {current}; {selected} is available.",
      loadsProviderCatalogs: "loads provider catalogs",
      loadingModels: "Loading available models",
      modelCount: "{count} model{plural}",
      providerSetupUnavailable: "Provider setup requires agent and runtime context.",
      providerSetupUnavailableTitle: "Provider setup unavailable",
      removeProviderModels: "Remove these provider models from the /model picker?",
      resolvesTo: "resolves to {value}",
    },
    remote: {
      auth: "Gateway auth",
      bonjour: "Discover gateway on LAN (Bonjour)?",
      connectionMethod: "Connection method",
      directAccessTitle: "Direct remote",
      enterUrlManually: "Enter URL manually",
      foundGateways: "Found {count} gateway(s)",
      fingerprintMissing: "not advertised (connection will not be pinned)",
      gatewayPasswordStoredMessage: "Where is this gateway password stored?",
      gatewayTokenStoredMessage: "Where is this gateway token stored?",
      insecureRemoteUrl:
        "Use wss:// for remote hosts, or ws://127.0.0.1/localhost via SSH tunnel. Break-glass: OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 for trusted private networks.",
      directDefaultsTls: "Direct remote access defaults to TLS.",
      loopbackSshHint:
        "If your gateway is loopback-only, choose SSH tunnel and keep ws://127.0.0.1:18789.",
      noGatewaysFound: "No gateways found",
      passwordPrompt: "Gateway password",
      plaintextPasswordHint: "Stores the password directly in OpenClaw config",
      plaintextPasswordLabel: "Enter password now",
      plaintextTokenHint: "Stores the token directly in OpenClaw config",
      plaintextTokenLabel: "Enter token now",
      searchProgress: "Searching for gateways...",
      selectGateway: "Select gateway",
      sshTunnel: "SSH tunnel (loopback)",
      sshTunnelTitle: "SSH tunnel",
      tokenPrompt: "Gateway token",
      trustGateway: "Trust this gateway? Host: {host} TLS fingerprint: {fingerprint}",
      validWebSocketUrl: "URL must start with ws:// or wss://",
      websocketUrl: "Gateway WebSocket URL",
    },
    setup: {
      authChoiceRequired: "auth choice is required",
      channelsTitle: "Channels",
      configHandling: "Config handling",
      existingConfigTitle: "Existing config detected",
      flowAdvanced: "Manual setup",
      flowAdvancedHint: "Choose Gateway port, network exposure, Tailscale, and auth.",
      flowQuickstart: "QuickStart (recommended)",
      flowQuickstartHint: "Recommended local setup. Change details later with {command}.",
      intro: "OpenClaw setup",
      invalidConfigTitle: "Invalid config",
      keepCurrent: "Keep current values",
      localGateway: "Local gateway (this machine)",
      localGatewayMissing: "No gateway detected ({url})",
      localGatewayReachable: "Gateway reachable ({url})",
      modifyCurrent: "Review and update",
      pluginCompatibilityTitle: "Plugin compatibility",
      quickstartOnlyLocal: "QuickStart only supports local gateways. Switching to Manual mode.",
      quickstartTitle: "QuickStart",
      quickstartAuthTokenDefault: "Token (default)",
      quickstartDirectChannels: "Direct to chat channels.",
      quickstartGatewayAuth: "Gateway auth: {auth}",
      quickstartGatewayBind: "Gateway bind: {bind}",
      quickstartGatewayCustomIp: "Gateway custom IP: {host}",
      quickstartGatewayPort: "Gateway port: {port}",
      quickstartKeepSettings: "Keeping your current gateway settings:",
      quickstartTailscaleExposure: "Tailscale exposure: {exposure}",
      remoteConfigured: "Remote gateway configured.",
      remoteGateway: "Remote gateway (info-only)",
      remoteGatewayMissing: "No remote URL configured yet",
      remoteGatewayReachable: "Gateway reachable ({url})",
      remoteGatewayUnreachable: "Configured but unreachable ({url})",
      resetBefore: "Reset before setup",
      resetConfig: "Config only",
      resetConfigCredsSessions: "Config + creds + sessions",
      resetFull: "Full reset (config + creds + sessions + workspace)",
      resetScope: "Reset scope",
      riskNotAccepted: "risk not accepted",
      searchTitle: "Search",
      setupMode: "Setup mode",
      secretRefProbeFailed: "Could not resolve {field} SecretRef for setup probe.",
      skillsTitle: "Skills",
      skipChannels: "Skipping channel setup.",
      skipSearch: "Skipping search setup.",
      skipSkills: "Skipping skills setup.",
      whatSetup: "What do you want to set up?",
      workspaceDirectory: "Workspace directory",
    },
    security: {
      askForHelp:
        "Ask someone experienced to help before enabling tools or exposing it to the internet.",
      baselineDmSessions:
        "Shared inboxes: isolate DM sessions (session.dmScope: per-channel-peer) and keep tool access minimal.",
      baselinePairing: "Pairing/allowlists + mention gating.",
      baselineSandbox: "Sandbox + least-privilege tools.",
      baselineSecrets: "Keep secrets out of the agent's reachable filesystem.",
      baselineSharedInbox:
        "Multi-user/shared inbox: split trust boundaries (separate gateway/credentials, ideally separate OS users/hosts).",
      baselineStrongModel:
        "Use the strongest available model for any bot with tools or untrusted inboxes.",
      beta: "OpenClaw is a hobby project and still in beta. Expect sharp edges.",
      confirm:
        "I understand this is personal-by-default and shared/multi-user use requires lock-down. Continue?",
      hardeningRequired:
        "If you're not comfortable with security hardening and access control, don't run OpenClaw.",
      learnMore: "Learn more",
      notMultitenant: "OpenClaw is not a hostile multi-tenant boundary by default.",
      personalAgent: "By default, OpenClaw is a personal agent: one trusted operator boundary.",
      promptRisk: "A bad prompt can trick it into doing unsafe things.",
      recommendedBaseline: "Recommended baseline",
      runRegularly: "Run regularly",
      sharedAuthority:
        "If multiple users can message one tool-enabled agent, they share that delegated tool authority.",
      title: "Security disclaimer",
      toolAccess: "This bot can read files and run actions if tools are enabled.",
    },
    skills: {
      configure: "Configure skills now? (recommended)",
      containerBrewHidden:
        "Brew-only skill installs are hidden in Linux containers because the official image does not ship Homebrew.",
      containerBrewManual:
        "Use a custom image with Homebrew preinstalled or install those dependencies manually.",
      containerInstallsTitle: "Container skill installs",
      docsLine: "Docs: https://docs.openclaw.ai/skills",
      enterEnv: "Enter {env}",
      homebrewCommand: "Show Homebrew install command?",
      homebrewInstallTitle: "Homebrew install",
      homebrewRecommendedTitle: "Homebrew recommended",
      installDeps: "Install missing skill dependencies",
      installFailed: "Install failed: {name}{code}{detail}",
      installed: "Installed {name}",
      installedWithWarnings: "Installed {name} (with warnings)",
      installing: "Installing {name}...",
      nodeManager: "Preferred node manager for skill installs",
      setEnv: "Set {env} for {name}?",
      skipDepsHint: "Continue without installing dependencies",
      statusTitle: "Skills status",
      allReadyTitle: "All skills ready",
    },
    channels: {
      account: "{label} account",
      configuredAction: "{label} already configured. What do you want to do?",
      configuredDeleteUnsupported: "{label} does not support deleting config entries.",
      configureDmPolicies: "Configure DM access policies now? (default: pairing)",
      deleteAccount: 'Delete {label} account "{account}"?',
      deleteConfig: "Delete config",
      dmAccessTitle: "{label} DM access",
      dmPolicy: "{label} DM policy",
      dmPolicyAllowlist: 'Allowlist DMs: {policyKey}="allowlist" + {allowFromKey} entries.',
      dmPolicyAllowlistOption: "Allowlist (specific users only)",
      dmPolicyApprove: "Approve: {command}",
      dmPolicyDefault: "Default: pairing (unknown DMs get a pairing code).",
      dmPolicyDisabledOption: "Disabled (ignore DMs)",
      dmPolicyMultiUser:
        'Multi-user DMs: run: {command} (or "per-account-channel-peer" for multi-account channels) to isolate sessions.',
      dmPolicyOpen: 'Public DMs: {policyKey}="open" + {allowFromKey} includes "*".',
      dmPolicyOpenOption: "Open (public inbound DMs)",
      dmPolicyPairing: "Pairing (recommended)",
      docs: "Docs: {link}",
      disabledBeforeSetup: "{channel} cannot be configured while {hint}. Enable it before setup.",
      disabledDuringSetup:
        "{channel} cannot be configured while {hint}. Enable it, then run {command} again.",
      disableKeepConfig: "Disable (keeps config)",
      doneHint: "Done",
      modifySettings: "Modify settings",
      noInteractiveSetup:
        "{channel} does not have an interactive setup screen yet. Run {command} for supported flags.",
      pluginEnableFailed:
        "Cannot enable {channel}: {reason}. Run {command} to inspect plugin state.",
      pluginMissingRecoverable:
        "{channel} plugin not available (continuing with setup). If the channel still doesn't work after setup, run `{listCommand}` and `{enableCommand}`, then restart the gateway.",
      pluginNotAvailable: "{channel} plugin not available.",
      removeTitle: "Remove channel",
      select: "Select a channel",
      selectQuickstart: "Select channel (QuickStart)",
      selectedTitle: "Selected channels",
      setupConfirm: "Set up a chat channel now?",
      setupTitle: "Channel setup",
      skipLeaveAsIs: "Skip (leave as-is)",
      skipLaterHint: "You can add channels later via `{command}`",
      statusTitle: "Channel status",
      statusBundledEnable: "bundled · enable to use",
      statusConfigured: "configured",
      statusConfiguredConnectionNotVerified: "configured (connection not verified)",
      statusConfiguredPluginDisabled: "configured (plugin disabled)",
      statusConnectedAs: "connected as {name}",
      statusInstallPluginEnable: "install plugin to enable",
      statusInstalled: "installed",
      statusInstalledPluginDisabled: "installed (plugin disabled)",
      statusLinked: "linked",
      statusNeedsAppCredentials: "needs app credentials",
      statusNeedsAppCreds: "needs app creds",
      statusNeedsAuth: "needs auth",
      statusNeedsHostNick: "needs host + nick",
      statusNeedsPrivateKey: "needs private key",
      statusNeedsQrLogin: "needs QR login",
      statusNeedsServiceAccount: "needs service account",
      statusNeedsSetup: "needs setup",
      statusNeedsToken: "needs token",
      statusNeedsTokens: "needs tokens",
      statusNeedsTokenIncomingWebhook: "needs token + incoming webhook",
      statusNeedsTokenUrl: "needs token + url",
      statusNeedsTokenSecret: "needs token + secret",
      statusNeedsUsernameTokenClientId: "needs username, token, and clientId",
      statusNotLinked: "not linked",
      statusNotConfigured: "not configured",
      statusLoggedIn: "logged in",
      statusRecommendedConfigured: "recommended · configured",
      statusRecommendedLoggedIn: "recommended · logged in",
      statusRecommendedNewcomerFriendly: "recommended · newcomer-friendly",
      statusRecommendedQrLogin: "recommended · QR login",
      statusSelfHostedChat: "self-hosted chat",
      statusSignalCliFound: "signal-cli found",
      statusSignalCliMissing: "signal-cli missing",
      statusUrbitMessenger: "urbit messenger",
      resolvedTitle: "Resolved",
    },
    feishu: {
      allowFromPrompt: "Feishu allowFrom (user open_ids)",
      allowlistFindUser: "You can find user open_id in Feishu admin console or via API.",
      allowlistIntro: "Allowlist Feishu DMs by open_id or user_id.",
      allowlistTitle: "Feishu allowlist",
      appIdPrompt: "Enter Feishu App ID",
      appSecretKeep: "Feishu App Secret already configured. Keep it?",
      appSecretPrompt: "Enter Feishu App Secret",
      botConfigured: "Bot configured.",
      configuring: "Configuring...",
      credentialsEnvTip: "Tip: you can also set FEISHU_APP_ID / FEISHU_APP_SECRET env vars.",
      credentialsStepCreateApp: "2) Create a self-built app",
      credentialsStepGetCredentials: "3) Get App ID and App Secret from Credentials page",
      credentialsStepOpenPlatform: "1) Go to Feishu Open Platform (open.feishu.cn)",
      credentialsStepPermissions:
        "4) Enable required permissions: im:message, im:chat, contact:user.base:readonly",
      credentialsStepPublish: "5) Publish the app or add it to a test group",
      credentialsTitle: "Feishu credentials",
      domainFeishu: "Feishu (feishu.cn) - China",
      domainLark: "Lark (larksuite.com) - International",
      domainPrompt: "Which Feishu domain?",
      examples: "Examples:",
      existingBotPrompt: "We found an existing bot (App ID: {appId}). Use it for this setup?",
      fetchingConfig: "Fetching configuration results...",
      groupPolicyAllowlist: "Allowlist - only respond in specific groups",
      groupPolicyDisabled: "Disabled - don't respond in groups",
      groupPolicyOpen: "Open - respond in all groups (requires mention)",
      groupPolicyPrompt: "Group chat policy",
      scanCompleted: "Scan completed.",
      scanDenied: "User denied authorization. Falling back to manual input.",
      scanError: "Registration error: {error}. Falling back to manual input.",
      scanExpired: "Session expired. Falling back to manual input.",
      scanQr:
        "Scan the QR with Lark/Feishu on your phone. If the mobile app does not react, rerun setup and choose manual input.",
      scanTimedOut: "Scan timed out. Falling back to manual input.",
      scanTitle: "Feishu scan-to-create",
      scanUnavailable:
        "Scan-to-create is not available in this environment. Falling back to manual input.",
      setupMethodManual: "Enter App ID and App Secret manually",
      setupMethodPrompt: "How do you want to connect Feishu?",
      setupMethodScan: "Scan a QR code to create a bot automatically",
      setupTitle: "Feishu setup",
    },
    telegram: {
      allowFromInvalid:
        "Telegram allowFrom requires numeric sender ids. DM your bot first, then copy from.id from logs or getUpdates.",
      allowFromPrompt: "Telegram allowFrom (numeric sender id)",
      allowlistTitle: "Telegram allowlist",
      botToken: "Telegram bot token",
      tokenEnvPrompt: "TELEGRAM_BOT_TOKEN detected. Use env var?",
      tokenEnvTip: "Tip: you can also set TELEGRAM_BOT_TOKEN in your env.",
      tokenHelpCopyToken: "3) Copy the token (looks like 123456:ABC...)",
      tokenHelpNewBot: "2) Run /newbot (or /mybots)",
      tokenHelpOpenBotFather: "1) Open Telegram and chat with @BotFather",
      tokenInputPrompt: "Enter Telegram bot token",
      tokenKeepPrompt: "Telegram token already configured. Keep it?",
      userIdHelpGetUpdates:
        "2) Or call https://api.telegram.org/bot<bot_token>/getUpdates and read message.from.id",
      userIdHelpLogs: "1) DM your bot, then read from.id in `{command}` (safest)",
      userIdHelpThirdParty: "3) Third-party: DM @userinfobot or @getidsbot",
      userIdTitle: "Telegram user id",
      website: "Website: {url}",
    },
    discord: {
      allowFromInvalidWithoutToken:
        "Bot token missing; use numeric user ids (or mention form) only.",
      allowFromPrompt: "Discord allowFrom (usernames or ids)",
      allowlistIntro: "Allowlist Discord DMs by username (we resolve to user ids).",
      allowlistTitle: "Discord allowlist",
      botToken: "Discord bot token",
      channelsLabel: "Discord channels",
      examples: "Examples:",
      multipleEntries: "Multiple entries: comma-separated.",
      tokenEnvPrompt: "DISCORD_BOT_TOKEN detected. Use env var?",
      tokenHelpCopyToken: "2) Bot -> Add Bot -> Reset Token -> copy token",
      tokenHelpCreateApplication: "1) Discord Developer Portal -> Applications -> New Application",
      tokenHelpInviteBot: "3) OAuth2 -> URL Generator -> scope 'bot' -> invite to your server",
      tokenHelpMessageContentIntent:
        "Tip: enable Message Content Intent if you need message text. (Bot -> Privileged Gateway Intents -> Message Content Intent)",
      tokenInputPrompt: "Enter Discord bot token",
      tokenKeepPrompt: "Discord token already configured. Keep it?",
    },
    googlechat: {
      allowFromPrompt: "Google Chat allowFrom (users/<id> or raw email; avoid users/<email>)",
      appUrl: "App URL",
      appUrlRecommended: "App URL (recommended)",
      authMethod: "Google Chat auth method",
      projectNumber: "Project number",
      serviceAccountFile: "Service account JSON file",
      serviceAccountInline: "Paste service account JSON",
      serviceAccountJson: "Service account JSON (single line)",
      serviceAccountPath: "Service account JSON path",
      setupAudience: "Webhook verification requires audience type + audience value.",
      setupScopes:
        "Set the Chat API scopes in your service account and configure the Chat app URL.",
      setupServiceAccount: "Google Chat apps use service-account auth and an HTTPS webhook.",
      setupTitle: "Google Chat setup",
      useEnvPrompt: "Use GOOGLE_CHAT_SERVICE_ACCOUNT env vars?",
      webhookAudienceType: "Webhook audience type",
    },
    line: {
      allowFromInvalid:
        "LINE allowFrom requires raw user ids like U1234567890abcdef1234567890abcdef.",
      allowFromPrompt: "LINE allowFrom (user id)",
      allowlistIntro: "Allowlist LINE DMs by user id.",
      allowlistTitle: "LINE allowlist",
      channelAccessToken: "channel access token",
      channelSecret: "channel secret",
      completionDefaultWebhook: "Default webhook URL: https://<gateway-host>/line/webhook",
      completionEnableWebhook: "Enable Use webhook in the LINE console after saving credentials.",
      completionWebhookPath: "If you set channels.line.webhookPath, update the URL to match.",
      examples: "Examples:",
      helpCopyCredentials: "2) Copy the channel access token and channel secret",
      helpEnableWebhook: "3) Enable Use webhook in the Messaging API settings",
      helpOpenConsole:
        "1) Open the LINE Developers Console and create or pick a Messaging API channel",
      helpWebhookUrl: "4) Point the webhook at https://<gateway-host>/line/webhook",
      idsCaseSensitive: "LINE ids are case-sensitive.",
      messagingApiTitle: "LINE Messaging API",
      multipleEntries: "Multiple entries: comma-separated.",
      secretEnvPrompt: "LINE_CHANNEL_SECRET detected. Use env var?",
      secretInputPrompt: "Enter LINE channel secret",
      secretKeepPrompt: "LINE channel secret already configured. Keep it?",
      tokenEnvPrompt: "LINE_CHANNEL_ACCESS_TOKEN detected. Use env var?",
      tokenInputPrompt: "Enter LINE channel access token",
      tokenKeepPrompt: "LINE channel access token already configured. Keep it?",
      webhookTitle: "LINE webhook",
    },
    slack: {
      allowFromInvalidWithoutToken: "Slack token missing; use user ids (or mention form) only.",
      allowFromPrompt: "Slack allowFrom (usernames or ids)",
      allowlistIntro: "Allowlist Slack DMs by username (we resolve to user ids).",
      allowlistTitle: "Slack allowlist",
      appToken: "Slack app token",
      appTokenInput: "Enter Slack app token (xapp-...)",
      appTokenKeep: "Slack app token already configured. Keep it?",
      botToken: "Slack bot token",
      botTokenInput: "Enter Slack bot token (xoxb-...)",
      botTokenKeep: "Slack bot token already configured. Keep it?",
      channelsLabel: "Slack channels",
      envPrompt: "SLACK_BOT_TOKEN + SLACK_APP_TOKEN detected. Use env vars?",
      examples: "Examples:",
      interactiveRepliesPrompt:
        "Enable Slack interactive replies (buttons/selects) for agent responses?",
      multipleEntries: "Multiple entries: comma-separated.",
      socketModeTokensTitle: "Slack socket mode tokens",
    },
    mattermost: {
      baseUrlPrompt: "Enter Mattermost base URL",
      botToken: "bot token",
      botTokenInput: "Enter Mattermost bot token",
      botTokenKeep: "Mattermost bot token already configured. Keep it?",
      botTokenTitle: "Mattermost bot token",
      envPrompt: "MATTERMOST_BOT_TOKEN + MATTERMOST_URL detected. Use env vars?",
      helpBaseUrl: "3) Use your server base URL (e.g., https://chat.example.com)",
      helpBotMember: "Tip: the bot must be a member of any channel you want it to monitor.",
      helpCreateBot: "2) Create a bot + copy its token",
      helpOpenConsole: "1) Mattermost System Console -> Integrations -> Bot Accounts",
    },
    nextcloudTalk: {
      allowFromPrompt: "Nextcloud Talk allowFrom (user id)",
      apiPassword: "API password",
      apiPasswordInput: "Enter Nextcloud Talk API password",
      apiPasswordKeep: "Nextcloud Talk API password already configured. Keep it?",
      apiUserPrompt: "Nextcloud Talk API user",
      botSecret: "bot secret",
      botSecretEnvPrompt: "NEXTCLOUD_TALK_BOT_SECRET detected. Use env var?",
      botSecretInput: "Enter Nextcloud Talk bot secret",
      botSecretKeep: "Nextcloud Talk bot secret already configured. Keep it?",
      configureApiCredentials:
        "Configure optional Nextcloud Talk API credentials for room lookups?",
      helpCopySecret: "3) Copy the shared secret you used in the command",
      helpEnableRoom: "4) Enable the bot in your Nextcloud Talk room settings",
      helpEnvTip: "Tip: you can also set NEXTCLOUD_TALK_BOT_SECRET in your env.",
      helpInstallCommand:
        '2) Run: ./occ talk:bot:install "OpenClaw" "<shared-secret>" "<webhook-url>" --feature webhook --feature response --feature reaction',
      helpSsh: "1) SSH into your Nextcloud server",
      instanceUrlPrompt: "Enter Nextcloud instance URL (e.g., https://cloud.example.com)",
      setupTitle: "Nextcloud Talk bot setup",
      userIdHelpAdmin: "1) Check the Nextcloud admin panel for user IDs",
      userIdHelpLogs: "2) Or look at the webhook payload logs when someone messages",
      userIdHelpLowercase: "3) User IDs are typically lowercase usernames in Nextcloud",
      userIdTitle: "Nextcloud Talk user id",
    },
    msteams: {
      allowFromPrompt: "MS Teams allowFrom (usernames or ids)",
      allowlistIntro: "Allowlist MS Teams DMs by display name, UPN/email, or user id.",
      allowlistResolve: "We resolve names to user IDs via Microsoft Graph when credentials allow.",
      allowlistTitle: "MS Teams allowlist",
      appIdPrompt: "Enter MS Teams App ID",
      appPasswordPrompt: "Enter MS Teams App Password",
      channelLookupFailed: "Channel lookup failed; keeping entries as typed. {error}",
      channelsLabel: "MS Teams channels",
      couldNotResolve: "Could not resolve: {entries}",
      credentialsKeep: "MS Teams credentials already configured. Keep them?",
      credentialsTitle: "MS Teams credentials",
      delegatedAuthConfigured: "Delegated auth configured",
      delegatedAuthPrompt: "Enable delegated auth? (required for reactions and write operations)",
      delegatedAuthRetry: "You can retry later via the setup wizard.",
      delegatedAuthTitle: "MS Teams delegated auth",
      delegatedOAuthProgress: "MSTeams Delegated OAuth",
      enterAtLeastOneUser: "Enter at least one user.",
      envPrompt:
        "MSTEAMS_APP_ID + MSTEAMS_APP_PASSWORD + MSTEAMS_TENANT_ID detected. Use env vars?",
      examples: "Examples:",
      graphLookupUnavailable: "Graph lookup unavailable. Use user IDs only.",
      helpAzureBot: "1) Azure Bot registration -> get App ID + Tenant ID",
      helpClientSecret: "2) Add a client secret (App Password)",
      helpEnvTip:
        "Tip: you can also set MSTEAMS_APP_ID / MSTEAMS_APP_PASSWORD / MSTEAMS_TENANT_ID.",
      helpWebhook: "3) Set webhook URL + messaging endpoint",
      resolvedChannels: "Resolved channels: {entries}",
      resolvedTeams: "Resolved teams: {entries}",
      tenantIdPrompt: "Enter MS Teams Tenant ID",
      unresolvedKept: "Unresolved (kept as typed): {entries}",
    },
    whatsapp: {
      allowedSenderNumbers: "Allowed sender numbers (comma-separated, E.164)",
      allowFromPrompt: "WhatsApp allowFrom (optional pre-allowlist)",
      allowlistModeEnabled: "Allowlist mode enabled.",
      allowlistTitle: "WhatsApp allowlist",
      credentialsStored: "Credentials are stored under {authDir}/ for future runs.",
      dmAccessTitle: "WhatsApp DM access",
      dmPolicyAllowlistOnly: "Allowlist only (block unknown senders)",
      dmPolicyDisabled: "Disabled (ignore WhatsApp DMs)",
      dmPolicyPrompt: "WhatsApp DM policy",
      dmPolicySetAllowlist: "- dmPolicy set to allowlist (pairing skipped)",
      helpTitle: "WhatsApp help",
      keepCurrentAllowFrom: "Keep current allowFrom",
      linkLater: "Run `{command}` later to link WhatsApp.",
      linkNowPrompt: "Link WhatsApp now (QR)?",
      linkingTitle: "WhatsApp linking",
      numberTitle: "WhatsApp number",
      ownerNumberNote: "We need the sender/owner number so OpenClaw can allowlist you.",
      personalNumberPrompt: "Your personal WhatsApp number (the phone you will message from)",
      personalPhoneLabel: "This is my personal phone number",
      personalPhoneModeEnabled: "Personal phone mode enabled.",
      personalPhoneTitle: "WhatsApp personal phone",
      phoneSetupPrompt: "WhatsApp phone setup",
      relinkPrompt: "WhatsApp already linked. Re-link now?",
      scanQr: "Scan the QR with WhatsApp on your phone.",
      separatePhoneLabel: "Separate phone just for OpenClaw",
      setAllowFromNumbers: "Set allowFrom to specific numbers",
      unsetAllowFromDefault: "Unset allowFrom (default)",
      unsetAllowFromPairing: "Unset allowFrom (use pairing approvals only)",
    },
    nostr: {
      allowFromPrompt: "Nostr allowFrom",
      allowlistIntro: "Allowlist Nostr DMs by npub or hex pubkey.",
      allowlistTitle: "Nostr allowlist",
      examples: "Examples:",
      helpEnvVars: "Env vars supported: NOSTR_PRIVATE_KEY (default account only).",
      helpPrivateKeyFormat: "Use a Nostr private key in nsec or 64-character hex format.",
      helpRelaysOptional: "Relay URLs are optional. Leave blank to keep the default relay set.",
      multipleEntries: "Multiple entries: comma-separated.",
      privateKeyEnvPrompt: "NOSTR_PRIVATE_KEY detected. Use env var?",
      privateKeyInput: "Nostr private key (nsec... or hex)",
      privateKeyKeep: "Nostr private key already configured. Keep it?",
      privateKeyTitle: "Nostr private key",
      relaysTitle: "Nostr relays",
      relayUrlsKeep: "Relay URLs set ({value}). Keep them?",
      relayUrlsPrompt: "Relay URLs (comma-separated, optional)",
      relaysWsOnly: "Use ws:// or wss:// relay URLs.",
      setupTitle: "Nostr setup",
    },
    irc: {
      allowFromInvalid: "Use an IRC nick or nick!user@host entry.",
      allowFromPrompt: "IRC allowFrom (nick or nick!user@host)",
      allowlistIntro: "Allowlist IRC DMs by sender.",
      allowlistTitle: "IRC allowlist",
      autoJoinPrompt: "Auto-join IRC channels (optional, comma-separated)",
      envPrompt: "IRC_HOST and IRC_NICK detected. Use env vars?",
      examples: "Examples:",
      helpEnvVars:
        "Env vars supported: IRC_HOST, IRC_PORT, IRC_TLS, IRC_NICK, IRC_USERNAME, IRC_REALNAME, IRC_PASSWORD, IRC_CHANNELS, IRC_NICKSERV_PASSWORD, IRC_NICKSERV_REGISTER_EMAIL.",
      helpGroupControl:
        'Set channels.irc.groupPolicy="allowlist" and channels.irc.groups for tighter channel control.',
      helpMentionGate:
        'Note: IRC channels are mention-gated by default. To allow unmentioned replies, set channels.irc.groups["#channel"].requireMention=false (or "*" for all).',
      helpNeedsHostNick: "IRC needs server host + bot nick.",
      helpNickServOptional:
        "Optional: NickServ identify/register can be configured after the basic account fields.",
      helpRecommendedTls: "Recommended: TLS on port 6697.",
      multipleEntries: "Multiple entries: comma-separated.",
      nextRestartGateway: "Next: restart gateway and verify status.",
      nextStatusCommand: "Command: openclaw channels status --probe",
      nextStepsTitle: "IRC next steps",
      nickPrompt: "IRC nick",
      nickServConfigurePrompt: "Configure NickServ identify/register?",
      nickServPasswordEnvPrompt: "IRC_NICKSERV_PASSWORD detected. Use env var?",
      nickServPasswordPrompt: "NickServ password (blank to disable NickServ auth)",
      nickServRegisterEmailPrompt: "NickServ register email",
      nickServRegisterPrompt: "Send NickServ REGISTER on connect?",
      nickServServicePrompt: "NickServ service nick",
      nickServUpdatePrompt: "Update NickServ settings?",
      realNamePrompt: "IRC real name",
      requireMentionPrompt: "Require @mention to reply in IRC channels?",
      serverHostPrompt: "IRC server host",
      serverPortPrompt: "IRC server port",
      setupTitle: "IRC setup",
      tlsPrompt: "Use TLS for IRC?",
      usernamePrompt: "IRC username",
    },
    tlon: {
      addGroupsPrompt: "Add group channels manually? (optional)",
      autoDiscoveryPrompt: "Enable auto-discovery of group channels?",
      dmAllowlistPrompt: "DM allowlist (comma-separated ship names)",
      groupChannelsPrompt: "Group channels (comma-separated)",
      helpExampleShip: "Example ship: ~sampel-palnet",
      helpExampleUrl: "Example URL: https://your-ship-host",
      helpNeedsUrlCode: "You need your Urbit ship URL and login code.",
      helpPrivateNetwork:
        "If your ship URL is on a private network (LAN/localhost), you must explicitly allow it during setup.",
      loginCodePrompt: "Login code",
      privateNetworkPrompt:
        "Ship URL looks like a private/internal host. Allow private network access? (SSRF risk)",
      restrictDmsPrompt: "Restrict DMs with an allowlist?",
      setupTitle: "Tlon setup",
      shipPrompt: "Ship name",
      shipUrlPrompt: "Ship URL",
    },
    synologyChat: {
      accessControlTitle: "Synology Chat access control",
      allowedUserIdsInvalid: "Synology Chat user ids must be numeric.",
      allowedUserIdsPrompt: "Allowed Synology Chat user ids",
      allowlistIntro: "Allowlist Synology Chat DMs by numeric user id.",
      allowlistTitle: "Synology Chat allowlist",
      defaultPath: "Default path: {path}",
      examples: "Examples:",
      helpAllowedUsers: "4) Keep allowed user IDs handy for DM allowlisting",
      helpIncomingWebhook: "1) Create an incoming webhook in Synology Chat and copy its URL",
      helpOutgoingWebhook: "2) Create an outgoing webhook and copy its secret token",
      helpPointWebhook: "3) Point the outgoing webhook to https://<gateway-host>{path}",
      incomingWebhookHelpReplies: "This is the URL OpenClaw uses to send replies back to Chat.",
      incomingWebhookHelpUseUrl: "Use the incoming webhook URL from Synology Chat integrations.",
      incomingWebhookKeep: "Incoming webhook URL set ({value}). Keep it?",
      incomingWebhookTitle: "Synology Chat incoming webhook",
      incomingWebhookUrlPrompt: "Incoming webhook URL",
      multipleEntries: "Multiple entries: comma-separated.",
      outgoingWebhookPathHelp:
        "Change this only if you need multiple Synology Chat webhook routes.",
      outgoingWebhookPathKeep: "Outgoing webhook path set ({value}). Keep it?",
      outgoingWebhookPathPrompt: "Outgoing webhook path (optional)",
      outgoingWebhookPathTitle: "Synology Chat outgoing webhook path",
      setupTitle: "Synology Chat webhook setup",
      tokenEnvPrompt: "SYNOLOGY_CHAT_TOKEN detected. Use env var?",
      tokenInput: "Enter Synology Chat outgoing webhook token",
      tokenKeep: "Synology Chat webhook token already configured. Keep it?",
      webhookTokenTitle: "Synology Chat webhook token",
    },
    signal: {
      accountKeep: "Signal account set ({value}). Keep it?",
      allowFromPrompt: "Signal allowFrom (E.164 or uuid)",
      allowlistIntro: "Allowlist Signal DMs by sender id.",
      allowlistTitle: "Signal allowlist",
      botNumberPrompt: "Signal bot number (E.164)",
      examples: "Examples:",
      installPrompt: "signal-cli not found. Install now?",
      multipleEntries: "Multiple entries: comma-separated.",
      nextLinkDevice: 'Link device with: signal-cli link -n "OpenClaw"',
      nextScanQr: "Scan QR in Signal -> Linked Devices",
      nextStepsTitle: "Signal next steps",
      reinstallPrompt: "signal-cli detected. Reinstall/update now?",
    },
    zalo: {
      allowFromNumeric: "Use a numeric Zalo user id",
      allowFromPrompt: "Zalo allowFrom (user id)",
      botToken: "bot token",
      botTokenTitle: "Zalo bot token",
      helpCreateBot: "2) Create a bot and get the token",
      helpEnvTip: "Tip: you can also set ZALO_BOT_TOKEN in your env.",
      helpOpenPlatform: "1) Open Zalo Bot Platform: https://bot.zaloplatforms.com",
      helpTokenFormat: "3) Token looks like 12345689:abc-xyz",
      tokenEnvPrompt: "ZALO_BOT_TOKEN detected. Use env var?",
      tokenInput: "Enter Zalo bot token",
      tokenKeep: "Zalo token already configured. Keep it?",
      webhookModePrompt: "Use webhook mode for Zalo?",
      webhookPathPrompt: "Webhook path (optional)",
      webhookSecret: "webhook secret",
      webhookSecretInput: "Webhook secret (8-256 chars)",
      webhookSecretKeep: "Zalo webhook secret already configured. Keep it?",
      webhookSecretLength: "Webhook secret must be between 8 and 256 characters.",
      webhookTitle: "Zalo webhook",
      webhookUrlPrompt: "Webhook URL (https://...) ",
    },
    zalouser: {
      allowFromPlaceholder: "Alice, 123456789, or leave empty to configure later",
      allowFromPrompt: "Zalouser allowFrom (name or user id)",
      allowlistTitle: "Zalo Personal allowlist",
      couldNotResolve: "Could not resolve: {entries}. Use numeric user ids or exact friend names.",
      directChatsBlocked: "Direct chats will stay blocked until you add people later.",
      dmAccessTitle: "Zalo Personal DM access",
      dmHelpAllowlist: "- allowlist: only listed people can DM",
      dmHelpAllowlistEmpty:
        "If you choose allowlist now, you can leave it empty and add people later.",
      dmHelpDisabled: "- disabled: ignore DMs",
      dmHelpOpen: "- open: anyone can DM",
      dmHelpPairing: "- pairing (default): unknown people get a pairing code",
      dmHelpSeparate: "Direct chats are configured separately from group chats.",
      dmPolicyPrompt: "Zalo Personal DM policy",
      groupChatsBlocked: "Group chats will stay blocked until you add groups later.",
      groupLookupFailed: "Group lookup failed; keeping entries as typed. {error}",
      groupMentionRequirement:
        "Mention requirement stays on by default for groups you allow later.",
      groupsLookupTip: "Tip: use `{command}` after onboarding to find group IDs.",
      groupsPlaceholder: "Family, Work, 123456789, or leave empty for now",
      groupsTitle: "Zalo groups",
      helpQrLogin: "Zalo Personal Account login via QR code.",
      helpZcaJs: "This plugin uses zca-js directly (no external CLI dependency).",
      keepSessionPrompt: "Zalo Personal already logged in. Keep session?",
      loginPendingTitle: "Login pending",
      loginQrPrompt: "Login via QR code now?",
      noDmAllowlist: "No DM allowlist entries added yet.",
      noGroupAllowlist: "No group allowlist entries added yet.",
      peersLookupTip: "Tip: use `{command}` to look up people after onboarding.",
      qrImageSaved: "QR image saved to: {path}",
      qrImageWriteFailed: "Could not write QR image file; use gateway web login UI instead.",
      qrLoginTitle: "QR Login",
      qrScannedPrompt: "Did you scan and approve the QR on your phone?",
      scanApproveContinue: "Scan + approve on phone, then continue.",
      setupTitle: "Zalo Personal Setup",
    },
    twitch: {
      accessTokenKeep: "Access token already configured. Keep it?",
      allowFromPrompt: "Twitch allowFrom (user IDs, one per line, recommended for security)",
      botUsernamePrompt: "Twitch bot username",
      channelJoinPrompt: "Channel to join",
      clientIdPrompt: "Twitch Client ID",
      clientSecretPrompt: "Twitch Client Secret (for token refresh)",
      envPrompt: "Twitch env var OPENCLAW_TWITCH_ACCESS_TOKEN detected. Use env token?",
      helpCopyToken: "3. Copy the token (starts with 'oauth:') and Client ID",
      helpCreateApp: "1. Create a Twitch application at https://dev.twitch.tv/console",
      helpEnvVars: "Env vars supported: OPENCLAW_TWITCH_ACCESS_TOKEN",
      helpGenerateToken: "2. Generate a token with scopes: chat:read and chat:write",
      helpRequiresBot: "Twitch requires a bot account with OAuth token.",
      helpTokenTools: "   Use https://twitchtokengenerator.com/ or https://twitchapps.com/tmi/",
      oauthTokenPrompt: "Twitch OAuth token (oauth:...)",
      refreshTokenInputPrompt: "Twitch Refresh Token",
      refreshTokenPrompt:
        "Enable automatic token refresh (requires client secret and refresh token)?",
      setupTitle: "Twitch setup",
    },
    imessage: {
      imsgFound: "imsg found",
      imsgMissing: "imsg missing",
    },
    channelsPrimer: {
      approveWith: "Approve with: {command}",
      docs: "Docs: {link}",
      inboundSafety:
        "Inbound DM safety defaults to pairing: unknown senders get a pairing code first.",
      multiUserDm:
        'For multi-user DMs, isolate sessions with: {command} (or "per-account-channel-peer" for multi-account channels).',
      openDm: 'Open/public DMs require dmPolicy="open" plus allowFrom=["*"].',
      title: "How channels work",
      blurbs: {
        clickclack: "self-hosted chat via first-class ClickClack bot tokens.",
        discord: "very well supported right now.",
        feishu: "飞书/Lark enterprise messaging.",
        googlechat: "Google Workspace Chat app with HTTP webhook.",
        imessage:
          "Local iMessage/SMS through the imsg bridge, including private API message actions when enabled.",
        irc: "classic IRC networks with DM/channel routing and pairing controls.",
        line: "LINE Messaging API webhook bot.",
        mattermost: "self-hosted Slack-style chat; install the plugin to enable.",
        matrix: "open protocol; install the plugin to enable.",
        msteams: "Teams SDK; enterprise support.",
        nextcloudTalk: "Self-hosted chat via Nextcloud Talk webhook bots.",
        nostr: "Decentralized protocol; encrypted DMs via NIP-04.",
        qqbot: "Connect to QQ via official QQ Bot API",
        signal: 'signal-cli linked device; more setup (David Reagans: "Hop on Discord.").',
        slack: "supported (Socket Mode).",
        synologyChat: "Connect your Synology NAS Chat to OpenClaw with full agent capabilities.",
        telegram: "simplest way to get started — register a bot with @BotFather and get going.",
        tlon: "decentralized messaging on Urbit; install the plugin to enable.",
        twitch: "Twitch chat integration",
        wecom: "Enterprise messaging and documents, scheduling, task tools.",
        whatsapp: "works with your own number; recommend a separate phone + eSIM.",
        yuanbao: "Tencent Yuanbao AI assistant conversation channel.",
        zalo: "Vietnam-focused messaging platform with Bot API.",
        zalouser: "Zalo personal account via QR code login.",
      },
    },
    search: {
      chooseProvider: "Choose a provider. Some providers need an API key, and some work key-free.",
      configured: "configured",
      configureLaterHint: "Configure later with openclaw configure --section web",
      docsLine: "Docs: {url}",
      intro: "Web search lets your agent look things up online.",
      keyFree: "key-free",
      noProvidersAction: "Enable plugins or remove deny rules, then run setup again.",
      noProvidersByPolicy:
        "No web search providers are currently available under this plugin policy.",
      providerPrompt: "Search provider",
      title: "Web search",
    },
    finalize: {
      addNodes: "Add nodes for extra features:",
      alreadyInstalled: "Gateway service already installed",
      backupWorkspace: "Back up your agent workspace.",
      browserHatch: "Hatch in Browser",
      codexNativeSearchOnly: "Used only for Codex-capable models.",
      codexNativeSearchTitle: "Codex native search",
      controlUiTitle: "Control UI",
      controlUiDocs: "Docs: https://docs.openclaw.ai/web/control-ui",
      dashboardCopyPaste: "Copy/paste this URL in a browser on this machine to control OpenClaw.",
      dashboardLinkWithToken: "Dashboard link (with token): {url}",
      dashboardOpened: "Opened in your browser. Keep that tab to control OpenClaw.",
      dashboardOpenAnytime: "Open the dashboard anytime: {command}",
      dashboardReady: "Dashboard ready",
      dashboardTokenMemory:
        "Web UI keeps dashboard URL tokens in memory for the current tab and strips them from the URL after load.",
      dashboardTokenPrompt:
        "If prompted: paste the token into Control UI settings (or use the tokenized dashboard URL).",
      dashboardWhenReady: "When you're ready: {command}",
      daemonRuntime: "Gateway service runtime",
      daemonRuntimeNode: "Node (recommended)",
      daemonRuntimeNodeHint:
        "Required for WhatsApp + Telegram. Bun can corrupt memory on reconnect.",
      editBootstrap: "Edit BOOTSTRAP.md later to change how the agent introduces itself.",
      bootstrapHatchMessage: "Wake up, my friend!",
      firstTerminalChat: 'The first Terminal chat run will send: "Wake up, my friend!"',
      gatewayInstallBlocked: "Gateway install blocked:",
      gatewayInstallFixAuth: "Fix gateway auth config/token input and rerun setup.",
      gatewayNotDetected: "Gateway not detected yet.",
      gatewayNotDetectedStatus: "Gateway: not detected{detail}",
      gatewayReachable: "Gateway: reachable",
      gatewayService: "Gateway service",
      gatewayServiceInstalled: "Gateway service installed.",
      gatewayServiceInstalling: "Installing Gateway service...",
      gatewayServiceInstallFailed: "Gateway service install failed.",
      gatewayServiceInstallFailedWithError: "Gateway service install failed: {error}",
      gatewayServicePreparing: "Preparing Gateway service...",
      gatewayServiceRestarted: "Gateway service restarted.",
      gatewayServiceRestarting: "Restarting Gateway service...",
      gatewayServiceRestartScheduled: "Gateway service restart scheduled.",
      gatewayServiceUninstalled: "Gateway service uninstalled.",
      gatewayServiceUninstalling: "Uninstalling Gateway service...",
      gatewayTokenGenerate: "Generate token: {command}",
      gatewayTokenShared: "Gateway token: shared auth for the Gateway + Control UI.",
      gatewayTokenStored:
        "Stored in: $OPENCLAW_CONFIG_PATH (default: ~/.openclaw/openclaw.json) under gateway.auth.token, or in OPENCLAW_GATEWAY_TOKEN.",
      gatewayTokenView: "View token: {command}",
      gatewayWsUrl: "Gateway WS: {url}",
      hatchLater: "Hatch later",
      hatchPrompt: "How do you want to hatch your agent?",
      hatchYourAgent: "Hatch your agent",
      healthCheckHelp: "Health check help",
      installGateway: "Install Gateway service (recommended)",
      laterTitle: "Later",
      managedWebSearchSkipped: "Managed web search provider was skipped.",
      noBackgroundGatewayExpected:
        "Setup was run without Gateway service install, so no background gateway is expected.",
      nodeAndroid: "Android app (camera/canvas)",
      nodeIos: "iOS app (camera/canvas)",
      nodeMac: "macOS app (system + notifications)",
      optionalApps: "Optional apps",
      outroDashboardLink: "Onboarding complete. Use the dashboard link above to control OpenClaw.",
      outroDashboardOpened:
        "Onboarding complete. Dashboard opened; keep that tab to control OpenClaw.",
      outroSeeded:
        "Onboarding complete. Web UI seeded in the background; open it anytime with the dashboard link above.",
      quickstartNodeRuntime: "QuickStart uses Node for the Gateway service (stable + supported).",
      reinstall: "Reinstall",
      rerunInstallDaemon: "Or rerun with: {command}",
      restart: "Restart",
      securityReminder:
        "Running agents on your computer is risky — harden your setup: https://docs.openclaw.ai/security",
      secretRefAuthFailed: "Could not resolve {field} SecretRef for setup auth.",
      skipHealthNextTime: "Or skip this probe next time: {command}",
      skipControlUi: "Skipping Control UI/TUI prompts.",
      startGatewayNow: "Start now: {command}",
      systemdInstallSkipped:
        "Systemd user services are unavailable; skipping service install. Use your container supervisor or `docker compose up -d`.",
      systemdLingerReason:
        "Linux installs use a systemd user service by default. Without lingering, systemd stops the user session on logout/idle and kills the Gateway.",
      systemdUnavailable:
        "Systemd user services are unavailable. Skipping lingering checks and service install.",
      terminalHatch: "Hatch in Terminal (recommended)",
      webDocs: "Docs: https://docs.openclaw.ai/tools/web",
      webSearchAutoDetected: "Web search is available via {provider} (auto-detected).",
      webSearchDisabled: "Web search ({provider}) is configured but disabled.",
      webSearchEnabled:
        "Web search is enabled, so your agent can look things up online when needed.",
      webSearchGetKey: "Get your key at: {url}",
      webSearchAuthProfile: "Credential: existing {provider} auth profile.",
      webSearchKeyEnv: "API key: provided via {env} env var.",
      webSearchKeyRef: "API key: configured via secret reference.",
      webSearchKeyStored: "API key: stored in config.",
      webSearchNeedsKey: "web_search will not work until a key is added.",
      webSearchNoKey: "Provider {provider} is selected but no API key was found.",
      webSearchOAuthProfile: "Credential: existing {provider} OAuth sign-in.",
      webSearchProvider: "Provider: {provider}",
      webSearchProviderUnavailable:
        "Web search provider {provider} is selected but unavailable under the current plugin policy.",
      webSearchReenable: "Re-enable: {command}",
      webSearchSkipped: "Web search was skipped. You can enable it later:",
      webSearchTitle: "Web search",
      webSearchUnavailableAction:
        "web_search will not work until the provider is re-enabled or a different provider is selected.",
      webUiUrl: "Web UI: {url}",
      webUiWithTokenUrl: "Web UI (with token): {url}",
      whatNow: 'What now: https://openclaw.ai/showcase ("What People Are Building").',
      whatNowTitle: "What now",
      workspaceBackupTitle: "Workspace backup",
      workspaceDocs: "Docs: https://docs.openclaw.ai/concepts/agent-workspace",
      workspaceReady: "Your workspace is ready.",
    },
    gatewayNotes: {
      bindTitle: "Gateway bind",
      tailscaleBindLoopback:
        "Tailscale exposure requires bind=loopback. I will switch the bind address to loopback.",
      tailscaleFunnelPassword:
        "Tailscale Funnel requires password auth. I will switch Gateway auth to password.",
    },
  },
} satisfies WizardTranslationMap;
