| 1 | // Package i18n holds the CLI's translatable strings and a small detection |
| 2 | // helper. Architecture: a single Messages struct of exported string fields |
| 3 | // (plain text or fmt format strings, suffix *Fmt flags the latter). Each |
| 4 | // language declares one Messages value in its own file. Call sites read |
| 5 | // i18n.M.SomeField; for parameterised messages they pass it to fmt.Sprintf. |
| 6 | // |
| 7 | // Adding a field requires updating every messages_*.go file — drift is caught |
| 8 | // at test time by TestCatalogsComplete via reflection, so a missing translation |
| 9 | // fails CI instead of surfacing as a blank line at runtime. |
| 10 | // |
| 11 | // Scope (v1): CLI surface only — welcome, init wizard, chat REPL banner, usage, |
| 12 | // user-facing CLI errors. System prompts, internal error wrappers, and agent |
| 13 | // runtime telemetry stay English so model behaviour and developer logs are |
| 14 | // language-stable. |
| 15 | package i18n |
| 16 | |
| 17 | import ( |
| 18 | "os" |
| 19 | "strings" |
| 20 | ) |
| 21 | |
| 22 | // Messages is the catalogue of translatable CLI strings. Plain fields are |
| 23 | // printed verbatim; *Fmt fields are fmt format strings the caller passes to |
| 24 | // fmt.Sprintf. Catalogue values do not include trailing newlines — call sites |
| 25 | // add framing whitespace, so the same field works wherever it appears. |
| 26 | type Messages struct { |
| 27 | // welcome / status screen |
| 28 | WelcomeTitleFmt string // first-run box title — %s = product name (styled) |
| 29 | NoConfigYet string // first-run cue under the welcome box |
| 30 | |
| 31 | // `reasonix init` — points to the in-session /init skill + setup |
| 32 | InitHint string |
| 33 | |
| 34 | // chat REPL |
| 35 | ChatTip string // tip line under the chat banner |
| 36 | TurnCancelled string // shown when Ctrl-C aborts the in-flight turn but the chat keeps running |
| 37 | InterruptedRecovery string // replay notice for a durable interrupted turn |
| 38 | FinalReadinessRecovery string // replay hint for a durable final-readiness pause |
| 39 | ReadinessContinuing string // host is automatically finishing known readiness gaps |
| 40 | RecoveryPaused string // controlled Auto retry pause; user can continue in the next message |
| 41 | CompletionUncertain string // completion validator could not confirm the result; work is kept |
| 42 | ReasoningReplayRepair string // provider rejected replayed thinking blocks; history repaired and retried once |
| 43 | ImageRequestRecovery string // current image cannot be included; request a fresh attachment |
| 44 | ExtensionRequestRecovery string // extension produced an invalid model request |
| 45 | ExtensionBlockRecovery string // actionable hint following an explicit extension block |
| 46 | ContextLimitRecovery string // automatic context recovery exhausted |
| 47 | SessionSaveRecovery string // durability failure; preserve the live conversation |
| 48 | // Host guard/recovery notices (event.Notice texts the fronts render verbatim). |
| 49 | EmptyFinal string // empty_final: no visible answer; retrying |
| 50 | ExecutorHandoff string // executor_handoff: answered without using tools |
| 51 | ToolBudget string // tool_budget: tool-call round limit reached |
| 52 | TaskBudget string // tool_budget variant: task spend budget reached |
| 53 | LoopGuard string // loop_guard: no-progress tool loop |
| 54 | ProgressGuard string // progress_guard: repeated work without new evidence |
| 55 | OperationNeedsUser string // operation_needs_user: host stopped retrying one operation |
| 56 | SoftBudgetConverge string // loop_guard: converging a long read-only investigation |
| 57 | EvidenceNudge string // evidence_nudge: unverified mutations |
| 58 | ReasoningGovernor string // reasoning_governor engaged |
| 59 | UnappliedSteerFmt string // unapplied_steer — %s = the dropped guidance |
| 60 | DeprecatedContextRetention string // agent.keep / agent.recent_keep deprecation warning |
| 61 | FinishReasonLength string |
| 62 | FinishReasonContentFilter string |
| 63 | FinishReasonRepetition string |
| 64 | StreamInterruptedIdleTimeout string |
| 65 | StreamInterruptedPrematureEOF string |
| 66 | StreamInterruptedConnectionReset string |
| 67 | ToolOutputTruncatedFmt string // %d = elided bytes, %d = original bytes |
| 68 | IncompleteReadFinishBlocked string |
| 69 | ReadContinuationRequired string |
| 70 | IncompleteReadDetected string |
| 71 | ReadStrategyRequired string |
| 72 | ReadStrategyProgress string |
| 73 | ReadStrategyResolved string |
| 74 | ReadLocalSafetyPaged string |
| 75 | ReadCompleted string |
| 76 | ReadRestrictedStrategyFmt string // %d = estimated tokens, %d = token budget |
| 77 | ContextRecoveryAdjustBudget string |
| 78 | PromptTruncatedByServerNotice string |
| 79 | ContextRecoveryCompacted string |
| 80 | PlannerFallback string |
| 81 | PlannerSafetyFallback string |
| 82 | PlannerPlanAwaitingApproval string |
| 83 | PlannerPlanNotApproved string |
| 84 | PlannerPlanOnly string |
| 85 | CapabilityProxyFmt string // %s = display name, %s = resolved target |
| 86 | ReceiptVerified string // end-of-turn receipt, nothing unproven |
| 87 | ReceiptGapsHeader string // end-of-turn receipt, header above the unproven list |
| 88 | ReceiptRisksHeader string // end-of-turn receipt, header above declared risks |
| 89 | ReceiptMore string // end-of-turn receipt, "and N more" tail |
| 90 | // ReceiptGapKinds maps a completion gap kind to its short human phrase. |
| 91 | ReceiptGapKinds map[string]string |
| 92 | NoSessionToResume string // shown when --continue / --resume finds nothing |
| 93 | ResumeRequiresTTY string // shown when --resume runs piped instead of on a terminal |
| 94 | AmbiguousResumeHint string // under the candidates of a --resume query that matched several sessions |
| 95 | PickSessionLabel string // header on the --resume picker |
| 96 | |
| 97 | // in-chat /resume command |
| 98 | ResumeBusy string // shown when /resume is used mid-turn |
| 99 | ResumeBadIndexFmt string // shown when /resume gets an out-of-range index (one %d) |
| 100 | ResumeAlreadyActive string // shown when /resume targets the current session |
| 101 | ResumedTitle string // banner title after a /resume switch |
| 102 | |
| 103 | RenameUsage string // /rename with no args |
| 104 | RenameNoSession string // /rename with no active session |
| 105 | RenameDoneFmt string // /rename succeeded (one %s = new title) |
| 106 | ResumePickTitle string // header in the interactive resume picker |
| 107 | ResumePickHint string // keyboard hint in the interactive resume picker |
| 108 | ResumeRecoveryBadgeFmt string // recovery-copy badge — %s = short parent session id |
| 109 | |
| 110 | // chat TUI status line / approval banner. |
| 111 | ChatThinking string // live reasoning marker label, e.g. "thinking…" |
| 112 | ChatThoughtForFmt string // collapsed reasoning summary, "%d" = elapsed s |
| 113 | ChatStatusThinkingFmt string // "%s thinking… (%ds · <cancel hint>)" — %s = spinner, %d = elapsed s |
| 114 | TurnPhaseWorking string // host turn_phase label: working |
| 115 | ReadStatusReadingFmt string // read status: reading a file |
| 116 | ReadStatusCoveredFmt string // read status: covered lines |
| 117 | ReadStatusDoneFmt string // read status: finished a window |
| 118 | ReadStatusPausedFmt string // read status: paused, needs attention |
| 119 | ReadStatusRecovery string // next step after a bounded read stops |
| 120 | TurnPhaseChecking string // host turn_phase label: checking |
| 121 | TurnPhaseVerifying string // host turn_phase label: verifying |
| 122 | TurnPhaseReviewing string // host turn_phase label: reviewing |
| 123 | CompletionSummaryBlocked string // concise non-verbose alert for a blocked turn |
| 124 | CompletionSummaryNeedsAttention string // concise non-verbose alert for verification/review gaps |
| 125 | ChatToolWorkingFmt string // "%s working · %ds" under a running tool — %s = spinner, %d = elapsed s |
| 126 | ChatSubagentPhaseQueued string // sub-agent progress phase label ("queued") |
| 127 | ChatSubagentPhaseRunning string // ("running") |
| 128 | ChatSubagentPhaseReasoning string // ("reasoning") |
| 129 | ChatSubagentPhaseResponding string // ("responding") |
| 130 | ChatSubagentPhaseTool string // ("using tools") |
| 131 | ChatSubagentPhaseRetrying string // ("retrying") |
| 132 | ChatSubagentPhaseCompleted string // ("completed") |
| 133 | ChatSubagentPhaseFailed string // ("failed") |
| 134 | ChatSubagentPhaseCancelled string // ("cancelled") |
| 135 | ChatSubagentProgressFmt string // live progress line — %s = phase label, %d = elapsed s, %d = idle s ("%s · %ds · %ds ago") |
| 136 | ChatSubagentProgressDoneFmt string // terminal summary — %s = phase label, %d = duration s ("%s · %ds") |
| 137 | ChatSubagentPreviewLabel string // verbose preview marker ("▎") |
| 138 | ChatStatusRetryingFmt string // "%s retrying (%d/%d)…" — %s = spinner, %d/%d = attempt/max |
| 139 | ChatStatusCancellingFmt string // "%s stopping… (%ds · Ctrl+C exits)" — %s = spinner, %d = elapsed s |
| 140 | ChatStatusIdle string // shortcuts hint when idle |
| 141 | ChatStatusCycleHint string // plan-toggle shortcut hint shown when no modal prompt owns the status row |
| 142 | ChatStatusCycleHintCompact string // readable shortcut hint used by the persistent footer |
| 143 | ChatTurnReceiptLabel string // compact per-turn usage receipt attached to the completed assistant response |
| 144 | RateBandPeak string |
| 145 | RateBandOffPeak string |
| 146 | RateBandMixed string |
| 147 | ChatStatusModelLabel string |
| 148 | ChatStatusEffortLabel string |
| 149 | ChatStatusPresetLabel string |
| 150 | ChatStatusCacheLabel string |
| 151 | ChatStatusContextLabel string |
| 152 | ChatStatusCompactLabel string |
| 153 | ChatStatusJobsLabel string |
| 154 | ChatStatusBalanceLabel string |
| 155 | ChatStatusCostLabel string |
| 156 | ChatStatusCacheNowFmt string // cache status tag, "%s" = latest-turn hit rate with percent sign |
| 157 | ChatStatusCacheAvgFmt string // cache status tag, "%s" = session-average hit rate with percent sign |
| 158 | ChatStatusPlanApproval string // shortcuts hint while a plan is pending |
| 159 | PlanApprovalPrompt string // one-line "plan above is ready" banner shown above the input |
| 160 | PlanApprovalChoices string // start / revise / exit-without-executing choice list |
| 161 | ChatStatusToolApproval string // shortcuts hint while a tool call awaits approval |
| 162 | ToolApprovalPromptFmt string // approval banner — tool, subject suffix, source/intent detail, choices |
| 163 | ToolApprovalChoices string // standard approval choice list |
| 164 | BashPrefixChoices string // approval choice list when a bash prefix can be granted |
| 165 | PlanModeReadOnlyCommandChoices string // approval choice list for plan-mode read-only command trust |
| 166 | FreshHumanApprovalChoices string // approval choice list for prompts that cannot be remembered |
| 167 | RecoveryApprovalChoices string // one-shot Auto Guard decision list |
| 168 | RecoveryPlanChangeChoices string // material Auto plan transition decision list |
| 169 | RecoveryPlanDecisionPrompt string // neutral title for a material Auto plan transition |
| 170 | RecoveryPlanBeforeFmt string // compact previous-plan line, one %s |
| 171 | RecoveryPlanAfterFmt string // compact proposed-plan line, one %s |
| 172 | RecoveryTaskGrantChoices string // Auto Guard list with a current-task semantic grant |
| 173 | SandboxEscapeApprovalChoices string // approval choice list for OS sandbox escape prompts |
| 174 | ApprovalNeededFmt string // notification text for a pending approval, tool only |
| 175 | ApprovalNeededWithSubjectFmt string // notification text for a pending approval with subject |
| 176 | ToolApprovalSourceFmt string // "Source: %s" / "来源: %s" |
| 177 | ToolApprovalBuiltIn string // built-in tool source label |
| 178 | ToolApprovalImageUse string // image-understanding detail for understand_image-style tools |
| 179 | ApprovalToolLabelBash string // user-facing label for bash approvals |
| 180 | ApprovalToolLabelEditFile string // user-facing label for edit_file approvals |
| 181 | ApprovalToolLabelWriteFile string // user-facing label for write_file approvals |
| 182 | ApprovalToolLabelMultiEdit string // user-facing label for multi_edit approvals |
| 183 | ApprovalToolLabelMoveFile string // user-facing label for move_file approvals |
| 184 | ApprovalToolLabelWebFetch string // user-facing label for web_fetch approvals |
| 185 | ApprovalToolLabelRunSkill string // user-facing label for run_skill approvals |
| 186 | ApprovalToolLabelRemember string // user-facing label for remember approvals |
| 187 | ApprovalToolLabelForget string // user-facing label for forget approvals |
| 188 | ApprovalToolLabelSandboxEscape string // user-facing label for OS sandbox escape approvals |
| 189 | ApprovalToolLabelPlanModeReadOnly string // user-facing label for plan-mode read-only command trust approvals |
| 190 | MemoryApprovalSaveUpdate string // subject prefix for remember approval |
| 191 | MemoryApprovalBodyLabel string // label before the body excerpt in remember approval |
| 192 | MemoryApprovalArchiveFmt string // subject for forget approval, %q = memory name |
| 193 | PlanModeBashTrustSubjectFmt string // subject for bash read-only prefix trust approval, prefix + command |
| 194 | PlanModeBashTrustReason string // reason for bash read-only prefix trust approval |
| 195 | PlanModeBashTrustDeclined string // model-facing denial after bash read-only prefix rejection |
| 196 | SandboxEscapeSubjectFallback string // fallback subject for a one-shot unconfined sandbox escape approval |
| 197 | SandboxEscapeSubjectPrefix string // subject prefix before the shell command for one-shot unconfined escape approval |
| 198 | SandboxEscapeWrapReason string // reason when no OS sandbox can wrap the command |
| 199 | SandboxEscapeRuntimeReason string // fallback reason when an OS sandbox cannot start the command |
| 200 | SandboxEscapeDeclined string // model-facing denial when the user declines a one-shot unconfined retry |
| 201 | ApprovalToolLabelConfigWrite string // user-facing label for Reasonix-managed config write approvals |
| 202 | ConfigWriteSubjectPrefix string // subject prefix before the config file path for managed config write approval |
| 203 | ConfigWriteReason string // reason shown for managed config write approval |
| 204 | ConfigWriteDeclined string // model-facing denial when the user declines a managed config write |
| 205 | ConfigWriteApprovalChoices string // approval choice list for managed config write prompts |
| 206 | WriteAccessApprovalChoices string // four-choice list for extending writable roots |
| 207 | WriteAccessHomeWarning string // high-risk warning when granting the whole home directory |
| 208 | WriteAccessMergedPermissionHint string // note that the same choice also grants ordinary tool permission |
| 209 | WriteAccessProjectHint string // note that project persist edits reasonix.toml |
| 210 | PermissionSavedFmt string // permission rule saved notice: path, rule |
| 211 | PermissionAlreadyAllowedFmt string // permission rule already covered notice: path, rule |
| 212 | PermissionSaveFailedFmt string // permission rule save failure notice: rule, error |
| 213 | PlanModeReadOnlyCommandTrustSavedFmt string // plan-mode bash read-only prefix saved notice: path, prefix |
| 214 | PlanModeReadOnlyCommandTrustAlreadyFmt string // plan-mode bash read-only prefix already covered notice: path, prefix |
| 215 | PlanModeReadOnlyCommandTrustFailedFmt string // plan-mode bash read-only prefix save failure notice: prefix, error |
| 216 | DiffFoldedFmt string // "… +%d more lines" footer when a writer diff is folded |
| 217 | DiffFoldEnabledFmt string // notice when /diff-fold enables folding, %d = line limit |
| 218 | DiffFoldDisabled string // notice when /diff-fold disables folding (shows all lines) |
| 219 | |
| 220 | // `ask` tool question card. |
| 221 | AskTypeSomething string // the "type your own answer" option label |
| 222 | AskTypingHint string // shown on that row while entering free text |
| 223 | AskChatInstead string // the "don't pick, just chat" option label |
| 224 | ChatStatusQuestion string // shortcuts hint while a question card is open |
| 225 | StatusResumePicker string // status tag while the resume picker is open (e.g. "select session") |
| 226 | AskSubmitTitle string // submit-tab title in the ask tool question card |
| 227 | AskUnanswered string // placeholder for an unanswered ask question |
| 228 | AskSubmitHint string // submit-tab keyboard hint |
| 229 | ElicitURLHint string // url-mode elicitation keyboard hint |
| 230 | ElicitConfirmOnly string // schema-less form elicitation hint |
| 231 | ElicitUnanswered string // placeholder for an unanswered elicitation field |
| 232 | ElicitSubmit string // elicitation submit row label |
| 233 | ElicitSubmitHint string // elicitation keyboard hint |
| 234 | |
| 235 | // output style listing (/output-style). |
| 236 | OutputStyleNone string // no styles available |
| 237 | ThemeHeader string // header above the /theme listing |
| 238 | ThemeHint string // how to select a theme |
| 239 | ThemeChangedFmt string // "/theme <name>" succeeded |
| 240 | ThemeUnknownFmt string // "/theme <name>" unknown |
| 241 | LanguageHeader string // header above the /language listing |
| 242 | LanguageHint string // how to select a language |
| 243 | LanguageChangedFmt string // "/language <tag>" succeeded, %s = saved tag, %s = resolved tag |
| 244 | CurrencyHeader string // header above the /currency listing |
| 245 | CurrencyHint string // how to select a pricing currency |
| 246 | CurrencyChangedFmt string // "/currency <mode>" succeeded, %s = saved mode, %s = resolved currency |
| 247 | RuntimeRefreshBusy string // runtime-affecting setting cannot change while work is active |
| 248 | RuntimeRefreshUnavailable string // current session cannot rebuild after a runtime-affecting setting change |
| 249 | |
| 250 | // context compaction card (CompactionStarted / CompactionDone events). |
| 251 | CompactionWorking string // shown while the summarizer runs |
| 252 | CompactionTitle string // card header before "· N messages · <trigger>" |
| 253 | CompactionUnit string // the noun counted, e.g. "messages" |
| 254 | CompactionAuto string // trigger label: reached the window threshold |
| 255 | CompactionManual string // trigger label: user ran /compact |
| 256 | CompactionStopping string // cancellation has been requested |
| 257 | CompactionSaving string // a committed result is being persisted |
| 258 | CompactionNoHistory string // the selected history has nothing to fold |
| 259 | CompactionStopped string // cancelled before applying a projection |
| 260 | CompactionStoppedPartial string // cancelled after at least one applied batch |
| 261 | CompactionRecoveryRequired string // persistence/cancellation state needs recovery |
| 262 | CompactionInterrupted string // a previous non-terminal operation was interrupted |
| 263 | CompactionEstimatedTokens string // label for estimated before/after token counts |
| 264 | |
| 265 | // extension structured-UI surfaces (ExtensionSurface / ExtensionStatus events). |
| 266 | ExtFormFieldsHint string // form card: field values are collected through the usual prompts |
| 267 | ExtRunActionFmt string // card action hint, one %s = the /<plugin>:<action> slash name |
| 268 | |
| 269 | // chat TUI slash commands. |
| 270 | SlashCompactFailed string // "/compact" errored, prefixed before the underlying error |
| 271 | SlashNewDone string // "/new" succeeded |
| 272 | SlashNewFailed string // "/new" errored |
| 273 | SlashClearPrompt string // "/clear" destructive confirmation prompt |
| 274 | SlashClearDone string // "/clear" succeeded |
| 275 | SlashClearFailed string // "/clear" errored |
| 276 | SlashClsDone string // "/cls" succeeded |
| 277 | SlashTodoCleared string // "/todo" dismissed the pinned task list |
| 278 | SlashUnknown string // shown when the user types an unrecognised "/cmd" |
| 279 | SlashUnknownSentAsMessage string // suffix: the unrecognised "/cmd" line was sent as a regular message |
| 280 | SlashPromptEmpty string // an MCP prompt returned no text to send |
| 281 | SlashMCPNone string // /mcp when no MCP servers are connected |
| 282 | CtrlCQuitHint string // shown on first Ctrl+C while idle; second press exits |
| 283 | CompHintSlash string // key hint footer under the slash-command menu |
| 284 | CompHintFile string // key hint footer under the @ file/resource menu |
| 285 | MouseCopiedHint string // transient status-line hint after a mouse/Ctrl+C selection copy |
| 286 | ClipboardCopyOSC52Hint string // copy was sent through OSC 52 because the session is remote |
| 287 | ClipboardCopyFallbackHint string // native clipboard failed and copy fell back to OSC 52 |
| 288 | ClipboardTextPasteRemoteHint string // mouse paste cannot read the user's local clipboard/PRIMARY selection over SSH |
| 289 | ClipboardTextPasteFailedFmt string // text clipboard read failed, one %v |
| 290 | ClipboardImagePastingHint string // shown while an image is being read from the system clipboard |
| 291 | ClipboardPasteEmptyNotice string |
| 292 | ClipboardImagePasteFailedFmt string // image clipboard read failed, one %v |
| 293 | MouseCaptureOnHint string // "/mouse" turned in-app mouse handling back on |
| 294 | MouseCaptureOffHint string // "/mouse" released mouse capture to the terminal |
| 295 | MouseCaptureTag string // persistent status-line marker while mouse capture is off |
| 296 | |
| 297 | // shell execution (! prefix). |
| 298 | ShellExecEmpty string // bare "!" with no command |
| 299 | ShellExecFailedFmt string // "shell command failed: %v" |
| 300 | ShellExecTimeoutFmt string // "shell command timed out (> %s)" |
| 301 | ShellModeHint string // status line hint when input starts with ! |
| 302 | |
| 303 | // slash command + sub-command descriptions shown in the menu (CLI and desktop |
| 304 | // share these via i18n.M, so both frontends localize identically). |
| 305 | CmdNew string // /new |
| 306 | CmdClear string // /clear |
| 307 | CmdCls string // /cls |
| 308 | CmdCompact string // /compact |
| 309 | CmdContinueChecks string // /continue-checks |
| 310 | CmdContext string // /context |
| 311 | CmdRewind string // /rewind |
| 312 | CmdTree string // /tree |
| 313 | CmdBranch string // /branch |
| 314 | CmdSwitchBranch string // /switch |
| 315 | CmdResume string // /resume |
| 316 | CmdRename string // /rename |
| 317 | CmdModel string // /model |
| 318 | CmdStatus string // /status |
| 319 | CmdWorkMode string // /work-mode |
| 320 | CmdDocs string // /docs |
| 321 | CmdMemory string // /memory |
| 322 | CmdMigrate string // /migrate |
| 323 | CmdGoal string // /goal |
| 324 | CmdRemember string // /remember |
| 325 | CmdForget string // /forget |
| 326 | CmdMcp string // /mcp |
| 327 | CmdRemote string // /remote |
| 328 | CmdHooks string // /hooks |
| 329 | CmdPlugins string // /plugins |
| 330 | CmdPasteImage string // /paste-image |
| 331 | CmdOutputStyle string // /output-style |
| 332 | CmdTheme string // /theme |
| 333 | CmdLanguage string // /language |
| 334 | CmdCurrency string // /currency |
| 335 | CmdSkill string // /skills |
| 336 | CmdVerbose string // /verbose |
| 337 | CmdReloadCmd string // /reload-cmd |
| 338 | CmdReload string // /reload |
| 339 | CmdDiffFold string // /diff-fold |
| 340 | CmdSandbox string // /sandbox |
| 341 | CmdEffort string // /effort |
| 342 | CmdMouse string // /mouse |
| 343 | CmdReasonLang string // /reasoning-language |
| 344 | CmdHelp string // /help |
| 345 | CmdWeb string // /web |
| 346 | CmdTodo string // /todo |
| 347 | CmdQuit string // /quit (also accepts /exit as hidden alias) |
| 348 | CmdCopy string // /copy |
| 349 | CmdExport string // /export |
| 350 | SlashCopyDone string // "/copy" succeeded |
| 351 | SlashCopyEmpty string // no assistant response to copy |
| 352 | SlashCopyListHeader string // header shown before the numbered list |
| 353 | SlashExportDoneFmt string // "/export" succeeded, %s = file path |
| 354 | SlashExportEmpty string // no messages to export |
| 355 | ArgSkillShow string // /skills show |
| 356 | ArgSkillNew string // /skills new |
| 357 | ArgSkillPaths string // /skills paths |
| 358 | ArgMcpAdd string // /mcp add |
| 359 | ArgMcpRemove string // /mcp remove |
| 360 | ArgMcpConnected string // /mcp remove <server> tag |
| 361 | ArgHooksList string // /hooks list |
| 362 | ArgModelCurrent string // /model <ref> active tag |
| 363 | ArgEffortAuto string // /effort auto |
| 364 | ArgEffortLow string // /effort low |
| 365 | ArgEffortMedium string // /effort medium |
| 366 | ArgEffortHigh string // /effort high |
| 367 | ArgEffortXHigh string // /effort xhigh |
| 368 | ArgEffortMax string // /effort max |
| 369 | ArgPresetStandard string // /preset standard |
| 370 | ArgPresetDelivery string // /preset delivery |
| 371 | ArgThemeCurrent string // /theme <style> active tag |
| 372 | ArgLanguageAuto string // /language auto |
| 373 | ArgLanguageEn string // /language en |
| 374 | ArgLanguageZh string // /language zh |
| 375 | |
| 376 | // management listing notices (the Submit path: desktop / HTTP frontends) |
| 377 | ListModelsHeaderFmt string // "models (active: %s)" |
| 378 | ListModelsHint string // how to switch |
| 379 | ListMemorySaved string // "saved memories" |
| 380 | ListMemoryArchived string // "archived memories" |
| 381 | ListMemoryNone string // no memory docs |
| 382 | ListSkillsHeaderFmt string // "skills (%d)" |
| 383 | ListSkillsNone string // no skills |
| 384 | ListHooksHeaderFmt string // "hooks (%d active)" |
| 385 | ListHooksNone string // no hooks |
| 386 | ListMcpHeader string // "mcp servers" |
| 387 | ListMcpNone string // no mcp servers |
| 388 | |
| 389 | // in-chat memory/model/rewind notices. |
| 390 | |
| 391 | MemoryEditHint string |
| 392 | ForgetUsage string |
| 393 | ForgetDoneFmt string |
| 394 | QuickRememberEmpty string |
| 395 | QuickRememberDoneFmt string |
| 396 | GoalEmpty string |
| 397 | GoalCurrentFmt string |
| 398 | GoalSetFmt string |
| 399 | GoalCleared string |
| 400 | GoalNotRunning string |
| 401 | GoalNotPaused string |
| 402 | GoalPaused string |
| 403 | GoalPausedReason string |
| 404 | GoalPausedFmt string // %s = stop cause |
| 405 | GoalRuntimeFmt string // turns, requests, tokens, work duration |
| 406 | GoalRuntimeLastReason string |
| 407 | ModelSwitchUnavailable string |
| 408 | ModelSwitchBusy string |
| 409 | ModelAlreadyOnFmt string |
| 410 | ModelSwitchingFmt string |
| 411 | ModelSwitchedFmt string |
| 412 | ModelListHeader string |
| 413 | RuntimeSwitchPending string |
| 414 | RuntimeReloadQueued string // /reload queued behind active work; the idle drain runs it |
| 415 | RuntimeReloaded string // /reload completed (no generation available) |
| 416 | RuntimeReloadedGenerationFmt string // /reload completed; %d is the runtime build generation |
| 417 | WorkModeUsage string |
| 418 | // WorkModeDeprecatedNotice is shown once when a legacy /work-mode or |
| 419 | // /profile command is used. Prefer /preset. |
| 420 | WorkModeDeprecatedNotice string |
| 421 | // QualityFloorApplied confirms a quality floor switch. |
| 422 | QualityFloorApplied string |
| 423 | RewindNone string |
| 424 | RewindCodeConversation string |
| 425 | RewindConversationOnly string |
| 426 | RewindCodeOnly string |
| 427 | RewindFork string |
| 428 | RewindSummarizeFrom string |
| 429 | RewindSummarizeUpto string |
| 430 | RewindPickTitle string |
| 431 | RewindPickHint string |
| 432 | RewindRestoreTitleFmt string |
| 433 | RewindApplyHint string |
| 434 | RewindCoverageTitle string |
| 435 | RewindCoverageWarningFmt string |
| 436 | RewindConfirmHint string |
| 437 | RewindUnavailableFmt string |
| 438 | RewindEmpty string |
| 439 | |
| 440 | // skill picker overlay (/skills interactive panel in CLI TUI) |
| 441 | SkillPickerAvailableFmt string |
| 442 | SkillPickerMatchingFmt string // "%d matching · %d total" when searching |
| 443 | SkillPickerHint string |
| 444 | SkillPickerDetailHint string |
| 445 | SkillPickerSearchEmpty string |
| 446 | SkillPickerSearchPlaceholder string |
| 447 | SkillPickerSourceTitle string |
| 448 | SkillPickerSourceActiveFmt string |
| 449 | SkillPickerSourceHint string |
| 450 | SkillPickerDiagHidden string |
| 451 | SkillPickerDiagShown string |
| 452 | SkillPickerBuiltinSource string |
| 453 | SkillPickerRescanned string |
| 454 | SkillPickerNoDescription string |
| 455 | SkillPickerScopeProject string |
| 456 | SkillPickerScopeCustom string |
| 457 | SkillPickerScopeGlobal string |
| 458 | SkillPickerScopeBuiltin string |
| 459 | SkillPickerSubagent string |
| 460 | SkillPickerAvailableLabel string |
| 461 | SkillPickerDisabledLabel string |
| 462 | SkillPickerNoChanges string |
| 463 | SkillPickerSourceSkillsHint string |
| 464 | SkillPickerSourceSkillsEmpty string |
| 465 | SkillPickerActionToggle string |
| 466 | SkillPickerActionDelete string |
| 467 | SkillPickerDeleteTitleFmt string // "Delete skill %s?" |
| 468 | SkillPickerDeleteConfirm string |
| 469 | SkillPickerDeleteCancel string |
| 470 | SkillPickerDeleteHint string |
| 471 | SkillPickerDeletedFmt string // "deleted skill %s" |
| 472 | SkillPickerMoreAboveFmt string // "↑ %d more above" |
| 473 | SkillPickerMoreBelowFmt string // "↓ %d more below" |
| 474 | SkillPickerTokenFmt string // "~%d tok" |
| 475 | SkillPickerDetailMetaFmt string // "Scope: %s Run as: %s" |
| 476 | SkillPickerSkillsUnit string // "skills" (used as "%d skills") |
| 477 | SkillPickerLinesUnit string // "lines" (used as "+N more lines") |
| 478 | SkillPickerStatusLabel string // shown in the TUI status bar while picker is open |
| 479 | SkillPickerStatusOK string // "ok" path status label |
| 480 | SkillPickerStatusMissing string // "missing" path status label |
| 481 | SkillPickerStatusNotDir string // "not-directory" path status label |
| 482 | SkillPickerStatusUnreadable string // "unreadable" path status label |
| 483 | |
| 484 | // init wizard |
| 485 | EnterAPIKeysHeader string // header before the per-env-var prompts |
| 486 | WroteFileFmt string // "Wrote %s" — used for reasonix.toml and .env both |
| 487 | SetupComplete string // success line at end of init |
| 488 | SetupCancelled string // shown when the user aborts the wizard |
| 489 | TryHintFmt string // "Try: %s" — %s = command to try (styled) |
| 490 | NextHint string // non-interactive post-write hint |
| 491 | ConfirmReconfigureFmt string // "%s already exists. Reconfigure and overwrite?" |
| 492 | NotOverwritingFmt string // non-interactive overwrite refusal |
| 493 | SetupManagerTitle string |
| 494 | SetupAddOpenAI string |
| 495 | SetupAddAnthropic string |
| 496 | SetupProviderExistsFmt string |
| 497 | SetupSaveExit string |
| 498 | SetupSaveExitDesc string |
| 499 | SetupCancel string |
| 500 | SetupCancelDesc string |
| 501 | SetupModelsUnit string |
| 502 | SetupKeySet string |
| 503 | SetupKeyMissing string |
| 504 | SetupDefaultBadge string |
| 505 | SetupProviderActionsFmt string |
| 506 | SetupEditProvider string |
| 507 | SetupUpdateKey string |
| 508 | SetupTestRefresh string |
| 509 | SetupSetDefault string |
| 510 | SetupRemoveProvider string |
| 511 | SetupBack string |
| 512 | SetupPromptModels string |
| 513 | SetupSharedKeyWarningFmt string |
| 514 | SetupKeyEnvTakenFmt string |
| 515 | SetupKeyEnvStoredFmt string |
| 516 | SetupKeyEnvSettingFmt string |
| 517 | SetupKeyEnvShellFmt string |
| 518 | SetupKeyEnvRetry string |
| 519 | SetupPromptAPIKeyFmt string |
| 520 | SetupSelectDefaultModel string |
| 521 | SetupConfirmRemoveFmt string |
| 522 | SetupSummaryTitle string |
| 523 | SetupSummaryAddedFmt string |
| 524 | SetupSummaryEditedFmt string |
| 525 | SetupSummaryRemovedFmt string |
| 526 | SetupSummaryDefaultFmt string |
| 527 | SetupSummaryKeysFmt string |
| 528 | SetupSummaryNoChanges string |
| 529 | SetupConfirmSave string |
| 530 | SetupConcurrentChangeFmt string |
| 531 | |
| 532 | // model fetching |
| 533 | FetchingModelsFmt string // "Fetching models for %s..." |
| 534 | FetchModelsSuccessFmt string // "Found %d models for %s" |
| 535 | FetchModelsFailedFmt string // "Failed to fetch models for %s: %v" |
| 536 | FetchModelsUsingPresetsFmt string // "Live fetch unavailable for %s, using preset model list" |
| 537 | SelectModelsLabel string // "Select models to enable for %s" |
| 538 | CustomFetchEmpty string // "/models returned an empty list — falling back to manual entry" |
| 539 | AnthropicFetchEmpty string // "/models returned an empty list — Anthropic-compatible providers usually don't expose one, falling back to manual entry" |
| 540 | APIKeyAlreadySetFmt string // "reusing existing value for %s" |
| 541 | APIKeyResetPromptFmt string // "Re-enter %s?" |
| 542 | InvalidAPIKeyEnvFmt string // "%q is not a valid API Key variable name..." |
| 543 | RepairedAPIKeyEnvFmt string // "provider %s: replaced invalid api_key_env %q with %q" |
| 544 | |
| 545 | // custom provider |
| 546 | CustomProviderDesc string // "Add third-party OpenAI compatible model" |
| 547 | CustomAddMethodLabel string // "Select add method" |
| 548 | CustomMethodManual string // "Enter model name manually" |
| 549 | CustomMethodURL string // "Fetch models from URL" |
| 550 | CustomPromptModel string // "Enter model name" |
| 551 | CustomPromptBaseURL string // "Enter Base URL" |
| 552 | CustomPromptKeyEnv string // "Enter API Key env var name" |
| 553 | CustomPromptAPIKey string // "Enter API Key" |
| 554 | CustomPromptWindow string // "Enter context window in tokens" |
| 555 | CustomAddedFmt string // "Added custom model: %s" |
| 556 | |
| 557 | // Anthropic compatible provider |
| 558 | AnthropicProviderDesc string // "Add Anthropic API compatible model" |
| 559 | AnthropicAddMethodLabel string // "Select add method" |
| 560 | AnthropicMethodManual string // "Enter model name manually" |
| 561 | AnthropicMethodURL string // "Fetch models from URL" |
| 562 | AnthropicPromptModel string // "Enter model name" |
| 563 | AnthropicPromptBaseURL string // "Enter Base URL" |
| 564 | AnthropicPromptKeyEnv string // "Enter API Key env var name" |
| 565 | AnthropicPromptAPIKey string // "Enter API Key" |
| 566 | AnthropicAddedFmt string // "Added Anthropic compatible model: %s" |
| 567 | AnthropicFetchingModelsFmt string // "Fetching models for %s..." |
| 568 | AnthropicFetchModelsSuccessFmt string // "Found %d models for %s" |
| 569 | AnthropicFetchModelsFailedFmt string // "Failed to fetch models for %s: %v" |
| 570 | AnthropicSelectModelsLabel string // "Select models to enable for %s" |
| 571 | |
| 572 | // remote SSH module |
| 573 | RemoteConnectingFmt string // "connecting to %s…" |
| 574 | RemoteConnectedFmt string // "connected to %s" |
| 575 | RemoteReconnectingFmt string // "reconnecting to %s (attempt %d)…" |
| 576 | RemoteDegradedFmt string // "connected to %s but some forwards are down" |
| 577 | RemoteDisconnected string // "disconnected" |
| 578 | RemoteServeReadyFmt string // "remote serve ready: %s" |
| 579 | RemoteHostKeyPromptFmt string // "host %s key (%s): %s" |
| 580 | RemotePassphrasePromptFmt string // "passphrase for %s:" |
| 581 | RemotePasswordPromptFmt string // "password for %s:" |
| 582 | RemoteBootstrapStepFmt string // "remote serve: %s %s" |
| 583 | RemoteNoHostsHint string // "no remote hosts configured; add one with `reasonix remote add`" |
| 584 | |
| 585 | // top-level / runAgent |
| 586 | UnknownCommandFmt string // "unknown command %q" |
| 587 | UsageRunHint string // "usage: reasonix run [--model NAME] <task>" |
| 588 | ErrorPrefix string // "error:" — prefix for fatal-error output |
| 589 | ReconfigureOnUnknownModel string // shown when the configured model no longer resolves and setup is re-run |
| 590 | WriteConfigErr string // "write config:" — prefix for write failure |
| 591 | WriteEnvErr string // "write .env:" — prefix for env-write failure |
| 592 | |
| 593 | // provider HTTP error explanations — actionable, reason + fix per status code |
| 594 | ProviderErrBadRequest string // 400 |
| 595 | ProviderErrContextOverflowFmt string // 400/413/422 shared-window overflow with numbers |
| 596 | ProviderErrAuth string // 401 — no key configured / sent |
| 597 | ProviderErrAuthRejected string // 401 — a key was sent but the server rejected it |
| 598 | ProviderErrModelFormatMismatch string // provider rejected the model on the selected wire format |
| 599 | ProviderErrOpenCodeGoGrokRoute string // recovery hint for OpenCode Go Grok routing |
| 600 | ProviderErrQuotaExhaustedFmt string // provider name, actual HTTP status |
| 601 | ProviderErrReasonMissing string |
| 602 | ProviderErrStreamInterruptedFmt string |
| 603 | ProviderErrDisconnectedFmt string |
| 604 | ProviderErrNonStreamingFmt string |
| 605 | SearchSourcesNotProvided string |
| 606 | SearchModelUnavailable string |
| 607 | ProtocolRecoveryLabel string |
| 608 | ProviderErrInsufficientBalance string // 402 |
| 609 | ProviderErrNotFound string // 404 |
| 610 | ProviderErrUnprocessable string // 422 |
| 611 | ProviderErrInputSensitive string // MiniMax 1026 |
| 612 | ProviderErrOutputSensitive string // MiniMax 1027 |
| 613 | ProviderErrRateLimited string // 429 |
| 614 | ProviderErrServer string // 500 |
| 615 | ProviderErrServerBusy string // 503 |
| 616 | ProviderErrWaitExhaustedFmt string // total time waited before giving up |
| 617 | |
| 618 | // selection menus |
| 619 | SelectOneHint string // "(↑/↓ · Enter · q to cancel)" |
| 620 | SelectManyHint string // "(↑/↓ · Space · Enter · q)" |
| 621 | SelectMoreAboveFmt string // "↑ %d more above" |
| 622 | SelectMoreBelowFmt string // "↓ %d more below" |
| 623 | SelectSearchHint string // "/ to search · Esc to cancel" |
| 624 | |
| 625 | // /provider command |
| 626 | CmdProvider string // /provider |
| 627 | ProviderListHeader string // header for /provider list |
| 628 | ProviderAlreadyOnFmt string // already on provider |
| 629 | ProviderUnknownFmt string // unknown provider |
| 630 | ProviderPickLabel string // label for provider model picker |
| 631 | ProviderNoModelsFmt string // provider has no models |
| 632 | |
| 633 | // `reasonix upgrade` / `reasonix update` — self-update |
| 634 | UpgradeChecking string // "Checking for updates…" |
| 635 | UpgradeChannelDeprecated string // legacy channel selection is ignored |
| 636 | UpgradeDevBuild string // dev builds cannot self-update |
| 637 | UpgradeFetchFailed string // "failed to check for updates: %v" |
| 638 | UpgradeInvalidVersion string // remote version not valid semver |
| 639 | UpgradeAlreadyLatest string // already on the latest version |
| 640 | UpgradeForcing string // "Reinstalling the same version…" |
| 641 | UpgradeAvailableFmt string // "Current: %s → Latest: %s" |
| 642 | UpgradeNoAssetFmt string // "no binary found for %s" |
| 643 | UpgradeDownloadingFmt string // "Downloading %s (%s)…" |
| 644 | UpgradeDownloadFailed string // "download failed: %v" |
| 645 | UpgradeVerifying string // "Verifying checksum…" |
| 646 | UpgradeChecksumFailed string // "could not fetch checksum file: %v" |
| 647 | UpgradeChecksumMismatchFmt string // SHA256 mismatch detail |
| 648 | UpgradeChecksumNotFoundFmt string // asset not listed in SHA256SUMS |
| 649 | UpgradeExtractFailed string // "failed to extract binary: %v" |
| 650 | UpgradeApplying string // "Replacing binary…" |
| 651 | UpgradeApplyFailed string // "failed to apply update: %v" |
| 652 | UpgradeSuccessFmt string // "Updated %s → %s" |
| 653 | |
| 654 | // `reasonix report` — local CLI crash review and explicit upload |
| 655 | ReportNoPending string |
| 656 | ReportHeaderFmt string |
| 657 | ReportCapturedFmt string |
| 658 | ReportPreviewOnlyFmt string |
| 659 | ReportSendPrompt string |
| 660 | ReportKept string |
| 661 | ReportDeletedFmt string |
| 662 | ReportSentFmt string |
| 663 | ReportConfigFailedFmt string |
| 664 | ReportUploadFailedFmt string |
| 665 | ReportSentDeleteFailedFmt string |
| 666 | ReportUsageBody string |
| 667 | |
| 668 | // First eligible interactive CLI telemetry consent. |
| 669 | CLITelemetryConsentNotice string |
| 670 | CLITelemetryConsentPrompt string |
| 671 | CLITelemetryConsentInvalid string |
| 672 | CLITelemetryConsentSaveFailedFmt string |
| 673 | CLITelemetryConsentCleanupFailedFmt string |
| 674 | |
| 675 | // usage / help |
| 676 | UsageBody string // full multi-line help text |
| 677 | } |
| 678 | |
| 679 | // ProviderStatusMessage returns an actionable explanation for a known provider |
| 680 | // HTTP status, or "" when the status has no specific guidance. |
| 681 | func (m Messages) ProviderStatusMessage(status int) string { |
| 682 | switch status { |
| 683 | case 400: |
| 684 | return m.ProviderErrBadRequest |
| 685 | case 401, 403: |
| 686 | return m.ProviderErrAuth |
| 687 | case 402: |
| 688 | return m.ProviderErrInsufficientBalance |
| 689 | case 404: |
| 690 | return m.ProviderErrNotFound |
| 691 | case 422: |
| 692 | return m.ProviderErrUnprocessable |
| 693 | case 429: |
| 694 | return m.ProviderErrRateLimited |
| 695 | case 500: |
| 696 | return m.ProviderErrServer |
| 697 | case 503: |
| 698 | return m.ProviderErrServerBusy |
| 699 | } |
| 700 | return "" |
| 701 | } |
| 702 | |
| 703 | // M is the active catalogue. DetectLanguage replaces it; English is the |
| 704 | // default so any code path that runs before detection still has text. |
| 705 | var ( |
| 706 | M = English |
| 707 | currentLanguage = "en" |
| 708 | ) |
| 709 | |
| 710 | // CurrentLanguage returns the language tag installed by the latest |
| 711 | // DetectLanguage call. It lets frontends reuse the resolved locale without |
| 712 | // re-reading the environment and accidentally ignoring an explicit override. |
| 713 | func CurrentLanguage() string { |
| 714 | return currentLanguage |
| 715 | } |
| 716 | |
| 717 | // DetectLanguage selects a catalogue from override (e.g. cfg.Language) or the |
| 718 | // environment and installs it as M. Returns the resolved tag ("en", "zh") so |
| 719 | // callers can log or expose it. |
| 720 | // |
| 721 | // Priority: override > REASONIX_LANG > LC_ALL > LC_MESSAGES > LANG > "en". |
| 722 | func DetectLanguage(override string) string { |
| 723 | for _, c := range append([]string{override}, envCandidates()...) { |
| 724 | if tag := normalize(c); tag != "" { |
| 725 | return setLanguage(tag) |
| 726 | } |
| 727 | } |
| 728 | return setLanguage("en") |
| 729 | } |
| 730 | |
| 731 | func envCandidates() []string { |
| 732 | keys := []string{"REASONIX_LANG", "LC_ALL", "LC_MESSAGES", "LANG"} |
| 733 | out := make([]string, len(keys)) |
| 734 | for i, k := range keys { |
| 735 | out[i] = os.Getenv(k) |
| 736 | } |
| 737 | return out |
| 738 | } |
| 739 | |
| 740 | func setLanguage(tag string) string { |
| 741 | switch tag { |
| 742 | case "zh-tw", "zh-TW": |
| 743 | M = ChineseTraditional |
| 744 | currentLanguage = "zh-TW" |
| 745 | case "zh": |
| 746 | M = Chinese |
| 747 | currentLanguage = "zh" |
| 748 | default: |
| 749 | M = English |
| 750 | currentLanguage = "en" |
| 751 | } |
| 752 | return currentLanguage |
| 753 | } |
| 754 | |
| 755 | // normalize maps a locale string (e.g. "zh_CN.UTF-8", "zh-Hans-CN", "Chinese |
| 756 | // (China)") to a short tag this package knows about. Returns "" for empty or |
| 757 | // unrecognised input so DetectLanguage can fall through to the next candidate. |
| 758 | func normalize(s string) string { |
| 759 | s = strings.ToLower(strings.TrimSpace(s)) |
| 760 | s = strings.ReplaceAll(s, "_", "-") // zh_TW.UTF-8 → zh-tw.utf-8 (POSIX locales use underscores) |
| 761 | if s == "" { |
| 762 | return "" |
| 763 | } |
| 764 | if strings.HasPrefix(s, "zh-tw") || strings.HasPrefix(s, "zh-hant") || strings.Contains(s, "chinese traditional") || strings.Contains(s, "繁體") { |
| 765 | return "zh-TW" |
| 766 | } |
| 767 | if strings.HasPrefix(s, "zh") || strings.Contains(s, "chinese") || strings.Contains(s, "中文") { |
| 768 | return "zh" |
| 769 | } |
| 770 | if strings.HasPrefix(s, "en") || strings.Contains(s, "english") { |
| 771 | return "en" |
| 772 | } |
| 773 | return "" |
| 774 | } |
| 775 |