@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
@@ -51,7 +51,6 @@ import {
51
51
  AgentToggleButton,
52
52
  DevDatabaseLink,
53
53
  FeedbackButton,
54
- LanguagePicker,
55
54
  NotificationsBell,
56
55
  agentNativePath,
57
56
  useT,
@@ -152,12 +151,12 @@ interface AppLayoutProps {
152
151
 
153
152
  // System views that can be shown/hidden via settings
154
153
  const collapsibleViews = [
155
- { id: "unread", label: "Unread" },
156
- { id: "starred", label: "Starred" },
157
- { id: "sent", label: "Sent" },
158
- { id: "drafts", label: "Drafts" },
159
- { id: "archive", label: "Archive" },
160
- { id: "trash", label: "Trash" },
154
+ { id: "unread", labelKey: "mail.views.unread" },
155
+ { id: "starred", labelKey: "mail.views.starred" },
156
+ { id: "sent", labelKey: "mail.views.sent" },
157
+ { id: "drafts", labelKey: "mail.views.drafts" },
158
+ { id: "archive", labelKey: "mail.views.archive" },
159
+ { id: "trash", labelKey: "mail.views.trash" },
161
160
  ];
162
161
 
163
162
  export function AppLayout({ children }: AppLayoutProps) {
@@ -191,6 +190,7 @@ export function AppLayout({ children }: AppLayoutProps) {
191
190
  }
192
191
 
193
192
  function AppLayoutInner({ children }: AppLayoutProps) {
193
+ const t = useT();
194
194
  const isMobile = useIsMobile();
195
195
  const compose = useComposeState();
196
196
  const headerActions = useHeaderActions();
@@ -448,7 +448,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
448
448
  if (!hasPinnedFilters) {
449
449
  tabs.push({
450
450
  id: "inbox",
451
- label: "Inbox",
451
+ label: t("mail.views.inbox"),
452
452
  href: "/inbox",
453
453
  isActive: view === "inbox" && !activeLabel,
454
454
  type: "system",
@@ -460,12 +460,12 @@ function AppLayoutInner({ children }: AppLayoutProps) {
460
460
  // Check if it's a system view
461
461
  const sysView = collapsibleViews.find((v) => v.id === id);
462
462
  if (sysView) {
463
- if (seenLabels.has(sysView.label.toLowerCase())) continue;
464
- seenLabels.add(sysView.label.toLowerCase());
463
+ if (seenLabels.has(sysView.id)) continue;
464
+ seenLabels.add(sysView.id);
465
465
  tabs.push({
466
466
  id: sysView.id,
467
467
  pinnedId: id,
468
- label: sysView.label,
468
+ label: t(sysView.labelKey),
469
469
  href: `/${sysView.id}`,
470
470
  isActive: view === sysView.id,
471
471
  type: "system",
@@ -507,7 +507,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
507
507
  if (hasPinnedFilters) {
508
508
  tabs.push({
509
509
  id: "inbox",
510
- label: "Other",
510
+ label: t("mail.views.other"),
511
511
  href: "/inbox",
512
512
  isActive: view === "inbox" && !activeLabel,
513
513
  type: "system",
@@ -515,7 +515,15 @@ function AppLayoutInner({ children }: AppLayoutProps) {
515
515
  }
516
516
 
517
517
  return tabs;
518
- }, [labels, pinnedLabels, labelAliases, view, activeLabel, hasPinnedFilters]);
518
+ }, [
519
+ labels,
520
+ pinnedLabels,
521
+ labelAliases,
522
+ view,
523
+ activeLabel,
524
+ hasPinnedFilters,
525
+ t,
526
+ ]);
519
527
 
520
528
  const topBarTabs = useMemo(() => {
521
529
  const tabs = [...visibleTabs];
@@ -639,7 +647,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
639
647
 
640
648
  const handleSpam = useCallback(() => {
641
649
  if (!targetEmail) {
642
- toast.error("No email selected.");
650
+ toast.error(t("mail.toasts.noEmailSelected"));
643
651
  return;
644
652
  }
645
653
  dismissEmail(targetEmail.id);
@@ -647,12 +655,12 @@ function AppLayoutInner({ children }: AppLayoutProps) {
647
655
  id: targetEmail.id,
648
656
  threadId: targetEmail.threadId || targetEmail.id,
649
657
  });
650
- toast("Reported as spam.");
651
- }, [targetEmail, reportSpam, dismissEmail]);
658
+ toast(t("mail.toasts.reportedSpam"));
659
+ }, [targetEmail, reportSpam, dismissEmail, t]);
652
660
 
653
661
  const handleBlockSender = useCallback(() => {
654
662
  if (!targetEmail) {
655
- toast.error("No email selected.");
663
+ toast.error(t("mail.toasts.noEmailSelected"));
656
664
  return;
657
665
  }
658
666
  dismissEmail(targetEmail.id);
@@ -661,21 +669,23 @@ function AppLayoutInner({ children }: AppLayoutProps) {
661
669
  threadId: targetEmail.threadId || targetEmail.id,
662
670
  senderEmail: targetEmail.from.email,
663
671
  });
664
- toast(`Reported as spam & blocked ${targetEmail.from.email}.`);
665
- }, [targetEmail, blockSender, dismissEmail]);
672
+ toast(
673
+ t("mail.toasts.reportedSpamBlocked", { email: targetEmail.from.email }),
674
+ );
675
+ }, [targetEmail, blockSender, dismissEmail, t]);
666
676
 
667
677
  const handleMuteThread = useCallback(() => {
668
678
  const tid =
669
679
  threadId ||
670
680
  (targetEmail ? targetEmail.threadId || targetEmail.id : undefined);
671
681
  if (!tid) {
672
- toast.error("No thread selected.");
682
+ toast.error(t("mail.toasts.noThreadSelected"));
673
683
  return;
674
684
  }
675
685
  if (targetEmail) dismissEmail(targetEmail.id);
676
686
  muteThread.mutate(tid);
677
- toast("Thread muted.");
678
- }, [threadId, targetEmail, muteThread, dismissEmail]);
687
+ toast(t("mail.toasts.threadMuted"));
688
+ }, [threadId, targetEmail, muteThread, dismissEmail, t]);
679
689
 
680
690
  const togglePinned = useCallback(
681
691
  (id: string) => {
@@ -969,12 +979,12 @@ function AppLayoutInner({ children }: AppLayoutProps) {
969
979
  <button
970
980
  onClick={() => setSidebarOpen(!sidebarOpen)}
971
981
  className="flex h-9 w-9 sm:h-7 sm:w-7 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors shrink-0"
972
- aria-label="Toggle menu"
982
+ aria-label={t("mail.toolbar.toggleMenu")}
973
983
  >
974
984
  <IconMenu2 className="h-4 w-4" />
975
985
  </button>
976
986
  </TooltipTrigger>
977
- <TooltipContent>Menu</TooltipContent>
987
+ <TooltipContent>{t("mail.toolbar.menu")}</TooltipContent>
978
988
  </Tooltip>
979
989
 
980
990
  {/* Primary tabs stay mounted during search so navigation does not jump. */}
@@ -1064,7 +1074,10 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1064
1074
  {/* If navigated to an unpinned view (e.g. via keyboard shortcut), show it */}
1065
1075
  {currentInHidden && (
1066
1076
  <span className="flex items-center whitespace-nowrap px-2.5 py-1 text-[13px] text-foreground font-semibold">
1067
- {collapsibleViews.find((v) => v.id === view)?.label}
1077
+ {t(
1078
+ collapsibleViews.find((v) => v.id === view)?.labelKey ??
1079
+ "mail.views.inbox",
1080
+ )}
1068
1081
  </span>
1069
1082
  )}
1070
1083
  </nav>
@@ -1089,13 +1102,15 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1089
1102
  ? "text-foreground bg-accent/50"
1090
1103
  : "text-muted-foreground hover:text-foreground hover:bg-accent/30",
1091
1104
  )}
1092
- aria-label="Configure tabs"
1105
+ aria-label={t("mail.toolbar.configureTabs")}
1093
1106
  >
1094
1107
  <IconSettings className="h-3.5 w-3.5" />
1095
1108
  </button>
1096
1109
  </PopoverTrigger>
1097
1110
  </TooltipTrigger>
1098
- <TooltipContent>Configure tabs</TooltipContent>
1111
+ <TooltipContent>
1112
+ {t("mail.toolbar.configureTabs")}
1113
+ </TooltipContent>
1099
1114
  </Tooltip>
1100
1115
  <PopoverContent
1101
1116
  align="start"
@@ -1150,12 +1165,12 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1150
1165
  <button
1151
1166
  onClick={() => setSearchFocused(true)}
1152
1167
  className="flex h-9 w-9 sm:h-7 sm:w-7 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
1153
- aria-label="Search"
1168
+ aria-label={t("mail.search.label")}
1154
1169
  >
1155
1170
  <IconSearch className="h-4 w-4" />
1156
1171
  </button>
1157
1172
  </TooltipTrigger>
1158
- <TooltipContent>Search</TooltipContent>
1173
+ <TooltipContent>{t("mail.search.label")}</TooltipContent>
1159
1174
  </Tooltip>
1160
1175
  )}
1161
1176
 
@@ -1188,7 +1203,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1188
1203
  className={cn(
1189
1204
  "flex h-9 w-9 sm:h-7 sm:w-7 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors shrink-0 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-muted-foreground",
1190
1205
  )}
1191
- aria-label="Refresh inbox"
1206
+ aria-label={t("mail.toolbar.refreshInbox")}
1192
1207
  >
1193
1208
  <IconRefresh
1194
1209
  className={cn(
@@ -1198,11 +1213,10 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1198
1213
  />
1199
1214
  </button>
1200
1215
  </TooltipTrigger>
1201
- <TooltipContent>Refresh inbox</TooltipContent>
1216
+ <TooltipContent>{t("mail.toolbar.refreshInbox")}</TooltipContent>
1202
1217
  </Tooltip>
1203
1218
 
1204
1219
  <NotificationsBell />
1205
- <LanguagePicker variant="icon" />
1206
1220
 
1207
1221
  {/* Compose — prominent outline button */}
1208
1222
  <Tooltip>
@@ -1212,12 +1226,12 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1212
1226
  variant="outline"
1213
1227
  size="sm"
1214
1228
  className="h-9 sm:h-7 px-3 text-[13px]"
1215
- aria-label="Compose email"
1229
+ aria-label={t("mail.toolbar.composeEmail")}
1216
1230
  >
1217
- <span>Compose</span>
1231
+ <span>{t("mail.toolbar.compose")}</span>
1218
1232
  </Button>
1219
1233
  </TooltipTrigger>
1220
- <TooltipContent>Compose (C)</TooltipContent>
1234
+ <TooltipContent>{t("mail.toolbar.composeShortcut")}</TooltipContent>
1221
1235
  </Tooltip>
1222
1236
 
1223
1237
  {/* Account avatars — overlapping stack like Figma */}
@@ -1270,7 +1284,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1270
1284
  </button>
1271
1285
  </PopoverTrigger>
1272
1286
  </TooltipTrigger>
1273
- <TooltipContent>Accounts</TooltipContent>
1287
+ <TooltipContent>{t("mail.toolbar.accounts")}</TooltipContent>
1274
1288
  </Tooltip>
1275
1289
  <PopoverContent
1276
1290
  align="end"
@@ -1333,7 +1347,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1333
1347
  >
1334
1348
  <div className="flex h-12 shrink-0 items-center justify-between border-b border-border/20 px-4">
1335
1349
  <span className="text-[13px] font-medium text-foreground">
1336
- Mail
1350
+ {t("mail.appName")}
1337
1351
  </span>
1338
1352
  <Tooltip>
1339
1353
  <TooltipTrigger asChild>
@@ -1348,7 +1362,9 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1348
1362
  sidebarPinned && "text-foreground bg-accent/50",
1349
1363
  )}
1350
1364
  aria-label={
1351
- sidebarPinned ? "Unpin sidebar" : "Pin sidebar"
1365
+ sidebarPinned
1366
+ ? t("mail.toolbar.unpinSidebar")
1367
+ : t("mail.toolbar.pinSidebar")
1352
1368
  }
1353
1369
  >
1354
1370
  {sidebarPinned ? (
@@ -1359,7 +1375,9 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1359
1375
  </button>
1360
1376
  </TooltipTrigger>
1361
1377
  <TooltipContent>
1362
- {sidebarPinned ? "Unpin sidebar" : "Pin sidebar"}
1378
+ {sidebarPinned
1379
+ ? t("mail.toolbar.unpinSidebar")
1380
+ : t("mail.toolbar.pinSidebar")}
1363
1381
  </TooltipContent>
1364
1382
  </Tooltip>
1365
1383
  </div>
@@ -1418,24 +1436,56 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1418
1436
  <div className="p-4">
1419
1437
  <div className="space-y-0.5">
1420
1438
  {[
1421
- { id: "inbox", label: "Inbox", href: "/inbox" },
1422
- { id: "unread", label: "Unread", href: "/unread" },
1423
- { id: "starred", label: "Starred", href: "/starred" },
1424
- { id: "snoozed", label: "Snoozed", href: "/snoozed" },
1425
- { id: "sent", label: "Sent", href: "/sent" },
1439
+ {
1440
+ id: "inbox",
1441
+ label: t("mail.views.inbox"),
1442
+ href: "/inbox",
1443
+ },
1444
+ {
1445
+ id: "unread",
1446
+ label: t("mail.views.unread"),
1447
+ href: "/unread",
1448
+ },
1449
+ {
1450
+ id: "starred",
1451
+ label: t("mail.views.starred"),
1452
+ href: "/starred",
1453
+ },
1454
+ {
1455
+ id: "snoozed",
1456
+ label: t("mail.views.snoozed"),
1457
+ href: "/snoozed",
1458
+ },
1459
+ {
1460
+ id: "sent",
1461
+ label: t("mail.views.sent"),
1462
+ href: "/sent",
1463
+ },
1426
1464
  {
1427
1465
  id: "draft-queue",
1428
- label: "Draft queue",
1466
+ label: t("mail.views.draftQueue"),
1429
1467
  href: "/draft-queue",
1430
1468
  },
1431
1469
  {
1432
1470
  id: "scheduled",
1433
- label: "Scheduled",
1471
+ label: t("mail.views.scheduled"),
1434
1472
  href: "/scheduled",
1435
1473
  },
1436
- { id: "drafts", label: "Drafts", href: "/drafts" },
1437
- { id: "archive", label: "Archive", href: "/archive" },
1438
- { id: "trash", label: "Trash", href: "/trash" },
1474
+ {
1475
+ id: "drafts",
1476
+ label: t("mail.views.drafts"),
1477
+ href: "/drafts",
1478
+ },
1479
+ {
1480
+ id: "archive",
1481
+ label: t("mail.views.archive"),
1482
+ href: "/archive",
1483
+ },
1484
+ {
1485
+ id: "trash",
1486
+ label: t("mail.views.trash"),
1487
+ href: "/trash",
1488
+ },
1439
1489
  ].map((item) => (
1440
1490
  <Link
1441
1491
  key={item.id}
@@ -1470,7 +1520,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1470
1520
  ).length > 0 && (
1471
1521
  <>
1472
1522
  <h2 className="text-[11px] font-medium text-muted-foreground/50 uppercase tracking-wider mt-5 mb-3">
1473
- Labels
1523
+ {t("mail.views.labels")}
1474
1524
  </h2>
1475
1525
  <div className="space-y-0.5">
1476
1526
  {visibleTabs
@@ -1540,7 +1590,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1540
1590
  <Link
1541
1591
  to="/settings"
1542
1592
  onClick={closeSidebar}
1543
- aria-label="Settings"
1593
+ aria-label={t("mail.toolbar.settings")}
1544
1594
  className={cn(
1545
1595
  "flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground",
1546
1596
  location.pathname === "/settings" &&
@@ -1550,7 +1600,9 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1550
1600
  <IconSettings className="h-4 w-4" />
1551
1601
  </Link>
1552
1602
  </TooltipTrigger>
1553
- <TooltipContent>Settings</TooltipContent>
1603
+ <TooltipContent>
1604
+ {t("mail.toolbar.settings")}
1605
+ </TooltipContent>
1554
1606
  </Tooltip>
1555
1607
  <ThemeToggle className="h-8 w-8 shrink-0" />
1556
1608
  </div>
@@ -1729,6 +1781,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1729
1781
  * `useSetPageTitle` / `useSetHeaderActions` from `./HeaderActions`.
1730
1782
  */
1731
1783
  function StandardLayout({ children }: AppLayoutProps) {
1784
+ const t = useT();
1732
1785
  const location = useLocation();
1733
1786
  const [sidebarOpen, setSidebarOpen] = useState(false);
1734
1787
  const headerTitle = useHeaderTitle();
@@ -1744,11 +1797,13 @@ function StandardLayout({ children }: AppLayoutProps) {
1744
1797
  location.pathname.startsWith("/extensions/");
1745
1798
 
1746
1799
  const fallbackTitle = (() => {
1747
- if (location.pathname === "/settings") return "Settings";
1748
- if (location.pathname === "/team") return "Team";
1749
- if (location.pathname.startsWith("/draft-queue")) return "Draft queue";
1750
- if (location.pathname.startsWith("/extensions")) return "Extensions";
1751
- return "Mail";
1800
+ if (location.pathname === "/settings") return t("settings.title");
1801
+ if (location.pathname === "/team") return t("mail.pages.team");
1802
+ if (location.pathname.startsWith("/draft-queue"))
1803
+ return t("mail.views.draftQueue");
1804
+ if (location.pathname.startsWith("/extensions"))
1805
+ return t("mail.views.extensions");
1806
+ return t("mail.appName");
1752
1807
  })();
1753
1808
 
1754
1809
  return (
@@ -1760,12 +1815,12 @@ function StandardLayout({ children }: AppLayoutProps) {
1760
1815
  <button
1761
1816
  onClick={() => setSidebarOpen(!sidebarOpen)}
1762
1817
  className="flex h-8 w-8 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors shrink-0 cursor-pointer"
1763
- aria-label="Toggle menu"
1818
+ aria-label={t("mail.toolbar.toggleMenu")}
1764
1819
  >
1765
1820
  <IconMenu2 className="h-4 w-4" />
1766
1821
  </button>
1767
1822
  </TooltipTrigger>
1768
- <TooltipContent>Menu</TooltipContent>
1823
+ <TooltipContent>{t("mail.toolbar.menu")}</TooltipContent>
1769
1824
  </Tooltip>
1770
1825
  <div className="flex min-w-0 flex-1 items-center gap-2">
1771
1826
  {headerTitle ?? (
@@ -1777,7 +1832,6 @@ function StandardLayout({ children }: AppLayoutProps) {
1777
1832
  <div className="flex shrink-0 items-center gap-2">
1778
1833
  {headerActions}
1779
1834
  <NotificationsBell />
1780
- <LanguagePicker variant="icon" />
1781
1835
  <AgentToggleButton />
1782
1836
  </div>
1783
1837
  </header>
@@ -1793,24 +1847,44 @@ function StandardLayout({ children }: AppLayoutProps) {
1793
1847
  <div className="min-h-0 flex-1 overflow-y-auto p-4">
1794
1848
  <div className="space-y-0.5">
1795
1849
  {[
1796
- { id: "inbox", label: "Inbox", href: "/inbox" },
1797
- { id: "unread", label: "Unread", href: "/unread" },
1798
- { id: "starred", label: "Starred", href: "/starred" },
1799
- { id: "snoozed", label: "Snoozed", href: "/snoozed" },
1800
- { id: "sent", label: "Sent", href: "/sent" },
1850
+ { id: "inbox", label: t("mail.views.inbox"), href: "/inbox" },
1851
+ {
1852
+ id: "unread",
1853
+ label: t("mail.views.unread"),
1854
+ href: "/unread",
1855
+ },
1856
+ {
1857
+ id: "starred",
1858
+ label: t("mail.views.starred"),
1859
+ href: "/starred",
1860
+ },
1861
+ {
1862
+ id: "snoozed",
1863
+ label: t("mail.views.snoozed"),
1864
+ href: "/snoozed",
1865
+ },
1866
+ { id: "sent", label: t("mail.views.sent"), href: "/sent" },
1801
1867
  {
1802
1868
  id: "draft-queue",
1803
- label: "Draft queue",
1869
+ label: t("mail.views.draftQueue"),
1804
1870
  href: "/draft-queue",
1805
1871
  },
1806
1872
  {
1807
1873
  id: "scheduled",
1808
- label: "Scheduled",
1874
+ label: t("mail.views.scheduled"),
1809
1875
  href: "/scheduled",
1810
1876
  },
1811
- { id: "drafts", label: "Drafts", href: "/drafts" },
1812
- { id: "archive", label: "Archive", href: "/archive" },
1813
- { id: "trash", label: "Trash", href: "/trash" },
1877
+ {
1878
+ id: "drafts",
1879
+ label: t("mail.views.drafts"),
1880
+ href: "/drafts",
1881
+ },
1882
+ {
1883
+ id: "archive",
1884
+ label: t("mail.views.archive"),
1885
+ href: "/archive",
1886
+ },
1887
+ { id: "trash", label: t("mail.views.trash"), href: "/trash" },
1814
1888
  ].map((item) => (
1815
1889
  <Link
1816
1890
  key={item.id}
@@ -1852,7 +1926,7 @@ function StandardLayout({ children }: AppLayoutProps) {
1852
1926
  <Link
1853
1927
  to="/settings"
1854
1928
  onClick={() => setSidebarOpen(false)}
1855
- aria-label="Settings"
1929
+ aria-label={t("mail.toolbar.settings")}
1856
1930
  className={cn(
1857
1931
  "flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground",
1858
1932
  location.pathname === "/settings" &&
@@ -1862,7 +1936,9 @@ function StandardLayout({ children }: AppLayoutProps) {
1862
1936
  <IconSettings className="h-4 w-4" />
1863
1937
  </Link>
1864
1938
  </TooltipTrigger>
1865
- <TooltipContent>Settings</TooltipContent>
1939
+ <TooltipContent>
1940
+ {t("mail.toolbar.settings")}
1941
+ </TooltipContent>
1866
1942
  </Tooltip>
1867
1943
  <ThemeToggle className="h-8 w-8 shrink-0" />
1868
1944
  </div>
@@ -1930,7 +2006,7 @@ function TabSettingsPopover({
1930
2006
  onToggle,
1931
2007
  onRename,
1932
2008
  }: {
1933
- systemViews: { id: string; label: string }[];
2009
+ systemViews: { id: string; labelKey: string }[];
1934
2010
  userLabels: Label[];
1935
2011
  pinnedLabels: string[];
1936
2012
  labelAliases: Record<string, string>;
@@ -1939,12 +2015,13 @@ function TabSettingsPopover({
1939
2015
  onToggle: (id: string) => void;
1940
2016
  onRename: (id: string, alias: string) => void;
1941
2017
  }) {
2018
+ const t = useT();
1942
2019
  const [editingId, setEditingId] = useState<string | null>(null);
1943
2020
  const [editValue, setEditValue] = useState("");
1944
2021
  const q = search.toLowerCase();
1945
2022
 
1946
2023
  const filteredViews = search
1947
- ? systemViews.filter((v) => v.label.toLowerCase().includes(q))
2024
+ ? systemViews.filter((v) => t(v.labelKey).toLowerCase().includes(q))
1948
2025
  : systemViews;
1949
2026
 
1950
2027
  // Split labels into Gmail categories and regular user labels
@@ -2004,7 +2081,7 @@ function TabSettingsPopover({
2004
2081
  autoFocus
2005
2082
  value={search}
2006
2083
  onChange={(e) => onSearchChange(e.target.value)}
2007
- placeholder="Search..."
2084
+ placeholder={t("mail.search.placeholder")}
2008
2085
  className="w-full bg-transparent text-[13px] text-foreground placeholder:text-muted-foreground/40 outline-none px-1 py-0.5"
2009
2086
  />
2010
2087
  </div>
@@ -2012,7 +2089,7 @@ function TabSettingsPopover({
2012
2089
  <div className="max-h-72 overflow-y-auto">
2013
2090
  {noResults && (
2014
2091
  <p className="px-3 py-3 text-[12px] text-muted-foreground/50">
2015
- No matches
2092
+ {t("mail.search.noMatches")}
2016
2093
  </p>
2017
2094
  )}
2018
2095
 
@@ -2020,13 +2097,13 @@ function TabSettingsPopover({
2020
2097
  {showViews && (
2021
2098
  <div>
2022
2099
  <p className="px-3 pt-2 pb-1 text-[10px] font-medium text-muted-foreground/50 uppercase tracking-wider">
2023
- Views
2100
+ {t("mail.tabSettings.views")}
2024
2101
  </p>
2025
2102
  {filteredViews.map((v) => (
2026
2103
  <CheckboxRow
2027
2104
  key={v.id}
2028
2105
  checked={pinnedLabels.includes(v.id)}
2029
- label={v.label}
2106
+ label={t(v.labelKey)}
2030
2107
  onToggle={() => onToggle(v.id)}
2031
2108
  />
2032
2109
  ))}
@@ -2042,7 +2119,7 @@ function TabSettingsPopover({
2042
2119
  showViews && "border-t border-border/20 mt-1",
2043
2120
  )}
2044
2121
  >
2045
- Categories
2122
+ {t("mail.tabSettings.categories")}
2046
2123
  </p>
2047
2124
  {filteredCategories.map((cat) => (
2048
2125
  <CheckboxRow
@@ -2065,7 +2142,7 @@ function TabSettingsPopover({
2065
2142
  "border-t border-border/20 mt-1",
2066
2143
  )}
2067
2144
  >
2068
- Labels
2145
+ {t("mail.views.labels")}
2069
2146
  </p>
2070
2147
  {sortedLabels.map((label) => {
2071
2148
  const isPinned = pinnedLabels.includes(label.id);
@@ -2116,10 +2193,12 @@ function TabSettingsPopover({
2116
2193
  }}
2117
2194
  className="shrink-0 me-2 px-1 py-0.5 text-[10px] text-muted-foreground/40 hover:text-foreground opacity-0 group-hover:opacity-100 rounded hover:bg-accent/50"
2118
2195
  >
2119
- Rename
2196
+ {t("mail.tabSettings.rename")}
2120
2197
  </button>
2121
2198
  </TooltipTrigger>
2122
- <TooltipContent>Rename tab</TooltipContent>
2199
+ <TooltipContent>
2200
+ {t("mail.tabSettings.renameTab")}
2201
+ </TooltipContent>
2123
2202
  </Tooltip>
2124
2203
  )}
2125
2204
  </div>
@@ -2131,7 +2210,7 @@ function TabSettingsPopover({
2131
2210
 
2132
2211
  <div className="px-3 py-1.5 border-t border-border/30">
2133
2212
  <p className="text-[11px] text-muted-foreground/40">
2134
- Checked items show as tabs. Label emails split from inbox.
2213
+ {t("mail.tabSettings.help")}
2135
2214
  </p>
2136
2215
  </div>
2137
2216
  </>
@@ -2151,6 +2230,7 @@ function AccountPopover({
2151
2230
  onToggleAccount: (email: string) => void;
2152
2231
  onRemoveAccount: (email: string) => void;
2153
2232
  }) {
2233
+ const t = useT();
2154
2234
  const [wantAuthUrl, setWantAuthUrl] = useState(false);
2155
2235
  const authUrl = useGoogleAuthUrl(wantAuthUrl);
2156
2236
  const disconnectGoogle = useDisconnectGoogle();
@@ -2183,7 +2263,7 @@ function AccountPopover({
2183
2263
  <>
2184
2264
  <div className="px-3 py-2 border-b border-border/30">
2185
2265
  <p className="text-[11px] font-medium text-muted-foreground uppercase tracking-wider">
2186
- Accounts
2266
+ {t("mail.toolbar.accounts")}
2187
2267
  </p>
2188
2268
  </div>
2189
2269
 
@@ -2237,7 +2317,7 @@ function AccountPopover({
2237
2317
  }}
2238
2318
  className="opacity-0 group-hover:opacity-100 text-[11px] text-muted-foreground hover:text-red-400 transition-all"
2239
2319
  >
2240
- Remove
2320
+ {t("mail.accounts.remove")}
2241
2321
  </button>
2242
2322
  </div>
2243
2323
  );
@@ -2251,7 +2331,9 @@ function AccountPopover({
2251
2331
  className="flex items-center gap-2 w-full text-[13px] text-muted-foreground hover:text-foreground transition-colors py-1"
2252
2332
  >
2253
2333
  <IconPlus className="h-3.5 w-3.5" />
2254
- {authUrl.isFetching ? "Connecting..." : "Add account"}
2334
+ {authUrl.isFetching
2335
+ ? t("mail.accounts.connecting")
2336
+ : t("mail.accounts.addAccount")}
2255
2337
  </button>
2256
2338
  </div>
2257
2339
  </>
@@ -15,6 +15,7 @@ import {
15
15
  TooltipContent,
16
16
  TooltipTrigger,
17
17
  } from "@/components/ui/tooltip";
18
+ import { useT } from "@agent-native/core/client";
18
19
 
19
20
  interface SearchBarProps {
20
21
  onClose: () => void;
@@ -29,6 +30,7 @@ export function SearchBar({
29
30
  autoFocus = true,
30
31
  hasActiveSearch = false,
31
32
  }: SearchBarProps) {
33
+ const t = useT();
32
34
  const navigate = useNavigate();
33
35
  const [query, setQuery] = useState(initialQuery);
34
36
  const [selectedIndex, setSelectedIndex] = useState(-1);
@@ -192,7 +194,7 @@ export function SearchBar({
192
194
  if (hasActiveSearch || query.trim()) return;
193
195
  setTimeout(onClose, 100);
194
196
  }}
195
- placeholder="Search..."
197
+ placeholder={t("mail.search.placeholder")}
196
198
  className={cn(
197
199
  "h-8 sm:h-7 flex-1 min-w-0 bg-transparent border-none px-2.5 text-[13px] text-foreground placeholder:text-muted-foreground/60 outline-none",
198
200
  hasActiveSearch && "font-medium",
@@ -212,7 +214,7 @@ export function SearchBar({
212
214
  <IconX className="h-3.5 w-3.5" />
213
215
  </button>
214
216
  </TooltipTrigger>
215
- <TooltipContent>Clear search (Esc)</TooltipContent>
217
+ <TooltipContent>{t("mail.search.clear")}</TooltipContent>
216
218
  </Tooltip>
217
219
  )}
218
220
  </div>