返回 DeepSeek-Reasonix
i18n.go
根目录 / internal / i18n / i18n.go
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 RecoveryPaused string // controlled Auto retry pause; user can continue in the next message
39 NoSessionToResume string // shown when --continue / --resume finds nothing
40 ResumeRequiresTTY string // shown when --resume runs piped instead of on a terminal
41 PickSessionLabel string // header on the --resume picker
42
43 // in-chat /resume command
44 ResumeBusy string // shown when /resume is used mid-turn
45 ResumeBadIndexFmt string // shown when /resume gets an out-of-range index (one %d)
46 ResumeAlreadyActive string // shown when /resume targets the current session
47 ResumedTitle string // banner title after a /resume switch
48
49 RenameUsage string // /rename with no args
50 RenameNoSession string // /rename with no active session
51 RenameDoneFmt string // /rename succeeded (one %s = new title)
52 ResumePickTitle string // header in the interactive resume picker
53 ResumePickHint string // keyboard hint in the interactive resume picker
54 ResumeRecoveryBadgeFmt string // recovery-copy badge — %s = short parent session id
55
56 // chat TUI status line / approval banner.
57 ChatThinking string // live reasoning marker label, e.g. "thinking…"
58 ChatThoughtForFmt string // collapsed reasoning summary, "%d" = elapsed s
59 ChatStatusThinkingFmt string // "%s thinking… (%ds · <cancel hint>)" — %s = spinner, %d = elapsed s
60 ChatToolWorkingFmt string // "%s working · %ds" under a running tool — %s = spinner, %d = elapsed s
61 ChatSubagentPhaseQueued string // sub-agent progress phase label ("queued")
62 ChatSubagentPhaseRunning string // ("running")
63 ChatSubagentPhaseReasoning string // ("reasoning")
64 ChatSubagentPhaseResponding string // ("responding")
65 ChatSubagentPhaseTool string // ("using tools")
66 ChatSubagentPhaseRetrying string // ("retrying")
67 ChatSubagentPhaseCompleted string // ("completed")
68 ChatSubagentPhaseFailed string // ("failed")
69 ChatSubagentPhaseCancelled string // ("cancelled")
70 ChatSubagentProgressFmt string // live progress line — %s = phase label, %d = elapsed s, %d = idle s ("%s · %ds · %ds ago")
71 ChatSubagentProgressDoneFmt string // terminal summary — %s = phase label, %d = duration s ("%s · %ds")
72 ChatSubagentPreviewLabel string // verbose preview marker ("▎")
73 ChatStatusRetryingFmt string // "%s retrying (%d/%d)…" — %s = spinner, %d/%d = attempt/max
74 ChatStatusCancellingFmt string // "%s stopping… (%ds · Ctrl+C exits)" — %s = spinner, %d = elapsed s
75 ChatStatusIdle string // shortcuts hint when idle
76 ChatStatusYoloIdle string // shortcuts hint when idle in YOLO/bypass mode
77 ChatStatusCycleHint string // plan-toggle shortcut hint shown when no modal prompt owns the status row
78 ChatStatusCycleHintCompact string // readable shortcut hint used by the persistent footer
79 ChatTurnReceiptLabel string // compact per-turn usage receipt attached to the completed assistant response
80 ChatStatusModelLabel string
81 ChatStatusEffortLabel string
82 ChatStatusWorkLabel string
83 ChatStatusCacheLabel string
84 ChatStatusContextLabel string
85 ChatStatusCompactLabel string
86 ChatStatusJobsLabel string
87 ChatStatusBalanceLabel string
88 ChatStatusCacheNowFmt string // cache status tag, "%s" = latest-turn hit rate with percent sign
89 ChatStatusCacheAvgFmt string // cache status tag, "%s" = session-average hit rate with percent sign
90 ChatStatusPlanApproval string // shortcuts hint while a plan is pending
91 PlanApprovalPrompt string // one-line "plan above is ready" banner shown above the input
92 PlanApprovalChoices string // start / revise / exit-without-executing choice list
93 ChatStatusToolApproval string // shortcuts hint while a tool call awaits approval
94 ToolApprovalPromptFmt string // approval banner — tool, subject suffix, source/intent detail, choices
95 ToolApprovalChoices string // standard approval choice list
96 BashPrefixChoices string // approval choice list when a bash prefix can be granted
97 PlanModeReadOnlyCommandChoices string // approval choice list for plan-mode read-only command trust
98 FreshHumanApprovalChoices string // approval choice list for prompts that cannot be remembered
99 RecoveryApprovalChoices string // one-shot Auto Guard decision list
100 RecoveryPlanChangeChoices string // material Auto plan transition decision list
101 RecoveryPlanDecisionPrompt string // neutral title for a material Auto plan transition
102 RecoveryPlanBeforeFmt string // compact previous-plan line, one %s
103 RecoveryPlanAfterFmt string // compact proposed-plan line, one %s
104 RecoveryTaskGrantChoices string // Auto Guard list with a current-task semantic grant
105 SandboxEscapeApprovalChoices string // approval choice list for OS sandbox escape prompts
106 ApprovalNeededFmt string // notification text for a pending approval, tool only
107 ApprovalNeededWithSubjectFmt string // notification text for a pending approval with subject
108 ToolApprovalSourceFmt string // "Source: %s" / "来源: %s"
109 ToolApprovalBuiltIn string // built-in tool source label
110 ToolApprovalImageUse string // image-understanding detail for understand_image-style tools
111 ApprovalToolLabelBash string // user-facing label for bash approvals
112 ApprovalToolLabelEditFile string // user-facing label for edit_file approvals
113 ApprovalToolLabelWriteFile string // user-facing label for write_file approvals
114 ApprovalToolLabelMultiEdit string // user-facing label for multi_edit approvals
115 ApprovalToolLabelMoveFile string // user-facing label for move_file approvals
116 ApprovalToolLabelWebFetch string // user-facing label for web_fetch approvals
117 ApprovalToolLabelRunSkill string // user-facing label for run_skill approvals
118 ApprovalToolLabelRemember string // user-facing label for remember approvals
119 ApprovalToolLabelForget string // user-facing label for forget approvals
120 ApprovalToolLabelSandboxEscape string // user-facing label for OS sandbox escape approvals
121 ApprovalToolLabelPlanModeReadOnly string // user-facing label for plan-mode read-only command trust approvals
122 MemoryApprovalSaveUpdate string // subject prefix for remember approval
123 MemoryApprovalBodyLabel string // label before the body excerpt in remember approval
124 MemoryApprovalArchiveFmt string // subject for forget approval, %q = memory name
125 PlanModeBashTrustSubjectFmt string // subject for bash read-only prefix trust approval, prefix + command
126 PlanModeBashTrustReason string // reason for bash read-only prefix trust approval
127 PlanModeBashTrustDeclined string // model-facing denial after bash read-only prefix rejection
128 SandboxEscapeSubjectFallback string // fallback subject for a one-shot unconfined sandbox escape approval
129 SandboxEscapeSubjectPrefix string // subject prefix before the shell command for one-shot unconfined escape approval
130 SandboxEscapeWrapReason string // reason when no OS sandbox can wrap the command
131 SandboxEscapeRuntimeReason string // fallback reason when an OS sandbox cannot start the command
132 SandboxEscapeDeclined string // model-facing denial when the user declines a one-shot unconfined retry
133 ApprovalToolLabelConfigWrite string // user-facing label for Reasonix-managed config write approvals
134 ConfigWriteSubjectPrefix string // subject prefix before the config file path for managed config write approval
135 ConfigWriteReason string // reason shown for managed config write approval
136 ConfigWriteDeclined string // model-facing denial when the user declines a managed config write
137 ConfigWriteApprovalChoices string // approval choice list for managed config write prompts
138 PermissionSavedFmt string // permission rule saved notice: path, rule
139 PermissionAlreadyAllowedFmt string // permission rule already covered notice: path, rule
140 PermissionSaveFailedFmt string // permission rule save failure notice: rule, error
141 PlanModeReadOnlyCommandTrustSavedFmt string // plan-mode bash read-only prefix saved notice: path, prefix
142 PlanModeReadOnlyCommandTrustAlreadyFmt string // plan-mode bash read-only prefix already covered notice: path, prefix
143 PlanModeReadOnlyCommandTrustFailedFmt string // plan-mode bash read-only prefix save failure notice: prefix, error
144 DiffFoldedFmt string // "… +%d more lines" footer when a writer diff is folded
145 DiffFoldEnabledFmt string // notice when /diff-fold enables folding, %d = line limit
146 DiffFoldDisabled string // notice when /diff-fold disables folding (shows all lines)
147
148 // `ask` tool question card.
149 AskTypeSomething string // the "type your own answer" option label
150 AskTypingHint string // shown on that row while entering free text
151 AskChatInstead string // the "don't pick, just chat" option label
152 ChatStatusQuestion string // shortcuts hint while a question card is open
153 StatusResumePicker string // status tag while the resume picker is open (e.g. "select session")
154 AskSubmitTitle string // submit-tab title in the ask tool question card
155 AskUnanswered string // placeholder for an unanswered ask question
156 AskSubmitHint string // submit-tab keyboard hint
157
158 // output style listing (/output-style).
159 OutputStyleNone string // no styles available
160 ThemeHeader string // header above the /theme listing
161 ThemeHint string // how to select a theme
162 ThemeChangedFmt string // "/theme <name>" succeeded
163 ThemeUnknownFmt string // "/theme <name>" unknown
164 LanguageHeader string // header above the /language listing
165 LanguageHint string // how to select a language
166 LanguageChangedFmt string // "/language <tag>" succeeded, %s = saved tag, %s = resolved tag
167 CurrencyHeader string // header above the /currency listing
168 CurrencyHint string // how to select a pricing currency
169 CurrencyChangedFmt string // "/currency <mode>" succeeded, %s = saved mode, %s = resolved currency
170 RuntimeRefreshBusy string // runtime-affecting setting cannot change while work is active
171 RuntimeRefreshUnavailable string // current session cannot rebuild after a runtime-affecting setting change
172
173 // context compaction card (CompactionStarted / CompactionDone events).
174 CompactionWorking string // shown while the summarizer runs
175 CompactionTitle string // card header before "· N messages · <trigger>"
176 CompactionUnit string // the noun counted, e.g. "messages"
177 CompactionAuto string // trigger label: reached the window threshold
178 CompactionManual string // trigger label: user ran /compact
179
180 // extension structured-UI surfaces (ExtensionSurface / ExtensionStatus events).
181 ExtFormFieldsHint string // form card: field values are collected through the usual prompts
182 ExtRunActionFmt string // card action hint, one %s = the /<plugin>:<action> slash name
183
184 // chat TUI slash commands.
185 SlashCompactFailed string // "/compact" errored, prefixed before the underlying error
186 SlashNewDone string // "/new" succeeded
187 SlashNewFailed string // "/new" errored
188 SlashClearPrompt string // "/clear" destructive confirmation prompt
189 SlashClearDone string // "/clear" succeeded
190 SlashClearFailed string // "/clear" errored
191 SlashClsDone string // "/cls" succeeded
192 SlashTodoCleared string // "/todo" dismissed the pinned task list
193 SlashUnknown string // shown when the user types an unrecognised "/cmd"
194 SlashUnknownSentAsMessage string // suffix: the unrecognised "/cmd" line was sent as a regular message
195 SlashPromptEmpty string // an MCP prompt returned no text to send
196 SlashMCPNone string // /mcp when no MCP servers are connected
197 CtrlCQuitHint string // shown on first Ctrl+C while idle; second press exits
198 CompHintSlash string // key hint footer under the slash-command menu
199 CompHintFile string // key hint footer under the @ file/resource menu
200 MouseCopiedHint string // transient status-line hint after a mouse/Ctrl+C selection copy
201 ClipboardCopyOSC52Hint string // copy was sent through OSC 52 because the session is remote
202 ClipboardCopyFallbackHint string // native clipboard failed and copy fell back to OSC 52
203 ClipboardTextPasteRemoteHint string // mouse paste cannot read the user's local clipboard/PRIMARY selection over SSH
204 ClipboardTextPasteFailedFmt string // text clipboard read failed, one %v
205 ClipboardImagePastingHint string // shown while an image is being read from the system clipboard
206 ClipboardImagePasteFailedFmt string // image clipboard read failed, one %v
207 MouseCaptureOnHint string // "/mouse" turned in-app mouse handling back on
208 MouseCaptureOffHint string // "/mouse" released mouse capture to the terminal
209 MouseCaptureTag string // persistent status-line marker while mouse capture is off
210
211 // shell execution (! prefix).
212 ShellExecEmpty string // bare "!" with no command
213 ShellExecFailedFmt string // "shell command failed: %v"
214 ShellExecTimeoutFmt string // "shell command timed out (> %s)"
215 ShellModeHint string // status line hint when input starts with !
216
217 // slash command + sub-command descriptions shown in the menu (CLI and desktop
218 // share these via i18n.M, so both frontends localize identically).
219 CmdNew string // /new
220 CmdClear string // /clear
221 CmdCls string // /cls
222 CmdCompact string // /compact
223 CmdRewind string // /rewind
224 CmdTree string // /tree
225 CmdBranch string // /branch
226 CmdSwitchBranch string // /switch
227 CmdResume string // /resume
228 CmdRename string // /rename
229 CmdModel string // /model
230 CmdStatus string // /status
231 CmdWorkMode string // /work-mode
232 CmdDocs string // /docs
233 CmdMemory string // /memory
234 CmdMigrate string // /migrate
235 CmdGoal string // /goal
236 CmdRemember string // /remember
237 CmdForget string // /forget
238 CmdMcp string // /mcp
239 CmdRemote string // /remote
240 CmdHooks string // /hooks
241 CmdPlugins string // /plugins
242 CmdPasteImage string // /paste-image
243 CmdOutputStyle string // /output-style
244 CmdTheme string // /theme
245 CmdLanguage string // /language
246 CmdCurrency string // /currency
247 CmdSkill string // /skills
248 CmdVerbose string // /verbose
249 CmdReloadCmd string // /reload-cmd
250 CmdReload string // /reload
251 CmdDiffFold string // /diff-fold
252 CmdSandbox string // /sandbox
253 CmdEffort string // /effort
254 CmdMouse string // /mouse
255 CmdReasonLang string // /reasoning-language
256 CmdHelp string // /help
257 CmdTodo string // /todo
258 CmdQuit string // /quit (also accepts /exit as hidden alias)
259 CmdCopy string // /copy
260 CmdExport string // /export
261 SlashCopyDone string // "/copy" succeeded
262 SlashCopyEmpty string // no assistant response to copy
263 SlashCopyListHeader string // header shown before the numbered list
264 SlashExportDoneFmt string // "/export" succeeded, %s = file path
265 SlashExportEmpty string // no messages to export
266 ArgSkillShow string // /skills show
267 ArgSkillNew string // /skills new
268 ArgSkillPaths string // /skills paths
269 ArgMcpAdd string // /mcp add
270 ArgMcpRemove string // /mcp remove
271 ArgMcpConnected string // /mcp remove <server> tag
272 ArgHooksList string // /hooks list
273 ArgModelCurrent string // /model <ref> active tag
274 ArgEffortAuto string // /effort auto
275 ArgEffortLow string // /effort low
276 ArgEffortMedium string // /effort medium
277 ArgEffortHigh string // /effort high
278 ArgEffortXHigh string // /effort xhigh
279 ArgEffortMax string // /effort max
280 ArgThemeCurrent string // /theme <style> active tag
281 ArgLanguageAuto string // /language auto
282 ArgLanguageEn string // /language en
283 ArgLanguageZh string // /language zh
284
285 // management listing notices (the Submit path: desktop / HTTP frontends)
286 ListModelsHeaderFmt string // "models (active: %s)"
287 ListModelsHint string // how to switch
288 ListMemorySaved string // "saved memories"
289 ListMemoryArchived string // "archived memories"
290 ListMemoryNone string // no memory docs
291 ListSkillsHeaderFmt string // "skills (%d)"
292 ListSkillsNone string // no skills
293 ListHooksHeaderFmt string // "hooks (%d active)"
294 ListHooksNone string // no hooks
295 ListMcpHeader string // "mcp servers"
296 ListMcpNone string // no mcp servers
297
298 // in-chat memory/model/rewind notices.
299
300 MemoryEditHint string
301 ForgetUsage string
302 ForgetDoneFmt string
303 QuickRememberEmpty string
304 QuickRememberDoneFmt string
305 GoalEmpty string
306 GoalCurrentFmt string
307 GoalSetFmt string
308 GoalCleared string
309 GoalNotRunning string
310 GoalNotPaused string
311 GoalPaused string
312 GoalPausedReason string
313 GoalPausedFmt string // %s = stop cause
314 GoalBudgetExtended string
315 GoalRuntimeFmt string // turns used/limit, tokens used, no-progress, extensions
316 GoalRuntimeLastReason string
317 ModelSwitchUnavailable string
318 ModelSwitchBusy string
319 ModelAlreadyOnFmt string
320 ModelSwitchingFmt string
321 ModelSwitchedFmt string
322 ModelListHeader string
323 RuntimeSwitchPending string
324 RuntimeReloadQueued string // /reload queued behind active work; the idle drain runs it
325 RuntimeReloaded string // /reload completed (no generation available)
326 RuntimeReloadedGenerationFmt string // /reload completed; %d is the runtime build generation
327 WorkModeStatusFmt string
328 WorkModeListHeaderFmt string
329 WorkModeListHint string
330 WorkModeEconomyLabel string
331 WorkModeBalancedLabel string
332 WorkModeDeliveryLabel string
333 WorkModeEconomyDesc string
334 WorkModeBalancedDesc string
335 WorkModeDeliveryDesc string
336 WorkModeUsage string
337 WorkModeSwitchUnavailable string
338 WorkModeSwitchBusy string
339 WorkModeAlreadyOnFmt string
340 WorkModeSwitchingFmt string
341 WorkModeSwitchedFmt string
342 RewindNone string
343 RewindCodeConversation string
344 RewindConversationOnly string
345 RewindCodeOnly string
346 RewindFork string
347 RewindSummarizeFrom string
348 RewindSummarizeUpto string
349 RewindPickTitle string
350 RewindPickHint string
351 RewindRestoreTitleFmt string
352 RewindApplyHint string
353 RewindCoverageTitle string
354 RewindCoverageWarningFmt string
355 RewindConfirmHint string
356 RewindUnavailableFmt string
357 RewindEmpty string
358
359 // skill picker overlay (/skills interactive panel in CLI TUI)
360 SkillPickerAvailableFmt string
361 SkillPickerMatchingFmt string // "%d matching · %d total" when searching
362 SkillPickerHint string
363 SkillPickerDetailHint string
364 SkillPickerSearchEmpty string
365 SkillPickerSearchPlaceholder string
366 SkillPickerSourceTitle string
367 SkillPickerSourceActiveFmt string
368 SkillPickerSourceHint string
369 SkillPickerDiagHidden string
370 SkillPickerDiagShown string
371 SkillPickerBuiltinSource string
372 SkillPickerRescanned string
373 SkillPickerNoDescription string
374 SkillPickerScopeProject string
375 SkillPickerScopeCustom string
376 SkillPickerScopeGlobal string
377 SkillPickerScopeBuiltin string
378 SkillPickerSubagent string
379 SkillPickerAvailableLabel string
380 SkillPickerDisabledLabel string
381 SkillPickerNoChanges string
382 SkillPickerSourceSkillsHint string
383 SkillPickerSourceSkillsEmpty string
384 SkillPickerActionToggle string
385 SkillPickerActionDelete string
386 SkillPickerDeleteTitleFmt string // "Delete skill %s?"
387 SkillPickerDeleteConfirm string
388 SkillPickerDeleteCancel string
389 SkillPickerDeleteHint string
390 SkillPickerDeletedFmt string // "deleted skill %s"
391 SkillPickerMoreAboveFmt string // "↑ %d more above"
392 SkillPickerMoreBelowFmt string // "↓ %d more below"
393 SkillPickerTokenFmt string // "~%d tok"
394 SkillPickerDetailMetaFmt string // "Scope: %s Run as: %s"
395 SkillPickerSkillsUnit string // "skills" (used as "%d skills")
396 SkillPickerLinesUnit string // "lines" (used as "+N more lines")
397 SkillPickerStatusLabel string // shown in the TUI status bar while picker is open
398 SkillPickerStatusOK string // "ok" path status label
399 SkillPickerStatusMissing string // "missing" path status label
400 SkillPickerStatusNotDir string // "not-directory" path status label
401 SkillPickerStatusUnreadable string // "unreadable" path status label
402
403 // init wizard
404 EnterAPIKeysHeader string // header before the per-env-var prompts
405 WroteFileFmt string // "Wrote %s" — used for reasonix.toml and .env both
406 SetupComplete string // success line at end of init
407 SetupCancelled string // shown when the user aborts the wizard
408 TryHintFmt string // "Try: %s" — %s = command to try (styled)
409 NextHint string // non-interactive post-write hint
410 ConfirmReconfigureFmt string // "%s already exists. Reconfigure and overwrite?"
411 NotOverwritingFmt string // non-interactive overwrite refusal
412 SetupManagerTitle string
413 SetupAddOpenAI string
414 SetupAddAnthropic string
415 SetupProviderExistsFmt string
416 SetupSaveExit string
417 SetupSaveExitDesc string
418 SetupCancel string
419 SetupCancelDesc string
420 SetupModelsUnit string
421 SetupKeySet string
422 SetupKeyMissing string
423 SetupDefaultBadge string
424 SetupProviderActionsFmt string
425 SetupEditProvider string
426 SetupUpdateKey string
427 SetupTestRefresh string
428 SetupSetDefault string
429 SetupRemoveProvider string
430 SetupBack string
431 SetupPromptModels string
432 SetupSharedKeyWarningFmt string
433 SetupPromptAPIKeyFmt string
434 SetupSelectDefaultModel string
435 SetupConfirmRemoveFmt string
436 SetupSummaryTitle string
437 SetupSummaryAddedFmt string
438 SetupSummaryEditedFmt string
439 SetupSummaryRemovedFmt string
440 SetupSummaryDefaultFmt string
441 SetupSummaryKeysFmt string
442 SetupSummaryNoChanges string
443 SetupConfirmSave string
444 SetupConcurrentChangeFmt string
445
446 // model fetching
447 FetchingModelsFmt string // "Fetching models for %s..."
448 FetchModelsSuccessFmt string // "Found %d models for %s"
449 FetchModelsFailedFmt string // "Failed to fetch models for %s: %v"
450 FetchModelsUsingPresetsFmt string // "Live fetch unavailable for %s, using preset model list"
451 SelectModelsLabel string // "Select models to enable for %s"
452 CustomFetchEmpty string // "/models returned an empty list — falling back to manual entry"
453 AnthropicFetchEmpty string // "/models returned an empty list — Anthropic-compatible providers usually don't expose one, falling back to manual entry"
454 APIKeyAlreadySetFmt string // "reusing existing value for %s"
455 APIKeyResetPromptFmt string // "Re-enter %s?"
456 InvalidAPIKeyEnvFmt string // "%q is not a valid API Key variable name..."
457 RepairedAPIKeyEnvFmt string // "provider %s: replaced invalid api_key_env %q with %q"
458
459 // custom provider
460 CustomProviderDesc string // "Add third-party OpenAI compatible model"
461 CustomAddMethodLabel string // "Select add method"
462 CustomMethodManual string // "Enter model name manually"
463 CustomMethodURL string // "Fetch models from URL"
464 CustomPromptModel string // "Enter model name"
465 CustomPromptBaseURL string // "Enter Base URL"
466 CustomPromptKeyEnv string // "Enter API Key env var name"
467 CustomPromptAPIKey string // "Enter API Key"
468 CustomAddedFmt string // "Added custom model: %s"
469
470 // Anthropic compatible provider
471 AnthropicProviderDesc string // "Add Anthropic API compatible model"
472 AnthropicAddMethodLabel string // "Select add method"
473 AnthropicMethodManual string // "Enter model name manually"
474 AnthropicMethodURL string // "Fetch models from URL"
475 AnthropicPromptModel string // "Enter model name"
476 AnthropicPromptBaseURL string // "Enter Base URL"
477 AnthropicPromptKeyEnv string // "Enter API Key env var name"
478 AnthropicPromptAPIKey string // "Enter API Key"
479 AnthropicAddedFmt string // "Added Anthropic compatible model: %s"
480 AnthropicFetchingModelsFmt string // "Fetching models for %s..."
481 AnthropicFetchModelsSuccessFmt string // "Found %d models for %s"
482 AnthropicFetchModelsFailedFmt string // "Failed to fetch models for %s: %v"
483 AnthropicSelectModelsLabel string // "Select models to enable for %s"
484
485 // remote SSH module
486 RemoteConnectingFmt string // "connecting to %s…"
487 RemoteConnectedFmt string // "connected to %s"
488 RemoteReconnectingFmt string // "reconnecting to %s (attempt %d)…"
489 RemoteDegradedFmt string // "connected to %s but some forwards are down"
490 RemoteDisconnected string // "disconnected"
491 RemoteServeReadyFmt string // "remote serve ready: %s"
492 RemoteHostKeyPromptFmt string // "host %s key (%s): %s"
493 RemotePassphrasePromptFmt string // "passphrase for %s:"
494 RemotePasswordPromptFmt string // "password for %s:"
495 RemoteBootstrapStepFmt string // "remote serve: %s %s"
496 RemoteNoHostsHint string // "no remote hosts configured; add one with `reasonix remote add`"
497
498 // top-level / runAgent
499 UnknownCommandFmt string // "unknown command %q"
500 UsageRunHint string // "usage: reasonix run [--model NAME] <task>"
501 ErrorPrefix string // "error:" — prefix for fatal-error output
502 ReconfigureOnUnknownModel string // shown when the configured model no longer resolves and setup is re-run
503 WriteConfigErr string // "write config:" — prefix for write failure
504 WriteEnvErr string // "write .env:" — prefix for env-write failure
505
506 // provider HTTP error explanations — actionable, reason + fix per status code
507 ProviderErrBadRequest string // 400
508 ProviderErrAuth string // 401 — no key configured / sent
509 ProviderErrAuthRejected string // 401 — a key was sent but the server rejected it
510 ProviderErrInsufficientBalance string // 402
511 ProviderErrUnprocessable string // 422
512 ProviderErrInputSensitive string // MiniMax 1026
513 ProviderErrOutputSensitive string // MiniMax 1027
514 ProviderErrRateLimited string // 429
515 ProviderErrServer string // 500
516 ProviderErrServerBusy string // 503
517
518 // selection menus
519 SelectOneHint string // "(↑/↓ · Enter · q to cancel)"
520 SelectManyHint string // "(↑/↓ · Space · Enter · q)"
521 SelectMoreAboveFmt string // "↑ %d more above"
522 SelectMoreBelowFmt string // "↓ %d more below"
523 SelectSearchHint string // "/ to search · Esc to cancel"
524
525 // /provider command
526 CmdProvider string // /provider
527 ProviderListHeader string // header for /provider list
528 ProviderAlreadyOnFmt string // already on provider
529 ProviderUnknownFmt string // unknown provider
530 ProviderPickLabel string // label for provider model picker
531 ProviderNoModelsFmt string // provider has no models
532
533 // `reasonix upgrade` / `reasonix update` — self-update
534 UpgradeChecking string // "Checking for updates…"
535 UpgradeChannelDeprecated string // legacy channel selection is ignored
536 UpgradeDevBuild string // dev builds cannot self-update
537 UpgradeFetchFailed string // "failed to check for updates: %v"
538 UpgradeInvalidVersion string // remote version not valid semver
539 UpgradeAlreadyLatest string // already on the latest version
540 UpgradeForcing string // "Reinstalling the same version…"
541 UpgradeAvailableFmt string // "Current: %s → Latest: %s"
542 UpgradeNoAssetFmt string // "no binary found for %s"
543 UpgradeDownloadingFmt string // "Downloading %s (%s)…"
544 UpgradeDownloadFailed string // "download failed: %v"
545 UpgradeVerifying string // "Verifying checksum…"
546 UpgradeChecksumFailed string // "could not fetch checksum file: %v"
547 UpgradeChecksumMismatchFmt string // SHA256 mismatch detail
548 UpgradeChecksumNotFoundFmt string // asset not listed in SHA256SUMS
549 UpgradeExtractFailed string // "failed to extract binary: %v"
550 UpgradeApplying string // "Replacing binary…"
551 UpgradeApplyFailed string // "failed to apply update: %v"
552 UpgradeSuccessFmt string // "Updated %s → %s"
553
554 // `reasonix report` — local CLI crash review and explicit upload
555 ReportNoPending string
556 ReportHeaderFmt string
557 ReportCapturedFmt string
558 ReportPreviewOnlyFmt string
559 ReportSendPrompt string
560 ReportKept string
561 ReportDeletedFmt string
562 ReportSentFmt string
563 ReportConfigFailedFmt string
564 ReportUploadFailedFmt string
565 ReportSentDeleteFailedFmt string
566 ReportUsageBody string
567
568 // First eligible interactive CLI telemetry consent.
569 CLITelemetryConsentNotice string
570 CLITelemetryConsentPrompt string
571 CLITelemetryConsentInvalid string
572 CLITelemetryConsentSaveFailedFmt string
573 CLITelemetryConsentCleanupFailedFmt string
574
575 // usage / help
576 UsageBody string // full multi-line help text
577 }
578
579 // ProviderStatusMessage returns an actionable explanation for a known provider
580 // HTTP status, or "" when the status has no specific guidance.
581 func (m Messages) ProviderStatusMessage(status int) string {
582 switch status {
583 case 400:
584 return m.ProviderErrBadRequest
585 case 401, 403:
586 return m.ProviderErrAuth
587 case 402:
588 return m.ProviderErrInsufficientBalance
589 case 422:
590 return m.ProviderErrUnprocessable
591 case 429:
592 return m.ProviderErrRateLimited
593 case 500:
594 return m.ProviderErrServer
595 case 503:
596 return m.ProviderErrServerBusy
597 }
598 return ""
599 }
600
601 // M is the active catalogue. DetectLanguage replaces it; English is the
602 // default so any code path that runs before detection still has text.
603 var (
604 M = English
605 currentLanguage = "en"
606 )
607
608 // CurrentLanguage returns the language tag installed by the latest
609 // DetectLanguage call. It lets frontends reuse the resolved locale without
610 // re-reading the environment and accidentally ignoring an explicit override.
611 func CurrentLanguage() string {
612 return currentLanguage
613 }
614
615 // DetectLanguage selects a catalogue from override (e.g. cfg.Language) or the
616 // environment and installs it as M. Returns the resolved tag ("en", "zh") so
617 // callers can log or expose it.
618 //
619 // Priority: override > REASONIX_LANG > LC_ALL > LC_MESSAGES > LANG > "en".
620 func DetectLanguage(override string) string {
621 for _, c := range append([]string{override}, envCandidates()...) {
622 if tag := normalize(c); tag != "" {
623 return setLanguage(tag)
624 }
625 }
626 return setLanguage("en")
627 }
628
629 func envCandidates() []string {
630 keys := []string{"REASONIX_LANG", "LC_ALL", "LC_MESSAGES", "LANG"}
631 out := make([]string, len(keys))
632 for i, k := range keys {
633 out[i] = os.Getenv(k)
634 }
635 return out
636 }
637
638 func setLanguage(tag string) string {
639 switch tag {
640 case "zh-tw", "zh-TW":
641 M = ChineseTraditional
642 currentLanguage = "zh-TW"
643 case "zh":
644 M = Chinese
645 currentLanguage = "zh"
646 default:
647 M = English
648 currentLanguage = "en"
649 }
650 return currentLanguage
651 }
652
653 // normalize maps a locale string (e.g. "zh_CN.UTF-8", "zh-Hans-CN", "Chinese
654 // (China)") to a short tag this package knows about. Returns "" for empty or
655 // unrecognised input so DetectLanguage can fall through to the next candidate.
656 func normalize(s string) string {
657 s = strings.ToLower(strings.TrimSpace(s))
658 s = strings.ReplaceAll(s, "_", "-") // zh_TW.UTF-8 → zh-tw.utf-8 (POSIX locales use underscores)
659 if s == "" {
660 return ""
661 }
662 if strings.HasPrefix(s, "zh-tw") || strings.HasPrefix(s, "zh-hant") || strings.Contains(s, "chinese traditional") || strings.Contains(s, "繁體") {
663 return "zh-TW"
664 }
665 if strings.HasPrefix(s, "zh") || strings.Contains(s, "chinese") || strings.Contains(s, "中文") {
666 return "zh"
667 }
668 if strings.HasPrefix(s, "en") || strings.Contains(s, "english") {
669 return "en"
670 }
671 return ""
672 }
673
673 lines GO