返回 CodeWhale
localization.rs
根目录 / crates / tui / src / localization.rs
1 //! Lightweight localization registry for high-visibility TUI strings.
2 //!
3 //! This intentionally covers UI chrome only. It does not change model prompts,
4 //! model output language, provider behavior, or media payload semantics.
5 use std::borrow::Cow;
6 use unicode_segmentation::UnicodeSegmentation;
7 use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
8
9 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10 pub enum Locale {
11 En,
12 Ja,
13 ZhHans,
14 ZhHant,
15 PtBr,
16 Es419,
17 Vi,
18 Ko,
19 Ca,
20 De,
21 Fr,
22 Id,
23 Hi,
24 Ru,
25 Uk,
26 }
27
28 impl Locale {
29 pub fn tag(self) -> &'static str {
30 match self {
31 Self::En => "en",
32 Self::Ja => "ja",
33 Self::ZhHans => "zh-Hans",
34 Self::ZhHant => "zh-Hant",
35 Self::PtBr => "pt-BR",
36 Self::Es419 => "es-419",
37 Self::Vi => "vi",
38 Self::Ko => "ko",
39 Self::Ca => "ca",
40 Self::De => "de",
41 Self::Fr => "fr",
42 Self::Id => "id",
43 Self::Hi => "hi",
44 Self::Ru => "ru",
45 Self::Uk => "uk",
46 }
47 }
48
49 pub fn translation_target_name(self) -> &'static str {
50 match self {
51 Self::En => "English",
52 Self::Ja => "Japanese (日本語)",
53 Self::ZhHans => "Simplified Chinese (简体中文)",
54 Self::ZhHant => "Traditional Chinese (繁體中文)",
55 Self::PtBr => "Brazilian Portuguese (Português do Brasil)",
56 Self::Es419 => "Latin American Spanish (Español latinoamericano)",
57 Self::Vi => "Vietnamese (Tiếng Việt)",
58 Self::Ko => "Korean (한국어)",
59 Self::Ca => "Catalan (Català)",
60 Self::De => "German (Deutsch)",
61 Self::Fr => "French (Français)",
62 Self::Id => "Indonesian (Bahasa Indonesia)",
63 Self::Hi => "Hindi (हिन्दी)",
64 Self::Ru => "Russian (Русский)",
65 Self::Uk => "Ukrainian (Українська)",
66 }
67 }
68
69 /// Every locale the TUI exposes in pickers and runtime resolution.
70 pub fn shipped() -> &'static [Self] {
71 &[
72 Self::En,
73 Self::Ja,
74 Self::ZhHans,
75 Self::ZhHant,
76 Self::PtBr,
77 Self::Es419,
78 Self::Vi,
79 Self::Ko,
80 Self::Ca,
81 Self::De,
82 Self::Fr,
83 Self::Id,
84 Self::Hi,
85 Self::Ru,
86 Self::Uk,
87 ]
88 }
89
90 /// Complete UI packs held to `en.json` parity.
91 pub fn shipped_complete() -> &'static [Self] {
92 &[
93 Self::En,
94 Self::Ja,
95 Self::ZhHans,
96 Self::ZhHant,
97 Self::PtBr,
98 Self::Es419,
99 Self::Vi,
100 Self::Ko,
101 Self::Ca,
102 Self::De,
103 Self::Fr,
104 Self::Id,
105 Self::Hi,
106 Self::Ru,
107 Self::Uk,
108 ]
109 }
110
111 #[must_use]
112 pub fn is_partial_pack(self) -> bool {
113 false
114 }
115 }
116
117 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
118 pub enum MessageId {
119 ComposerPlaceholder,
120 ComposerDispatchFailedRestored,
121 DispatchFailedQueued,
122 DispatchFailedInitial,
123 HistorySearchPlaceholder,
124 HistorySearchTitle,
125 HistoryHintMove,
126 HistoryHintAccept,
127 HistoryHintRestore,
128 HistoryNoMatches,
129 // StatusPicker — `/statusline` multi-select footer-item picker.
130 StatusPickerTitle,
131 StatusPickerInstruction,
132 StatusPickerActionToggle,
133 StatusPickerActionAll,
134 StatusPickerActionNone,
135 StatusPickerActionSave,
136 StatusPickerActionCancel,
137 // Hotbar setup wizard chrome and validation.
138 HotbarSetupTitle,
139 HotbarSetupSourceApp,
140 HotbarSetupSourceSlash,
141 HotbarSetupSourceMcp,
142 HotbarSetupSourceSkill,
143 HotbarSetupSourcePlugin,
144 HotbarSetupStatusDisabled,
145 HotbarSetupStatusPrefill,
146 HotbarSetupStatusReady,
147 HotbarSetupDirtyModified,
148 HotbarSetupDirtyClean,
149 HotbarSetupNoAction,
150 HotbarSetupStatusLine,
151 HotbarSetupSlotOutOfRange,
152 HotbarSetupNoActionSelected,
153 HotbarSetupCannotAssign,
154 HotbarSetupNoActions,
155 HotbarSetupRecommended,
156 HotbarSetupEmptySlot,
157 HotbarSetupHelp,
158 HotbarActionVoiceToggleName,
159 HotbarActionVoiceToggleDescription,
160 HotbarActionSessionCompactName,
161 HotbarActionSessionCompactDescription,
162 HotbarActionModePlanName,
163 HotbarActionModePlanDescription,
164 HotbarActionModeAgentName,
165 HotbarActionModeAgentDescription,
166 HotbarActionModeYoloName,
167 HotbarActionModeYoloDescription,
168 HotbarActionModeOperateName,
169 HotbarActionModeOperateDescription,
170 HotbarActionReasoningCycleName,
171 HotbarActionReasoningCycleDescription,
172 HotbarActionReasoningCycleAutoDisabled,
173 HotbarActionSidebarToggleName,
174 HotbarActionSidebarToggleDescription,
175 HotbarActionFileTreeToggleName,
176 HotbarActionFileTreeToggleDescription,
177 HotbarActionPaletteOpenName,
178 HotbarActionPaletteOpenDescription,
179 HotbarActionTrustToggleName,
180 HotbarActionTrustToggleDescription,
181 CommandPaletteTitle,
182 CommandPaletteSubtitle,
183 ConfigTitle,
184 ConfigSubtitle,
185 ConfigModalTitle,
186 ConfigSearchPlaceholder,
187 ConfigNoSettings,
188 ConfigNoMatchesPrefix,
189 ConfigFilteredSettings,
190 ConfigShowing,
191 ConfigFooterDefault,
192 ConfigFooterScrollable,
193 ConfigFooterFiltered,
194 ConfigSectionProvider,
195 ConfigSectionModel,
196 ConfigSectionPermissions,
197 ConfigSectionNetwork,
198 ConfigSectionDisplay,
199 ConfigSectionComposer,
200 ConfigSectionSidebar,
201 ConfigSectionHistory,
202 ConfigSectionMcp,
203 ConfigSectionFleet,
204 ConfigSectionWorkflow,
205 ConfigSectionSession,
206 ConfigSectionLegacy,
207 ConfigSectionExperimental,
208 ConfigScopeSession,
209 ConfigScopeSaved,
210 ConfigEditCancelled,
211 ConfigEditTitlePrefix,
212 ConfigEditScopeLabel,
213 ConfigEditCurrentLabel,
214 ConfigEditHintLabel,
215 ConfigEditNewLabel,
216 ConfigEditFooter,
217 ConfigLocalePartialBadge,
218 ConfigLocalePartialDetail,
219 ConfigRowEffective,
220 ConfigDefaultValue,
221 ConfigDefaultReasoning,
222 ConfigUnavailable,
223 ConfigLabelProvider,
224 ConfigLabelBaseUrlDeepseek,
225 ConfigLabelProviderUrl,
226 ConfigLabelModel,
227 ConfigLabelFastModel,
228 ConfigLabelDefaultModel,
229 ConfigLabelReasoningEffort,
230 ConfigLabelApprovalMode,
231 ConfigLabelPermissionPosture,
232 ConfigLabelApprovalPolicy,
233 ConfigLabelManagedApprovalPolicy,
234 ConfigLabelDefaultMode,
235 ConfigLabelAllowShell,
236 ConfigLabelManagedAllowShell,
237 ConfigLabelStreamTimeout,
238 ConfigLabelTheme,
239 ConfigLabelLocale,
240 ConfigLabelBackground,
241 ConfigLabelOceanTreatment,
242 ConfigLabelWorkSurfacePlacement,
243 ConfigLabelTopHeight,
244 ConfigLabelSideWidth,
245 ConfigLabelCalmMode,
246 ConfigLabelLowMotion,
247 ConfigLabelFancyAnimations,
248 ConfigLabelLaunchScreen,
249 ConfigLabelShowThinking,
250 ConfigLabelThinkingHighlight,
251 ConfigLabelShowToolDetails,
252 ConfigLabelInlineDiffs,
253 ConfigLabelStatusIndicator,
254 ConfigLabelSynchronizedOutput,
255 ConfigLabelCostCurrency,
256 ConfigLabelTranscriptSpacing,
257 ConfigLabelToolCollapse,
258 ConfigLabelComposerDensity,
259 ConfigLabelComposerBorder,
260 ConfigLabelComposerVimMode,
261 ConfigLabelBracketedPaste,
262 ConfigLabelPasteBurstDetection,
263 ConfigLabelMentionMenuLimit,
264 ConfigLabelMentionMenuBehavior,
265 ConfigLabelMentionWalkDepth,
266 ConfigLabelWorkspaceFollowSymlinks,
267 ConfigLabelSidebarWidth,
268 ConfigLabelSidebarFocus,
269 ConfigLabelContextPanel,
270 ConfigLabelSessionsRail,
271 ConfigLabelSessionAutoResume,
272 ConfigLabelAutoCompact,
273 ConfigLabelAutoCompactThreshold,
274 ConfigLabelMaxHistory,
275 ConfigLabelMcpConfigPath,
276 ConfigLabelFleetSpawnDepth,
277 ConfigLabelGoalCommand,
278 ConfigLabelWorkflow,
279 ConfigLabelFeaturePrefix,
280 ConfigColumnSetting,
281 ConfigColumnValue,
282 ConfigColumnScope,
283 ConfigActionOpenProvider,
284 ConfigActionOpenModel,
285 ConfigActionToggle,
286 ConfigActionChoose,
287 ConfigActionEdit,
288 ConfigActionReadOnly,
289 ModelPickerAutoNetworkHint,
290 ModelPickerAutoNetworkActiveProviderHint,
291 ModelPickerAutoLocalHint,
292 ModelPickerAutoLastRoute,
293 AutoRouteSelectedToast,
294 HelpTitle,
295 HelpSubtitle,
296 HelpFilterPlaceholder,
297 HelpFilterPrefix,
298 HelpNoMatches,
299 HelpSlashCommands,
300 HelpKeybindings,
301 HelpUserCommands,
302 HelpSkills,
303 HelpFooterTypeFilter,
304 HelpFooterMove,
305 HelpFooterJump,
306 HelpFooterClose,
307 CmdAttachDescription,
308 CmdAnchorDescription,
309 CmdCacheDescription,
310 CmdPreviewRequestDescription,
311 CmdToolsDescription,
312 CmdTurnInspectDescription,
313 CmdChangeDescription,
314 CmdEffortDescription,
315 CmdChangeHeader,
316 CmdChangeTranslationQueued,
317 CmdChangeTranslationUnavailable,
318 CmdChangePreviousVersion,
319 CmdBalanceDescription,
320 CmdClearDescription,
321 CmdCompactDescription,
322 CmdPurgeDescription,
323 CmdConfigDescription,
324 CmdPermissionsDescription,
325 PermissionsListHeader,
326 PermissionsNoRules,
327 PermissionsFileMissing,
328 PermissionsFileEmpty,
329 PermissionsFilePresent,
330 PermissionsRuleEntry,
331 PermissionsMatchExactCommand,
332 PermissionsMatchCommandPrefix,
333 PermissionsMatchExactPath,
334 PermissionsMatchAnyInvocation,
335 PermissionsScopeGlobal,
336 PermissionsScopeRepo,
337 PermissionsAppliesHere,
338 PermissionsInactiveHere,
339 PermissionsRemovePreview,
340 PermissionsRemoved,
341 PermissionsUsage,
342 PermissionsRuleNotFound,
343 PermissionsOperationFailed,
344 CmdAuthDescription,
345 CmdConstitutionDescription,
346 CmdContextDescription,
347 CmdCostDescription,
348 CmdDiffDescription,
349 CmdEditDescription,
350 CmdExitDescription,
351 CmdExportDescription,
352 CmdFeedbackDescription,
353 CmdHfDescription,
354 CmdHelpDescription,
355 CmdProfileDescription,
356 CmdHomeDescription,
357 CmdHooksDescription,
358 CmdAgentDescription,
359 CmdGoalDescription,
360 CmdInitDescription,
361 CmdJobsDescription,
362 CmdLinksDescription,
363 CmdLoadDescription,
364 CmdLogoutDescription,
365 CmdMcpDescription,
366 CmdMemoryDescription,
367 CmdPluginDescription,
368 CmdPluginBundleUsage,
369 CmdPluginBundleNoneFound,
370 CmdPluginBundleListHeader,
371 CmdPluginLegacyListHeader,
372 CmdPluginBundleNotFound,
373 CmdPluginBundleReloaded,
374 CmdPluginBundleDetail,
375 CmdPluginBundleDiagnosticsHeader,
376 CmdPluginBundleMutationSuccess,
377 CmdPluginActionFailed,
378 CmdPluginNoneFound,
379 CmdPluginNotFound,
380 CmdPluginListHeader,
381 CmdPluginDetailDescription,
382 CmdPluginDetailSchema,
383 CmdPluginDetailApproval,
384 CmdPluginDetailPath,
385 CmdModeDescription,
386 CmdModelDescription,
387 CmdModelsDescription,
388 CmdModelDbDescription,
389 CmdNetworkDescription,
390 CmdNoteDescription,
391 CmdThemeDescription,
392 CmdProviderDescription,
393 CmdQueueDescription,
394 CmdQueueUsage,
395 CmdQueueDraftHeader,
396 CmdQueueNoMessages,
397 CmdQueueListHeader,
398 CmdQueueTip,
399 CmdQueueAlreadyEditing,
400 CmdQueueNotFound,
401 CmdQueueEditingStatus,
402 CmdQueueEditingMessage,
403 CmdQueueDropped,
404 CmdQueueAlreadyEmpty,
405 CmdQueueCleared,
406 CmdQueueMissingIndex,
407 CmdQueueIndexPositive,
408 CmdQueueIndexMin,
409 CmdRelayDescription,
410 CmdRemoteControlDescription,
411 CmdRenameDescription,
412 CmdRestoreDescription,
413 CmdRetryDescription,
414 CmdReviewDescription,
415 CmdRlmDescription,
416 CmdSaveDescription,
417 CmdForkDescription,
418 CmdNewDescription,
419 CmdSessionsDescription,
420 CmdSettingsDescription,
421 CmdSidebarDescription,
422 CmdSkillDescription,
423 CmdSkillsDescription,
424 CmdStashDescription,
425 CmdStatusDescription,
426 CmdStatuslineDescription,
427 CmdStructcopyDescription,
428 CmdStructcopyKindTurn,
429 CmdStructcopyKindTool,
430 CmdStructcopyKindPlan,
431 CmdStructcopyKindWorkflow,
432 CmdStructcopyUsageError,
433 CmdStructcopyUnavailable,
434 CmdStructcopyBusy,
435 CmdStructcopyPrepareFailed,
436 CmdStructcopyClipboardQueued,
437 CmdStructcopyClipboardAccepted,
438 CmdStructcopyClipboardFailed,
439 CmdStructcopyReceiptTooLarge,
440 CmdFleetDescription,
441 CmdLaneDescription,
442 CmdWorkflowDescription,
443 CmdHotbarDescription,
444 CmdSetupDescription,
445 CmdSubagentsDescription,
446 CmdAdvisorDescription,
447 CmdSystemDescription,
448 CmdAutomationDescription,
449 CmdTaskDescription,
450 CmdTokensDescription,
451 CmdTranslateDescription,
452 CmdTranslateOff,
453 CmdTranslateOn,
454 TranslationInProgress,
455 TranslationComplete,
456 TranslationFailed,
457 CmdTrustDescription,
458 CmdLspDescription,
459 CmdShareDescription,
460 CmdWorkspaceDescription,
461 CmdUndoDescription,
462 CmdVerboseDescription,
463 CmdCacheAdvice,
464 CmdCacheFootnote,
465 CmdCacheHeader,
466 CmdCacheNoData,
467 CmdCacheTotals,
468 CmdCostReport,
469 CmdCostReportSubtotal,
470 CmdCostReportUnknown,
471 CmdCostUnknownValue,
472 CmdCostEstimateOnly,
473 CmdCostCoverage,
474 CmdCostCoverageUnknownLegacy,
475 CmdCostUnpricedTurns,
476 CmdCostUnpricedClasses,
477 CmdCostPricingProvenance,
478 CmdCostLivePricingDowngraded,
479 CmdCostLivePricingUnavailable,
480 CmdCostRoutesHeader,
481 CmdTokensCacheWriteTotal,
482 CmdTokensCacheBoth,
483 CmdTokensCacheHitOnly,
484 CmdTokensCacheMissOnly,
485 CmdTokensContextUnknownWindow,
486 CmdTokensContextWithWindow,
487 CmdTokensNotReported,
488 CmdTokensReport,
489 FooterAgentSingular,
490 FooterAgentsPlural,
491 HeaderAgentsChip,
492 FooterPressCtrlCAgain,
493 FooterWorking,
494 FooterBalancePrefix,
495 HelpSectionActions,
496 HelpSectionClipboard,
497 HelpSectionEditing,
498 HelpSectionHelp,
499 HelpSectionModes,
500 HelpSectionNavigation,
501 HelpSectionSessions,
502 KbScrollTranscript,
503 KbNavigateHistory,
504 KbScrollTranscriptAlt,
505 KbBrowseHistory,
506 KbScrollPage,
507 KbJumpTopBottom,
508 KbJumpTopBottomEmpty,
509 KbJumpToolBlocks,
510 KbMoveCursor,
511 KbJumpLineStartEnd,
512 KbDeleteChar,
513 KbDeleteWord,
514 KbYank,
515 KbToggleFileTree,
516 KbSelectText,
517 KbSelectAllDraft,
518 KbClearDraft,
519 KbRestoreClearedDraft,
520 KbStashDraft,
521 KbSearchHistory,
522 KbInsertNewline,
523 KbSendDraft,
524 KbSteerCurrentTurn,
525 KbCloseMenu,
526 KbCancelOrExit,
527 KbShellControls,
528 KbExitEmpty,
529 KbCommandPalette,
530 KbSettings,
531 KbCancelBackgroundShellJobs,
532 KbFuzzyFilePicker,
533 KbCompactInspector,
534 KbCompactContext,
535 KbLastMessagePager,
536 KbSelectedDetails,
537 KbToolDetailsPager,
538 KbReasoningDetail,
539 KbTurnInspector,
540 KbExternalEditor,
541 KbLiveTranscript,
542 KbBacktrackMessage,
543 KbCompleteCycleModes,
544 KbCycleThinking,
545 KbCyclePermissions,
546 KbJumpPlanAgentYolo,
547 KbAltJumpPlanAgentYolo,
548 KbFocusSidebar,
549 KbSessionPicker,
550 KbTerminalPaste,
551 KbPasteAttach,
552 KbCopySelection,
553 ClipboardSshPasteHint,
554 KbContextMenu,
555 KbAttachPath,
556 KbHelpOverlay,
557 KbToggleHelp,
558 KbToggleHelpSlash,
559 HelpUsageLabel,
560 HelpAliasesLabel,
561 SettingsTitle,
562 SettingsConfigFile,
563 ClearConversation,
564 ClearConversationBusy,
565 ModelChanged,
566 LinksProjectTitle,
567 LinksDocumentation,
568 LinksCommunity,
569 LinksGitHub,
570 LinksManagedApp,
571 LinksManagedAppNote,
572 LinksTitle,
573 LinksDashboard,
574 LinksDocs,
575 LinksKimiCodeRouteNote,
576 LinksTip,
577 SubagentsFetching,
578 HelpUnknownCommand,
579 HomeDashboardTitle,
580 HomeModel,
581 HomeMode,
582 HomeWorkspace,
583 HomeHistory,
584 HomeTokens,
585 HomeQueued,
586 HomeSubagents,
587 HomeSkill,
588 HomeQuickActions,
589 HomeQuickLinks,
590 HomeQuickSkills,
591 HomeQuickConfig,
592 HomeQuickSettings,
593 HomeQuickModel,
594 HomeQuickSubagents,
595 HomeQuickTaskList,
596 HomeQuickHelp,
597 HomeModeTips,
598 HomeAgentModeTip,
599 HomeAgentModeReviewTip,
600 HomeAgentModeYoloTip,
601 HomeYoloModeTip,
602 HomeYoloModeCaution,
603 HomePlanModeTip,
604 HomePlanModeChecklistTip,
605 HomeOperateModeTip,
606 HomeOperateModeFleetTip,
607 HomeGoalModeTip,
608 // Onboarding screens — welcome.
609 OnboardWelcomeVersion,
610 OnboardWelcomeLead,
611 OnboardWelcomeSetupBlurb,
612 OnboardWelcomeSteps,
613 OnboardWelcomeStepLanguage,
614 OnboardWelcomeStepAppearance,
615 OnboardWelcomeStepApiKey,
616 OnboardWelcomeStepTrust,
617 OnboardWelcomeStepMentalModels,
618 OnboardWelcomeStepTips,
619 OnboardWelcomeDefaults,
620 OnboardWelcomeEnter,
621 OnboardWelcomeExit,
622 // Onboarding screens — language picker.
623 OnboardLanguageTitle,
624 OnboardLanguageBlurb,
625 OnboardLanguageFooter,
626 OnboardProviderTitle,
627 OnboardProviderBlurb,
628 OnboardProviderFooter,
629 OnboardApiKeyTitle,
630 OnboardApiKeyStep1,
631 OnboardApiKeyStep2,
632 OnboardApiKeyLocalHint,
633 OnboardApiKeySavedHint,
634 OnboardApiKeyFormatHint,
635 KimiCodePlanApiKeyHint,
636 KimiCodePlanRouteHint,
637 KimiCodePlanNoImportHint,
638 StepfunBillingRouteTitle,
639 StepfunBillingRouteIntro,
640 StepfunBillingRoutePaygOption,
641 StepfunBillingRoutePlanOption,
642 StepfunPlanApiKeyHint,
643 StepfunPlanRouteHint,
644 OnboardApiKeyPlaceholder,
645 OnboardApiKeyLabel,
646 OnboardApiKeyFooter,
647 OnboardApiKeyRejectedEnv,
648 // Onboarding screens — workspace trust prompt.
649 OnboardTrustTitle,
650 OnboardTrustQuestion,
651 OnboardTrustLocationPrefix,
652 OnboardTrustRiskHint,
653 OnboardTrustEffectHint,
654 OnboardTrustFooterPrefix,
655 OnboardTrustFooterMiddle,
656 OnboardTrustFooterUntrustedMiddle,
657 OnboardTrustFooterSuffix,
658 OnboardTrustEnterHint,
659 OnboardTrustUntrustedNotice,
660 // Onboarding screens — product mental model primer.
661 OnboardMentalTitle,
662 OnboardMentalModesLabel,
663 OnboardMentalPlanHint,
664 OnboardMentalActHint,
665 OnboardMentalOperateHint,
666 OnboardMentalPermissionLabel,
667 OnboardMentalCurrentLabel,
668 OnboardMentalConstitution,
669 OnboardMentalCycleMode,
670 OnboardMentalCyclePermission,
671 OnboardMentalContinue,
672 OnboardMentalBack,
673 // Onboarding screens — "Make it yours" appearance step (#3937).
674 OnboardAppearanceTitle,
675 OnboardAppearanceBlurb,
676 OnboardAppearanceFooter,
677 // Onboarding screens — explicit offline ("explore") choice (#3927).
678 OnboardOfflineOption,
679 OnboardOfflineNotice,
680 OnboardOfflineTipsLine,
681 // Onboarding screens — final tips screen.
682 OnboardTipsTitle,
683 OnboardTipsLine1,
684 OnboardTipsLine2,
685 OnboardTipsLine3,
686 OnboardTipsLine4,
687 OnboardTipsDoctorPrefix,
688 OnboardTipsDoctorSuffix,
689 OnboardTipsFooterEnter,
690 OnboardTipsFooterAction,
691 // Constitution-first setup wizard.
692 SetupWizardTitle,
693 SetupWizardWhy,
694 SetupWizardProgress,
695 SetupActionBack,
696 SetupActionContinue,
697 SetupActionSkip,
698 SetupActionRetry,
699 SetupActionScrollBody,
700 SetupActionGuided,
701 SetupActionTuneGuided,
702 SetupActionModelDraft,
703 SetupActionFreeform,
704 SetupActionKeepExisting,
705 SetupActionProvider,
706 SetupActionModel,
707 SetupActionFleet,
708 SetupActionHotbar,
709 SetupActionRemote,
710 SetupActionMode,
711 SetupActionConfig,
712 SetupActionRuntimePreset,
713 SetupActionApplyRuntimePreset,
714 SetupActionUseBundled,
715 SetupActionDefer,
716 SetupActionCancel,
717 SetupStatusNotStarted,
718 SetupStatusRecommended,
719 SetupStatusOptional,
720 SetupStatusDeferred,
721 SetupStatusInProgress,
722 SetupStatusNeedsAction,
723 SetupStatusVerified,
724 SetupStatusSkipped,
725 SetupStatusFailed,
726 SetupStepLanguageTitle,
727 SetupStepLanguageWhy,
728 SetupStepProviderModelTitle,
729 SetupStepProviderModelWhy,
730 SetupStepTrustSandboxTitle,
731 SetupStepTrustSandboxWhy,
732 SetupStepOperateFleetTitle,
733 SetupStepOperateFleetWhy,
734 SetupStepToolsMcpTitle,
735 SetupStepToolsMcpWhy,
736 SetupStepHotbarTitle,
737 SetupStepHotbarWhy,
738 SetupStepRemoteRuntimeTitle,
739 SetupStepRemoteRuntimeWhy,
740 SetupStepPersistenceTitle,
741 SetupStepPersistenceWhy,
742 SetupStepConstitutionTitle,
743 SetupStepConstitutionWhy,
744 SetupStepVerificationTitle,
745 SetupStepVerificationWhy,
746 SetupCheckpointLayerOrder,
747 SetupCheckpointDoneBundled,
748 SetupCheckpointDoneGuided,
749 SetupCheckpointDoneKept,
750 SetupCheckpointDeferred,
751 SetupStepSkipped,
752 SetupStepRetryRecorded,
753 SetupLanguageReviewed,
754 SetupConstitutionChoiceLabel,
755 SetupConstitutionSourceLabel,
756 SetupConstitutionValidityLabel,
757 SetupConstitutionPreviewLabel,
758 SetupConstitutionExistingLabel,
759 SetupConstitutionExpertOverrideLabel,
760 SetupConstitutionGuidedHint,
761 SetupConstitutionGuidedAnswersHint,
762 SetupConstitutionPurposeLabel,
763 SetupConstitutionAutonomyLabel,
764 SetupConstitutionEvidenceLabel,
765 SetupConstitutionCommunicationLabel,
766 SetupConstitutionPrivacyLabel,
767 SetupConstitutionPrinciplesLabel,
768 SetupCardRouteLabel,
769 SetupCardModelLabel,
770 SetupCardAuthLabel,
771 SetupCardHealthLabel,
772 SetupCardIntentLabel,
773 SetupCardApprovalLabel,
774 SetupCardShellLabel,
775 SetupCardTrustLabel,
776 SetupCardSandboxLabel,
777 SetupCardNetworkLabel,
778 SetupOperateRuntimeLabel,
779 SetupOperateRosterLabel,
780 SetupOperateConcurrencyLabel,
781 SetupOperateReadinessLabel,
782 SetupOperateReviewHint,
783 SetupOperateReviewed,
784 SetupOperateNeedsActionSaved,
785 SetupHotbarBindingsLabel,
786 SetupHotbarActionsLabel,
787 SetupHotbarReviewHint,
788 SetupHotbarReviewed,
789 SetupToolsMcpServersLabel,
790 SetupToolsMcpSkillsLabel,
791 SetupToolsMcpToolsLabel,
792 SetupToolsMcpPluginsLabel,
793 SetupToolsMcpHotbarLabel,
794 SetupToolsMcpReviewHint,
795 SetupToolsMcpReviewed,
796 SetupToolsMcpNeedsActionSaved,
797 SetupToolsMcpPreviewTitle,
798 SetupToolsMcpOnRampText,
799 SetupRemoteCloudsLabel,
800 SetupRemoteBridgesLabel,
801 SetupRemoteProvidersLabel,
802 SetupRemoteModeLabel,
803 SetupRemoteModeLocalOnly,
804 SetupRemoteModeRuntimeApi,
805 SetupRemoteModeMobileLan,
806 SetupRemoteModeChatBridge,
807 SetupRemoteStatusDisabled,
808 SetupRemoteStatusReady,
809 SetupRemoteStatusNeedsAction,
810 SetupRemoteReviewHint,
811 SetupRemotePreviewTitle,
812 SetupRemoteReviewed,
813 SetupPersistenceHomeLabel,
814 SetupPersistenceConfigLabel,
815 SetupPersistenceStateLabel,
816 SetupPersistenceConstitutionLabel,
817 SetupPersistenceMemoryLabel,
818 SetupPersistenceNotesLabel,
819 SetupPersistenceReviewHint,
820 SetupPersistenceReviewed,
821 SetupProviderModelReadyHint,
822 SetupProviderModelNeedsActionHint,
823 SetupProviderModelReviewed,
824 SetupProviderModelNeedsActionSaved,
825 SetupRuntimePostureBoundary,
826 SetupRuntimePostureReviewHint,
827 SetupRuntimePostureReviewed,
828 SetupRuntimePresetSelectedLabel,
829 SetupRuntimePresetDiffLabel,
830 SetupRuntimePresetAskFirstTitle,
831 SetupRuntimePresetAskFirstDescription,
832 SetupRuntimePresetNormalAgentTitle,
833 SetupRuntimePresetNormalAgentDescription,
834 SetupRuntimePresetHighTrustTitle,
835 SetupRuntimePresetHighTrustDescription,
836 SetupRuntimePresetPreviewTitle,
837 SetupRuntimePresetSafetyFloor,
838 SetupRuntimePresetApplyHint,
839 SetupRuntimePresetApplied,
840 SetupRuntimeProjectOverrideLabel,
841 SetupRuntimeProjectOverrideNone,
842 SetupReportFirstRunLabel,
843 SetupReportUpdateLabel,
844 SetupReportOperateLabel,
845 SetupReportSourceLabel,
846 SetupReportAutonomyLabel,
847 SetupReportRuntimePostureLabel,
848 SetupReportPersisted,
849 SetupReportInherited,
850 SetupReportReady,
851 SetupReportRequired,
852 SetupReportOptional,
853 SetupReportRowsLabel,
854 SetupReportNextActionLabel,
855 SetupReportNextActionNone,
856 SetupReportNextActionConstitution,
857 SetupReportNextActionProvider,
858 SetupReportNextActionRuntime,
859 SetupReportNextActionOperate,
860 SetupReportNextActionRequired,
861 SetupReportRecorded,
862 // Context menu.
863 CtxMenuTitle,
864 CtxMenuCopySelection,
865 CtxMenuCopySelectionDesc,
866 CtxMenuOpenSelection,
867 CtxMenuOpenSelectionDesc,
868 CtxMenuClearSelection,
869 CtxMenuOpenDetails,
870 CtxMenuCopyMessage,
871 CtxMenuCopyMessageDesc,
872 CtxMenuOpenInEditor,
873 CtxMenuOpenInEditorDesc,
874 CtxMenuShowCell,
875 CtxMenuShowCellDesc,
876 CtxMenuHideCell,
877 CtxMenuHideCellDesc,
878 CtxMenuShowHidden,
879 CtxMenuShowHiddenDesc,
880 CtxMenuPaste,
881 CtxMenuPasteDesc,
882 CtxMenuCmdPalette,
883 CtxMenuCmdPaletteDesc,
884 CtxMenuContextInspector,
885 CtxMenuContextInspectorDesc,
886 CtxMenuHelp,
887 CtxMenuHelpDesc,
888 // Agent fanout card.
889 FanoutCounts,
890
891 // App mode picker (names, hints) and composer vim indicator.
892 AppModeAgent,
893 AppModeAuto,
894 AppModeYolo,
895 AppModePlan,
896 AppModeOperate,
897 AppModeAgentHint,
898 AppModeAutoHint,
899 AppModePlanHint,
900 AppModeYoloHint,
901 AppModeOperateHint,
902 VimModeNormal,
903 VimModeInsert,
904 VimModeVisual,
905
906 // Approval dialog — risk badges, category labels, field labels, options.
907 ApprovalRiskReview,
908 ApprovalRiskElevated,
909 ApprovalRiskDestructive,
910 ApprovalCategorySafe,
911 ApprovalCategoryFileWrite,
912 ApprovalCategoryShell,
913 ApprovalCategoryNetwork,
914 ApprovalCategoryMcpRead,
915 ApprovalCategoryMcpAction,
916 ApprovalCategoryAgent,
917 ApprovalCategoryUnknown,
918 ApprovalFieldType,
919 ApprovalFieldAbout,
920 ApprovalFieldImpact,
921 ApprovalFieldParams,
922 ApprovalOptionApproveOnce,
923 ApprovalOptionApproveAlways,
924 ApprovalOptionAllowExactRepo,
925 ApprovalSaveAskRuleHint,
926 ApprovalOptionDeny,
927 ApprovalOptionAbortTurn,
928 ApprovalBlockTitle,
929 ApprovalControlsHint,
930 ApprovalTruncationHint,
931 ApprovalFullAccessPolicyBlocked,
932 AutoReviewQuestionSkipped,
933 ApprovalChooseHint,
934 ApprovalChooseAction,
935 ApprovalIntentLabel,
936 ApprovalMoreLines,
937 ApprovalAutoDeniedSession,
938 // Sandbox elevation dialog.
939 ElevationTitleSandboxDenied,
940 ElevationTitleRequired,
941 ElevationFieldTool,
942 ElevationFieldCmd,
943 ElevationFieldReason,
944 ElevationImpactHeader,
945 ElevationImpactNetwork,
946 ElevationImpactWrite,
947 ElevationImpactFullAccess,
948 ElevationPromptProceed,
949 ElevationOptionNetwork,
950 ElevationOptionWrite,
951 ElevationOptionFullAccess,
952 ElevationOptionAbort,
953 ElevationOptionNetworkDesc,
954 ElevationOptionWriteDesc,
955 ElevationOptionFullAccessDesc,
956 ElevationOptionAbortDesc,
957
958 CtxInspTitle,
959 CtxInspSessionContext,
960 CtxInspSystemPrompt,
961 CtxInspReferences,
962 CtxInspRecentTools,
963 CtxInspModel,
964 CtxInspWorkspace,
965 CtxInspSession,
966 CtxInspContext,
967 CtxInspTranscript,
968 CtxInspWorkspaceStatus,
969 CtxInspNotSampledYet,
970 CtxInspOk,
971 CtxInspHigh,
972 CtxInspCritical,
973 CtxInspIncluded,
974 CtxInspAttached,
975 CtxInspNotIncluded,
976 CtxInspOutputCaptured,
977 CtxInspNoOutputYet,
978 CtxInspNoSystemPrompt,
979 CtxInspNoReferences,
980 CtxInspNoToolActivity,
981 CtxInspVHint,
982 CtxInspCells,
983 CtxInspApiMessages,
984 CtxInspActive,
985 CtxInspCell,
986 CtxInspMoreReferences,
987 CtxInspStablePrefix,
988 CtxInspVolatileWorkingSet,
989 CtxInspFirstLine,
990 CtxInspTotal,
991 CtxInspTextPromptLayers,
992 CtxInspSingleTextBlob,
993 CtxInspBlocks,
994 CtxInspBlock,
995 CtxInspTokens,
996 CtxInspLayers,
997 CtxInspNone,
998 CtxInspEmpty,
999 CtxInspCacheFriendly,
1000 CtxInspChangesByTurn,
1001 CtxInspStablePrefixOnly,
1002 CtxInspCacheTip,
1003 // Tool family labels (card headers, sidebar, footer).
1004 ToolFamilyRead,
1005 ToolFamilyPatch,
1006 ToolFamilyRun,
1007 ToolFamilyFind,
1008 ToolFamilyDelegate,
1009 ToolFamilyFanout,
1010 ToolFamilyRlm,
1011 ToolFamilyVerify,
1012 ToolFamilyThink,
1013 ToolFamilyGeneric,
1014 // Voice commands (/voice, /voice-send, /voice-control)
1015 CmdVoiceDescription,
1016 CmdVoiceSendDescription,
1017 CmdVoiceControlDescription,
1018 VoiceEnabled,
1019 VoiceDisabled,
1020 VoiceSendEnabled,
1021 VoiceSendDisabled,
1022 VoiceControlEnabled,
1023 VoiceControlDisabled,
1024 VoiceErrNoAuth,
1025 VoiceErrNoRecorder,
1026 VoiceErrNetwork,
1027 VoiceErrEmptySend,
1028 VoiceErrTooShort,
1029 VoiceRecording,
1030 VoiceProcessing,
1031 VoiceTranscribed,
1032 // Notifications (turn/agent completion).
1033 NotificationTurnComplete,
1034 NotificationSubagentComplete,
1035 NotificationSubagentFailed,
1036 NotificationSubagentInterrupted,
1037 NotificationSubagentCancelled,
1038 NotificationSubagentBudgetExhausted,
1039 // Footer chips.
1040 FooterWorkedChip,
1041 // Fleet setup wizard.
1042 FleetDraftTitle,
1043 FleetDraftHeader,
1044 // Remote setup on-ramp.
1045 SetupRemoteOnRampText,
1046 // Approval dialog — localized descriptions.
1047 ApprovalDescSafe,
1048 ApprovalDescFileWrite,
1049 ApprovalDescShell,
1050 ApprovalDescNetwork,
1051 ApprovalDescMcpRead,
1052 ApprovalDescMcpAction,
1053 ApprovalDescAgent,
1054 ApprovalDescUnknown,
1055 // Approval impact summaries.
1056 ApprovalImpactSafe,
1057 ApprovalImpactFileWrite,
1058 ApprovalImpactShell,
1059 ApprovalImpactNetwork,
1060 ApprovalImpactMcpRead,
1061 ApprovalImpactMcpAction,
1062 ApprovalImpactAgent,
1063 ApprovalImpactUnknown,
1064 // Approval detail labels.
1065 ApprovalLabelCommand,
1066 ApprovalLabelDir,
1067 ApprovalLabelFile,
1068 ApprovalLabelPreview,
1069 ApprovalLabelProposedContent,
1070 ApprovalLabelReplaceThis,
1071 ApprovalLabelWithThis,
1072 ApprovalLabelReplacementContent,
1073 ApprovalLabelPath,
1074 ApprovalLabelTarget,
1075 ApprovalLabelInput,
1076 ApprovalLabelAction,
1077 ApprovalLabelType,
1078 ApprovalLabelPrompt,
1079 // Approval header labels.
1080 ApprovalLabelAbout,
1081 ApprovalLabelImpact,
1082 // Setup wizard — constitution file state.
1083 SetupConstitutionFileNotChecked,
1084 SetupConstitutionFileMissing,
1085 SetupConstitutionFileLoadedSelected,
1086 SetupConstitutionFileLoadedInactive,
1087 SetupConstitutionFileLoadedUnselected,
1088 SetupConstitutionFileEmpty,
1089 SetupConstitutionFileInvalid,
1090 SetupConstitutionFileUnreadable,
1091 SetupConstitutionFilePathError,
1092 // Setup wizard — expert override state.
1093 SetupExpertOverrideNotChecked,
1094 SetupExpertOverrideMissing,
1095 SetupExpertOverrideActive,
1096 SetupExpertOverrideDisabled,
1097 SetupExpertOverrideEmpty,
1098 SetupExpertOverrideUnreadable,
1099 SetupExpertOverridePathError,
1100 // Setup wizard — autonomy fallback.
1101 SetupAutonomyUnspecified,
1102 // Setup wizard — purpose labels.
1103 SetupGuidedPurposeCoding,
1104 SetupGuidedPurposeResearch,
1105 SetupGuidedPurposeOperations,
1106 SetupGuidedPurposeMixed,
1107 // Setup wizard — purpose about descriptions.
1108 SetupGuidedPurposeAboutCoding,
1109 SetupGuidedPurposeAboutResearch,
1110 SetupGuidedPurposeAboutOperations,
1111 SetupGuidedPurposeAboutMixed,
1112 // Setup wizard — working style descriptions.
1113 SetupGuidedStyleCoding,
1114 SetupGuidedStyleResearch,
1115 SetupGuidedStyleOperations,
1116 SetupGuidedStyleMixed,
1117 // Setup wizard — evidence labels.
1118 SetupGuidedEvidenceAssumptions,
1119 SetupGuidedEvidenceTestsAndReceipts,
1120 SetupGuidedEvidenceReleaseReceipts,
1121 // Setup wizard — guided answer notes.
1122 SetupGuidedNotes,
1123 // Underwater launch screen (pre-session menu + worktree flow).
1124 LaunchMenuNewSession,
1125 LaunchMenuNewWorktree,
1126 LaunchMenuResumeSession,
1127 LaunchMenuChangelog,
1128 LaunchMenuQuit,
1129 LaunchMenuUnavailable,
1130 LaunchMenuSavedCount,
1131 LaunchWorktreePrompt,
1132 LaunchWorktreeNeedsGit,
1133 LaunchWorktreeNameLabel,
1134 LaunchHintMove,
1135 LaunchHintOpen,
1136 LaunchTipFlags,
1137 LaunchSavedSessionSingular,
1138 LaunchSavedSessionsPlural,
1139 LaunchCreatingWorktree,
1140 LaunchWorktreeFailed,
1141 LaunchNoSavedSessions,
1142 // Underwater shell phase words (footer status band).
1143 PhaseIdle,
1144 PhaseDraft,
1145 PhaseWorking,
1146 PhaseReasoning,
1147 PhaseReading,
1148 PhaseUsingTool,
1149 /// Metered verification pass (tests/checks) — distinct from `working`
1150 /// so checking reads differently from searching (ocean state model).
1151 PhaseVerifying,
1152 PhaseWaitingOnYou,
1153 PhaseDone,
1154 PhaseFailed,
1155 PhaseFinishing,
1156 // Underwater header chips: mode and permission words.
1157 ChipModeAct,
1158 ChipModePlan,
1159 ChipModeOperate,
1160 ChipPermissionReadOnly,
1161 ChipPermissionAsk,
1162 ChipPermissionAuto,
1163 ChipPermissionFullAccess,
1164 ChipPermissionNever,
1165 // Underwater footer right-hand hint words (keys stay literal in code).
1166 FooterHintKeys,
1167 FooterHintOutput,
1168 FooterHintContext,
1169 // Underwater post-launch empty state.
1170 EmptyStateNoGit,
1171 EmptyStateMcpLabel,
1172 EmptyStateFleetLabel,
1173 EmptyStateFleetSetupLabel,
1174 EmptyStateHelpHint,
1175 // Session picker surface.
1176 SessionsSurfaceTitle,
1177 SessionsPaneTitle,
1178 SessionsHistoryPaneTitle,
1179 SessionsActionResume,
1180 SessionsActionSearch,
1181 SessionsActionSort,
1182 SessionsActionRename,
1183 SessionsActionAllWorkspaces,
1184 SessionsActionDelete,
1185 SessionsActionClose,
1186 SessionsScopeSortHeader,
1187 SessionsEmptyTitle,
1188 SessionsEmptyHint,
1189 SessionsShowingAllWorkspaces,
1190 SessionsScopedToWorkspace,
1191 SessionsNewTitlePrompt,
1192 SessionsDeletePrompt,
1193 SessionsConfirmDelete,
1194 SessionsNewSessionTitle,
1195 SessionsOpenedHistory,
1196 SessionsSortStatus,
1197 SessionsSortRecent,
1198 SessionsSortName,
1199 SessionsSortSize,
1200 SessionsSearchPrompt,
1201 SessionsDeleteFailed,
1202 SessionsDeleted,
1203 SessionsNoSelection,
1204 SessionsTitleLength,
1205 SessionsOpenFailed,
1206 SessionsLoadFailed,
1207 SessionsRenameFailed,
1208 SessionsRenamed,
1209 SessionsRailTitle,
1210 SessionsRailEmpty,
1211 SessionsRailBrowseAll,
1212 SessionsRailShowingCount,
1213 SessionsRailUnavailable,
1214 SessionsActionArchive,
1215 SessionsActionShowArchived,
1216 SessionsArchived,
1217 SessionsRestored,
1218 SessionsArchiveFailed,
1219 SessionsShowingArchived,
1220 SessionsHidingArchived,
1221 SessionsArchivedCompact,
1222 SessionsNoResults,
1223 SessionsDirectoryFailed,
1224 SessionsPreviewFailed,
1225 SessionsDeleteCancelled,
1226 SessionsRenameCancelled,
1227 SessionsShowingRange,
1228 SessionsMessageCountCompact,
1229 SessionsForkCompact,
1230 SessionsUnknownMode,
1231 SessionsPreviewTitle,
1232 SessionsPreviewUpdated,
1233 SessionsPreviewMessagesModel,
1234 SessionsPreviewMode,
1235 SessionsToolCall,
1236 SessionsToolError,
1237 SessionsToolResult,
1238 SessionsServerTool,
1239 SessionsImage,
1240 SessionsTimeJustNow,
1241 SessionsTimeMinutesAgo,
1242 SessionsTimeHoursAgo,
1243 SessionsTimeDaysAgo,
1244 // Compact context inspector (Alt+C surface).
1245 CtxInspRowSystemPrompt,
1246 CtxInspRowMessages,
1247 CtxInspRowFree,
1248 CtxInspFreeTokensDetail,
1249 CtxInspDrillTitle,
1250 CtxInspSurfaceTitle,
1251 CtxInspActionSelect,
1252 CtxInspActionDrillDown,
1253 CtxInspActionClose,
1254 CtxInspUsedTokens,
1255 CtxInspAutoCompactAt,
1256 CtxInspRowTokens,
1257 // Model picker route surface.
1258 RouteSurfaceTitle,
1259 RouteBrowseCatalog,
1260 RouteActionType,
1261 RouteActionSearchAnyModel,
1262 RoutePanelHeader,
1263 RouteProviderLabel,
1264 RouteModelFirstAtomic,
1265 PickerActionMove,
1266 PickerActionSwitch,
1267 PickerActionApply,
1268 PickerActionSetStartupDefault,
1269 PickerActionCancel,
1270 PickerActionClear,
1271 PickerActionClearSearch,
1272 PickerActionBrowseAll,
1273 PickerActionCustom,
1274 PickerActionJump,
1275 PickerActionEditKey,
1276 PickerActionModels,
1277 PickerActionUnavailable,
1278 PickerActionSetKey,
1279 PickerActionConfigured,
1280 RouteNoModels,
1281 RouteNoModelMatch,
1282 ProviderNoMatchesTitle,
1283 ProviderNoMatchesHint,
1284 ProviderNoConfiguredTitle,
1285 ProviderNoConfiguredHint,
1286 ProviderNoCatalogModels,
1287 // Provider picker — informed external-credential consent.
1288 ProviderExternalActionRevoke,
1289 ProviderExternalActionChoices,
1290 ProviderExternalActionReuseGrok,
1291 ProviderExternalHintCodexReview,
1292 ProviderExternalHintXaiReview,
1293 ProviderExternalHintXaiApiKey,
1294 XaiAuthChoiceTitle,
1295 XaiAuthChoiceIntro,
1296 XaiAuthChoiceApiKeyOption,
1297 XaiAuthChoiceDeviceOAuthOption,
1298 ProviderExternalDetailScope,
1299 ProviderExternalDormant,
1300 ProviderExternalOwnerPath,
1301 ProviderExternalPinnedPathWarning,
1302 ProviderExternalSemanticsRevoke,
1303 ProviderExternalRevoke,
1304 ProviderExternalChoiceTitle,
1305 ProviderExternalActionChoose,
1306 ProviderExternalChoiceIntro,
1307 ProviderExternalDisabledLabel,
1308 ProviderExternalDisabledDetail,
1309 ProviderExternalReadOnlyLabel,
1310 ProviderExternalReadOnlyDetail,
1311 ProviderExternalReadOnlySemantics,
1312 ProviderExternalManagedLabel,
1313 ProviderExternalManagedDetail,
1314 ProviderExternalConfirmTitle,
1315 ProviderExternalActionGrant,
1316 ProviderExternalOwnerLabel,
1317 ProviderExternalExactPathLabel,
1318 ProviderExternalSemanticsLabel,
1319 ProviderExternalRejectUnsafe,
1320 ProviderExternalRevokeLabel,
1321 ProviderExternalGrantedToast,
1322 ProviderExternalSaveFailedToast,
1323 ProviderExternalRevokedToast,
1324 ProviderExternalRevokeFailedToast,
1325 // Theme picker surface.
1326 ThemeSurfaceTitle,
1327 ThemeTreatmentOmbreUnavailable,
1328 ThemeTreatmentFlatActive,
1329 ThemeTreatmentOmbreActive,
1330 // Fleet roster room.
1331 FleetRosterHeaderLabel,
1332 FleetRosterTabRoster,
1333 FleetRosterTabSetup,
1334 FleetRosterWorkers,
1335 FleetRosterMembersCount,
1336 FleetRosterOperatorFirst,
1337 FleetRosterOperatorRow,
1338 FleetReadyNotice,
1339 /// Sticky error when Fleet profile save cannot prove collision safety.
1340 FleetProfileIdentityVerifyFailed,
1341 /// Sticky error when the drafted profile id collides with another file.
1342 FleetProfileIdConflict,
1343 /// Sticky error when the drafted profile pins an unconfigured provider.
1344 FleetProfileProviderUnconfigured,
1345 // Workflow panel.
1346 WorkflowStatusWaiting,
1347 WorkflowDebrief,
1348 WorkflowTranscriptDetails,
1349 WorkflowReceiptRole,
1350 WorkflowReceiptReasoning,
1351 WorkflowReceiptVia,
1352 WorkflowReceiptTokens,
1353 WorkflowReceiptTools,
1354 WorkflowReceiptDuration,
1355 WorkflowReceiptUnknown,
1356 WorkflowReceiptProviderReported,
1357 WorkflowReceiptEstimated,
1358 // Sidebar work strip.
1359 SidebarTasksLabel,
1360 SidebarTodoLabel,
1361 SidebarStopControl,
1362 SidebarDestructiveArmed,
1363 WorkSurfaceTodoProgress,
1364 WorkSurfaceStopConfirmHint,
1365 CoordinationWorkTitle,
1366 CoordinationSummaryDecisions,
1367 CoordinationSummaryContentions,
1368 CoordinationSummaryReconciled,
1369 CoordinationSchema,
1370 CoordinationSequence,
1371 CoordinationPerSectionLimit,
1372 CoordinationDecisionsHeading,
1373 CoordinationNone,
1374 CoordinationNoneValue,
1375 CoordinationStatus,
1376 CoordinationOwner,
1377 CoordinationVersion,
1378 CoordinationWriteClaimsHeading,
1379 CoordinationIsolated,
1380 CoordinationSharedWorkspace,
1381 CoordinationPaths,
1382 CoordinationContracts,
1383 CoordinationContentionsHeading,
1384 CoordinationClaimant,
1385 CoordinationDisposition,
1386 CoordinationNeutralReconciliationHeading,
1387 CoordinationCandidates,
1388 CoordinationRetry,
1389 CoordinationReviewer,
1390 CoordinationVerifier,
1391 CoordinationVerification,
1392 CoordinationContextProjectionsHeading,
1393 CoordinationContextDecisions,
1394 CoordinationBytes,
1395 CoordinationDeduplicated,
1396 CoordinationOmitted,
1397 CoordinationActiveHotPathsHeading,
1398 CoordinationActiveClaims,
1399 CoordinationMetricsNoteHeading,
1400 CoordinationMetricsNoAuthoritativeSource,
1401 CoordinationStatusProposed,
1402 CoordinationStatusAccepted,
1403 CoordinationStatusSuperseded,
1404 // Composer slash menu.
1405 ComposerSlashMenuHint,
1406 // Approval modal — repository law band.
1407 ApprovalRepoLawBadge,
1408 ApprovalRepoLawTitle,
1409 ApprovalRepoLawWarning,
1410 ApprovalRepoLawRuleLabel,
1411 // Fuzzy file picker (@ attach overlay).
1412 FilePickerMatchSingular,
1413 FilePickerMatchesPlural,
1414 FilePickerScanning,
1415 // Quiet action-triggered product guidance.
1416 BehavioralTipPlanning,
1417 BehavioralTipBackgroundReceipt,
1418 BehavioralTipClearedInput,
1419 BehavioralTipMcpValidation,
1420 BehavioralTipRepeatedCommand,
1421 // Live-route settings lock (#2982): refusals and startup-default receipts.
1422 SettingLockedDuringTurn,
1423 SettingSubjectMode,
1424 SettingSubjectThinking,
1425 SettingSubjectModel,
1426 SettingSubjectModelAndThinking,
1427 SettingSubjectProvider,
1428 SettingSubjectPermissions,
1429 ThinkingControlledByAutoRouting,
1430 SavedAsStartupDefault,
1431 ModeAlreadyActiveSavedAsDefault,
1432 StartupDefaultNotSaved,
1433 StartupDefaultSubjectMode,
1434 StartupDefaultSubjectThinking,
1435 StartupDefaultSubjectModel,
1436 StartupDefaultSubjectAll,
1437 // Durable scheduled automation operator receipts.
1438 AutomationUsage,
1439 AutomationManagerUnavailable,
1440 AutomationListFailed,
1441 AutomationActionFailed,
1442 AutomationEmpty,
1443 AutomationListHeading,
1444 AutomationNoun,
1445 AutomationStatusLabel,
1446 AutomationStatusActive,
1447 AutomationStatusPaused,
1448 AutomationRunStatusQueued,
1449 AutomationRunStatusRunning,
1450 AutomationRunStatusCompleted,
1451 AutomationRunStatusFailed,
1452 AutomationRunStatusCanceled,
1453 AutomationActionInspect,
1454 AutomationActionPause,
1455 AutomationActionResume,
1456 AutomationActionDelete,
1457 AutomationActionRun,
1458 AutomationActionPaused,
1459 AutomationActionResumed,
1460 AutomationNextLabel,
1461 AutomationNameLabel,
1462 AutomationPromptLabel,
1463 AutomationCwdLabel,
1464 AutomationModeLabel,
1465 AutomationAllowShellLabel,
1466 AutomationTrustModeLabel,
1467 AutomationAutoApproveLabel,
1468 AutomationRruleLabel,
1469 AutomationDeliveryLabel,
1470 AutomationLastLabel,
1471 AutomationRecentRunsLabel,
1472 AutomationNoRuns,
1473 AutomationRunsUnavailable,
1474 AutomationTaskLabel,
1475 AutomationMutationReceipt,
1476 AutomationRunEnqueued,
1477 AutomationDeletePreview,
1478 AutomationDeleteConfirmationStale,
1479 AutomationDeleted,
1480 }
1481
1482 #[allow(dead_code)]
1483 pub const ALL_MESSAGE_IDS: &[MessageId] = &[
1484 MessageId::ComposerPlaceholder,
1485 MessageId::ComposerDispatchFailedRestored,
1486 MessageId::DispatchFailedQueued,
1487 MessageId::DispatchFailedInitial,
1488 MessageId::HistorySearchPlaceholder,
1489 MessageId::HistorySearchTitle,
1490 MessageId::HistoryHintMove,
1491 MessageId::HistoryHintAccept,
1492 MessageId::HistoryHintRestore,
1493 MessageId::HistoryNoMatches,
1494 MessageId::StatusPickerTitle,
1495 MessageId::StatusPickerInstruction,
1496 MessageId::StatusPickerActionToggle,
1497 MessageId::StatusPickerActionAll,
1498 MessageId::StatusPickerActionNone,
1499 MessageId::StatusPickerActionSave,
1500 MessageId::StatusPickerActionCancel,
1501 MessageId::HotbarSetupTitle,
1502 MessageId::HotbarSetupSourceApp,
1503 MessageId::HotbarSetupSourceSlash,
1504 MessageId::HotbarSetupSourceMcp,
1505 MessageId::HotbarSetupSourceSkill,
1506 MessageId::HotbarSetupSourcePlugin,
1507 MessageId::HotbarSetupStatusDisabled,
1508 MessageId::HotbarSetupStatusPrefill,
1509 MessageId::HotbarSetupStatusReady,
1510 MessageId::HotbarSetupDirtyModified,
1511 MessageId::HotbarSetupDirtyClean,
1512 MessageId::HotbarSetupNoAction,
1513 MessageId::HotbarSetupStatusLine,
1514 MessageId::HotbarSetupSlotOutOfRange,
1515 MessageId::HotbarSetupNoActionSelected,
1516 MessageId::HotbarSetupCannotAssign,
1517 MessageId::HotbarSetupNoActions,
1518 MessageId::HotbarSetupRecommended,
1519 MessageId::HotbarSetupEmptySlot,
1520 MessageId::HotbarSetupHelp,
1521 MessageId::HotbarActionVoiceToggleName,
1522 MessageId::HotbarActionVoiceToggleDescription,
1523 MessageId::HotbarActionSessionCompactName,
1524 MessageId::HotbarActionSessionCompactDescription,
1525 MessageId::HotbarActionModePlanName,
1526 MessageId::HotbarActionModePlanDescription,
1527 MessageId::HotbarActionModeAgentName,
1528 MessageId::HotbarActionModeAgentDescription,
1529 MessageId::HotbarActionModeYoloName,
1530 MessageId::HotbarActionModeYoloDescription,
1531 MessageId::HotbarActionModeOperateName,
1532 MessageId::HotbarActionModeOperateDescription,
1533 MessageId::HotbarActionReasoningCycleName,
1534 MessageId::HotbarActionReasoningCycleDescription,
1535 MessageId::HotbarActionReasoningCycleAutoDisabled,
1536 MessageId::HotbarActionSidebarToggleName,
1537 MessageId::HotbarActionSidebarToggleDescription,
1538 MessageId::HotbarActionFileTreeToggleName,
1539 MessageId::HotbarActionFileTreeToggleDescription,
1540 MessageId::HotbarActionPaletteOpenName,
1541 MessageId::HotbarActionPaletteOpenDescription,
1542 MessageId::HotbarActionTrustToggleName,
1543 MessageId::HotbarActionTrustToggleDescription,
1544 MessageId::CommandPaletteTitle,
1545 MessageId::CommandPaletteSubtitle,
1546 MessageId::ConfigTitle,
1547 MessageId::ConfigSubtitle,
1548 MessageId::ConfigModalTitle,
1549 MessageId::ConfigSearchPlaceholder,
1550 MessageId::ConfigNoSettings,
1551 MessageId::ConfigNoMatchesPrefix,
1552 MessageId::ConfigFilteredSettings,
1553 MessageId::ConfigShowing,
1554 MessageId::ConfigFooterDefault,
1555 MessageId::ConfigFooterScrollable,
1556 MessageId::ConfigFooterFiltered,
1557 MessageId::ConfigSectionProvider,
1558 MessageId::ConfigSectionModel,
1559 MessageId::ConfigSectionPermissions,
1560 MessageId::ConfigSectionNetwork,
1561 MessageId::ConfigSectionDisplay,
1562 MessageId::ConfigSectionComposer,
1563 MessageId::ConfigSectionSidebar,
1564 MessageId::ConfigSectionHistory,
1565 MessageId::ConfigSectionMcp,
1566 MessageId::ConfigSectionFleet,
1567 MessageId::ConfigSectionWorkflow,
1568 MessageId::ConfigSectionSession,
1569 MessageId::ConfigSectionLegacy,
1570 MessageId::ConfigSectionExperimental,
1571 MessageId::ConfigScopeSession,
1572 MessageId::ConfigScopeSaved,
1573 MessageId::ConfigEditCancelled,
1574 MessageId::ConfigEditTitlePrefix,
1575 MessageId::ConfigEditScopeLabel,
1576 MessageId::ConfigEditCurrentLabel,
1577 MessageId::ConfigEditHintLabel,
1578 MessageId::ConfigEditNewLabel,
1579 MessageId::ConfigEditFooter,
1580 MessageId::ConfigLocalePartialBadge,
1581 MessageId::ConfigLocalePartialDetail,
1582 MessageId::ConfigRowEffective,
1583 MessageId::ConfigDefaultValue,
1584 MessageId::ConfigDefaultReasoning,
1585 MessageId::ConfigUnavailable,
1586 MessageId::ConfigLabelProvider,
1587 MessageId::ConfigLabelBaseUrlDeepseek,
1588 MessageId::ConfigLabelProviderUrl,
1589 MessageId::ConfigLabelModel,
1590 MessageId::ConfigLabelFastModel,
1591 MessageId::ConfigLabelDefaultModel,
1592 MessageId::ConfigLabelReasoningEffort,
1593 MessageId::ConfigLabelApprovalMode,
1594 MessageId::ConfigLabelPermissionPosture,
1595 MessageId::ConfigLabelApprovalPolicy,
1596 MessageId::ConfigLabelManagedApprovalPolicy,
1597 MessageId::ConfigLabelDefaultMode,
1598 MessageId::ConfigLabelAllowShell,
1599 MessageId::ConfigLabelManagedAllowShell,
1600 MessageId::ConfigLabelStreamTimeout,
1601 MessageId::ConfigLabelTheme,
1602 MessageId::ConfigLabelLocale,
1603 MessageId::ConfigLabelBackground,
1604 MessageId::ConfigLabelOceanTreatment,
1605 MessageId::ConfigLabelWorkSurfacePlacement,
1606 MessageId::ConfigLabelTopHeight,
1607 MessageId::ConfigLabelSideWidth,
1608 MessageId::ConfigLabelCalmMode,
1609 MessageId::ConfigLabelLowMotion,
1610 MessageId::ConfigLabelFancyAnimations,
1611 MessageId::ConfigLabelLaunchScreen,
1612 MessageId::ConfigLabelShowThinking,
1613 MessageId::ConfigLabelThinkingHighlight,
1614 MessageId::ConfigLabelShowToolDetails,
1615 MessageId::ConfigLabelInlineDiffs,
1616 MessageId::ConfigLabelStatusIndicator,
1617 MessageId::ConfigLabelSynchronizedOutput,
1618 MessageId::ConfigLabelCostCurrency,
1619 MessageId::ConfigLabelTranscriptSpacing,
1620 MessageId::ConfigLabelToolCollapse,
1621 MessageId::ConfigLabelComposerDensity,
1622 MessageId::ConfigLabelComposerBorder,
1623 MessageId::ConfigLabelComposerVimMode,
1624 MessageId::ConfigLabelBracketedPaste,
1625 MessageId::ConfigLabelPasteBurstDetection,
1626 MessageId::ConfigLabelMentionMenuLimit,
1627 MessageId::ConfigLabelMentionMenuBehavior,
1628 MessageId::ConfigLabelMentionWalkDepth,
1629 MessageId::ConfigLabelWorkspaceFollowSymlinks,
1630 MessageId::ConfigLabelSidebarWidth,
1631 MessageId::ConfigLabelSidebarFocus,
1632 MessageId::ConfigLabelContextPanel,
1633 MessageId::ConfigLabelSessionsRail,
1634 MessageId::ConfigLabelSessionAutoResume,
1635 MessageId::ConfigLabelAutoCompact,
1636 MessageId::ConfigLabelAutoCompactThreshold,
1637 MessageId::ConfigLabelMaxHistory,
1638 MessageId::ConfigLabelMcpConfigPath,
1639 MessageId::ConfigLabelFleetSpawnDepth,
1640 MessageId::ConfigLabelGoalCommand,
1641 MessageId::ConfigLabelWorkflow,
1642 MessageId::ConfigLabelFeaturePrefix,
1643 MessageId::ConfigColumnSetting,
1644 MessageId::ConfigColumnValue,
1645 MessageId::ConfigColumnScope,
1646 MessageId::ConfigActionOpenProvider,
1647 MessageId::ConfigActionOpenModel,
1648 MessageId::ConfigActionToggle,
1649 MessageId::ConfigActionChoose,
1650 MessageId::ConfigActionEdit,
1651 MessageId::ConfigActionReadOnly,
1652 MessageId::ModelPickerAutoNetworkHint,
1653 MessageId::ModelPickerAutoNetworkActiveProviderHint,
1654 MessageId::ModelPickerAutoLocalHint,
1655 MessageId::ModelPickerAutoLastRoute,
1656 MessageId::AutoRouteSelectedToast,
1657 MessageId::HelpTitle,
1658 MessageId::HelpSubtitle,
1659 MessageId::HelpFilterPlaceholder,
1660 MessageId::HelpFilterPrefix,
1661 MessageId::HelpNoMatches,
1662 MessageId::HelpSlashCommands,
1663 MessageId::HelpKeybindings,
1664 MessageId::HelpUserCommands,
1665 MessageId::HelpSkills,
1666 MessageId::HelpFooterTypeFilter,
1667 MessageId::HelpFooterMove,
1668 MessageId::HelpFooterJump,
1669 MessageId::HelpFooterClose,
1670 MessageId::CmdAnchorDescription,
1671 MessageId::CmdAttachDescription,
1672 MessageId::CmdBalanceDescription,
1673 MessageId::CmdCacheDescription,
1674 MessageId::CmdPreviewRequestDescription,
1675 MessageId::CmdToolsDescription,
1676 MessageId::CmdEffortDescription,
1677 MessageId::CmdTurnInspectDescription,
1678 MessageId::CmdClearDescription,
1679 MessageId::CmdCompactDescription,
1680 MessageId::CmdPurgeDescription,
1681 MessageId::CmdConfigDescription,
1682 MessageId::CmdPermissionsDescription,
1683 MessageId::PermissionsListHeader,
1684 MessageId::PermissionsNoRules,
1685 MessageId::PermissionsFileMissing,
1686 MessageId::PermissionsFileEmpty,
1687 MessageId::PermissionsFilePresent,
1688 MessageId::PermissionsRuleEntry,
1689 MessageId::PermissionsMatchExactCommand,
1690 MessageId::PermissionsMatchCommandPrefix,
1691 MessageId::PermissionsMatchExactPath,
1692 MessageId::PermissionsMatchAnyInvocation,
1693 MessageId::PermissionsScopeGlobal,
1694 MessageId::PermissionsScopeRepo,
1695 MessageId::PermissionsAppliesHere,
1696 MessageId::PermissionsInactiveHere,
1697 MessageId::PermissionsRemovePreview,
1698 MessageId::PermissionsRemoved,
1699 MessageId::PermissionsUsage,
1700 MessageId::PermissionsRuleNotFound,
1701 MessageId::PermissionsOperationFailed,
1702 MessageId::CmdAuthDescription,
1703 MessageId::CmdConstitutionDescription,
1704 MessageId::CmdContextDescription,
1705 MessageId::CmdCostDescription,
1706 MessageId::CmdDiffDescription,
1707 MessageId::CmdEditDescription,
1708 MessageId::CmdExitDescription,
1709 MessageId::CmdExportDescription,
1710 MessageId::CmdFeedbackDescription,
1711 MessageId::CmdForkDescription,
1712 MessageId::CmdGoalDescription,
1713 MessageId::CmdThemeDescription,
1714 MessageId::CmdHfDescription,
1715 MessageId::CmdHelpDescription,
1716 MessageId::CmdProfileDescription,
1717 MessageId::CmdHomeDescription,
1718 MessageId::CmdHooksDescription,
1719 MessageId::CmdAgentDescription,
1720 MessageId::CmdInitDescription,
1721 MessageId::CmdJobsDescription,
1722 MessageId::CmdLinksDescription,
1723 MessageId::CmdLoadDescription,
1724 MessageId::CmdLogoutDescription,
1725 MessageId::CmdMcpDescription,
1726 MessageId::CmdPluginDescription,
1727 MessageId::CmdPluginBundleUsage,
1728 MessageId::CmdPluginBundleNoneFound,
1729 MessageId::CmdPluginBundleListHeader,
1730 MessageId::CmdPluginLegacyListHeader,
1731 MessageId::CmdPluginBundleNotFound,
1732 MessageId::CmdPluginBundleReloaded,
1733 MessageId::CmdPluginBundleDetail,
1734 MessageId::CmdPluginBundleDiagnosticsHeader,
1735 MessageId::CmdPluginBundleMutationSuccess,
1736 MessageId::CmdPluginActionFailed,
1737 MessageId::CmdPluginNoneFound,
1738 MessageId::CmdPluginNotFound,
1739 MessageId::CmdPluginListHeader,
1740 MessageId::CmdPluginDetailDescription,
1741 MessageId::CmdPluginDetailSchema,
1742 MessageId::CmdPluginDetailApproval,
1743 MessageId::CmdPluginDetailPath,
1744 MessageId::CmdMemoryDescription,
1745 MessageId::CmdModeDescription,
1746 MessageId::CmdModelDescription,
1747 MessageId::CmdModelsDescription,
1748 MessageId::CmdModelDbDescription,
1749 MessageId::CmdNetworkDescription,
1750 MessageId::CmdNoteDescription,
1751 MessageId::CmdProviderDescription,
1752 MessageId::CmdQueueDescription,
1753 MessageId::CmdQueueUsage,
1754 MessageId::CmdQueueDraftHeader,
1755 MessageId::CmdQueueNoMessages,
1756 MessageId::CmdQueueListHeader,
1757 MessageId::CmdQueueTip,
1758 MessageId::CmdQueueAlreadyEditing,
1759 MessageId::CmdQueueNotFound,
1760 MessageId::CmdQueueEditingStatus,
1761 MessageId::CmdQueueEditingMessage,
1762 MessageId::CmdQueueDropped,
1763 MessageId::CmdQueueAlreadyEmpty,
1764 MessageId::CmdQueueCleared,
1765 MessageId::CmdQueueMissingIndex,
1766 MessageId::CmdQueueIndexPositive,
1767 MessageId::CmdQueueIndexMin,
1768 MessageId::CmdRelayDescription,
1769 MessageId::CmdRemoteControlDescription,
1770 MessageId::CmdRenameDescription,
1771 MessageId::CmdRestoreDescription,
1772 MessageId::CmdRetryDescription,
1773 MessageId::CmdReviewDescription,
1774 MessageId::CmdRlmDescription,
1775 MessageId::CmdSaveDescription,
1776 MessageId::CmdNewDescription,
1777 MessageId::CmdSessionsDescription,
1778 MessageId::CmdSettingsDescription,
1779 MessageId::CmdSidebarDescription,
1780 MessageId::CmdSkillDescription,
1781 MessageId::CmdSkillsDescription,
1782 MessageId::CmdStashDescription,
1783 MessageId::CmdStatusDescription,
1784 MessageId::CmdStatuslineDescription,
1785 MessageId::CmdStructcopyDescription,
1786 MessageId::CmdStructcopyKindTurn,
1787 MessageId::CmdStructcopyKindTool,
1788 MessageId::CmdStructcopyKindPlan,
1789 MessageId::CmdStructcopyKindWorkflow,
1790 MessageId::CmdStructcopyUsageError,
1791 MessageId::CmdStructcopyUnavailable,
1792 MessageId::CmdStructcopyBusy,
1793 MessageId::CmdStructcopyPrepareFailed,
1794 MessageId::CmdStructcopyClipboardQueued,
1795 MessageId::CmdStructcopyClipboardAccepted,
1796 MessageId::CmdStructcopyClipboardFailed,
1797 MessageId::CmdStructcopyReceiptTooLarge,
1798 MessageId::CmdFleetDescription,
1799 MessageId::CmdLaneDescription,
1800 MessageId::CmdWorkflowDescription,
1801 MessageId::CmdHotbarDescription,
1802 MessageId::CmdSetupDescription,
1803 MessageId::CmdSubagentsDescription,
1804 MessageId::CmdAdvisorDescription,
1805 MessageId::CmdSystemDescription,
1806 MessageId::CmdAutomationDescription,
1807 MessageId::CmdTaskDescription,
1808 MessageId::CmdTokensDescription,
1809 MessageId::CmdTranslateDescription,
1810 MessageId::CmdTranslateOff,
1811 MessageId::CmdTranslateOn,
1812 MessageId::TranslationInProgress,
1813 MessageId::TranslationComplete,
1814 MessageId::TranslationFailed,
1815 MessageId::CmdTrustDescription,
1816 MessageId::CmdLspDescription,
1817 MessageId::CmdShareDescription,
1818 MessageId::CmdWorkspaceDescription,
1819 MessageId::CmdUndoDescription,
1820 MessageId::CmdVerboseDescription,
1821 MessageId::CmdCacheAdvice,
1822 MessageId::CmdCacheFootnote,
1823 MessageId::CmdCacheHeader,
1824 MessageId::CmdCacheNoData,
1825 MessageId::CmdCacheTotals,
1826 MessageId::CmdChangeDescription,
1827 MessageId::CmdChangeHeader,
1828 MessageId::CmdChangeTranslationQueued,
1829 MessageId::CmdChangeTranslationUnavailable,
1830 MessageId::CmdChangePreviousVersion,
1831 MessageId::CmdCostReport,
1832 MessageId::CmdCostReportSubtotal,
1833 MessageId::CmdCostReportUnknown,
1834 MessageId::CmdCostUnknownValue,
1835 MessageId::CmdCostEstimateOnly,
1836 MessageId::CmdCostCoverage,
1837 MessageId::CmdCostCoverageUnknownLegacy,
1838 MessageId::CmdCostUnpricedTurns,
1839 MessageId::CmdCostUnpricedClasses,
1840 MessageId::CmdCostPricingProvenance,
1841 MessageId::CmdCostLivePricingDowngraded,
1842 MessageId::CmdCostLivePricingUnavailable,
1843 MessageId::CmdCostRoutesHeader,
1844 MessageId::CmdTokensCacheWriteTotal,
1845 MessageId::CmdTokensCacheBoth,
1846 MessageId::CmdTokensCacheHitOnly,
1847 MessageId::CmdTokensCacheMissOnly,
1848 MessageId::CmdTokensContextUnknownWindow,
1849 MessageId::CmdTokensContextWithWindow,
1850 MessageId::CmdTokensNotReported,
1851 MessageId::CmdTokensReport,
1852 MessageId::FooterAgentSingular,
1853 MessageId::FooterAgentsPlural,
1854 MessageId::HeaderAgentsChip,
1855 MessageId::FooterPressCtrlCAgain,
1856 MessageId::FooterWorking,
1857 MessageId::FooterBalancePrefix,
1858 MessageId::HelpSectionActions,
1859 MessageId::HelpSectionClipboard,
1860 MessageId::HelpSectionEditing,
1861 MessageId::HelpSectionHelp,
1862 MessageId::HelpSectionModes,
1863 MessageId::HelpSectionNavigation,
1864 MessageId::HelpSectionSessions,
1865 MessageId::KbScrollTranscript,
1866 MessageId::KbNavigateHistory,
1867 MessageId::KbScrollTranscriptAlt,
1868 MessageId::KbBrowseHistory,
1869 MessageId::KbScrollPage,
1870 MessageId::KbJumpTopBottom,
1871 MessageId::KbJumpTopBottomEmpty,
1872 MessageId::KbJumpToolBlocks,
1873 MessageId::KbMoveCursor,
1874 MessageId::KbJumpLineStartEnd,
1875 MessageId::KbDeleteChar,
1876 MessageId::KbDeleteWord,
1877 MessageId::KbYank,
1878 MessageId::KbToggleFileTree,
1879 MessageId::KbSelectText,
1880 MessageId::KbSelectAllDraft,
1881 MessageId::KbClearDraft,
1882 MessageId::KbRestoreClearedDraft,
1883 MessageId::KbStashDraft,
1884 MessageId::KbSearchHistory,
1885 MessageId::KbInsertNewline,
1886 MessageId::KbSendDraft,
1887 MessageId::KbSteerCurrentTurn,
1888 MessageId::KbCloseMenu,
1889 MessageId::KbCancelOrExit,
1890 MessageId::KbShellControls,
1891 MessageId::KbExitEmpty,
1892 MessageId::KbCommandPalette,
1893 MessageId::KbSettings,
1894 MessageId::KbCancelBackgroundShellJobs,
1895 MessageId::KbFuzzyFilePicker,
1896 MessageId::KbCompactInspector,
1897 MessageId::KbCompactContext,
1898 MessageId::KbLastMessagePager,
1899 MessageId::KbSelectedDetails,
1900 MessageId::KbToolDetailsPager,
1901 MessageId::KbReasoningDetail,
1902 MessageId::KbTurnInspector,
1903 MessageId::KbExternalEditor,
1904 MessageId::KbLiveTranscript,
1905 MessageId::KbBacktrackMessage,
1906 MessageId::KbCompleteCycleModes,
1907 MessageId::KbCycleThinking,
1908 MessageId::KbCyclePermissions,
1909 MessageId::KbJumpPlanAgentYolo,
1910 MessageId::KbAltJumpPlanAgentYolo,
1911 MessageId::KbFocusSidebar,
1912 MessageId::KbSessionPicker,
1913 MessageId::KbTerminalPaste,
1914 MessageId::KbPasteAttach,
1915 MessageId::KbCopySelection,
1916 MessageId::ClipboardSshPasteHint,
1917 MessageId::KbContextMenu,
1918 MessageId::KbAttachPath,
1919 MessageId::KbHelpOverlay,
1920 MessageId::KbToggleHelp,
1921 MessageId::KbToggleHelpSlash,
1922 MessageId::HelpUsageLabel,
1923 MessageId::HelpAliasesLabel,
1924 MessageId::SettingsTitle,
1925 MessageId::SettingsConfigFile,
1926 MessageId::ClearConversation,
1927 MessageId::ClearConversationBusy,
1928 MessageId::ModelChanged,
1929 MessageId::LinksProjectTitle,
1930 MessageId::LinksDocumentation,
1931 MessageId::LinksCommunity,
1932 MessageId::LinksGitHub,
1933 MessageId::LinksManagedApp,
1934 MessageId::LinksManagedAppNote,
1935 MessageId::LinksTitle,
1936 MessageId::LinksDashboard,
1937 MessageId::LinksDocs,
1938 MessageId::LinksKimiCodeRouteNote,
1939 MessageId::LinksTip,
1940 MessageId::SubagentsFetching,
1941 MessageId::HelpUnknownCommand,
1942 MessageId::HomeDashboardTitle,
1943 MessageId::HomeModel,
1944 MessageId::HomeMode,
1945 MessageId::HomeWorkspace,
1946 MessageId::HomeHistory,
1947 MessageId::HomeTokens,
1948 MessageId::HomeQueued,
1949 MessageId::HomeSubagents,
1950 MessageId::HomeSkill,
1951 MessageId::HomeQuickActions,
1952 MessageId::HomeQuickLinks,
1953 MessageId::HomeQuickSkills,
1954 MessageId::HomeQuickConfig,
1955 MessageId::HomeQuickSettings,
1956 MessageId::HomeQuickModel,
1957 MessageId::HomeQuickSubagents,
1958 MessageId::HomeQuickTaskList,
1959 MessageId::HomeQuickHelp,
1960 MessageId::HomeModeTips,
1961 MessageId::HomeAgentModeTip,
1962 MessageId::HomeAgentModeReviewTip,
1963 MessageId::HomeAgentModeYoloTip,
1964 MessageId::HomeYoloModeTip,
1965 MessageId::HomeYoloModeCaution,
1966 MessageId::HomePlanModeTip,
1967 MessageId::HomePlanModeChecklistTip,
1968 MessageId::HomeOperateModeTip,
1969 MessageId::HomeOperateModeFleetTip,
1970 MessageId::HomeGoalModeTip,
1971 MessageId::OnboardWelcomeVersion,
1972 MessageId::OnboardWelcomeLead,
1973 MessageId::OnboardWelcomeSetupBlurb,
1974 MessageId::OnboardWelcomeSteps,
1975 MessageId::OnboardWelcomeStepLanguage,
1976 MessageId::OnboardWelcomeStepAppearance,
1977 MessageId::OnboardWelcomeStepApiKey,
1978 MessageId::OnboardWelcomeStepTrust,
1979 MessageId::OnboardWelcomeStepMentalModels,
1980 MessageId::OnboardWelcomeStepTips,
1981 MessageId::OnboardWelcomeDefaults,
1982 MessageId::OnboardWelcomeEnter,
1983 MessageId::OnboardWelcomeExit,
1984 MessageId::OnboardLanguageTitle,
1985 MessageId::OnboardLanguageBlurb,
1986 MessageId::OnboardLanguageFooter,
1987 MessageId::OnboardProviderTitle,
1988 MessageId::OnboardProviderBlurb,
1989 MessageId::OnboardProviderFooter,
1990 MessageId::OnboardApiKeyTitle,
1991 MessageId::OnboardApiKeyStep1,
1992 MessageId::OnboardApiKeyStep2,
1993 MessageId::OnboardApiKeyLocalHint,
1994 MessageId::OnboardApiKeySavedHint,
1995 MessageId::OnboardApiKeyFormatHint,
1996 MessageId::KimiCodePlanApiKeyHint,
1997 MessageId::KimiCodePlanRouteHint,
1998 MessageId::KimiCodePlanNoImportHint,
1999 MessageId::StepfunBillingRouteTitle,
2000 MessageId::StepfunBillingRouteIntro,
2001 MessageId::StepfunBillingRoutePaygOption,
2002 MessageId::StepfunBillingRoutePlanOption,
2003 MessageId::StepfunPlanApiKeyHint,
2004 MessageId::StepfunPlanRouteHint,
2005 MessageId::OnboardApiKeyPlaceholder,
2006 MessageId::OnboardApiKeyLabel,
2007 MessageId::OnboardApiKeyFooter,
2008 MessageId::OnboardApiKeyRejectedEnv,
2009 MessageId::OnboardTrustTitle,
2010 MessageId::OnboardTrustQuestion,
2011 MessageId::OnboardTrustLocationPrefix,
2012 MessageId::OnboardTrustRiskHint,
2013 MessageId::OnboardTrustEffectHint,
2014 MessageId::OnboardTrustFooterPrefix,
2015 MessageId::OnboardTrustFooterMiddle,
2016 MessageId::OnboardTrustFooterUntrustedMiddle,
2017 MessageId::OnboardTrustFooterSuffix,
2018 MessageId::OnboardTrustEnterHint,
2019 MessageId::OnboardTrustUntrustedNotice,
2020 MessageId::OnboardMentalTitle,
2021 MessageId::OnboardMentalModesLabel,
2022 MessageId::OnboardMentalPlanHint,
2023 MessageId::OnboardMentalActHint,
2024 MessageId::OnboardMentalOperateHint,
2025 MessageId::OnboardMentalPermissionLabel,
2026 MessageId::OnboardMentalCurrentLabel,
2027 MessageId::OnboardMentalConstitution,
2028 MessageId::OnboardMentalCycleMode,
2029 MessageId::OnboardMentalCyclePermission,
2030 MessageId::OnboardMentalContinue,
2031 MessageId::OnboardMentalBack,
2032 MessageId::OnboardAppearanceTitle,
2033 MessageId::OnboardAppearanceBlurb,
2034 MessageId::OnboardAppearanceFooter,
2035 MessageId::OnboardOfflineOption,
2036 MessageId::OnboardOfflineNotice,
2037 MessageId::OnboardOfflineTipsLine,
2038 MessageId::OnboardTipsTitle,
2039 MessageId::OnboardTipsLine1,
2040 MessageId::OnboardTipsLine2,
2041 MessageId::OnboardTipsLine3,
2042 MessageId::OnboardTipsLine4,
2043 MessageId::OnboardTipsDoctorPrefix,
2044 MessageId::OnboardTipsDoctorSuffix,
2045 MessageId::OnboardTipsFooterEnter,
2046 MessageId::OnboardTipsFooterAction,
2047 MessageId::SetupWizardTitle,
2048 MessageId::SetupWizardWhy,
2049 MessageId::SetupWizardProgress,
2050 MessageId::SetupActionBack,
2051 MessageId::SetupActionContinue,
2052 MessageId::SetupActionSkip,
2053 MessageId::SetupActionRetry,
2054 MessageId::SetupActionScrollBody,
2055 MessageId::SetupActionGuided,
2056 MessageId::SetupActionTuneGuided,
2057 MessageId::SetupActionModelDraft,
2058 MessageId::SetupActionFreeform,
2059 MessageId::SetupActionKeepExisting,
2060 MessageId::SetupActionProvider,
2061 MessageId::SetupActionModel,
2062 MessageId::SetupActionFleet,
2063 MessageId::SetupActionHotbar,
2064 MessageId::SetupActionRemote,
2065 MessageId::SetupActionMode,
2066 MessageId::SetupActionConfig,
2067 MessageId::SetupActionRuntimePreset,
2068 MessageId::SetupActionApplyRuntimePreset,
2069 MessageId::SetupActionUseBundled,
2070 MessageId::SetupActionDefer,
2071 MessageId::SetupActionCancel,
2072 MessageId::SetupStatusNotStarted,
2073 MessageId::SetupStatusRecommended,
2074 MessageId::SetupStatusOptional,
2075 MessageId::SetupStatusDeferred,
2076 MessageId::SetupStatusInProgress,
2077 MessageId::SetupStatusNeedsAction,
2078 MessageId::SetupStatusVerified,
2079 MessageId::SetupStatusSkipped,
2080 MessageId::SetupStatusFailed,
2081 MessageId::SetupStepLanguageTitle,
2082 MessageId::SetupStepLanguageWhy,
2083 MessageId::SetupStepProviderModelTitle,
2084 MessageId::SetupStepProviderModelWhy,
2085 MessageId::SetupStepTrustSandboxTitle,
2086 MessageId::SetupStepTrustSandboxWhy,
2087 MessageId::SetupStepOperateFleetTitle,
2088 MessageId::SetupStepOperateFleetWhy,
2089 MessageId::SetupStepToolsMcpTitle,
2090 MessageId::SetupStepToolsMcpWhy,
2091 MessageId::SetupStepHotbarTitle,
2092 MessageId::SetupStepHotbarWhy,
2093 MessageId::SetupStepRemoteRuntimeTitle,
2094 MessageId::SetupStepRemoteRuntimeWhy,
2095 MessageId::SetupStepPersistenceTitle,
2096 MessageId::SetupStepPersistenceWhy,
2097 MessageId::SetupStepConstitutionTitle,
2098 MessageId::SetupStepConstitutionWhy,
2099 MessageId::SetupStepVerificationTitle,
2100 MessageId::SetupStepVerificationWhy,
2101 MessageId::SetupCheckpointLayerOrder,
2102 MessageId::SetupCheckpointDoneBundled,
2103 MessageId::SetupCheckpointDoneGuided,
2104 MessageId::SetupCheckpointDoneKept,
2105 MessageId::SetupCheckpointDeferred,
2106 MessageId::SetupStepSkipped,
2107 MessageId::SetupStepRetryRecorded,
2108 MessageId::SetupLanguageReviewed,
2109 MessageId::SetupConstitutionChoiceLabel,
2110 MessageId::SetupConstitutionSourceLabel,
2111 MessageId::SetupConstitutionValidityLabel,
2112 MessageId::SetupConstitutionPreviewLabel,
2113 MessageId::SetupConstitutionExistingLabel,
2114 MessageId::SetupConstitutionExpertOverrideLabel,
2115 MessageId::SetupConstitutionGuidedHint,
2116 MessageId::SetupConstitutionGuidedAnswersHint,
2117 MessageId::SetupConstitutionPurposeLabel,
2118 MessageId::SetupConstitutionAutonomyLabel,
2119 MessageId::SetupConstitutionEvidenceLabel,
2120 MessageId::SetupConstitutionCommunicationLabel,
2121 MessageId::SetupConstitutionPrivacyLabel,
2122 MessageId::SetupConstitutionPrinciplesLabel,
2123 MessageId::SetupCardRouteLabel,
2124 MessageId::SetupCardModelLabel,
2125 MessageId::SetupCardAuthLabel,
2126 MessageId::SetupCardHealthLabel,
2127 MessageId::SetupCardIntentLabel,
2128 MessageId::SetupCardApprovalLabel,
2129 MessageId::SetupCardShellLabel,
2130 MessageId::SetupCardTrustLabel,
2131 MessageId::SetupCardSandboxLabel,
2132 MessageId::SetupCardNetworkLabel,
2133 MessageId::SetupOperateRuntimeLabel,
2134 MessageId::SetupOperateRosterLabel,
2135 MessageId::SetupOperateConcurrencyLabel,
2136 MessageId::SetupOperateReadinessLabel,
2137 MessageId::SetupOperateReviewHint,
2138 MessageId::SetupOperateReviewed,
2139 MessageId::SetupOperateNeedsActionSaved,
2140 MessageId::SetupHotbarBindingsLabel,
2141 MessageId::SetupHotbarActionsLabel,
2142 MessageId::SetupHotbarReviewHint,
2143 MessageId::SetupHotbarReviewed,
2144 MessageId::SetupToolsMcpServersLabel,
2145 MessageId::SetupToolsMcpSkillsLabel,
2146 MessageId::SetupToolsMcpToolsLabel,
2147 MessageId::SetupToolsMcpPluginsLabel,
2148 MessageId::SetupToolsMcpHotbarLabel,
2149 MessageId::SetupToolsMcpReviewHint,
2150 MessageId::SetupToolsMcpReviewed,
2151 MessageId::SetupToolsMcpNeedsActionSaved,
2152 MessageId::SetupToolsMcpPreviewTitle,
2153 MessageId::SetupToolsMcpOnRampText,
2154 MessageId::SetupRemoteCloudsLabel,
2155 MessageId::SetupRemoteBridgesLabel,
2156 MessageId::SetupRemoteProvidersLabel,
2157 MessageId::SetupRemoteModeLabel,
2158 MessageId::SetupRemoteModeLocalOnly,
2159 MessageId::SetupRemoteModeRuntimeApi,
2160 MessageId::SetupRemoteModeMobileLan,
2161 MessageId::SetupRemoteModeChatBridge,
2162 MessageId::SetupRemoteStatusDisabled,
2163 MessageId::SetupRemoteStatusReady,
2164 MessageId::SetupRemoteStatusNeedsAction,
2165 MessageId::SetupRemoteReviewHint,
2166 MessageId::SetupRemotePreviewTitle,
2167 MessageId::SetupRemoteReviewed,
2168 MessageId::SetupPersistenceHomeLabel,
2169 MessageId::SetupPersistenceConfigLabel,
2170 MessageId::SetupPersistenceStateLabel,
2171 MessageId::SetupPersistenceConstitutionLabel,
2172 MessageId::SetupPersistenceMemoryLabel,
2173 MessageId::SetupPersistenceNotesLabel,
2174 MessageId::SetupPersistenceReviewHint,
2175 MessageId::SetupPersistenceReviewed,
2176 MessageId::SetupProviderModelReadyHint,
2177 MessageId::SetupProviderModelNeedsActionHint,
2178 MessageId::SetupProviderModelReviewed,
2179 MessageId::SetupProviderModelNeedsActionSaved,
2180 MessageId::SetupRuntimePostureBoundary,
2181 MessageId::SetupRuntimePostureReviewHint,
2182 MessageId::SetupRuntimePostureReviewed,
2183 MessageId::SetupRuntimePresetSelectedLabel,
2184 MessageId::SetupRuntimePresetDiffLabel,
2185 MessageId::SetupRuntimePresetAskFirstTitle,
2186 MessageId::SetupRuntimePresetAskFirstDescription,
2187 MessageId::SetupRuntimePresetNormalAgentTitle,
2188 MessageId::SetupRuntimePresetNormalAgentDescription,
2189 MessageId::SetupRuntimePresetHighTrustTitle,
2190 MessageId::SetupRuntimePresetHighTrustDescription,
2191 MessageId::SetupRuntimePresetPreviewTitle,
2192 MessageId::SetupRuntimePresetSafetyFloor,
2193 MessageId::SetupRuntimePresetApplyHint,
2194 MessageId::SetupRuntimePresetApplied,
2195 MessageId::SetupRuntimeProjectOverrideLabel,
2196 MessageId::SetupRuntimeProjectOverrideNone,
2197 MessageId::SetupReportFirstRunLabel,
2198 MessageId::SetupReportUpdateLabel,
2199 MessageId::SetupReportOperateLabel,
2200 MessageId::SetupReportSourceLabel,
2201 MessageId::SetupReportAutonomyLabel,
2202 MessageId::SetupReportRuntimePostureLabel,
2203 MessageId::SetupReportPersisted,
2204 MessageId::SetupReportInherited,
2205 MessageId::SetupReportReady,
2206 MessageId::SetupReportRequired,
2207 MessageId::SetupReportOptional,
2208 MessageId::SetupReportRowsLabel,
2209 MessageId::SetupReportNextActionLabel,
2210 MessageId::SetupReportNextActionNone,
2211 MessageId::SetupReportNextActionConstitution,
2212 MessageId::SetupReportNextActionProvider,
2213 MessageId::SetupReportNextActionRuntime,
2214 MessageId::SetupReportNextActionOperate,
2215 MessageId::SetupReportNextActionRequired,
2216 MessageId::SetupReportRecorded,
2217 // Context menu.
2218 MessageId::CtxMenuTitle,
2219 MessageId::CtxMenuCopySelection,
2220 MessageId::CtxMenuCopySelectionDesc,
2221 MessageId::CtxMenuOpenSelection,
2222 MessageId::CtxMenuOpenSelectionDesc,
2223 MessageId::CtxMenuClearSelection,
2224 MessageId::CtxMenuOpenDetails,
2225 MessageId::CtxMenuCopyMessage,
2226 MessageId::CtxMenuCopyMessageDesc,
2227 MessageId::CtxMenuOpenInEditor,
2228 MessageId::CtxMenuOpenInEditorDesc,
2229 MessageId::CtxMenuShowCell,
2230 MessageId::CtxMenuShowCellDesc,
2231 MessageId::CtxMenuHideCell,
2232 MessageId::CtxMenuHideCellDesc,
2233 MessageId::CtxMenuShowHidden,
2234 MessageId::CtxMenuShowHiddenDesc,
2235 MessageId::CtxMenuPaste,
2236 MessageId::CtxMenuPasteDesc,
2237 MessageId::CtxMenuCmdPalette,
2238 MessageId::CtxMenuCmdPaletteDesc,
2239 MessageId::CtxMenuContextInspector,
2240 MessageId::CtxMenuContextInspectorDesc,
2241 MessageId::CtxMenuHelp,
2242 MessageId::CtxMenuHelpDesc,
2243 MessageId::FanoutCounts,
2244 MessageId::AppModeAgent,
2245 MessageId::AppModeAuto,
2246 MessageId::AppModeYolo,
2247 MessageId::AppModePlan,
2248 MessageId::AppModeOperate,
2249 MessageId::AppModeAgentHint,
2250 MessageId::AppModeAutoHint,
2251 MessageId::AppModePlanHint,
2252 MessageId::AppModeYoloHint,
2253 MessageId::AppModeOperateHint,
2254 MessageId::VimModeNormal,
2255 MessageId::VimModeInsert,
2256 MessageId::VimModeVisual,
2257 MessageId::ApprovalRiskReview,
2258 MessageId::ApprovalRiskElevated,
2259 MessageId::ApprovalRiskDestructive,
2260 MessageId::ApprovalCategorySafe,
2261 MessageId::ApprovalCategoryFileWrite,
2262 MessageId::ApprovalCategoryShell,
2263 MessageId::ApprovalCategoryNetwork,
2264 MessageId::ApprovalCategoryMcpRead,
2265 MessageId::ApprovalCategoryMcpAction,
2266 MessageId::ApprovalCategoryAgent,
2267 MessageId::ApprovalCategoryUnknown,
2268 MessageId::ApprovalFieldType,
2269 MessageId::ApprovalFieldAbout,
2270 MessageId::ApprovalFieldImpact,
2271 MessageId::ApprovalFieldParams,
2272 MessageId::ApprovalOptionApproveOnce,
2273 MessageId::ApprovalOptionApproveAlways,
2274 MessageId::ApprovalOptionAllowExactRepo,
2275 MessageId::ApprovalSaveAskRuleHint,
2276 MessageId::ApprovalOptionDeny,
2277 MessageId::ApprovalOptionAbortTurn,
2278 MessageId::ApprovalBlockTitle,
2279 MessageId::ApprovalControlsHint,
2280 MessageId::ApprovalTruncationHint,
2281 MessageId::ApprovalFullAccessPolicyBlocked,
2282 MessageId::AutoReviewQuestionSkipped,
2283 MessageId::ApprovalChooseHint,
2284 MessageId::ApprovalChooseAction,
2285 MessageId::ApprovalIntentLabel,
2286 MessageId::ApprovalMoreLines,
2287 MessageId::ApprovalAutoDeniedSession,
2288 MessageId::ElevationTitleSandboxDenied,
2289 MessageId::ElevationTitleRequired,
2290 MessageId::ElevationFieldTool,
2291 MessageId::ElevationFieldCmd,
2292 MessageId::ElevationFieldReason,
2293 MessageId::ElevationImpactHeader,
2294 MessageId::ElevationImpactNetwork,
2295 MessageId::ElevationImpactWrite,
2296 MessageId::ElevationImpactFullAccess,
2297 MessageId::ElevationPromptProceed,
2298 MessageId::ElevationOptionNetwork,
2299 MessageId::ElevationOptionWrite,
2300 MessageId::ElevationOptionFullAccess,
2301 MessageId::ElevationOptionAbort,
2302 MessageId::ElevationOptionNetworkDesc,
2303 MessageId::ElevationOptionWriteDesc,
2304 MessageId::ElevationOptionFullAccessDesc,
2305 MessageId::ElevationOptionAbortDesc,
2306 MessageId::CtxInspTitle,
2307 MessageId::CtxInspSessionContext,
2308 MessageId::CtxInspSystemPrompt,
2309 MessageId::CtxInspReferences,
2310 MessageId::CtxInspRecentTools,
2311 MessageId::CtxInspModel,
2312 MessageId::CtxInspWorkspace,
2313 MessageId::CtxInspSession,
2314 MessageId::CtxInspContext,
2315 MessageId::CtxInspTranscript,
2316 MessageId::CtxInspWorkspaceStatus,
2317 MessageId::CtxInspNotSampledYet,
2318 MessageId::CtxInspOk,
2319 MessageId::CtxInspHigh,
2320 MessageId::CtxInspCritical,
2321 MessageId::CtxInspIncluded,
2322 MessageId::CtxInspAttached,
2323 MessageId::CtxInspNotIncluded,
2324 MessageId::CtxInspOutputCaptured,
2325 MessageId::CtxInspNoOutputYet,
2326 MessageId::CtxInspNoSystemPrompt,
2327 MessageId::CtxInspNoReferences,
2328 MessageId::CtxInspNoToolActivity,
2329 MessageId::CtxInspVHint,
2330 MessageId::CtxInspCells,
2331 MessageId::CtxInspApiMessages,
2332 MessageId::CtxInspActive,
2333 MessageId::CtxInspCell,
2334 MessageId::CtxInspMoreReferences,
2335 MessageId::CtxInspStablePrefix,
2336 MessageId::CtxInspVolatileWorkingSet,
2337 MessageId::CtxInspFirstLine,
2338 MessageId::CtxInspTotal,
2339 MessageId::CtxInspTextPromptLayers,
2340 MessageId::CtxInspSingleTextBlob,
2341 MessageId::CtxInspBlocks,
2342 MessageId::CtxInspBlock,
2343 MessageId::CtxInspTokens,
2344 MessageId::CtxInspLayers,
2345 MessageId::CtxInspNone,
2346 MessageId::CtxInspEmpty,
2347 MessageId::CtxInspCacheFriendly,
2348 MessageId::CtxInspChangesByTurn,
2349 MessageId::CtxInspStablePrefixOnly,
2350 MessageId::CtxInspCacheTip,
2351 MessageId::ToolFamilyRead,
2352 MessageId::ToolFamilyPatch,
2353 MessageId::ToolFamilyRun,
2354 MessageId::ToolFamilyFind,
2355 MessageId::ToolFamilyDelegate,
2356 MessageId::ToolFamilyFanout,
2357 MessageId::ToolFamilyRlm,
2358 MessageId::ToolFamilyVerify,
2359 MessageId::ToolFamilyThink,
2360 MessageId::ToolFamilyGeneric,
2361 MessageId::CmdVoiceDescription,
2362 MessageId::CmdVoiceSendDescription,
2363 MessageId::CmdVoiceControlDescription,
2364 MessageId::VoiceEnabled,
2365 MessageId::VoiceDisabled,
2366 MessageId::VoiceSendEnabled,
2367 MessageId::VoiceSendDisabled,
2368 MessageId::VoiceControlEnabled,
2369 MessageId::VoiceControlDisabled,
2370 MessageId::VoiceErrNoAuth,
2371 MessageId::VoiceErrNoRecorder,
2372 MessageId::VoiceErrNetwork,
2373 MessageId::VoiceErrEmptySend,
2374 MessageId::VoiceErrTooShort,
2375 MessageId::VoiceRecording,
2376 MessageId::VoiceProcessing,
2377 MessageId::VoiceTranscribed,
2378 MessageId::NotificationTurnComplete,
2379 MessageId::NotificationSubagentComplete,
2380 MessageId::NotificationSubagentFailed,
2381 MessageId::NotificationSubagentInterrupted,
2382 MessageId::NotificationSubagentCancelled,
2383 MessageId::NotificationSubagentBudgetExhausted,
2384 MessageId::FooterWorkedChip,
2385 MessageId::FleetDraftTitle,
2386 MessageId::FleetDraftHeader,
2387 MessageId::SetupRemoteOnRampText,
2388 MessageId::ApprovalDescSafe,
2389 MessageId::ApprovalDescFileWrite,
2390 MessageId::ApprovalDescShell,
2391 MessageId::ApprovalDescNetwork,
2392 MessageId::ApprovalDescMcpRead,
2393 MessageId::ApprovalDescMcpAction,
2394 MessageId::ApprovalDescAgent,
2395 MessageId::ApprovalDescUnknown,
2396 MessageId::ApprovalImpactSafe,
2397 MessageId::ApprovalImpactFileWrite,
2398 MessageId::ApprovalImpactShell,
2399 MessageId::ApprovalImpactNetwork,
2400 MessageId::ApprovalImpactMcpRead,
2401 MessageId::ApprovalImpactMcpAction,
2402 MessageId::ApprovalImpactAgent,
2403 MessageId::ApprovalImpactUnknown,
2404 MessageId::ApprovalLabelCommand,
2405 MessageId::ApprovalLabelDir,
2406 MessageId::ApprovalLabelFile,
2407 MessageId::ApprovalLabelPreview,
2408 MessageId::ApprovalLabelProposedContent,
2409 MessageId::ApprovalLabelReplaceThis,
2410 MessageId::ApprovalLabelWithThis,
2411 MessageId::ApprovalLabelReplacementContent,
2412 MessageId::ApprovalLabelPath,
2413 MessageId::ApprovalLabelTarget,
2414 MessageId::ApprovalLabelInput,
2415 MessageId::ApprovalLabelAction,
2416 MessageId::ApprovalLabelType,
2417 MessageId::ApprovalLabelPrompt,
2418 MessageId::ApprovalLabelAbout,
2419 MessageId::ApprovalLabelImpact,
2420 MessageId::SetupConstitutionFileNotChecked,
2421 MessageId::SetupConstitutionFileMissing,
2422 MessageId::SetupConstitutionFileLoadedSelected,
2423 MessageId::SetupConstitutionFileLoadedInactive,
2424 MessageId::SetupConstitutionFileLoadedUnselected,
2425 MessageId::SetupConstitutionFileEmpty,
2426 MessageId::SetupConstitutionFileInvalid,
2427 MessageId::SetupConstitutionFileUnreadable,
2428 MessageId::SetupConstitutionFilePathError,
2429 MessageId::SetupExpertOverrideNotChecked,
2430 MessageId::SetupExpertOverrideMissing,
2431 MessageId::SetupExpertOverrideActive,
2432 MessageId::SetupExpertOverrideDisabled,
2433 MessageId::SetupExpertOverrideEmpty,
2434 MessageId::SetupExpertOverrideUnreadable,
2435 MessageId::SetupExpertOverridePathError,
2436 MessageId::SetupAutonomyUnspecified,
2437 MessageId::SetupGuidedPurposeCoding,
2438 MessageId::SetupGuidedPurposeResearch,
2439 MessageId::SetupGuidedPurposeOperations,
2440 MessageId::SetupGuidedPurposeMixed,
2441 MessageId::SetupGuidedPurposeAboutCoding,
2442 MessageId::SetupGuidedPurposeAboutResearch,
2443 MessageId::SetupGuidedPurposeAboutOperations,
2444 MessageId::SetupGuidedPurposeAboutMixed,
2445 MessageId::SetupGuidedStyleCoding,
2446 MessageId::SetupGuidedStyleResearch,
2447 MessageId::SetupGuidedStyleOperations,
2448 MessageId::SetupGuidedStyleMixed,
2449 MessageId::SetupGuidedEvidenceAssumptions,
2450 MessageId::SetupGuidedEvidenceTestsAndReceipts,
2451 MessageId::SetupGuidedEvidenceReleaseReceipts,
2452 MessageId::SetupGuidedNotes,
2453 MessageId::LaunchMenuNewSession,
2454 MessageId::LaunchMenuNewWorktree,
2455 MessageId::LaunchMenuResumeSession,
2456 MessageId::LaunchMenuChangelog,
2457 MessageId::LaunchMenuQuit,
2458 MessageId::LaunchMenuUnavailable,
2459 MessageId::LaunchMenuSavedCount,
2460 MessageId::LaunchWorktreePrompt,
2461 MessageId::LaunchWorktreeNeedsGit,
2462 MessageId::LaunchWorktreeNameLabel,
2463 MessageId::LaunchHintMove,
2464 MessageId::LaunchHintOpen,
2465 MessageId::LaunchTipFlags,
2466 MessageId::LaunchSavedSessionSingular,
2467 MessageId::LaunchSavedSessionsPlural,
2468 MessageId::LaunchCreatingWorktree,
2469 MessageId::LaunchWorktreeFailed,
2470 MessageId::LaunchNoSavedSessions,
2471 MessageId::PhaseIdle,
2472 MessageId::PhaseDraft,
2473 MessageId::PhaseWorking,
2474 MessageId::PhaseReasoning,
2475 MessageId::PhaseReading,
2476 MessageId::PhaseUsingTool,
2477 MessageId::PhaseVerifying,
2478 MessageId::PhaseWaitingOnYou,
2479 MessageId::PhaseDone,
2480 MessageId::PhaseFailed,
2481 MessageId::PhaseFinishing,
2482 MessageId::ChipModeAct,
2483 MessageId::ChipModePlan,
2484 MessageId::ChipModeOperate,
2485 MessageId::ChipPermissionReadOnly,
2486 MessageId::ChipPermissionAsk,
2487 MessageId::ChipPermissionAuto,
2488 MessageId::ChipPermissionFullAccess,
2489 MessageId::ChipPermissionNever,
2490 MessageId::FooterHintKeys,
2491 MessageId::FooterHintOutput,
2492 MessageId::FooterHintContext,
2493 MessageId::EmptyStateNoGit,
2494 MessageId::EmptyStateMcpLabel,
2495 MessageId::EmptyStateFleetLabel,
2496 MessageId::EmptyStateFleetSetupLabel,
2497 MessageId::EmptyStateHelpHint,
2498 MessageId::SessionsSurfaceTitle,
2499 MessageId::SessionsPaneTitle,
2500 MessageId::SessionsHistoryPaneTitle,
2501 MessageId::SessionsActionResume,
2502 MessageId::SessionsActionSearch,
2503 MessageId::SessionsActionSort,
2504 MessageId::SessionsActionRename,
2505 MessageId::SessionsActionAllWorkspaces,
2506 MessageId::SessionsActionDelete,
2507 MessageId::SessionsActionClose,
2508 MessageId::SessionsScopeSortHeader,
2509 MessageId::SessionsEmptyTitle,
2510 MessageId::SessionsEmptyHint,
2511 MessageId::SessionsShowingAllWorkspaces,
2512 MessageId::SessionsScopedToWorkspace,
2513 MessageId::SessionsNewTitlePrompt,
2514 MessageId::SessionsDeletePrompt,
2515 MessageId::SessionsConfirmDelete,
2516 MessageId::SessionsNewSessionTitle,
2517 MessageId::SessionsOpenedHistory,
2518 MessageId::SessionsSortStatus,
2519 MessageId::SessionsSortRecent,
2520 MessageId::SessionsSortName,
2521 MessageId::SessionsSortSize,
2522 MessageId::SessionsSearchPrompt,
2523 MessageId::SessionsDeleteFailed,
2524 MessageId::SessionsDeleted,
2525 MessageId::SessionsNoSelection,
2526 MessageId::SessionsTitleLength,
2527 MessageId::SessionsOpenFailed,
2528 MessageId::SessionsLoadFailed,
2529 MessageId::SessionsRenameFailed,
2530 MessageId::SessionsRenamed,
2531 MessageId::SessionsRailTitle,
2532 MessageId::SessionsRailEmpty,
2533 MessageId::SessionsRailBrowseAll,
2534 MessageId::SessionsRailShowingCount,
2535 MessageId::SessionsRailUnavailable,
2536 MessageId::SessionsActionArchive,
2537 MessageId::SessionsActionShowArchived,
2538 MessageId::SessionsArchived,
2539 MessageId::SessionsRestored,
2540 MessageId::SessionsArchiveFailed,
2541 MessageId::SessionsShowingArchived,
2542 MessageId::SessionsHidingArchived,
2543 MessageId::SessionsArchivedCompact,
2544 MessageId::SessionsNoResults,
2545 MessageId::SessionsDirectoryFailed,
2546 MessageId::SessionsPreviewFailed,
2547 MessageId::SessionsDeleteCancelled,
2548 MessageId::SessionsRenameCancelled,
2549 MessageId::SessionsShowingRange,
2550 MessageId::SessionsMessageCountCompact,
2551 MessageId::SessionsForkCompact,
2552 MessageId::SessionsUnknownMode,
2553 MessageId::SessionsPreviewTitle,
2554 MessageId::SessionsPreviewUpdated,
2555 MessageId::SessionsPreviewMessagesModel,
2556 MessageId::SessionsPreviewMode,
2557 MessageId::SessionsToolCall,
2558 MessageId::SessionsToolError,
2559 MessageId::SessionsToolResult,
2560 MessageId::SessionsServerTool,
2561 MessageId::SessionsImage,
2562 MessageId::SessionsTimeJustNow,
2563 MessageId::SessionsTimeMinutesAgo,
2564 MessageId::SessionsTimeHoursAgo,
2565 MessageId::SessionsTimeDaysAgo,
2566 MessageId::CtxInspRowSystemPrompt,
2567 MessageId::CtxInspRowMessages,
2568 MessageId::CtxInspRowFree,
2569 MessageId::CtxInspFreeTokensDetail,
2570 MessageId::CtxInspDrillTitle,
2571 MessageId::CtxInspSurfaceTitle,
2572 MessageId::CtxInspActionSelect,
2573 MessageId::CtxInspActionDrillDown,
2574 MessageId::CtxInspActionClose,
2575 MessageId::CtxInspUsedTokens,
2576 MessageId::CtxInspAutoCompactAt,
2577 MessageId::CtxInspRowTokens,
2578 MessageId::RouteSurfaceTitle,
2579 MessageId::RouteBrowseCatalog,
2580 MessageId::RouteActionType,
2581 MessageId::RouteActionSearchAnyModel,
2582 MessageId::RoutePanelHeader,
2583 MessageId::RouteProviderLabel,
2584 MessageId::RouteModelFirstAtomic,
2585 MessageId::PickerActionMove,
2586 MessageId::PickerActionSwitch,
2587 MessageId::PickerActionApply,
2588 MessageId::PickerActionSetStartupDefault,
2589 MessageId::PickerActionCancel,
2590 MessageId::PickerActionClear,
2591 MessageId::PickerActionClearSearch,
2592 MessageId::PickerActionBrowseAll,
2593 MessageId::PickerActionCustom,
2594 MessageId::PickerActionJump,
2595 MessageId::PickerActionEditKey,
2596 MessageId::PickerActionModels,
2597 MessageId::PickerActionUnavailable,
2598 MessageId::PickerActionSetKey,
2599 MessageId::PickerActionConfigured,
2600 MessageId::RouteNoModels,
2601 MessageId::RouteNoModelMatch,
2602 MessageId::ProviderNoMatchesTitle,
2603 MessageId::ProviderNoMatchesHint,
2604 MessageId::ProviderNoConfiguredTitle,
2605 MessageId::ProviderNoConfiguredHint,
2606 MessageId::ProviderNoCatalogModels,
2607 MessageId::ProviderExternalActionRevoke,
2608 MessageId::ProviderExternalActionChoices,
2609 MessageId::ProviderExternalActionReuseGrok,
2610 MessageId::ProviderExternalHintCodexReview,
2611 MessageId::ProviderExternalHintXaiReview,
2612 MessageId::ProviderExternalHintXaiApiKey,
2613 MessageId::XaiAuthChoiceTitle,
2614 MessageId::XaiAuthChoiceIntro,
2615 MessageId::XaiAuthChoiceApiKeyOption,
2616 MessageId::XaiAuthChoiceDeviceOAuthOption,
2617 MessageId::ProviderExternalDetailScope,
2618 MessageId::ProviderExternalDormant,
2619 MessageId::ProviderExternalOwnerPath,
2620 MessageId::ProviderExternalPinnedPathWarning,
2621 MessageId::ProviderExternalSemanticsRevoke,
2622 MessageId::ProviderExternalRevoke,
2623 MessageId::ProviderExternalChoiceTitle,
2624 MessageId::ProviderExternalActionChoose,
2625 MessageId::ProviderExternalChoiceIntro,
2626 MessageId::ProviderExternalDisabledLabel,
2627 MessageId::ProviderExternalDisabledDetail,
2628 MessageId::ProviderExternalReadOnlyLabel,
2629 MessageId::ProviderExternalReadOnlyDetail,
2630 MessageId::ProviderExternalReadOnlySemantics,
2631 MessageId::ProviderExternalManagedLabel,
2632 MessageId::ProviderExternalManagedDetail,
2633 MessageId::ProviderExternalConfirmTitle,
2634 MessageId::ProviderExternalActionGrant,
2635 MessageId::ProviderExternalOwnerLabel,
2636 MessageId::ProviderExternalExactPathLabel,
2637 MessageId::ProviderExternalSemanticsLabel,
2638 MessageId::ProviderExternalRejectUnsafe,
2639 MessageId::ProviderExternalRevokeLabel,
2640 MessageId::ProviderExternalGrantedToast,
2641 MessageId::ProviderExternalSaveFailedToast,
2642 MessageId::ProviderExternalRevokedToast,
2643 MessageId::ProviderExternalRevokeFailedToast,
2644 MessageId::ThemeSurfaceTitle,
2645 MessageId::ThemeTreatmentOmbreUnavailable,
2646 MessageId::ThemeTreatmentFlatActive,
2647 MessageId::ThemeTreatmentOmbreActive,
2648 MessageId::FleetRosterHeaderLabel,
2649 MessageId::FleetRosterTabRoster,
2650 MessageId::FleetRosterTabSetup,
2651 MessageId::FleetRosterWorkers,
2652 MessageId::FleetRosterMembersCount,
2653 MessageId::FleetRosterOperatorFirst,
2654 MessageId::FleetRosterOperatorRow,
2655 MessageId::FleetReadyNotice,
2656 MessageId::FleetProfileIdentityVerifyFailed,
2657 MessageId::FleetProfileIdConflict,
2658 MessageId::FleetProfileProviderUnconfigured,
2659 MessageId::WorkflowStatusWaiting,
2660 MessageId::WorkflowDebrief,
2661 MessageId::WorkflowTranscriptDetails,
2662 MessageId::WorkflowReceiptRole,
2663 MessageId::WorkflowReceiptReasoning,
2664 MessageId::WorkflowReceiptVia,
2665 MessageId::WorkflowReceiptTokens,
2666 MessageId::WorkflowReceiptTools,
2667 MessageId::WorkflowReceiptDuration,
2668 MessageId::WorkflowReceiptUnknown,
2669 MessageId::WorkflowReceiptProviderReported,
2670 MessageId::WorkflowReceiptEstimated,
2671 MessageId::SidebarTasksLabel,
2672 MessageId::SidebarTodoLabel,
2673 MessageId::SidebarStopControl,
2674 MessageId::SidebarDestructiveArmed,
2675 MessageId::WorkSurfaceTodoProgress,
2676 MessageId::WorkSurfaceStopConfirmHint,
2677 MessageId::CoordinationWorkTitle,
2678 MessageId::CoordinationSummaryDecisions,
2679 MessageId::CoordinationSummaryContentions,
2680 MessageId::CoordinationSummaryReconciled,
2681 MessageId::CoordinationSchema,
2682 MessageId::CoordinationSequence,
2683 MessageId::CoordinationPerSectionLimit,
2684 MessageId::CoordinationDecisionsHeading,
2685 MessageId::CoordinationNone,
2686 MessageId::CoordinationNoneValue,
2687 MessageId::CoordinationStatus,
2688 MessageId::CoordinationOwner,
2689 MessageId::CoordinationVersion,
2690 MessageId::CoordinationWriteClaimsHeading,
2691 MessageId::CoordinationIsolated,
2692 MessageId::CoordinationSharedWorkspace,
2693 MessageId::CoordinationPaths,
2694 MessageId::CoordinationContracts,
2695 MessageId::CoordinationContentionsHeading,
2696 MessageId::CoordinationClaimant,
2697 MessageId::CoordinationDisposition,
2698 MessageId::CoordinationNeutralReconciliationHeading,
2699 MessageId::CoordinationCandidates,
2700 MessageId::CoordinationRetry,
2701 MessageId::CoordinationReviewer,
2702 MessageId::CoordinationVerifier,
2703 MessageId::CoordinationVerification,
2704 MessageId::CoordinationContextProjectionsHeading,
2705 MessageId::CoordinationContextDecisions,
2706 MessageId::CoordinationBytes,
2707 MessageId::CoordinationDeduplicated,
2708 MessageId::CoordinationOmitted,
2709 MessageId::CoordinationActiveHotPathsHeading,
2710 MessageId::CoordinationActiveClaims,
2711 MessageId::CoordinationMetricsNoteHeading,
2712 MessageId::CoordinationMetricsNoAuthoritativeSource,
2713 MessageId::CoordinationStatusProposed,
2714 MessageId::CoordinationStatusAccepted,
2715 MessageId::CoordinationStatusSuperseded,
2716 MessageId::ComposerSlashMenuHint,
2717 MessageId::ApprovalRepoLawBadge,
2718 MessageId::ApprovalRepoLawTitle,
2719 MessageId::ApprovalRepoLawWarning,
2720 MessageId::ApprovalRepoLawRuleLabel,
2721 MessageId::FilePickerMatchSingular,
2722 MessageId::FilePickerMatchesPlural,
2723 MessageId::FilePickerScanning,
2724 MessageId::BehavioralTipPlanning,
2725 MessageId::BehavioralTipBackgroundReceipt,
2726 MessageId::BehavioralTipClearedInput,
2727 MessageId::BehavioralTipMcpValidation,
2728 MessageId::BehavioralTipRepeatedCommand,
2729 MessageId::SettingLockedDuringTurn,
2730 MessageId::SettingSubjectMode,
2731 MessageId::SettingSubjectThinking,
2732 MessageId::SettingSubjectModel,
2733 MessageId::SettingSubjectModelAndThinking,
2734 MessageId::SettingSubjectProvider,
2735 MessageId::SettingSubjectPermissions,
2736 MessageId::ThinkingControlledByAutoRouting,
2737 MessageId::SavedAsStartupDefault,
2738 MessageId::ModeAlreadyActiveSavedAsDefault,
2739 MessageId::StartupDefaultNotSaved,
2740 MessageId::StartupDefaultSubjectMode,
2741 MessageId::StartupDefaultSubjectThinking,
2742 MessageId::StartupDefaultSubjectModel,
2743 MessageId::StartupDefaultSubjectAll,
2744 MessageId::AutomationUsage,
2745 MessageId::AutomationManagerUnavailable,
2746 MessageId::AutomationListFailed,
2747 MessageId::AutomationActionFailed,
2748 MessageId::AutomationEmpty,
2749 MessageId::AutomationListHeading,
2750 MessageId::AutomationNoun,
2751 MessageId::AutomationStatusLabel,
2752 MessageId::AutomationStatusActive,
2753 MessageId::AutomationStatusPaused,
2754 MessageId::AutomationRunStatusQueued,
2755 MessageId::AutomationRunStatusRunning,
2756 MessageId::AutomationRunStatusCompleted,
2757 MessageId::AutomationRunStatusFailed,
2758 MessageId::AutomationRunStatusCanceled,
2759 MessageId::AutomationActionInspect,
2760 MessageId::AutomationActionPause,
2761 MessageId::AutomationActionResume,
2762 MessageId::AutomationActionDelete,
2763 MessageId::AutomationActionRun,
2764 MessageId::AutomationActionPaused,
2765 MessageId::AutomationActionResumed,
2766 MessageId::AutomationNextLabel,
2767 MessageId::AutomationNameLabel,
2768 MessageId::AutomationPromptLabel,
2769 MessageId::AutomationCwdLabel,
2770 MessageId::AutomationModeLabel,
2771 MessageId::AutomationAllowShellLabel,
2772 MessageId::AutomationTrustModeLabel,
2773 MessageId::AutomationAutoApproveLabel,
2774 MessageId::AutomationRruleLabel,
2775 MessageId::AutomationDeliveryLabel,
2776 MessageId::AutomationLastLabel,
2777 MessageId::AutomationRecentRunsLabel,
2778 MessageId::AutomationNoRuns,
2779 MessageId::AutomationRunsUnavailable,
2780 MessageId::AutomationTaskLabel,
2781 MessageId::AutomationMutationReceipt,
2782 MessageId::AutomationRunEnqueued,
2783 MessageId::AutomationDeletePreview,
2784 MessageId::AutomationDeleteConfirmationStale,
2785 MessageId::AutomationDeleted,
2786 ];
2787
2788 pub fn tr(locale: Locale, id: MessageId) -> Cow<'static, str> {
2789 rust_i18n::t!(format!("{id:?}"), locale = locale.tag())
2790 }
2791
2792 pub fn thinking_translation_placeholder(locale: Locale) -> &'static str {
2793 match locale {
2794 Locale::En => "Thinking; translating when complete...",
2795 Locale::Ja => "思考中です。完了後に日本語へ翻訳します...",
2796 Locale::ZhHans => "正在思考,完成后翻译为简体中文...",
2797 Locale::ZhHant => "正在思考,完成後翻譯為繁體中文...",
2798 Locale::PtBr => "Pensando; traduzindo ao concluir...",
2799 Locale::Es419 => "Pensando; traduciendo al finalizar...",
2800 Locale::Vi => "Đang suy nghĩ; sẽ dịch sau khi hoàn thành...",
2801 Locale::Ko => "생각하는 중입니다. 완료되면 번역합니다...",
2802 Locale::Ca => "S'està pensant; es traduirà en acabar...",
2803 Locale::De => "Denkt nach; Übersetzung folgt nach Abschluss...",
2804 Locale::Fr => "Réflexion en cours ; traduction à la fin...",
2805 Locale::Id => "Sedang berpikir; akan diterjemahkan setelah selesai...",
2806 Locale::Hi => "सोच रहा है; पूरा होने पर अनुवाद होगा...",
2807 Locale::Ru => "Идут размышления; перевод будет после завершения...",
2808 Locale::Uk => "Тривають роздуми; переклад буде після завершення...",
2809 }
2810 }
2811
2812 pub fn thinking_translation_in_progress(locale: Locale) -> &'static str {
2813 match locale {
2814 Locale::En => "Translating thinking content...",
2815 Locale::Ja => "思考内容を翻訳中...",
2816 Locale::ZhHans => "正在翻译思考内容...",
2817 Locale::ZhHant => "正在翻譯思考內容...",
2818 Locale::PtBr => "Traduzindo o conteúdo de raciocínio...",
2819 Locale::Es419 => "Traduciendo el contenido de razonamiento...",
2820 Locale::Vi => "Đang dịch nội dung suy nghĩ...",
2821 Locale::Ko => "생각 내용을 번역하는 중...",
2822 Locale::Ca => "S'està traduint el contingut del raonament...",
2823 Locale::De => "Denkinhalte werden übersetzt...",
2824 Locale::Fr => "Traduction du contenu de réflexion...",
2825 Locale::Id => "Menerjemahkan konten pemikiran...",
2826 Locale::Hi => "विचार सामग्री का अनुवाद हो रहा है...",
2827 Locale::Ru => "Перевод содержимого рассуждений...",
2828 Locale::Uk => "Переклад вмісту міркувань...",
2829 }
2830 }
2831
2832 pub fn thinking_translation_complete(locale: Locale) -> &'static str {
2833 match locale {
2834 Locale::En => "Thinking translation complete",
2835 Locale::Ja => "思考内容の翻訳が完了しました",
2836 Locale::ZhHans => "思考内容翻译完成",
2837 Locale::ZhHant => "思考內容翻譯完成",
2838 Locale::PtBr => "Tradução do raciocínio concluída",
2839 Locale::Es419 => "Traducción del razonamiento completada",
2840 Locale::Vi => "Đã dịch xong nội dung suy nghĩ",
2841 Locale::Ko => "생각 내용 번역 완료",
2842 Locale::Ca => "Traducció del raonament completada",
2843 Locale::De => "Übersetzung der Denkinhalte abgeschlossen",
2844 Locale::Fr => "Traduction de la réflexion terminée",
2845 Locale::Id => "Terjemahan pemikiran selesai",
2846 Locale::Hi => "विचार अनुवाद पूरा हुआ",
2847 Locale::Ru => "Перевод рассуждений завершён",
2848 Locale::Uk => "Переклад міркувань завершено",
2849 }
2850 }
2851
2852 pub fn thinking_translation_failed(locale: Locale) -> &'static str {
2853 match locale {
2854 Locale::En => "Thinking translation failed",
2855 Locale::Ja => "思考内容の翻訳に失敗しました",
2856 Locale::ZhHans => "思考内容翻译失败",
2857 Locale::ZhHant => "思考內容翻譯失敗",
2858 Locale::PtBr => "Falha ao traduzir o raciocínio",
2859 Locale::Es419 => "Falló la traducción del razonamiento",
2860 Locale::Vi => "Dịch nội dung suy nghĩ thất bại",
2861 Locale::Ko => "생각 내용 번역 실패",
2862 Locale::Ca => "Ha fallat la traducció del raonament",
2863 Locale::De => "Übersetzung der Denkinhalte fehlgeschlagen",
2864 Locale::Fr => "Échec de la traduction de la réflexion",
2865 Locale::Id => "Terjemahan pemikiran gagal",
2866 Locale::Hi => "विचार अनुवाद विफल",
2867 Locale::Ru => "Не удалось перевести рассуждения",
2868 Locale::Uk => "Не вдалося перекласти міркування",
2869 }
2870 }
2871
2872 pub fn hidden_translation_failed(locale: Locale) -> &'static str {
2873 match locale {
2874 Locale::En => "Translation failed; original text is hidden.",
2875 Locale::Ja => "翻訳に失敗しました。原文は非表示です。",
2876 Locale::ZhHans => "翻译失败,原文已隐藏。",
2877 Locale::ZhHant => "翻譯失敗,原文已隱藏。",
2878 Locale::PtBr => "A tradução falhou; o texto original está oculto.",
2879 Locale::Es419 => "La traducción falló; el texto original está oculto.",
2880 Locale::Vi => "Dịch thất bại; văn bản gốc đã bị ẩn.",
2881 Locale::Ko => "번역에 실패했습니다. 원문은 숨겨져 있습니다.",
2882 Locale::Ca => "La traducció ha fallat; el text original està amagat.",
2883 Locale::De => "Übersetzung fehlgeschlagen; der Originaltext ist ausgeblendet.",
2884 Locale::Fr => "La traduction a échoué ; le texte original est masqué.",
2885 Locale::Id => "Terjemahan gagal; teks asli disembunyikan.",
2886 Locale::Hi => "अनुवाद विफल; मूल पाठ छिपा हुआ है.",
2887 Locale::Ru => "Перевод не удался; исходный текст скрыт.",
2888 Locale::Uk => "Переклад не вдався; оригінальний текст приховано.",
2889 }
2890 }
2891
2892 pub fn normalize_configured_locale(input: &str) -> Option<&'static str> {
2893 let normalized = normalize_locale_input(input);
2894 if matches!(normalized.as_str(), "" | "auto" | "system") {
2895 return Some("auto");
2896 }
2897 parse_locale(&normalized).map(Locale::tag)
2898 }
2899
2900 /// Whether a configured locale selects a shipped pack that intentionally
2901 /// relies on English fallback for missing messages.
2902 #[must_use]
2903 pub fn configured_locale_is_partial_pack(input: &str) -> bool {
2904 let normalized = normalize_locale_input(input);
2905 if matches!(normalized.as_str(), "" | "auto" | "system") {
2906 return false;
2907 }
2908 parse_locale(&normalized).is_some_and(|locale| {
2909 Locale::shipped().contains(&locale)
2910 && locale.is_partial_pack()
2911 && !Locale::shipped_complete().contains(&locale)
2912 })
2913 }
2914
2915 /// Human-facing list of accepted `locale` setting values, derived from the
2916 /// shipped packs so config hints and error messages cannot go stale as new
2917 /// locales land. `separator` is `", "` for prose and `" | "` for hints.
2918 #[must_use]
2919 pub fn configured_locale_values(separator: &str) -> String {
2920 let mut out = String::from("auto");
2921 for locale in Locale::shipped() {
2922 out.push_str(separator);
2923 out.push_str(locale.tag());
2924 }
2925 out
2926 }
2927
2928 pub fn resolve_locale(setting: &str) -> Locale {
2929 resolve_locale_with_env(setting, |key| std::env::var(key).ok())
2930 }
2931
2932 pub fn resolve_locale_with_env<F>(setting: &str, env: F) -> Locale
2933 where
2934 F: Fn(&str) -> Option<String>,
2935 {
2936 let normalized = normalize_locale_input(setting);
2937 if !matches!(normalized.as_str(), "" | "auto" | "system") {
2938 return parse_locale(&normalized).unwrap_or(Locale::En);
2939 }
2940
2941 for key in ["LC_ALL", "LC_MESSAGES", "LANG"] {
2942 if let Some(value) = env(key)
2943 && let Some(locale) = parse_locale(&normalize_locale_input(&value))
2944 {
2945 return locale;
2946 }
2947 }
2948
2949 Locale::En
2950 }
2951
2952 #[allow(dead_code)]
2953 pub fn truncate_to_width(text: &str, max_width: usize) -> String {
2954 if max_width == 0 {
2955 return String::new();
2956 }
2957 if text.width() <= max_width {
2958 return text.to_string();
2959 }
2960
2961 let ellipsis_width = '…'.width().unwrap_or(1);
2962 if max_width <= ellipsis_width {
2963 return "…".to_string();
2964 }
2965
2966 let limit = max_width - ellipsis_width;
2967 let mut out = String::new();
2968 let mut width = 0usize;
2969 // Iterate extended grapheme clusters, not chars: a Devanagari conjunct
2970 // (क + ् + ष), a combined mark (e + ́), or a ZWJ emoji sequence must
2971 // never be cut apart — a trailing virama or orphaned combining mark
2972 // renders as visibly broken shaping in the terminal.
2973 for cluster in text.graphemes(true) {
2974 let cluster_width = UnicodeWidthStr::width(cluster);
2975 if width + cluster_width > limit {
2976 break;
2977 }
2978 out.push_str(cluster);
2979 width += cluster_width;
2980 }
2981 out.push('…');
2982 out
2983 }
2984
2985 fn normalize_locale_input(input: &str) -> String {
2986 input
2987 .split('.')
2988 .next()
2989 .unwrap_or(input)
2990 .split('@')
2991 .next()
2992 .unwrap_or(input)
2993 .trim()
2994 .replace('_', "-")
2995 .to_lowercase()
2996 }
2997
2998 fn parse_locale(value: &str) -> Option<Locale> {
2999 if value == "c" || value == "posix" || value.starts_with("en") {
3000 return Some(Locale::En);
3001 }
3002 if value.starts_with("ja") {
3003 return Some(Locale::Ja);
3004 }
3005 if value.starts_with("zh") {
3006 if value.contains("hant")
3007 || value.contains("-tw")
3008 || value.contains("-hk")
3009 || value.contains("-mo")
3010 {
3011 return Some(Locale::ZhHant);
3012 }
3013 return Some(Locale::ZhHans);
3014 }
3015 if value.starts_with("pt") || value == "br" {
3016 return Some(Locale::PtBr);
3017 }
3018 if value.starts_with("es") {
3019 return Some(Locale::Es419);
3020 }
3021 if value.starts_with("vi") {
3022 return Some(Locale::Vi);
3023 }
3024 if value.starts_with("ko") {
3025 return Some(Locale::Ko);
3026 }
3027 if value.starts_with("ca") {
3028 return Some(Locale::Ca);
3029 }
3030 if value.starts_with("de") {
3031 return Some(Locale::De);
3032 }
3033 if value.starts_with("fr") {
3034 return Some(Locale::Fr);
3035 }
3036 if value.starts_with("id") {
3037 return Some(Locale::Id);
3038 }
3039 if value.starts_with("hi") {
3040 return Some(Locale::Hi);
3041 }
3042 if value.starts_with("ru") {
3043 return Some(Locale::Ru);
3044 }
3045 if value.starts_with("uk") {
3046 return Some(Locale::Uk);
3047 }
3048 None
3049 }
3050
3051 #[cfg(test)]
3052 mod tests {
3053 use super::*;
3054 use ratatui::{
3055 buffer::Buffer,
3056 layout::Rect,
3057 widgets::{Paragraph, Widget, Wrap},
3058 };
3059
3060 #[test]
3061 fn locale_setting_normalizes_supported_tags() {
3062 assert_eq!(normalize_configured_locale("auto"), Some("auto"));
3063 assert_eq!(normalize_configured_locale("ja_JP.UTF-8"), Some("ja"));
3064 assert_eq!(normalize_configured_locale("zh-CN"), Some("zh-Hans"));
3065 assert_eq!(normalize_configured_locale("zh-TW"), Some("zh-Hant"));
3066 assert_eq!(normalize_configured_locale("zh_HK.UTF-8"), Some("zh-Hant"));
3067 assert_eq!(normalize_configured_locale("pt"), Some("pt-BR"));
3068 assert_eq!(normalize_configured_locale("pt-PT"), Some("pt-BR"));
3069 assert_eq!(normalize_configured_locale("es"), Some("es-419"));
3070 assert_eq!(normalize_configured_locale("es-MX"), Some("es-419"));
3071 assert_eq!(normalize_configured_locale("ca-ES"), Some("ca"));
3072 assert_eq!(normalize_configured_locale("de_DE.UTF-8"), Some("de"));
3073 assert_eq!(normalize_configured_locale("fr-FR"), Some("fr"));
3074 assert_eq!(normalize_configured_locale("id-ID"), Some("id"));
3075 assert_eq!(normalize_configured_locale("hi_IN.UTF-8"), Some("hi"));
3076 assert_eq!(normalize_configured_locale("ru-RU"), Some("ru"));
3077 assert_eq!(normalize_configured_locale("uk_UA.UTF-8"), Some("uk"));
3078 }
3079
3080 #[test]
3081 fn partial_pack_status_tracks_the_shipped_locale_registry() {
3082 assert!(!configured_locale_is_partial_pack("auto"));
3083 assert!(!configured_locale_is_partial_pack("system"));
3084 assert!(!configured_locale_is_partial_pack("zh-Hant"));
3085 assert!(!configured_locale_is_partial_pack("zh_TW.UTF-8"));
3086 assert!(!configured_locale_is_partial_pack("vi"));
3087 assert!(!configured_locale_is_partial_pack("ko"));
3088
3089 for locale in Locale::shipped() {
3090 assert_eq!(
3091 configured_locale_is_partial_pack(locale.tag()),
3092 locale.is_partial_pack(),
3093 "{} partial-pack classification drifted",
3094 locale.tag()
3095 );
3096 assert_ne!(
3097 Locale::shipped_complete().contains(locale),
3098 locale.is_partial_pack(),
3099 "{} must be exactly one of complete or partial",
3100 locale.tag()
3101 );
3102 }
3103 }
3104
3105 #[test]
3106 fn locale_resolution_uses_config_then_environment_then_english() {
3107 assert_eq!(
3108 resolve_locale_with_env("ja", |_| Some("pt_BR.UTF-8".to_string())),
3109 Locale::Ja
3110 );
3111 assert_eq!(
3112 resolve_locale_with_env("auto", |key| {
3113 (key == "LANG").then(|| "zh_CN.UTF-8".to_string())
3114 }),
3115 Locale::ZhHans
3116 );
3117 assert_eq!(
3118 resolve_locale_with_env("auto", |key| {
3119 (key == "LANG").then(|| "zh_TW.UTF-8".to_string())
3120 }),
3121 Locale::ZhHant
3122 );
3123 assert_eq!(resolve_locale_with_env("auto", |_| None), Locale::En);
3124 }
3125
3126 pub fn missing_message_ids(locale: Locale) -> Vec<MessageId> {
3127 ALL_MESSAGE_IDS
3128 .iter()
3129 .copied()
3130 .filter(|id| tr(locale, *id).eq(&format!("{id:?}")))
3131 .collect()
3132 }
3133
3134 fn locale_json_source(locale: Locale) -> &'static str {
3135 match locale {
3136 Locale::En => include_str!("../locales/en.json"),
3137 Locale::Ja => include_str!("../locales/ja.json"),
3138 Locale::ZhHans => include_str!("../locales/zh-Hans.json"),
3139 Locale::ZhHant => include_str!("../locales/zh-Hant.json"),
3140 Locale::PtBr => include_str!("../locales/pt-BR.json"),
3141 Locale::Es419 => include_str!("../locales/es-419.json"),
3142 Locale::Vi => include_str!("../locales/vi.json"),
3143 Locale::Ko => include_str!("../locales/ko.json"),
3144 Locale::Ca => include_str!("../locales/ca.json"),
3145 Locale::De => include_str!("../locales/de.json"),
3146 Locale::Fr => include_str!("../locales/fr.json"),
3147 Locale::Id => include_str!("../locales/id.json"),
3148 Locale::Hi => include_str!("../locales/hi.json"),
3149 Locale::Ru => include_str!("../locales/ru.json"),
3150 Locale::Uk => include_str!("../locales/uk.json"),
3151 }
3152 }
3153
3154 #[test]
3155 fn shipped_complete_packs_have_no_missing_core_messages() {
3156 for locale in Locale::shipped_complete() {
3157 assert!(
3158 missing_message_ids(*locale).is_empty(),
3159 "{} is missing messages",
3160 locale.tag()
3161 );
3162 }
3163 }
3164
3165 #[test]
3166 fn work_stop_confirmation_is_explicitly_localized() {
3167 for locale in Locale::shipped_complete() {
3168 if *locale == Locale::En {
3169 continue;
3170 }
3171 assert_ne!(tr(*locale, MessageId::SidebarStopControl), "stop");
3172 assert_ne!(
3173 tr(*locale, MessageId::WorkSurfaceStopConfirmHint),
3174 "confirm stop · Esc cancels"
3175 );
3176 }
3177 }
3178
3179 #[test]
3180 fn coordination_work_chrome_is_explicitly_localized() {
3181 for locale in Locale::shipped_complete() {
3182 if *locale == Locale::En {
3183 continue;
3184 }
3185 assert_ne!(
3186 tr(*locale, MessageId::CoordinationWorkTitle),
3187 tr(Locale::En, MessageId::CoordinationWorkTitle),
3188 "{} fell back to the English Coordination Work title",
3189 locale.tag()
3190 );
3191 assert_ne!(
3192 tr(*locale, MessageId::CoordinationMetricsNoAuthoritativeSource),
3193 tr(
3194 Locale::En,
3195 MessageId::CoordinationMetricsNoAuthoritativeSource
3196 ),
3197 "{} fell back to the English coordination metrics note",
3198 locale.tag()
3199 );
3200 }
3201 }
3202
3203 fn raw_locale_messages(locale: Locale) -> serde_json::Map<String, serde_json::Value> {
3204 serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(locale_json_source(
3205 locale,
3206 ))
3207 .unwrap_or_else(|err| panic!("{} locale json should parse: {err}", locale.tag()))
3208 }
3209
3210 fn raw_locale_keys(locale: Locale) -> std::collections::BTreeSet<String> {
3211 raw_locale_messages(locale).keys().cloned().collect()
3212 }
3213
3214 fn message_placeholders(value: &str) -> std::collections::BTreeSet<String> {
3215 value
3216 .split('{')
3217 .skip(1)
3218 .filter_map(|suffix| suffix.split_once('}').map(|(name, _)| name.to_string()))
3219 .collect()
3220 }
3221
3222 #[test]
3223 fn coordination_complete_packs_have_raw_key_and_placeholder_parity() {
3224 let english = raw_locale_messages(Locale::En);
3225 let coordination_keys = english
3226 .keys()
3227 .filter(|key| key.starts_with("Coordination"))
3228 .collect::<Vec<_>>();
3229 assert_eq!(coordination_keys.len(), 39);
3230
3231 for locale in Locale::shipped_complete() {
3232 let pack = raw_locale_messages(*locale);
3233 for key in &coordination_keys {
3234 let english_value = english
3235 .get(*key)
3236 .and_then(serde_json::Value::as_str)
3237 .unwrap_or_else(|| panic!("English {key} must be a string"));
3238 let translated = pack
3239 .get(*key)
3240 .and_then(serde_json::Value::as_str)
3241 .unwrap_or_else(|| panic!("{} is missing raw key {key}", locale.tag()));
3242 assert_eq!(
3243 message_placeholders(translated),
3244 message_placeholders(english_value),
3245 "{} changed placeholders for {key}",
3246 locale.tag()
3247 );
3248 }
3249 }
3250 }
3251
3252 #[test]
3253 fn automation_complete_packs_have_raw_key_and_placeholder_parity() {
3254 let english = raw_locale_messages(Locale::En);
3255 let automation_keys = english
3256 .keys()
3257 .filter(|key| key.starts_with("Automation"))
3258 .collect::<Vec<_>>();
3259 assert_eq!(automation_keys.len(), 42);
3260
3261 for locale in Locale::shipped_complete() {
3262 let pack = raw_locale_messages(*locale);
3263 for key in &automation_keys {
3264 let english_value = english
3265 .get(*key)
3266 .and_then(serde_json::Value::as_str)
3267 .unwrap_or_else(|| panic!("English {key} must be a string"));
3268 let translated = pack
3269 .get(*key)
3270 .and_then(serde_json::Value::as_str)
3271 .unwrap_or_else(|| panic!("{} is missing raw key {key}", locale.tag()));
3272 assert_eq!(
3273 message_placeholders(translated),
3274 message_placeholders(english_value),
3275 "{} changed placeholders for {key}",
3276 locale.tag()
3277 );
3278 }
3279 }
3280 }
3281
3282 /// The `/cost` and `/tokens` honesty block is assembled by `{placeholder}`
3283 /// substitution, so a translation that drops or renames one silently ships a
3284 /// line with a literal `{priced}` in it — or worse, omits the count that
3285 /// makes the sentence true. Cost copy is exactly where a mistranslation
3286 /// becomes a false claim about money, so it gets the same hard parity gate
3287 /// the coordination pack has (#4318).
3288 #[test]
3289 fn cost_copy_has_raw_key_and_placeholder_parity_across_complete_packs() {
3290 let english = raw_locale_messages(Locale::En);
3291 let cost_keys = english
3292 .keys()
3293 .filter(|key| key.starts_with("CmdCost") || key.starts_with("CmdTokensCache"))
3294 .cloned()
3295 .collect::<Vec<_>>();
3296 // Guard against the filter silently matching nothing after a rename.
3297 assert!(
3298 cost_keys.len() >= 12,
3299 "expected the full CmdCost*/CmdTokensCache* set, found {cost_keys:?}"
3300 );
3301 // The keys this pass added must be in the set the gate covers.
3302 for required in [
3303 "CmdCostEstimateOnly",
3304 "CmdCostCoverage",
3305 "CmdCostCoverageUnknownLegacy",
3306 "CmdCostUnpricedTurns",
3307 "CmdCostUnpricedClasses",
3308 "CmdCostPricingProvenance",
3309 "CmdCostLivePricingDowngraded",
3310 "CmdCostLivePricingUnavailable",
3311 "CmdCostRoutesHeader",
3312 "CmdTokensCacheWriteTotal",
3313 ] {
3314 assert!(
3315 cost_keys.iter().any(|key| key == required),
3316 "{required} is missing from en.json"
3317 );
3318 }
3319
3320 for locale in Locale::shipped_complete() {
3321 let pack = raw_locale_messages(*locale);
3322 for key in &cost_keys {
3323 let english_value = english
3324 .get(key)
3325 .and_then(serde_json::Value::as_str)
3326 .unwrap_or_else(|| panic!("English {key} must be a string"));
3327 let translated = pack
3328 .get(key)
3329 .and_then(serde_json::Value::as_str)
3330 .unwrap_or_else(|| panic!("{} is missing raw key {key}", locale.tag()));
3331 assert_eq!(
3332 message_placeholders(translated),
3333 message_placeholders(english_value),
3334 "{} changed placeholders for {key}",
3335 locale.tag()
3336 );
3337 }
3338 }
3339 }
3340
3341 /// Key parity proves a pack *has* the subtotal and audited-route lines; it
3342 /// does not prove anyone translated them. A pack that copies the English
3343 /// string passes every structural gate and still ships English text to a
3344 /// Japanese user — and these two lines are the ones that say a money figure
3345 /// is incomplete and name the routes it was built from, which is exactly
3346 /// the copy a reader must be able to understand (#4318).
3347 #[test]
3348 fn every_complete_pack_localizes_the_subtotal_and_audited_route_copy() {
3349 for locale in Locale::shipped_complete()
3350 .iter()
3351 .filter(|locale| **locale != Locale::En)
3352 {
3353 for id in [
3354 MessageId::CmdCostReportSubtotal,
3355 MessageId::CmdCostReportUnknown,
3356 MessageId::CmdCostRoutesHeader,
3357 MessageId::CmdCostUnknownValue,
3358 MessageId::CmdCostCoverageUnknownLegacy,
3359 ] {
3360 let localized = tr(*locale, id);
3361 let english = tr(Locale::En, id);
3362 assert!(
3363 !localized.trim().is_empty(),
3364 "{} has empty copy for {id:?}",
3365 locale.tag()
3366 );
3367 assert_ne!(
3368 localized,
3369 english,
3370 "{} still ships the English string for {id:?}",
3371 locale.tag()
3372 );
3373 }
3374 // The subtotal headline must still carry its amount, and must not
3375 // reuse the complete-total wording — those two states are the whole
3376 // point of having separate keys.
3377 let subtotal = tr(*locale, MessageId::CmdCostReportSubtotal);
3378 assert!(
3379 subtotal.contains("{cost}"),
3380 "{} subtotal headline lost its amount",
3381 locale.tag()
3382 );
3383 assert_ne!(
3384 subtotal,
3385 tr(*locale, MessageId::CmdCostReport),
3386 "{} cannot distinguish a subtotal from a complete total",
3387 locale.tag()
3388 );
3389 // The unknown headline names no amount at all.
3390 let unknown = tr(*locale, MessageId::CmdCostReportUnknown);
3391 assert!(
3392 !unknown.contains("{cost}"),
3393 "{} unknown headline must not interpolate an amount",
3394 locale.tag()
3395 );
3396 }
3397 }
3398
3399 /// Both money surfaces must say "estimate". `/tokens` quotes the same total
3400 /// as `/cost`, so it cannot present it as settled while `/cost` hedges.
3401 #[test]
3402 fn every_complete_pack_marks_the_cost_total_as_an_estimate() {
3403 for locale in Locale::shipped_complete() {
3404 let disclaimer = tr(*locale, MessageId::CmdCostEstimateOnly);
3405 assert!(
3406 !disclaimer.trim().is_empty(),
3407 "{} has no cost estimate disclaimer",
3408 locale.tag()
3409 );
3410 let coverage = tr(*locale, MessageId::CmdCostCoverage);
3411 assert!(
3412 coverage.contains("{priced}") && coverage.contains("{turns}"),
3413 "{} coverage line lost its counts",
3414 locale.tag()
3415 );
3416 }
3417 }
3418
3419 /// `missing_message_ids` is blind to keys that exist in en but not in a
3420 /// "complete" pack — the English fallback returns the English string, so
3421 /// nothing looks missing. Keep the enum, en.json, and ALL_MESSAGE_IDS in
3422 /// exact sync so every other parity gate actually sees every message.
3423 #[test]
3424 fn message_id_list_english_pack_stay_in_exact_sync() {
3425 let en = raw_locale_keys(Locale::En);
3426 let ids: std::collections::BTreeSet<String> =
3427 ALL_MESSAGE_IDS.iter().map(|id| format!("{id:?}")).collect();
3428 assert_eq!(
3429 ids.len(),
3430 ALL_MESSAGE_IDS.len(),
3431 "ALL_MESSAGE_IDS contains duplicates"
3432 );
3433 let unlisted: Vec<_> = en.difference(&ids).collect();
3434 assert!(
3435 unlisted.is_empty(),
3436 "en.json keys absent from ALL_MESSAGE_IDS — every parity test is blind to them: {unlisted:?}"
3437 );
3438 let untranslatable: Vec<_> = ids.difference(&en).collect();
3439 assert!(
3440 untranslatable.is_empty(),
3441 "ALL_MESSAGE_IDS entries without an en.json string: {untranslatable:?}"
3442 );
3443 }
3444
3445 /// Raw key-set parity for every pack that claims completeness, in both
3446 /// directions. This is the test that fails when a new en key ships
3447 /// without translations instead of silently falling back to English.
3448 #[test]
3449 fn shipped_complete_packs_have_raw_key_parity_with_english() {
3450 let en = raw_locale_keys(Locale::En);
3451 for locale in Locale::shipped_complete() {
3452 if *locale == Locale::En {
3453 continue;
3454 }
3455 let pack = raw_locale_keys(*locale);
3456 let missing: Vec<_> = en.difference(&pack).collect();
3457 assert!(
3458 missing.is_empty(),
3459 "{} claims completeness but lacks {} key(s); the English fallback hides these at runtime: {missing:?}",
3460 locale.tag(),
3461 missing.len()
3462 );
3463 let extra: Vec<_> = pack.difference(&en).collect();
3464 assert!(
3465 extra.is_empty(),
3466 "{} defines key(s) en.json lacks: {extra:?}",
3467 locale.tag()
3468 );
3469 }
3470 }
3471
3472 #[test]
3473 fn zh_hant_has_reached_en_parity_and_is_complete() {
3474 assert!(
3475 !Locale::ZhHant.is_partial_pack(),
3476 "zh-Hant is now a complete pack and must not be marked partial"
3477 );
3478 assert!(
3479 Locale::shipped_complete().contains(&Locale::ZhHant),
3480 "zh-Hant must be included in shipped_complete now that it has full en.json parity"
3481 );
3482 let en_keys = serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(
3483 locale_json_source(Locale::En),
3484 )
3485 .expect("en locale json");
3486 let zh_hant_keys = serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(
3487 locale_json_source(Locale::ZhHant),
3488 )
3489 .expect("zh-Hant locale json");
3490 assert_eq!(
3491 zh_hant_keys.len(),
3492 en_keys.len(),
3493 "zh-Hant must have the same number of keys as en.json"
3494 );
3495 }
3496
3497 #[test]
3498 fn shipped_setup_strings_are_explicitly_localized() {
3499 let setup_keys = ALL_MESSAGE_IDS
3500 .iter()
3501 .map(|id| format!("{id:?}"))
3502 .filter(|id| id.starts_with("Setup"))
3503 .collect::<Vec<_>>();
3504
3505 for locale in Locale::shipped_complete() {
3506 let messages = serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(
3507 locale_json_source(*locale),
3508 )
3509 .unwrap_or_else(|err| panic!("{} locale json should parse: {err}", locale.tag()));
3510 for key in &setup_keys {
3511 assert!(
3512 messages.contains_key(key),
3513 "{} should define {key} explicitly",
3514 locale.tag()
3515 );
3516 }
3517 }
3518 }
3519
3520 #[test]
3521 fn zh_hans_constitution_copy_uses_charter_term() {
3522 let messages = serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(
3523 locale_json_source(Locale::ZhHans),
3524 )
3525 .expect("zh-Hans locale json");
3526
3527 for (key, value) in &messages {
3528 let Some(value) = value.as_str() else {
3529 continue;
3530 };
3531 for literal_metaphor in ["宪法", "教义", "自由原则", "仓库法则"] {
3532 assert!(
3533 !value.contains(literal_metaphor),
3534 "zh-Hans {key} should use functional terminology instead of {literal_metaphor}: {value}"
3535 );
3536 }
3537 }
3538
3539 let setup_intro = tr(Locale::ZhHans, MessageId::SetupStepConstitutionWhy);
3540 assert!(setup_intro.contains("Codewhale"));
3541 assert!(setup_intro.contains("宪章"));
3542 assert!(!setup_intro.contains("代码"));
3543 let welcome = tr(Locale::ZhHans, MessageId::OnboardWelcomeLead);
3544 assert!(welcome.contains("Codewhale"));
3545 assert!(!welcome.contains("代码"));
3546 assert!(tr(Locale::ZhHans, MessageId::OnboardTipsLine2).contains("/constitution"));
3547 assert!(
3548 tr(
3549 Locale::ZhHans,
3550 MessageId::SetupConstitutionFileLoadedUnselected
3551 )
3552 .contains("constitution.json")
3553 );
3554 }
3555
3556 #[test]
3557 fn route_and_provider_picker_strings_are_translated_in_complete_locales() {
3558 // High-visibility model/provider empty states and footers must not
3559 // leak English through the fallback chain in complete packs.
3560 let ids = [
3561 MessageId::PickerActionMove,
3562 MessageId::PickerActionSwitch,
3563 MessageId::PickerActionApply,
3564 MessageId::PickerActionSetStartupDefault,
3565 MessageId::PickerActionCancel,
3566 MessageId::PickerActionClear,
3567 MessageId::PickerActionClearSearch,
3568 MessageId::PickerActionBrowseAll,
3569 MessageId::PickerActionCustom,
3570 MessageId::PickerActionJump,
3571 MessageId::PickerActionEditKey,
3572 MessageId::PickerActionModels,
3573 MessageId::PickerActionConfigured,
3574 MessageId::RouteNoModels,
3575 MessageId::RouteNoModelMatch,
3576 MessageId::ProviderNoMatchesTitle,
3577 MessageId::ProviderNoMatchesHint,
3578 MessageId::ProviderNoConfiguredTitle,
3579 MessageId::ProviderNoConfiguredHint,
3580 MessageId::ProviderNoCatalogModels,
3581 MessageId::SessionsOpenedHistory,
3582 MessageId::SessionsTimeJustNow,
3583 ];
3584 for locale in Locale::shipped_complete() {
3585 if *locale == Locale::En {
3586 continue;
3587 }
3588 for id in ids {
3589 let localized = tr(*locale, id);
3590 assert!(!localized.is_empty(), "{} empty for {id:?}", locale.tag());
3591 // Catalan "models" is the correct translation of the English
3592 // picker action — the words coincide. Every other id must
3593 // differ from English, or the pack is leaking the fallback.
3594 if matches!((*locale, id), (Locale::Ca, MessageId::PickerActionModels)) {
3595 continue;
3596 }
3597 assert_ne!(
3598 localized,
3599 tr(Locale::En, id),
3600 "{} should translate {id:?}",
3601 locale.tag()
3602 );
3603 }
3604 }
3605 }
3606
3607 #[test]
3608 fn mode_picker_strings_are_translated_in_non_english_locales() {
3609 // The mode hints are full sentences; every shipped non-English locale
3610 // must provide a real translation rather than leaking the English
3611 // string through the fallback chain.
3612 let sentences = [
3613 MessageId::AppModeAgentHint,
3614 MessageId::AppModeAutoHint,
3615 MessageId::AppModePlanHint,
3616 MessageId::AppModeYoloHint,
3617 MessageId::AppModeOperateHint,
3618 ];
3619 for locale in Locale::shipped_complete() {
3620 if *locale == Locale::En {
3621 continue;
3622 }
3623 for id in sentences {
3624 let localized = tr(*locale, id);
3625 assert!(!localized.is_empty(), "{} empty for {id:?}", locale.tag());
3626 assert_ne!(
3627 localized,
3628 tr(Locale::En, id),
3629 "{} should translate {id:?}",
3630 locale.tag()
3631 );
3632 }
3633 }
3634 }
3635
3636 #[test]
3637 fn zh_hant_hotbar_command_and_keybinding_strings_are_native() {
3638 for id in [
3639 MessageId::CmdHotbarDescription,
3640 MessageId::KbJumpPlanAgentYolo,
3641 MessageId::KbAltJumpPlanAgentYolo,
3642 ] {
3643 let localized = tr(Locale::ZhHant, id);
3644 assert!(!localized.is_empty(), "zh-Hant empty for {id:?}");
3645 assert_ne!(
3646 localized,
3647 tr(Locale::En, id),
3648 "zh-Hant should translate {id:?}"
3649 );
3650 }
3651 }
3652
3653 #[test]
3654 fn unsupported_locale_falls_back_to_english() {
3655 assert_eq!(
3656 resolve_locale_with_env("ar", |_| None),
3657 Locale::En,
3658 "Arabic is planned for QA but not shipped in the v0.7.6 core pack"
3659 );
3660 }
3661
3662 #[test]
3663 fn provider_description_is_present_for_all_locales() {
3664 for locale in Locale::shipped_complete() {
3665 let description = tr(*locale, MessageId::CmdProviderDescription);
3666 assert!(
3667 !description.is_empty(),
3668 "{} provider description should not be empty",
3669 locale.tag()
3670 );
3671 assert!(
3672 !description.contains("codewhale |"),
3673 "{} provider description should not name codewhale as a backend: {description}",
3674 locale.tag()
3675 );
3676 }
3677 }
3678
3679 #[test]
3680 fn width_truncation_handles_cjk_rtl_indic_and_latin_samples() {
3681 let samples = [
3682 ("zh-Hans", "输入以筛选配置"),
3683 ("ar", "تصفية الإعدادات"),
3684 ("hi", "सेटिंग खोजें"),
3685 ("pt-BR", "configurações filtradas"),
3686 ];
3687
3688 for (tag, sample) in samples {
3689 let truncated = truncate_to_width(sample, 12);
3690 assert!(
3691 truncated.width() <= 12,
3692 "{tag} sample overflowed: {truncated:?}"
3693 );
3694 }
3695 }
3696
3697 #[test]
3698 fn planned_script_samples_render_in_narrow_terminal_buffer() {
3699 let samples = [
3700 ("CJK", "输入以筛选配置"),
3701 ("RTL", "تصفية الإعدادات"),
3702 ("Indic", "सेटिंग खोजें"),
3703 ("Latin Global South", "configurações filtradas"),
3704 ];
3705
3706 for (label, sample) in samples {
3707 let area = Rect::new(0, 0, 18, 4);
3708 let mut buf = Buffer::empty(area);
3709 Paragraph::new(sample)
3710 .wrap(Wrap { trim: false })
3711 .render(area, &mut buf);
3712 let dump = buffer_text(&buf, area);
3713
3714 assert!(
3715 dump.chars().any(|ch| !ch.is_whitespace()),
3716 "{label} sample produced an empty render"
3717 );
3718 }
3719 }
3720
3721 fn buffer_text(buf: &Buffer, area: Rect) -> String {
3722 let mut out = String::new();
3723 for y in area.top()..area.bottom() {
3724 for x in area.left()..area.right() {
3725 out.push_str(buf[(x, y)].symbol());
3726 }
3727 out.push('\n');
3728 }
3729 out
3730 }
3731
3732 fn visible_row_text(buf: &Buffer, area: Rect, y: u16) -> String {
3733 let mut out = String::new();
3734 let mut skip_cells = 0usize;
3735 for x in area.left()..area.right() {
3736 if skip_cells > 0 {
3737 skip_cells -= 1;
3738 continue;
3739 }
3740 let symbol = buf[(x, y)].symbol();
3741 out.push_str(symbol);
3742 skip_cells = UnicodeWidthStr::width(symbol).saturating_sub(1);
3743 }
3744 out
3745 }
3746
3747 // --- Unicode / CJK / terminal-width QA (issue #3488) -------------------
3748 // `truncate_to_width` is the localization-layer truncation helper. These
3749 // verify it clips by display width (never byte/char count), preserves
3750 // semantic prefixes, never splits a grapheme cluster, and that mixed
3751 // English/CJK rows wrap inside a narrow (40-col) and medium (80-col)
3752 // terminal buffer without overflowing the column.
3753
3754 #[test]
3755 fn truncate_to_width_clips_cjk_by_display_width_and_keeps_prefix_intact() {
3756 // Each Han glyph is two columns. A 12-column budget fits the six-glyph
3757 // title exactly, so no truncation/ellipsis happens and the prefix survives.
3758 let title = "项目报告结果"; // 12 columns
3759 assert_eq!(truncate_to_width(title, 12), title);
3760
3761 // Oversized: clip on a whole-glyph boundary, append the ellipsis, and
3762 // stay within the budget by display width.
3763 let out = truncate_to_width("数据库迁移任务结果", 7); // 10 glyphs = 20 cols
3764 assert!(
3765 UnicodeWidthStr::width(out.as_str()) <= 7,
3766 "{out:?} overflowed"
3767 );
3768 assert!(out.ends_with('…'), "expected ellipsis, got {out:?}");
3769 assert!(!out.contains('\u{FFFD}'), "split a wide glyph: {out:?}");
3770 // The kept body is whole wide glyphs (each two columns) — never a half cell.
3771 let body = out.strip_suffix('…').unwrap_or(&out);
3772 assert!(
3773 body.chars()
3774 .map(|c| UnicodeWidthChar::width(c).unwrap_or(0))
3775 .sum::<usize>()
3776 <= 6,
3777 "body exceeded budget-minus-ellipsis: {out:?}"
3778 );
3779
3780 // A semantic ASCII prefix (e.g. a status verb) survives when it fits.
3781 let row = "running 数据库迁移任务结果预览测试";
3782 let out = truncate_to_width(row, 16);
3783 assert!(
3784 out.starts_with("running"),
3785 "semantic prefix dropped: {out:?}"
3786 );
3787 assert!(UnicodeWidthStr::width(out.as_str()) <= 16);
3788 assert!(!out.contains('\u{FFFD}'));
3789 }
3790
3791 #[test]
3792 fn truncate_to_width_never_splits_combining_marks_or_emoji() {
3793 // Combining mark (U+0301) and ZWJ are zero-width; they must not be
3794 // counted as columns and must never be cut mid-cluster into U+FFFD.
3795 let cafe = "cafe\u{0301}"; // "café", 4 columns
3796 assert_eq!(truncate_to_width(cafe, 10), cafe);
3797 let out = truncate_to_width("cafe\u{0301} overflow here", 6);
3798 assert!(UnicodeWidthStr::width(out.as_str()) <= 6);
3799 assert!(!out.contains('\u{FFFD}'));
3800
3801 // Emoji is two columns; truncation lands on a cluster boundary.
3802 let out = truncate_to_width("\u{1F433}\u{1F433}\u{1F433} whales everywhere", 5);
3803 assert!(UnicodeWidthStr::width(out.as_str()) <= 5);
3804 assert!(!out.contains('\u{FFFD}'));
3805 }
3806
3807 #[test]
3808 fn narrow_and_medium_terminal_wraps_mixed_width_rows_without_overflow() {
3809 // Issue #3488 acceptance: at a 40-col (narrow, macOS-Terminal-like) and
3810 // 80-col (medium) terminal, mixed English/CJK task titles and transcript
3811 // lines must (a) truncate to the column by display width, and (b) wrap
3812 // inside the buffer so no rendered row exceeds the terminal width.
3813 let fixtures = [
3814 "Task: 数据库迁移任务 — verify provider routing for issue #3488",
3815 "抹香鲸 is running codex/issue-3439-zhipu-glm-fixture @ issue-3439",
3816 "满員電車🫠 — full-width punctuation:『』【】 mixes with ASCII ids",
3817 ];
3818
3819 for width in [40usize, 80] {
3820 // (a) The truncation helper clips by display width.
3821 for fixture in fixtures {
3822 let out = truncate_to_width(fixture, width);
3823 assert!(
3824 UnicodeWidthStr::width(out.as_str()) <= width,
3825 "width={width}: truncated row overflowed: {out:?}"
3826 );
3827 assert!(
3828 !out.contains('\u{FFFD}'),
3829 "width={width}: split a glyph: {out:?}"
3830 );
3831 }
3832
3833 // (b) Wrapping the full mixed-width line inside a buffer of `width`
3834 // columns never lets a rendered row exceed the terminal width.
3835 for fixture in fixtures {
3836 let area = Rect::new(0, 0, width as u16, 6);
3837 let mut buf = Buffer::empty(area);
3838 Paragraph::new(fixture)
3839 .wrap(Wrap { trim: false })
3840 .render(area, &mut buf);
3841 let mut saw_text = false;
3842 for (row_idx, y) in (area.top()..area.bottom()).enumerate() {
3843 let row = visible_row_text(&buf, area, y);
3844 let trimmed = row.trim_end_matches('\u{0}').trim_end();
3845 assert!(
3846 UnicodeWidthStr::width(trimmed) <= width,
3847 "width={width} row {row_idx}: wrapped row overflowed ({} cols): {trimmed:?}",
3848 UnicodeWidthStr::width(trimmed)
3849 );
3850 saw_text |= trimmed.chars().any(|ch| !ch.is_whitespace());
3851 }
3852 assert!(
3853 saw_text,
3854 "width={width}: mixed fixture produced an empty render"
3855 );
3856 }
3857 }
3858 }
3859
3860 // --- Cyrillic script fixtures (ru/uk, #3092 / #4791) -------------------
3861 // Russian and Ukrainian share the Cyrillic script but are different
3862 // languages. These fixtures lock the failure modes seen in real
3863 // machine-translated packs: Russian-only letters (ы/э/ъ) leaking into
3864 // the Ukrainian pack, Ukrainian-only letters (і/ї/є/ґ) leaking into the
3865 // Russian pack, untranslated English prose hiding behind the fallback,
3866 // and one pack copied into the other.
3867
3868 fn has_cyrillic(value: &str) -> bool {
3869 value
3870 .chars()
3871 .any(|ch| ('\u{0400}'..='\u{04FF}').contains(&ch))
3872 }
3873
3874 fn has_devanagari(value: &str) -> bool {
3875 value
3876 .chars()
3877 .any(|ch| ('\u{0900}'..='\u{097F}').contains(&ch))
3878 }
3879
3880 /// Latin words remaining after the exempt categories are stripped:
3881 /// `code spans`, {placeholders}, URLs, slash commands, env-style
3882 /// ALL-CAPS tokens, and the product-term allowlist from
3883 /// `locales/AGENTS.md`. Anything left over in a Cyrillic or Devanagari
3884 /// string is mixed-language copy.
3885 fn latin_words_in_translated_copy(value: &str) -> Vec<String> {
3886 const ALLOWED: &[&str] = &[
3887 "codewhale",
3888 "deepseek",
3889 "fleet",
3890 "plan",
3891 "act",
3892 "operate",
3893 "ask",
3894 "auto",
3895 "review",
3896 "full",
3897 "access",
3898 "enter",
3899 "esc",
3900 "alt",
3901 "ctrl",
3902 "shift",
3903 "tab",
3904 "space",
3905 "backspace",
3906 "delete",
3907 "api",
3908 "json",
3909 "toml",
3910 "yaml",
3911 "yml",
3912 "tui",
3913 "ci",
3914 "cd",
3915 "mcp",
3916 "url",
3917 "uri",
3918 "dns",
3919 "ssh",
3920 "http",
3921 "https",
3922 "git",
3923 "github",
3924 "gitee",
3925 "openai",
3926 "anthropic",
3927 "gemini",
3928 "kimi",
3929 "codex",
3930 "claude",
3931 "vllm",
3932 "ollama",
3933 "sglang",
3934 "npm",
3935 "rust",
3936 "cargo",
3937 "linux",
3938 "macos",
3939 "windows",
3940 "id",
3941 "ok",
3942 "true",
3943 "false",
3944 "utf",
3945 "ascii",
3946 "cli",
3947 "ui",
3948 "md",
3949 "ai",
3950 "llm",
3951 "gpt",
3952 "faq",
3953 "docs",
3954 "admin",
3955 "oauth",
3956 "ssl",
3957 "tls",
3958 "jwt",
3959 "svg",
3960 "png",
3961 "wasm",
3962 "app",
3963 "slash",
3964 "skill",
3965 "plugin",
3966 "shell",
3967 ];
3968 let mut scrubbed = String::with_capacity(value.len());
3969 let mut chars = value.chars();
3970 let mut in_backtick = false;
3971 let mut in_brace = false;
3972 for ch in chars.by_ref() {
3973 match ch {
3974 '`' => in_backtick = !in_backtick,
3975 '{' if !in_backtick => in_brace = true,
3976 '}' if in_brace => in_brace = false,
3977 _ if !in_backtick && !in_brace => scrubbed.push(ch),
3978 _ => {}
3979 }
3980 }
3981 scrubbed
3982 .split(|c: char| !c.is_ascii_alphanumeric() && c != '-' && c != '/')
3983 .filter(|token| token.len() >= 2)
3984 .filter(|token| !token.contains('/') && !token.contains("://"))
3985 .filter(|token| token.is_ascii())
3986 .filter(|token| !token.chars().any(|c| c.is_ascii_digit()))
3987 .filter(|token| !token.chars().all(|c| c.is_ascii_uppercase()))
3988 .filter(|token| !ALLOWED.contains(&token.to_ascii_lowercase().as_str()))
3989 .map(str::to_string)
3990 .collect()
3991 }
3992
3993 /// High-visibility chrome where mixed-language copy is most visible.
3994 const SCRIPT_FIXTURE_IDS: &[MessageId] = &[
3995 MessageId::ComposerPlaceholder,
3996 MessageId::HistorySearchTitle,
3997 MessageId::HistorySearchPlaceholder,
3998 MessageId::StatusPickerTitle,
3999 MessageId::StatusPickerInstruction,
4000 MessageId::ConfigTitle,
4001 MessageId::CommandPaletteTitle,
4002 MessageId::AppModeAgentHint,
4003 MessageId::AppModePlanHint,
4004 MessageId::RouteNoModels,
4005 MessageId::ProviderNoMatchesTitle,
4006 MessageId::SessionsOpenedHistory,
4007 ];
4008
4009 #[test]
4010 fn cyrillic_packs_have_script_purity_and_no_mixed_language_fixtures() {
4011 for locale in [Locale::Ru, Locale::Uk] {
4012 let messages = raw_locale_messages(locale);
4013 let total = messages.len();
4014 let with_cyrillic = messages
4015 .values()
4016 .filter(|v| v.as_str().is_some_and(has_cyrillic))
4017 .count();
4018 assert!(
4019 with_cyrillic * 100 >= total * 85,
4020 "{}: only {with_cyrillic}/{total} values contain Cyrillic — pack looks under-translated",
4021 locale.tag()
4022 );
4023 for (key, value) in &messages {
4024 let Some(value) = value.as_str() else {
4025 continue;
4026 };
4027 if locale == Locale::Uk {
4028 assert!(
4029 !value.chars().any(|c| "ыэъЫЭЪ".contains(c)),
4030 "uk {key} contains a Russian-only letter: {value}"
4031 );
4032 } else {
4033 assert!(
4034 !value.chars().any(|c| "іІїЇєЄґҐ".contains(c)),
4035 "ru {key} contains a Ukrainian-only letter: {value}"
4036 );
4037 }
4038 }
4039 for id in SCRIPT_FIXTURE_IDS {
4040 let value = tr(locale, *id);
4041 assert!(
4042 has_cyrillic(&value),
4043 "{} {id:?} fixture has no Cyrillic: {value}",
4044 locale.tag()
4045 );
4046 let leaked = latin_words_in_translated_copy(&value);
4047 assert!(
4048 leaked.is_empty(),
4049 "{} {id:?} mixes Latin prose into Cyrillic copy: {leaked:?} in {value}",
4050 locale.tag()
4051 );
4052 }
4053 }
4054 // The two packs are translations of the same source, not copies of
4055 // each other: sentence-length fixtures must differ between ru and uk.
4056 for id in [
4057 MessageId::ComposerPlaceholder,
4058 MessageId::StatusPickerInstruction,
4059 MessageId::AppModeAgentHint,
4060 MessageId::AppModePlanHint,
4061 MessageId::ProviderNoMatchesTitle,
4062 ] {
4063 assert_ne!(
4064 tr(Locale::Ru, id),
4065 tr(Locale::Uk, id),
4066 "ru and uk share an identical sentence for {id:?} — one pack was copied from the other"
4067 );
4068 }
4069 }
4070
4071 #[test]
4072 fn hindi_pack_uses_devanagari_for_prose_fixtures() {
4073 let messages = raw_locale_messages(Locale::Hi);
4074 let total = messages.len();
4075 let with_devanagari = messages
4076 .values()
4077 .filter(|v| v.as_str().is_some_and(has_devanagari))
4078 .count();
4079 assert!(
4080 with_devanagari * 100 >= total * 80,
4081 "hi: only {with_devanagari}/{total} values contain Devanagari — pack looks under-translated"
4082 );
4083 for id in SCRIPT_FIXTURE_IDS {
4084 let value = tr(Locale::Hi, *id);
4085 assert!(
4086 has_devanagari(&value),
4087 "hi {id:?} fixture has no Devanagari: {value}"
4088 );
4089 let leaked = latin_words_in_translated_copy(&value);
4090 assert!(
4091 leaked.is_empty(),
4092 "hi {id:?} mixes Latin prose into Devanagari copy: {leaked:?} in {value}"
4093 );
4094 }
4095 }
4096
4097 #[test]
4098 fn no_shipped_locale_renders_a_missing_message_marker() {
4099 // rust_i18n falls back to en for absent keys, so a "{MessageId}"
4100 // debug string in the UI would mean the fallback chain itself broke.
4101 for locale in Locale::shipped() {
4102 assert!(
4103 missing_message_ids(*locale).is_empty(),
4104 "{} renders raw message ids (missing-marker UI)",
4105 locale.tag()
4106 );
4107 }
4108 }
4109
4110 // --- Devanagari grapheme safety (#4790 spike) --------------------------
4111
4112 #[test]
4113 fn truncate_to_width_never_splits_devanagari_clusters() {
4114 // क्ष is क + ् + ष — a single cluster. A budget landing inside it
4115 // must drop the whole cluster; a dangling virama (U+094D) renders as
4116 // visibly broken shaping (क् instead of a conjunct).
4117 let conjuncts = "क्षत्रिय ज्ञान श्रृंखला प्रत्यक्ष";
4118 for budget in [1usize, 2, 3, 5, 7, 40, 60, 80] {
4119 let out = truncate_to_width(conjuncts, budget);
4120 assert!(
4121 UnicodeWidthStr::width(out.as_str()) <= budget,
4122 "budget={budget}: overflowed: {out:?}"
4123 );
4124 assert!(!out.contains('\u{FFFD}'), "budget={budget}: {out:?}");
4125 let body = out.strip_suffix('…').unwrap_or(&out);
4126 assert!(
4127 !body.ends_with('\u{094D}'),
4128 "budget={budget}: dangling virama: {out:?}"
4129 );
4130 assert!(
4131 !body.ends_with('\u{200D}'),
4132 "budget={budget}: dangling ZWJ: {out:?}"
4133 );
4134 if let Some(last) = body.chars().last() {
4135 let cp = last as u32;
4136 let combining = (0x0900..=0x0903).contains(&cp) || (0x093A..=0x094F).contains(&cp);
4137 assert!(
4138 !combining,
4139 "budget={budget}: trailing combining mark: {out:?}"
4140 );
4141 }
4142 }
4143 }
4144
4145 #[test]
4146 fn cyrillic_latin_extended_and_devanagari_rows_wrap_within_terminal_columns() {
4147 // Width/grapheme QA for the v0.9.2 scripts at narrow (40), medium
4148 // (60), and standard (80) terminal columns: truncation clips by
4149 // display width and wrapped rows never overflow the buffer.
4150 let fixtures = [
4151 (
4152 "ru",
4153 "Задача: миграция базы данных — проверка маршрутизации провайдера #3092",
4154 ),
4155 (
4156 "uk",
4157 "Завдання: міграція бази даних — перевірка маршрутизації провайдера #4791",
4158 ),
4159 (
4160 "de",
4161 "Aufgabe: Datenbankmigration — Anbieter-Routing für #4788 prüfen",
4162 ),
4163 (
4164 "fr",
4165 "Tâche : migration de la base — vérifier le routage fournisseur #4788",
4166 ),
4167 (
4168 "ca",
4169 "Tasca: migració de la base de dades — comprovar l'encaminament #4788",
4170 ),
4171 (
4172 "id",
4173 "Tugas: migrasi basis data — periksa perutean penyedia untuk #4789",
4174 ),
4175 ("hi", "कार्य: डेटाबेस माइग्रेशन — प्रदाता रूटिंग की जांच करें #4790"),
4176 ];
4177
4178 for width in [40usize, 60, 80] {
4179 for (tag, fixture) in fixtures {
4180 let out = truncate_to_width(fixture, width);
4181 assert!(
4182 UnicodeWidthStr::width(out.as_str()) <= width,
4183 "{tag} width={width}: truncated row overflowed: {out:?}"
4184 );
4185 assert!(
4186 !out.contains('\u{FFFD}'),
4187 "{tag} width={width}: split a glyph: {out:?}"
4188 );
4189
4190 let area = Rect::new(0, 0, width as u16, 6);
4191 let mut buf = Buffer::empty(area);
4192 Paragraph::new(fixture)
4193 .wrap(Wrap { trim: false })
4194 .render(area, &mut buf);
4195 let mut saw_text = false;
4196 for (row_idx, y) in (area.top()..area.bottom()).enumerate() {
4197 let row = visible_row_text(&buf, area, y);
4198 let trimmed = row.trim_end_matches('\u{0}').trim_end();
4199 assert!(
4200 UnicodeWidthStr::width(trimmed) <= width,
4201 "{tag} width={width} row {row_idx}: wrapped row overflowed ({} cols): {trimmed:?}",
4202 UnicodeWidthStr::width(trimmed)
4203 );
4204 saw_text |= trimmed.chars().any(|ch| !ch.is_whitespace());
4205 }
4206 assert!(
4207 saw_text,
4208 "{tag} width={width}: fixture produced an empty render"
4209 );
4210 }
4211 }
4212 }
4213 }
4214
4214 lines RUST