@agent-native/core 0.76.9 → 0.76.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +39 -0
  3. package/corpus/core/docs/content/locales/ar-SA/actions.md +7 -7
  4. package/corpus/core/docs/content/locales/ar-SA/template-plan.md +6 -4
  5. package/corpus/core/docs/content/locales/de-DE/actions.md +9 -9
  6. package/corpus/core/docs/content/locales/de-DE/template-plan.md +6 -4
  7. package/corpus/core/docs/content/locales/es-ES/actions.md +9 -9
  8. package/corpus/core/docs/content/locales/es-ES/template-plan.md +6 -4
  9. package/corpus/core/docs/content/locales/fr-FR/actions.md +9 -9
  10. package/corpus/core/docs/content/locales/fr-FR/template-plan.md +6 -4
  11. package/corpus/core/docs/content/locales/hi-IN/actions.md +9 -9
  12. package/corpus/core/docs/content/locales/hi-IN/template-plan.md +4 -4
  13. package/corpus/core/docs/content/locales/ja-JP/actions.md +9 -9
  14. package/corpus/core/docs/content/locales/ja-JP/template-plan.md +4 -4
  15. package/corpus/core/docs/content/locales/ko-KR/actions.md +9 -9
  16. package/corpus/core/docs/content/locales/ko-KR/template-plan.md +4 -4
  17. package/corpus/core/docs/content/locales/pt-BR/actions.md +9 -9
  18. package/corpus/core/docs/content/locales/pt-BR/template-plan.md +6 -4
  19. package/corpus/core/docs/content/locales/zh-CN/actions.md +9 -9
  20. package/corpus/core/docs/content/locales/zh-CN/template-plan.md +4 -4
  21. package/corpus/core/package.json +1 -1
  22. package/corpus/core/scripts/generate-og-font-data.mjs +9 -5
  23. package/corpus/core/src/client/AgentPanel.tsx +70 -1
  24. package/corpus/core/src/client/AssistantChat.tsx +1 -3
  25. package/corpus/core/src/client/ErrorBoundary.tsx +151 -10
  26. package/corpus/core/src/client/MultiTabAssistantChat.tsx +0 -62
  27. package/corpus/core/src/client/composer/TiptapComposer.tsx +6 -13
  28. package/corpus/core/src/server/og-fonts-data.ts +7 -4
  29. package/corpus/core/src/server/og-fonts.ts +10 -3
  30. package/corpus/core/src/server/social-og-image.ts +45 -6
  31. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +199 -19
  32. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +51 -31
  33. package/corpus/templates/analytics/app/components/layout/DashboardHeader.tsx +26 -16
  34. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -2
  35. package/corpus/templates/analytics/app/components/layout/HeaderActions.tsx +8 -1
  36. package/corpus/templates/analytics/app/components/layout/Layout.tsx +2 -5
  37. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +172 -107
  38. package/corpus/templates/analytics/app/i18n-data.ts +1076 -5
  39. package/corpus/templates/analytics/app/pages/Settings.tsx +2 -2
  40. package/corpus/templates/analytics/app/pages/adhoc/AdhocRouter.tsx +1 -21
  41. package/corpus/templates/analytics/app/pages/adhoc/DashboardSkeleton.tsx +35 -0
  42. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -23
  43. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +3 -26
  44. package/corpus/templates/analytics/changelog/2026-06-24-analytics-navigation-command-palette-and-settings-now-honor-.md +6 -0
  45. package/corpus/templates/analytics/changelog/2026-06-24-daily-dashboard-charts-now-use-local-day-buckets-and-show-th.md +6 -0
  46. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-loading-placeholders-now-span-the-available-page-w.md +6 -0
  47. package/corpus/templates/analytics/changelog/2026-06-24-first-party-dashboard-dates-now-align-to-pacific-time-for-da.md +6 -0
  48. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +19 -7
  49. package/corpus/templates/assets/app/components/layout/Header.tsx +0 -2
  50. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +0 -2
  51. package/corpus/templates/calendar/app/pages/CalendarView.tsx +0 -2
  52. package/corpus/templates/chat/app/components/layout/Header.tsx +1 -6
  53. package/corpus/templates/clips/app/components/layout/Header.tsx +1 -6
  54. package/corpus/templates/clips/app/hooks/use-library.ts +2 -0
  55. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +3 -1
  56. package/corpus/templates/clips/changelog/2026-06-24-archive-and-spaces-navigation-is-more-resilient-when-sidebar.md +6 -0
  57. package/corpus/templates/content/app/components/layout/Header.tsx +0 -2
  58. package/corpus/templates/design/app/components/layout/Header.tsx +1 -6
  59. package/corpus/templates/forms/app/components/layout/Header.tsx +1 -6
  60. package/corpus/templates/macros/app/components/layout/Header.tsx +1 -6
  61. package/corpus/templates/mail/app/components/email/CodeBlockLangPicker.tsx +4 -2
  62. package/corpus/templates/mail/app/components/email/ComposeBubbleToolbar.tsx +18 -12
  63. package/corpus/templates/mail/app/components/email/ComposeEditor.tsx +9 -5
  64. package/corpus/templates/mail/app/components/email/ComposeModal.tsx +36 -19
  65. package/corpus/templates/mail/app/components/email/EmailList.tsx +59 -55
  66. package/corpus/templates/mail/app/components/email/EmailListItem.tsx +7 -3
  67. package/corpus/templates/mail/app/components/email/EmailThread.tsx +25 -16
  68. package/corpus/templates/mail/app/components/email/InlineReplyComposer.tsx +25 -19
  69. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +32 -17
  70. package/corpus/templates/mail/app/components/email/RecipientInput.tsx +26 -10
  71. package/corpus/templates/mail/app/components/email/SendLaterButton.tsx +5 -3
  72. package/corpus/templates/mail/app/components/email/SnoozeModal.tsx +4 -2
  73. package/corpus/templates/mail/app/components/email/SnoozePopover.tsx +9 -5
  74. package/corpus/templates/mail/app/components/email/extensions/ComposeImageBlock.tsx +4 -2
  75. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +168 -86
  76. package/corpus/templates/mail/app/components/layout/SearchBar.tsx +4 -2
  77. package/corpus/templates/mail/app/i18n/ar-SA.ts +212 -0
  78. package/corpus/templates/mail/app/i18n/de-DE.ts +212 -0
  79. package/corpus/templates/mail/app/i18n/en-US.ts +212 -0
  80. package/corpus/templates/mail/app/i18n/es-ES.ts +212 -0
  81. package/corpus/templates/mail/app/i18n/fr-FR.ts +212 -0
  82. package/corpus/templates/mail/app/i18n/hi-IN.ts +212 -0
  83. package/corpus/templates/mail/app/i18n/ja-JP.ts +212 -0
  84. package/corpus/templates/mail/app/i18n/ko-KR.ts +212 -0
  85. package/corpus/templates/mail/app/i18n/pt-BR.ts +212 -0
  86. package/corpus/templates/mail/app/i18n/zh-CN.ts +211 -0
  87. package/corpus/templates/mail/changelog/2026-06-24-interface-language-support-now-covers-more-mail-controls-and.md +6 -0
  88. package/corpus/templates/plan/app/components/layout/Header.tsx +1 -6
  89. package/corpus/templates/slides/app/components/layout/Header.tsx +1 -6
  90. package/corpus/templates/videos/app/components/layout/Header.tsx +1 -6
  91. package/dist/client/AgentPanel.d.ts +5 -1
  92. package/dist/client/AgentPanel.d.ts.map +1 -1
  93. package/dist/client/AgentPanel.js +23 -4
  94. package/dist/client/AgentPanel.js.map +1 -1
  95. package/dist/client/AssistantChat.d.ts +1 -3
  96. package/dist/client/AssistantChat.d.ts.map +1 -1
  97. package/dist/client/AssistantChat.js.map +1 -1
  98. package/dist/client/ErrorBoundary.d.ts.map +1 -1
  99. package/dist/client/ErrorBoundary.js +128 -7
  100. package/dist/client/ErrorBoundary.js.map +1 -1
  101. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  102. package/dist/client/MultiTabAssistantChat.js +1 -17
  103. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  104. package/dist/client/composer/TiptapComposer.d.ts +4 -0
  105. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  106. package/dist/client/composer/TiptapComposer.js +5 -9
  107. package/dist/client/composer/TiptapComposer.js.map +1 -1
  108. package/dist/server/og-fonts-data.d.ts +1 -0
  109. package/dist/server/og-fonts-data.d.ts.map +1 -1
  110. package/dist/server/og-fonts-data.js +5 -4
  111. package/dist/server/og-fonts-data.js.map +1 -1
  112. package/dist/server/og-fonts.d.ts +1 -0
  113. package/dist/server/og-fonts.d.ts.map +1 -1
  114. package/dist/server/og-fonts.js +10 -4
  115. package/dist/server/og-fonts.js.map +1 -1
  116. package/dist/server/social-og-image.d.ts.map +1 -1
  117. package/dist/server/social-og-image.js +33 -6
  118. package/dist/server/social-og-image.js.map +1 -1
  119. package/docs/content/locales/ar-SA/actions.md +7 -7
  120. package/docs/content/locales/ar-SA/template-plan.md +6 -4
  121. package/docs/content/locales/de-DE/actions.md +9 -9
  122. package/docs/content/locales/de-DE/template-plan.md +6 -4
  123. package/docs/content/locales/es-ES/actions.md +9 -9
  124. package/docs/content/locales/es-ES/template-plan.md +6 -4
  125. package/docs/content/locales/fr-FR/actions.md +9 -9
  126. package/docs/content/locales/fr-FR/template-plan.md +6 -4
  127. package/docs/content/locales/hi-IN/actions.md +9 -9
  128. package/docs/content/locales/hi-IN/template-plan.md +4 -4
  129. package/docs/content/locales/ja-JP/actions.md +9 -9
  130. package/docs/content/locales/ja-JP/template-plan.md +4 -4
  131. package/docs/content/locales/ko-KR/actions.md +9 -9
  132. package/docs/content/locales/ko-KR/template-plan.md +4 -4
  133. package/docs/content/locales/pt-BR/actions.md +9 -9
  134. package/docs/content/locales/pt-BR/template-plan.md +6 -4
  135. package/docs/content/locales/zh-CN/actions.md +9 -9
  136. package/docs/content/locales/zh-CN/template-plan.md +4 -4
  137. package/package.json +1 -1
@@ -228,6 +228,8 @@ function SidebarSectionSettingsPopover({
228
228
  showHidden?: boolean;
229
229
  onShowHiddenChange?: (value: boolean) => void;
230
230
  }) {
231
+ const t = useT();
232
+ const settingsLabel = t("sidebar.sectionSettings", { label });
231
233
  return (
232
234
  <Popover>
233
235
  <Tooltip>
@@ -236,13 +238,13 @@ function SidebarSectionSettingsPopover({
236
238
  <button
237
239
  type="button"
238
240
  className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground/65 opacity-0 transition-all hover:bg-sidebar-accent hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring group-hover/section:opacity-100 data-[state=open]:opacity-100"
239
- aria-label={`${label} settings`}
241
+ aria-label={settingsLabel}
240
242
  >
241
243
  <IconSettings className="h-3.5 w-3.5" />
242
244
  </button>
243
245
  </PopoverTrigger>
244
246
  </TooltipTrigger>
245
- <TooltipContent side="right">{`${label} settings`}</TooltipContent>
247
+ <TooltipContent side="right">{settingsLabel}</TooltipContent>
246
248
  </Tooltip>
247
249
  <PopoverContent side="right" align="start" className="w-60 p-2">
248
250
  <div className="px-2 pb-2">
@@ -251,7 +253,7 @@ function SidebarSectionSettingsPopover({
251
253
  <div className="grid gap-3">
252
254
  <div className="grid gap-1.5">
253
255
  <p className="px-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
254
- Sort by
256
+ {t("sidebar.sortBy")}
255
257
  </p>
256
258
  <ToggleGroup
257
259
  type="single"
@@ -269,24 +271,24 @@ function SidebarSectionSettingsPopover({
269
271
  >
270
272
  <ToggleGroupItem
271
273
  value="most-used"
272
- aria-label="Sort by most used"
274
+ aria-label={t("sidebar.sortMostUsed")}
273
275
  className="h-7 px-2 text-[11px]"
274
276
  >
275
- Used
277
+ {t("sidebar.used")}
276
278
  </ToggleGroupItem>
277
279
  <ToggleGroupItem
278
280
  value="alphabetical"
279
- aria-label="Sort alphabetically"
281
+ aria-label={t("sidebar.sortAlphabetically")}
280
282
  className="h-7 px-2 text-[11px]"
281
283
  >
282
- A-Z
284
+ {t("sidebar.alphabetical")}
283
285
  </ToggleGroupItem>
284
286
  <ToggleGroupItem
285
287
  value="manual"
286
- aria-label="Sort manually"
288
+ aria-label={t("sidebar.sortManually")}
287
289
  className="h-7 px-2 text-[11px]"
288
290
  >
289
- Manual
291
+ {t("sidebar.manual")}
290
292
  </ToggleGroupItem>
291
293
  </ToggleGroup>
292
294
  </div>
@@ -295,12 +297,14 @@ function SidebarSectionSettingsPopover({
295
297
  htmlFor={`${label.toLowerCase()}-shared-filter`}
296
298
  className="flex items-center justify-between gap-3 rounded-md px-2 py-1.5 text-xs text-foreground hover:bg-sidebar-accent/60"
297
299
  >
298
- <span className="min-w-0 truncate">Org shared only</span>
300
+ <span className="min-w-0 truncate">
301
+ {t("sidebar.orgSharedOnly")}
302
+ </span>
299
303
  <Switch
300
304
  id={`${label.toLowerCase()}-shared-filter`}
301
305
  checked={sharedOnly}
302
306
  onCheckedChange={onSharedOnlyChange}
303
- aria-label={`${label} org shared only`}
307
+ aria-label={`${label} ${t("sidebar.orgSharedOnly")}`}
304
308
  />
305
309
  </label>
306
310
  {onShowHiddenChange && showHidden !== undefined && (
@@ -308,12 +312,14 @@ function SidebarSectionSettingsPopover({
308
312
  htmlFor={`${label.toLowerCase()}-hidden-filter`}
309
313
  className="flex items-center justify-between gap-3 rounded-md px-2 py-1.5 text-xs text-foreground hover:bg-sidebar-accent/60"
310
314
  >
311
- <span className="min-w-0 truncate">Hidden analyses</span>
315
+ <span className="min-w-0 truncate">
316
+ {t("sidebar.hiddenAnalyses")}
317
+ </span>
312
318
  <Switch
313
319
  id={`${label.toLowerCase()}-hidden-filter`}
314
320
  checked={showHidden}
315
321
  onCheckedChange={onShowHiddenChange}
316
- aria-label={`${label} hidden analyses`}
322
+ aria-label={`${label} ${t("sidebar.hiddenAnalyses")}`}
317
323
  />
318
324
  </label>
319
325
  )}
@@ -370,6 +376,7 @@ function SortableRow({
370
376
  onSetVisibility?: (visibility: Visibility) => Promise<void> | void;
371
377
  children?: React.ReactNode;
372
378
  }) {
379
+ const t = useT();
373
380
  const {
374
381
  attributes,
375
382
  listeners,
@@ -407,11 +414,14 @@ function SortableRow({
407
414
  setRenameValue(name);
408
415
  toast.error(
409
416
  e instanceof Error
410
- ? `Couldn't rename ${name}: ${e.message}`
411
- : `Couldn't rename ${name}`,
417
+ ? t("sidebar.renameFailedWithMessage", {
418
+ name,
419
+ message: e.message,
420
+ })
421
+ : t("sidebar.renameFailed", { name }),
412
422
  );
413
423
  }
414
- }, [name, onRename, renameValue]);
424
+ }, [name, onRename, renameValue, t]);
415
425
 
416
426
  const runDelete = useCallback(async () => {
417
427
  setMenuOpen(false);
@@ -421,11 +431,14 @@ function SortableRow({
421
431
  } catch (e) {
422
432
  toast.error(
423
433
  e instanceof Error
424
- ? `Couldn't delete ${name}: ${e.message}`
425
- : `Couldn't delete ${name}`,
434
+ ? t("sidebar.deleteFailedWithMessage", {
435
+ name,
436
+ message: e.message,
437
+ })
438
+ : t("sidebar.deleteFailed", { name }),
426
439
  );
427
440
  }
428
- }, [name, onDelete]);
441
+ }, [name, onDelete, t]);
429
442
 
430
443
  const runArchive = useCallback(async () => {
431
444
  setMenuOpen(false);
@@ -435,11 +448,14 @@ function SortableRow({
435
448
  } catch (e) {
436
449
  toast.error(
437
450
  e instanceof Error
438
- ? `Couldn't archive ${name}: ${e.message}`
439
- : `Couldn't archive ${name}`,
451
+ ? t("sidebar.archiveFailedWithMessage", {
452
+ name,
453
+ message: e.message,
454
+ })
455
+ : t("sidebar.archiveFailed", { name }),
440
456
  );
441
457
  }
442
- }, [name, onArchive]);
458
+ }, [name, onArchive, t]);
443
459
 
444
460
  const runHide = useCallback(async () => {
445
461
  setMenuOpen(false);
@@ -449,11 +465,14 @@ function SortableRow({
449
465
  } catch (e) {
450
466
  toast.error(
451
467
  e instanceof Error
452
- ? `Couldn't hide ${name}: ${e.message}`
453
- : `Couldn't hide ${name}`,
468
+ ? t("sidebar.hideFailedWithMessage", {
469
+ name,
470
+ message: e.message,
471
+ })
472
+ : t("sidebar.hideFailed", { name }),
454
473
  );
455
474
  }
456
- }, [name, onHide]);
475
+ }, [name, onHide, t]);
457
476
 
458
477
  const runUnhide = useCallback(async () => {
459
478
  setMenuOpen(false);
@@ -463,11 +482,14 @@ function SortableRow({
463
482
  } catch (e) {
464
483
  toast.error(
465
484
  e instanceof Error
466
- ? `Couldn't unhide ${name}: ${e.message}`
467
- : `Couldn't unhide ${name}`,
485
+ ? t("sidebar.unhideFailedWithMessage", {
486
+ name,
487
+ message: e.message,
488
+ })
489
+ : t("sidebar.unhideFailed", { name }),
468
490
  );
469
491
  }
470
- }, [name, onUnhide]);
492
+ }, [name, onUnhide, t]);
471
493
 
472
494
  const runSetVisibility = useCallback(
473
495
  async (visibility: Visibility) => {
@@ -478,29 +500,31 @@ function SortableRow({
478
500
  } catch (e) {
479
501
  toast.error(
480
502
  e instanceof Error
481
- ? `Couldn't update visibility: ${e.message}`
482
- : "Couldn't update visibility",
503
+ ? t("sidebar.updateVisibilityFailedWithMessage", {
504
+ message: e.message,
505
+ })
506
+ : t("sidebar.updateVisibilityFailed"),
483
507
  );
484
508
  }
485
509
  },
486
- [onSetVisibility],
510
+ [onSetVisibility, t],
487
511
  );
488
512
 
489
513
  const copyLink = useCallback(() => {
490
514
  const url = window.location.origin + href;
491
515
  navigator.clipboard.writeText(url).then(
492
- () => toast.success("Link copied"),
493
- () => toast.error("Couldn't copy link"),
516
+ () => toast.success(t("sidebar.linkCopied")),
517
+ () => toast.error(t("sidebar.copyLinkFailed")),
494
518
  );
495
519
  setMenuOpen(false);
496
- }, [href]);
520
+ }, [href, t]);
497
521
 
498
522
  return (
499
523
  <div ref={setNodeRef} style={style} className="group/item relative min-w-0">
500
524
  <button
501
525
  type="button"
502
526
  className="absolute -start-4 top-1/2 z-10 -translate-y-1/2 cursor-grab rounded p-1 text-muted-foreground/30 opacity-0 transition-colors hover:text-muted-foreground/60 group-hover/item:opacity-100 active:cursor-grabbing"
503
- aria-label={`Drag ${name}`}
527
+ aria-label={t("sidebar.dragItem", { name })}
504
528
  {...attributes}
505
529
  {...listeners}
506
530
  >
@@ -557,13 +581,15 @@ function SortableRow({
557
581
  ? "text-yellow-500"
558
582
  : "text-muted-foreground/50 hover:text-yellow-500",
559
583
  )}
560
- aria-label={isFav ? "Unfavorite" : "Favorite"}
584
+ aria-label={
585
+ isFav ? t("sidebar.unfavorite") : t("sidebar.favorite")
586
+ }
561
587
  >
562
588
  <IconStar className={cn("h-3 w-3", isFav && "fill-current")} />
563
589
  </button>
564
590
  </TooltipTrigger>
565
591
  <TooltipContent side="right">
566
- {isFav ? "Unfavorite" : "Favorite"}
592
+ {isFav ? t("sidebar.unfavorite") : t("sidebar.favorite")}
567
593
  </TooltipContent>
568
594
  </Tooltip>
569
595
  <DropdownMenu open={menuOpen} onOpenChange={setMenuOpen}>
@@ -573,13 +599,15 @@ function SortableRow({
573
599
  <button
574
600
  type="button"
575
601
  className="pointer-events-auto rounded p-0.5 text-muted-foreground/50 transition-colors hover:text-foreground"
576
- aria-label={`${name} actions`}
602
+ aria-label={t("sidebar.itemActions", { name })}
577
603
  >
578
604
  <IconDots className="h-3 w-3" />
579
605
  </button>
580
606
  </DropdownMenuTrigger>
581
607
  </TooltipTrigger>
582
- <TooltipContent side="right">{`${name} actions`}</TooltipContent>
608
+ <TooltipContent side="right">
609
+ {t("sidebar.itemActions", { name })}
610
+ </TooltipContent>
583
611
  </Tooltip>
584
612
  <DropdownMenuContent side="right" align="start" className="w-44">
585
613
  <DropdownMenuItem
@@ -589,7 +617,7 @@ function SortableRow({
589
617
  }}
590
618
  >
591
619
  <IconPencil className="me-2 h-3.5 w-3.5" />
592
- Rename
620
+ {t("sidebar.rename")}
593
621
  </DropdownMenuItem>
594
622
  {onSetVisibility && visibility !== undefined && (
595
623
  <DropdownMenuItem
@@ -605,12 +633,14 @@ function SortableRow({
605
633
  ) : (
606
634
  <IconLock className="me-2 h-3.5 w-3.5" />
607
635
  )}
608
- {visibility === "private" ? "Share with org" : "Make private"}
636
+ {visibility === "private"
637
+ ? t("sidebar.shareWithOrg")
638
+ : t("sidebar.makePrivate")}
609
639
  </DropdownMenuItem>
610
640
  )}
611
641
  <DropdownMenuItem onSelect={copyLink}>
612
642
  <IconLink className="me-2 h-3.5 w-3.5" />
613
- Copy link
643
+ {t("sidebar.copyLink")}
614
644
  </DropdownMenuItem>
615
645
  {onUnhide && hidden ? (
616
646
  <DropdownMenuItem
@@ -620,7 +650,7 @@ function SortableRow({
620
650
  }}
621
651
  >
622
652
  <IconEye className="me-2 h-3.5 w-3.5" />
623
- Unhide
653
+ {t("sidebar.unhide")}
624
654
  </DropdownMenuItem>
625
655
  ) : onHide ? (
626
656
  <DropdownMenuItem
@@ -630,7 +660,7 @@ function SortableRow({
630
660
  }}
631
661
  >
632
662
  <IconEyeOff className="me-2 h-3.5 w-3.5" />
633
- Hide
663
+ {t("sidebar.hide")}
634
664
  </DropdownMenuItem>
635
665
  ) : null}
636
666
  <DropdownMenuSeparator />
@@ -643,7 +673,7 @@ function SortableRow({
643
673
  }}
644
674
  >
645
675
  <IconArchive className="me-2 h-3.5 w-3.5" />
646
- Archive
676
+ {t("sidebar.archive")}
647
677
  </DropdownMenuItem>
648
678
  <DropdownMenuSeparator />
649
679
  <DropdownMenuItem
@@ -655,7 +685,7 @@ function SortableRow({
655
685
  className="text-destructive focus:text-destructive"
656
686
  >
657
687
  <IconTrash className="me-2 h-3.5 w-3.5" />
658
- Delete permanently
688
+ {t("sidebar.deletePermanently")}
659
689
  </DropdownMenuItem>
660
690
  </>
661
691
  ) : (
@@ -668,7 +698,7 @@ function SortableRow({
668
698
  className="text-destructive focus:text-destructive"
669
699
  >
670
700
  <IconTrash className="me-2 h-3.5 w-3.5" />
671
- Delete
701
+ {t("sidebar.delete")}
672
702
  </DropdownMenuItem>
673
703
  )}
674
704
  </DropdownMenuContent>
@@ -679,22 +709,21 @@ function SortableRow({
679
709
  <AlertDialog open={confirmDeleteOpen} onOpenChange={setConfirmDeleteOpen}>
680
710
  <AlertDialogContent>
681
711
  <AlertDialogHeader>
682
- <AlertDialogTitle>Delete permanently?</AlertDialogTitle>
712
+ <AlertDialogTitle>
713
+ {t("sidebar.deletePermanentlyTitle")}
714
+ </AlertDialogTitle>
683
715
  <AlertDialogDescription>
684
- This permanently deletes &ldquo;{name}&rdquo; and cannot be
685
- undone.
686
- {onArchive
687
- ? " To keep it recoverable, choose Archive instead."
688
- : ""}
716
+ {t("sidebar.deletePermanentlyDescription", { name })}
717
+ {onArchive ? t("sidebar.deletePermanentlyArchiveHint") : ""}
689
718
  </AlertDialogDescription>
690
719
  </AlertDialogHeader>
691
720
  <AlertDialogFooter>
692
- <AlertDialogCancel>Cancel</AlertDialogCancel>
721
+ <AlertDialogCancel>{t("sidebar.cancel")}</AlertDialogCancel>
693
722
  <AlertDialogAction
694
723
  onClick={() => void runDelete()}
695
724
  className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
696
725
  >
697
- Delete permanently
726
+ {t("sidebar.deletePermanently")}
698
727
  </AlertDialogAction>
699
728
  </AlertDialogFooter>
700
729
  </AlertDialogContent>
@@ -734,6 +763,7 @@ function SortableDashboardItem({
734
763
  ) => Promise<void>;
735
764
  }) {
736
765
  const href = `/dashboards/${d.id}`;
766
+ const t = useT();
737
767
  const { mutateAsync: deleteView } = useDeleteDashboardView();
738
768
  const [deletingViewId, setDeletingViewId] = useState<string | null>(null);
739
769
 
@@ -845,8 +875,8 @@ function SortableDashboardItem({
845
875
  </TooltipTrigger>
846
876
  <TooltipContent side="right">
847
877
  {favoriteIds.has(`view:${d.id}:${sv.id}`)
848
- ? "Unfavorite"
849
- : "Favorite"}
878
+ ? t("sidebar.unfavorite")
879
+ : t("sidebar.favorite")}
850
880
  </TooltipContent>
851
881
  </Tooltip>
852
882
  <Popover
@@ -863,7 +893,9 @@ function SortableDashboardItem({
863
893
  </button>
864
894
  </PopoverTrigger>
865
895
  </TooltipTrigger>
866
- <TooltipContent side="right">{`Delete ${sv.name}`}</TooltipContent>
896
+ <TooltipContent side="right">
897
+ {t("sidebar.deleteView", { name: sv.name })}
898
+ </TooltipContent>
867
899
  </Tooltip>
868
900
  <PopoverContent
869
901
  className="w-56 p-3"
@@ -871,7 +903,7 @@ function SortableDashboardItem({
871
903
  align="start"
872
904
  >
873
905
  <p className="text-sm mb-3">
874
- Delete view <strong>{sv.name}</strong>?
906
+ {t("sidebar.deleteView", { name: sv.name })}
875
907
  </p>
876
908
  <div className="flex gap-2">
877
909
  <button
@@ -888,8 +920,10 @@ function SortableDashboardItem({
888
920
  setDeletingViewId(sv.id);
889
921
  toast.error(
890
922
  err instanceof Error
891
- ? `Couldn't delete view: ${err.message}`
892
- : "Couldn't delete view",
923
+ ? t("sidebar.deleteViewFailedWithMessage", {
924
+ message: err.message,
925
+ })
926
+ : t("sidebar.deleteViewFailed"),
893
927
  );
894
928
  }
895
929
  }}
@@ -898,14 +932,16 @@ function SortableDashboardItem({
898
932
  {isDeleting && (
899
933
  <IconLoader2 className="h-3 w-3 animate-spin" />
900
934
  )}
901
- {isDeleting ? "Deleting..." : "Delete"}
935
+ {isDeleting
936
+ ? t("sidebar.deleting")
937
+ : t("sidebar.delete")}
902
938
  </button>
903
939
  <button
904
940
  disabled={isDeleting}
905
941
  onClick={() => setDeletingViewId(null)}
906
942
  className="flex-1 rounded-md border border-border px-3 py-1.5 text-xs font-medium hover:bg-sidebar-accent/50 transition-colors disabled:opacity-60"
907
943
  >
908
- Cancel
944
+ {t("sidebar.cancel")}
909
945
  </button>
910
946
  </div>
911
947
  </PopoverContent>
@@ -990,7 +1026,9 @@ type SqlDashboardListItem = {
990
1026
  visibility?: Visibility;
991
1027
  };
992
1028
 
993
- async function fetchSqlDashboards(): Promise<SqlDashboardListItem[]> {
1029
+ async function fetchSqlDashboards(
1030
+ t: (key: string) => string,
1031
+ ): Promise<SqlDashboardListItem[]> {
994
1032
  try {
995
1033
  const rows = await callAction("list-sql-dashboards", {}, { method: "GET" });
996
1034
  return (Array.isArray(rows) ? rows : [])
@@ -1000,7 +1038,7 @@ async function fetchSqlDashboards(): Promise<SqlDashboardListItem[]> {
1000
1038
  name:
1001
1039
  typeof d.name === "string" && d.name.trim().length > 0
1002
1040
  ? d.name
1003
- : "Untitled dashboard",
1041
+ : t("sidebar.untitledDashboard"),
1004
1042
  visibility:
1005
1043
  d.visibility === "org" || d.visibility === "public"
1006
1044
  ? (d.visibility as Visibility)
@@ -1012,6 +1050,7 @@ async function fetchSqlDashboards(): Promise<SqlDashboardListItem[]> {
1012
1050
  }
1013
1051
 
1014
1052
  async function fetchSidebarAnalyses(
1053
+ t: (key: string) => string,
1015
1054
  hidden: AnalysisHiddenFilter = "visible",
1016
1055
  ): Promise<
1017
1056
  {
@@ -1036,7 +1075,7 @@ async function fetchSidebarAnalyses(
1036
1075
  name:
1037
1076
  typeof a.name === "string" && a.name.trim().length > 0
1038
1077
  ? a.name
1039
- : "Untitled analysis",
1078
+ : t("sidebar.untitledAnalysis"),
1040
1079
  visibility:
1041
1080
  a.visibility === "org" || a.visibility === "public"
1042
1081
  ? a.visibility
@@ -1068,6 +1107,7 @@ type PrefetchedSqlDashboard = {
1068
1107
 
1069
1108
  async function fetchSqlDashboardForPrefetch(
1070
1109
  id: string,
1110
+ t: (key: string) => string,
1071
1111
  ): Promise<PrefetchedSqlDashboard | null> {
1072
1112
  try {
1073
1113
  const data: any = await callAction(
@@ -1082,7 +1122,7 @@ async function fetchSqlDashboardForPrefetch(
1082
1122
  name:
1083
1123
  typeof data.name === "string" && data.name.trim().length > 0
1084
1124
  ? data.name
1085
- : "Untitled Dashboard",
1125
+ : t("sidebar.untitledDashboard"),
1086
1126
  description: data.description,
1087
1127
  filters: data.filters,
1088
1128
  variables: data.variables,
@@ -1282,14 +1322,14 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1282
1322
  const { data: sqlDashboards = [], isLoading: sqlDashboardsLoading } =
1283
1323
  useQuery({
1284
1324
  queryKey: ["sql-dashboards-sidebar", dashboardsSync],
1285
- queryFn: fetchSqlDashboards,
1325
+ queryFn: () => fetchSqlDashboards(t),
1286
1326
  staleTime: 30_000,
1287
1327
  placeholderData: (prev) => prev,
1288
1328
  });
1289
1329
 
1290
1330
  const { data: analysesList = [], isLoading: analysesLoading } = useQuery({
1291
1331
  queryKey: ["analyses-sidebar", analysesSync, analysisHiddenFilter],
1292
- queryFn: () => fetchSidebarAnalyses(analysisHiddenFilter),
1332
+ queryFn: () => fetchSidebarAnalyses(t, analysisHiddenFilter),
1293
1333
  staleTime: 30_000,
1294
1334
  placeholderData: (prev) => prev,
1295
1335
  });
@@ -1365,13 +1405,13 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1365
1405
  void queryClient.prefetchQuery({
1366
1406
  queryKey,
1367
1407
  queryFn: async () => ({
1368
- data: await fetchSqlDashboardForPrefetch(d.id),
1408
+ data: await fetchSqlDashboardForPrefetch(d.id, t),
1369
1409
  syncVersion: dashboardsSync,
1370
1410
  }),
1371
1411
  staleTime: cached?.syncVersion === dashboardsSync ? 30_000 : 0,
1372
1412
  });
1373
1413
  },
1374
- [dashboardsSync, queryClient],
1414
+ [dashboardsSync, queryClient, t],
1375
1415
  );
1376
1416
 
1377
1417
  const prefetchAnalysis = useCallback(
@@ -1504,13 +1544,13 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1504
1544
  await archiveDashboardMut({ id: d.id, archived: true });
1505
1545
  queryClient.removeQueries({ queryKey: sqlDashboardPrefetchKey(d.id) });
1506
1546
  queryClient.invalidateQueries({ queryKey: activeKey });
1507
- toast.success(`Archived "${d.name}"`);
1547
+ toast.success(t("sidebar.archivedName", { name: d.name }));
1508
1548
  } catch (err) {
1509
1549
  restoreQuerySnapshots(queryClient, prevActive);
1510
1550
  throw err;
1511
1551
  }
1512
1552
  },
1513
- [queryClient, archiveDashboardMut],
1553
+ [queryClient, archiveDashboardMut, t],
1514
1554
  );
1515
1555
 
1516
1556
  const handleDashboardRename = useCallback(
@@ -1603,15 +1643,15 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1603
1643
  queryClient.invalidateQueries({ queryKey });
1604
1644
  toast.success(
1605
1645
  visibility === "org"
1606
- ? `"${d.name}" shared with org`
1607
- : `"${d.name}" made private`,
1646
+ ? t("sidebar.nameSharedWithOrg", { name: d.name })
1647
+ : t("sidebar.nameMadePrivate", { name: d.name }),
1608
1648
  );
1609
1649
  } catch (err) {
1610
1650
  restoreQuerySnapshots(queryClient, prev);
1611
1651
  throw err;
1612
1652
  }
1613
1653
  },
1614
- [queryClient, setResourceVisibility],
1654
+ [queryClient, setResourceVisibility, t],
1615
1655
  );
1616
1656
 
1617
1657
  const handleAnalysisSetVisibility = useCallback(
@@ -1644,8 +1684,8 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1644
1684
  queryClient.invalidateQueries({ queryKey: listKey });
1645
1685
  toast.success(
1646
1686
  visibility === "org"
1647
- ? `"${a.name}" shared with org`
1648
- : `"${a.name}" made private`,
1687
+ ? t("sidebar.nameSharedWithOrg", { name: a.name })
1688
+ : t("sidebar.nameMadePrivate", { name: a.name }),
1649
1689
  );
1650
1690
  } catch (err) {
1651
1691
  restoreQuerySnapshots(queryClient, prevSidebar);
@@ -1653,7 +1693,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1653
1693
  throw err;
1654
1694
  }
1655
1695
  },
1656
- [queryClient, setResourceVisibility],
1696
+ [queryClient, setResourceVisibility, t],
1657
1697
  );
1658
1698
 
1659
1699
  const handleAnalysisRename = useCallback(
@@ -1719,13 +1759,13 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1719
1759
  await hideAnalysisMut({ id: a.id, hidden: true });
1720
1760
  queryClient.invalidateQueries({ queryKey: sidebarKey });
1721
1761
  queryClient.invalidateQueries({ queryKey: ["analyses-list"] });
1722
- toast.success(`"${a.name}" hidden`);
1762
+ toast.success(t("sidebar.nameHidden", { name: a.name }));
1723
1763
  } catch (err) {
1724
1764
  restoreQuerySnapshots(queryClient, prev);
1725
1765
  throw err;
1726
1766
  }
1727
1767
  },
1728
- [queryClient, hideAnalysisMut],
1768
+ [queryClient, hideAnalysisMut, t],
1729
1769
  );
1730
1770
 
1731
1771
  const handleAnalysisUnhide = useCallback(
@@ -1742,13 +1782,13 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1742
1782
  await hideAnalysisMut({ id: a.id, hidden: false });
1743
1783
  queryClient.invalidateQueries({ queryKey: sidebarKey });
1744
1784
  queryClient.invalidateQueries({ queryKey: ["analyses-list"] });
1745
- toast.success(`"${a.name}" unhidden`);
1785
+ toast.success(t("sidebar.nameUnhidden", { name: a.name }));
1746
1786
  } catch (err) {
1747
1787
  restoreQuerySnapshots(queryClient, prev);
1748
1788
  throw err;
1749
1789
  }
1750
1790
  },
1751
- [queryClient, hideAnalysisMut],
1791
+ [queryClient, hideAnalysisMut, t],
1752
1792
  );
1753
1793
 
1754
1794
  const sensors = useSensors(
@@ -1859,7 +1899,9 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1859
1899
  aria-hidden="true"
1860
1900
  className="hidden h-5 w-auto shrink-0 dark:block"
1861
1901
  />
1862
- <span className="text-lg font-bold tracking-tight">Analytics</span>
1902
+ <span className="text-lg font-bold tracking-tight">
1903
+ {t("navigation.brand")}
1904
+ </span>
1863
1905
  </Link>
1864
1906
  </div>
1865
1907
  <div className="flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-hidden py-2">
@@ -1887,7 +1929,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1887
1929
  )}
1888
1930
  >
1889
1931
  <IconMessageCircle className="h-4 w-4" />
1890
- Ask
1932
+ {t("navigation.ask")}
1891
1933
  </Link>
1892
1934
 
1893
1935
  {/* Overview link */}
@@ -1901,7 +1943,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1901
1943
  )}
1902
1944
  >
1903
1945
  <IconHome className="h-4 w-4" />
1904
- Overview
1946
+ {t("navigation.overview")}
1905
1947
  </Link>
1906
1948
 
1907
1949
  {/* Data Sources link */}
@@ -1915,7 +1957,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1915
1957
  )}
1916
1958
  >
1917
1959
  <IconDatabase className="h-4 w-4" />
1918
- Data Sources
1960
+ {t("navigation.dataSources")}
1919
1961
  </Link>
1920
1962
 
1921
1963
  {/* Data Dictionary link */}
@@ -1929,7 +1971,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1929
1971
  )}
1930
1972
  >
1931
1973
  <IconBook2 className="h-4 w-4" />
1932
- Data Dictionary
1974
+ {t("navigation.dataDictionary")}
1933
1975
  </Link>
1934
1976
 
1935
1977
  {/* Catalog link */}
@@ -1943,7 +1985,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1943
1985
  )}
1944
1986
  >
1945
1987
  <IconTemplate className="h-4 w-4" />
1946
- Catalog
1988
+ {t("navigation.templateCatalog")}
1947
1989
  </Link>
1948
1990
 
1949
1991
  {/* Dashboards section */}
@@ -1963,10 +2005,12 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1963
2005
  aria-expanded={dashOpen}
1964
2006
  >
1965
2007
  <IconChartBar className="h-4 w-4 shrink-0" />
1966
- <span className="min-w-0 flex-1 truncate">Dashboards</span>
2008
+ <span className="min-w-0 flex-1 truncate">
2009
+ {t("navigation.dashboards")}
2010
+ </span>
1967
2011
  </button>
1968
2012
  <SidebarSectionSettingsPopover
1969
- label="Dashboards"
2013
+ label={t("navigation.dashboards")}
1970
2014
  sortMode={dashboardSortMode}
1971
2015
  onSortModeChange={setDashboardSortMode}
1972
2016
  sharedOnly={dashFilter === "org"}
@@ -1979,7 +2023,9 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1979
2023
  onClick={toggleDashOpen}
1980
2024
  className="me-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground/70 hover:bg-sidebar-accent hover:text-foreground"
1981
2025
  aria-label={
1982
- dashOpen ? "Collapse dashboards" : "Expand dashboards"
2026
+ dashOpen
2027
+ ? t("sidebar.collapseDashboards")
2028
+ : t("sidebar.expandDashboards")
1983
2029
  }
1984
2030
  >
1985
2031
  <IconChevronDown
@@ -2024,8 +2070,12 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2024
2070
  className="flex items-center gap-1 px-3 py-1 text-[11px] text-muted-foreground/70 hover:text-primary"
2025
2071
  >
2026
2072
  {dashShowAll
2027
- ? "Show less"
2028
- : `Show ${filteredDashboards.length - SIDEBAR_PREVIEW_COUNT} more`}
2073
+ ? t("sidebar.showLess")
2074
+ : t("sidebar.showMore", {
2075
+ count:
2076
+ filteredDashboards.length -
2077
+ SIDEBAR_PREVIEW_COUNT,
2078
+ })}
2029
2079
  </button>
2030
2080
  )}
2031
2081
  {sqlDashboardsLoading &&
@@ -2066,10 +2116,12 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2066
2116
  aria-expanded={analysesOpen}
2067
2117
  >
2068
2118
  <IconReportAnalytics className="h-4 w-4 shrink-0" />
2069
- <span className="min-w-0 flex-1 truncate">Analyses</span>
2119
+ <span className="min-w-0 flex-1 truncate">
2120
+ {t("navigation.analyses")}
2121
+ </span>
2070
2122
  </button>
2071
2123
  <SidebarSectionSettingsPopover
2072
- label="Analyses"
2124
+ label={t("navigation.analyses")}
2073
2125
  sortMode={analysisSortMode}
2074
2126
  onSortModeChange={setAnalysisSortMode}
2075
2127
  sharedOnly={analysisFilter === "org"}
@@ -2086,7 +2138,9 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2086
2138
  onClick={toggleAnalysesOpen}
2087
2139
  className="me-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground/70 hover:bg-sidebar-accent hover:text-foreground"
2088
2140
  aria-label={
2089
- analysesOpen ? "Collapse analyses" : "Expand analyses"
2141
+ analysesOpen
2142
+ ? t("sidebar.collapseAnalyses")
2143
+ : t("sidebar.expandAnalyses")
2090
2144
  }
2091
2145
  >
2092
2146
  <IconChevronDown
@@ -2145,8 +2199,11 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2145
2199
  className="flex items-center gap-1 px-3 py-1 text-[11px] text-muted-foreground/70 hover:text-primary"
2146
2200
  >
2147
2201
  {analysesShowAll
2148
- ? "Show less"
2149
- : `Show ${filteredAnalyses.length - SIDEBAR_PREVIEW_COUNT} more`}
2202
+ ? t("sidebar.showLess")
2203
+ : t("sidebar.showMore", {
2204
+ count:
2205
+ filteredAnalyses.length - SIDEBAR_PREVIEW_COUNT,
2206
+ })}
2150
2207
  </button>
2151
2208
  )}
2152
2209
  {analysesLoading &&
@@ -2165,7 +2222,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2165
2222
  ))}
2166
2223
  {!analysesLoading && sortedAnalyses.length === 0 && (
2167
2224
  <p className="px-3 py-1 text-[11px] text-muted-foreground/60">
2168
- No analyses yet
2225
+ {t("sidebar.noAnalysesYet")}
2169
2226
  </p>
2170
2227
  )}
2171
2228
  <NewAnalysisDialog />
@@ -2218,14 +2275,18 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2218
2275
  new CustomEvent("analytics:open-command-palette"),
2219
2276
  )
2220
2277
  }
2221
- aria-label="Search"
2278
+ aria-label={t("sidebar.search")}
2222
2279
  className="flex items-center justify-center rounded-lg p-2 text-muted-foreground transition-all hover:text-primary cursor-pointer hover:bg-sidebar-accent/50"
2223
2280
  >
2224
2281
  <IconSearch className="h-4 w-4" />
2225
2282
  </button>
2226
2283
  </TooltipTrigger>
2227
2284
  <TooltipContent side="top">
2228
- <p>Search ({shortcutModifierLabel()}+K)</p>
2285
+ <p>
2286
+ {t("sidebar.searchShortcut", {
2287
+ shortcut: `${shortcutModifierLabel()}+K`,
2288
+ })}
2289
+ </p>
2229
2290
  </TooltipContent>
2230
2291
  </Tooltip>
2231
2292
  <Popover open={logoutOpen} onOpenChange={setLogoutOpen}>
@@ -2238,7 +2299,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2238
2299
  </PopoverTrigger>
2239
2300
  </TooltipTrigger>
2240
2301
  <TooltipContent side="top">
2241
- <p>Sign Out</p>
2302
+ <p>{t("sidebar.signOut")}</p>
2242
2303
  </TooltipContent>
2243
2304
  </Tooltip>
2244
2305
  <PopoverContent
@@ -2246,7 +2307,9 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2246
2307
  side="top"
2247
2308
  align="start"
2248
2309
  >
2249
- <p className="text-sm mb-3">Sign out?</p>
2310
+ <p className="text-sm mb-3">
2311
+ {t("sidebar.signOutTitle")}
2312
+ </p>
2250
2313
  <div className="flex gap-2">
2251
2314
  <button
2252
2315
  onClick={() => {
@@ -2255,13 +2318,13 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2255
2318
  }}
2256
2319
  className="flex-1 rounded-md bg-destructive px-3 py-1.5 text-xs font-medium text-destructive-foreground hover:bg-destructive/90 transition-colors"
2257
2320
  >
2258
- Yes
2321
+ {t("sidebar.yes")}
2259
2322
  </button>
2260
2323
  <button
2261
2324
  onClick={() => setLogoutOpen(false)}
2262
2325
  className="flex-1 rounded-md border border-border px-3 py-1.5 text-xs font-medium hover:bg-sidebar-accent/50 transition-colors"
2263
2326
  >
2264
- Cancel
2327
+ {t("sidebar.cancel")}
2265
2328
  </button>
2266
2329
  </div>
2267
2330
  </PopoverContent>
@@ -2284,7 +2347,9 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
2284
2347
  </button>
2285
2348
  </TooltipTrigger>
2286
2349
  <TooltipContent side="top">
2287
- <p>{light ? "Dark mode" : "Light mode"}</p>
2350
+ <p>
2351
+ {light ? t("sidebar.darkMode") : t("sidebar.lightMode")}
2352
+ </p>
2288
2353
  </TooltipContent>
2289
2354
  </Tooltip>
2290
2355
  </div>