@agent-native/core 0.76.10 → 0.76.12

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 (130) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +13 -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/src/client/ErrorBoundary.tsx +151 -10
  23. package/corpus/core/src/client/FeedbackButton.tsx +162 -18
  24. package/corpus/core/src/client/blocks/library/AnnotatedCodeBlock.tsx +11 -2
  25. package/corpus/core/src/client/blocks/library/ApiEndpointBlock.tsx +46 -19
  26. package/corpus/core/src/client/blocks/library/MermaidBlock.tsx +7 -5
  27. package/corpus/core/src/client/blocks/library/block-copy.ts +367 -0
  28. package/corpus/core/src/client/blocks/library/diagram.tsx +8 -6
  29. package/corpus/core/src/client/blocks/library/wireframe.tsx +7 -2
  30. package/corpus/core/src/client/i18n.tsx +4 -0
  31. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +51 -31
  32. package/corpus/templates/analytics/app/components/layout/DashboardHeader.tsx +26 -16
  33. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -2
  34. package/corpus/templates/analytics/app/components/layout/HeaderActions.tsx +8 -1
  35. package/corpus/templates/analytics/app/components/layout/Layout.tsx +2 -5
  36. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +172 -107
  37. package/corpus/templates/analytics/app/i18n-data.ts +1076 -5
  38. package/corpus/templates/analytics/app/pages/Settings.tsx +2 -2
  39. package/corpus/templates/analytics/changelog/2026-06-24-analytics-navigation-command-palette-and-settings-now-honor-.md +6 -0
  40. package/corpus/templates/assets/app/components/layout/Header.tsx +0 -2
  41. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +0 -2
  42. package/corpus/templates/calendar/app/pages/CalendarView.tsx +0 -2
  43. package/corpus/templates/chat/app/components/layout/Header.tsx +1 -6
  44. package/corpus/templates/clips/app/components/layout/Header.tsx +1 -6
  45. package/corpus/templates/clips/app/hooks/use-library.ts +2 -0
  46. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +3 -1
  47. package/corpus/templates/clips/changelog/2026-06-24-archive-and-spaces-navigation-is-more-resilient-when-sidebar.md +6 -0
  48. package/corpus/templates/content/app/components/layout/Header.tsx +0 -2
  49. package/corpus/templates/design/app/components/layout/Header.tsx +1 -6
  50. package/corpus/templates/forms/app/components/layout/Header.tsx +1 -6
  51. package/corpus/templates/macros/app/components/layout/Header.tsx +1 -6
  52. package/corpus/templates/mail/app/components/email/CodeBlockLangPicker.tsx +4 -2
  53. package/corpus/templates/mail/app/components/email/ComposeBubbleToolbar.tsx +18 -12
  54. package/corpus/templates/mail/app/components/email/ComposeEditor.tsx +9 -5
  55. package/corpus/templates/mail/app/components/email/ComposeModal.tsx +36 -19
  56. package/corpus/templates/mail/app/components/email/EmailList.tsx +59 -55
  57. package/corpus/templates/mail/app/components/email/EmailListItem.tsx +7 -3
  58. package/corpus/templates/mail/app/components/email/EmailThread.tsx +25 -16
  59. package/corpus/templates/mail/app/components/email/InlineReplyComposer.tsx +25 -19
  60. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +32 -17
  61. package/corpus/templates/mail/app/components/email/RecipientInput.tsx +26 -10
  62. package/corpus/templates/mail/app/components/email/SendLaterButton.tsx +5 -3
  63. package/corpus/templates/mail/app/components/email/SnoozeModal.tsx +4 -2
  64. package/corpus/templates/mail/app/components/email/SnoozePopover.tsx +9 -5
  65. package/corpus/templates/mail/app/components/email/extensions/ComposeImageBlock.tsx +4 -2
  66. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +168 -86
  67. package/corpus/templates/mail/app/components/layout/SearchBar.tsx +4 -2
  68. package/corpus/templates/mail/app/i18n/ar-SA.ts +212 -0
  69. package/corpus/templates/mail/app/i18n/de-DE.ts +212 -0
  70. package/corpus/templates/mail/app/i18n/en-US.ts +212 -0
  71. package/corpus/templates/mail/app/i18n/es-ES.ts +212 -0
  72. package/corpus/templates/mail/app/i18n/fr-FR.ts +212 -0
  73. package/corpus/templates/mail/app/i18n/hi-IN.ts +212 -0
  74. package/corpus/templates/mail/app/i18n/ja-JP.ts +212 -0
  75. package/corpus/templates/mail/app/i18n/ko-KR.ts +212 -0
  76. package/corpus/templates/mail/app/i18n/pt-BR.ts +212 -0
  77. package/corpus/templates/mail/app/i18n/zh-CN.ts +211 -0
  78. package/corpus/templates/mail/app/root.tsx +90 -6
  79. package/corpus/templates/mail/changelog/2026-06-24-interface-language-support-now-covers-more-mail-controls-and.md +6 -0
  80. package/corpus/templates/plan/app/components/layout/Header.tsx +1 -6
  81. package/corpus/templates/slides/app/components/layout/Header.tsx +1 -6
  82. package/corpus/templates/videos/app/components/layout/Header.tsx +1 -6
  83. package/dist/client/ErrorBoundary.d.ts.map +1 -1
  84. package/dist/client/ErrorBoundary.js +128 -7
  85. package/dist/client/ErrorBoundary.js.map +1 -1
  86. package/dist/client/FeedbackButton.d.ts.map +1 -1
  87. package/dist/client/FeedbackButton.js +142 -14
  88. package/dist/client/FeedbackButton.js.map +1 -1
  89. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  90. package/dist/client/blocks/library/AnnotatedCodeBlock.js +6 -2
  91. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  92. package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
  93. package/dist/client/blocks/library/ApiEndpointBlock.js +14 -6
  94. package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
  95. package/dist/client/blocks/library/MermaidBlock.d.ts.map +1 -1
  96. package/dist/client/blocks/library/MermaidBlock.js +6 -4
  97. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  98. package/dist/client/blocks/library/block-copy.d.ts +33 -0
  99. package/dist/client/blocks/library/block-copy.d.ts.map +1 -0
  100. package/dist/client/blocks/library/block-copy.js +329 -0
  101. package/dist/client/blocks/library/block-copy.js.map +1 -0
  102. package/dist/client/blocks/library/diagram.d.ts.map +1 -1
  103. package/dist/client/blocks/library/diagram.js +7 -5
  104. package/dist/client/blocks/library/diagram.js.map +1 -1
  105. package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
  106. package/dist/client/blocks/library/wireframe.js +4 -2
  107. package/dist/client/blocks/library/wireframe.js.map +1 -1
  108. package/dist/client/i18n.d.ts +1 -0
  109. package/dist/client/i18n.d.ts.map +1 -1
  110. package/dist/client/i18n.js +3 -0
  111. package/dist/client/i18n.js.map +1 -1
  112. package/docs/content/locales/ar-SA/actions.md +7 -7
  113. package/docs/content/locales/ar-SA/template-plan.md +6 -4
  114. package/docs/content/locales/de-DE/actions.md +9 -9
  115. package/docs/content/locales/de-DE/template-plan.md +6 -4
  116. package/docs/content/locales/es-ES/actions.md +9 -9
  117. package/docs/content/locales/es-ES/template-plan.md +6 -4
  118. package/docs/content/locales/fr-FR/actions.md +9 -9
  119. package/docs/content/locales/fr-FR/template-plan.md +6 -4
  120. package/docs/content/locales/hi-IN/actions.md +9 -9
  121. package/docs/content/locales/hi-IN/template-plan.md +4 -4
  122. package/docs/content/locales/ja-JP/actions.md +9 -9
  123. package/docs/content/locales/ja-JP/template-plan.md +4 -4
  124. package/docs/content/locales/ko-KR/actions.md +9 -9
  125. package/docs/content/locales/ko-KR/template-plan.md +4 -4
  126. package/docs/content/locales/pt-BR/actions.md +9 -9
  127. package/docs/content/locales/pt-BR/template-plan.md +6 -4
  128. package/docs/content/locales/zh-CN/actions.md +9 -9
  129. package/docs/content/locales/zh-CN/template-plan.md +4 -4
  130. package/package.json +1 -1
@@ -17,8 +17,6 @@ export default function Settings() {
17
17
 
18
18
  return (
19
19
  <div className="space-y-6 max-w-2xl">
20
- <ChangelogSettingsCard markdown={changelog} />
21
-
22
20
  <Card className="bg-card border-border/50">
23
21
  <CardHeader>
24
22
  <CardTitle className="text-base">{t("settings.account")}</CardTitle>
@@ -92,6 +90,8 @@ export default function Settings() {
92
90
  <p>{t("settings.aboutUsage")}</p>
93
91
  </CardContent>
94
92
  </Card>
93
+
94
+ <ChangelogSettingsCard markdown={changelog} />
95
95
  </div>
96
96
  );
97
97
  }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-06-24
4
+ ---
5
+
6
+ Analytics navigation, command palette, and settings now honor the selected interface language.
@@ -1,7 +1,6 @@
1
1
  import { useLocation } from "react-router";
2
2
  import {
3
3
  AgentToggleButton,
4
- LanguagePicker,
5
4
  useActionQuery,
6
5
  useT,
7
6
  } from "@agent-native/core/client";
@@ -55,7 +54,6 @@ export function Header() {
55
54
  </div>
56
55
  <div className="flex items-center gap-2 shrink-0">
57
56
  {actions}
58
- <LanguagePicker variant="icon" />
59
57
  {showAgentToggle ? <AgentToggleButton /> : null}
60
58
  </div>
61
59
  </header>
@@ -12,7 +12,6 @@ import { Button } from "@/components/ui/button";
12
12
  import {
13
13
  AgentSidebar,
14
14
  AgentToggleButton,
15
- LanguagePicker,
16
15
  NotificationsBell,
17
16
  useAppearanceSync,
18
17
  } from "@agent-native/core/client";
@@ -288,7 +287,6 @@ export function AppLayout({ children }: AppLayoutProps) {
288
287
  </div>
289
288
  <div className="flex shrink-0 items-center gap-2">
290
289
  {headerControls?.right}
291
- <LanguagePicker variant="icon" />
292
290
  {!isMobile && (
293
291
  <NotificationsBell emptyDescription="Calendar can pop browser alerts while this app is open. Clips desktop handles fuller meeting prompts with one-click notes." />
294
292
  )}
@@ -72,7 +72,6 @@ import { useQueryClient } from "@tanstack/react-query";
72
72
  import {
73
73
  AgentToggleButton,
74
74
  agentNativePath,
75
- LanguagePicker,
76
75
  NotificationsBell,
77
76
  } from "@agent-native/core/client";
78
77
  import { useIsMobile } from "@/hooks/use-mobile";
@@ -1416,7 +1415,6 @@ export default function CalendarView() {
1416
1415
  emptyDescription="Calendar can pop browser alerts while this app is open. Clips desktop handles fuller meeting prompts with one-click notes."
1417
1416
  />
1418
1417
  )}
1419
- <LanguagePicker variant="icon" />
1420
1418
  <CreateEventPopover
1421
1419
  open={createDialogOpen}
1422
1420
  onOpenChange={(open) => {
@@ -1,11 +1,7 @@
1
1
  import { useLocation } from "react-router";
2
2
  import { IconMenu2 } from "@tabler/icons-react";
3
3
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
4
- import {
5
- AgentToggleButton,
6
- LanguagePicker,
7
- useT,
8
- } from "@agent-native/core/client";
4
+ import { AgentToggleButton, useT } from "@agent-native/core/client";
9
5
  import { APP_TITLE } from "@/lib/app-config";
10
6
 
11
7
  const pageTitleKeys: Record<string, string> = {
@@ -52,7 +48,6 @@ export function Header({ onOpenMobileSidebar }: HeaderProps) {
52
48
  </div>
53
49
  <div className="flex items-center gap-2 shrink-0">
54
50
  {actions}
55
- <LanguagePicker variant="icon" />
56
51
  <AgentToggleButton />
57
52
  </div>
58
53
  </header>
@@ -1,10 +1,6 @@
1
1
  import { useLocation } from "react-router";
2
2
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
3
- import {
4
- AgentToggleButton,
5
- LanguagePicker,
6
- useT,
7
- } from "@agent-native/core/client";
3
+ import { AgentToggleButton, useT } from "@agent-native/core/client";
8
4
 
9
5
  const pageTitleKeys: Record<string, string> = {
10
6
  "/": "navigation.library",
@@ -44,7 +40,6 @@ export function Header() {
44
40
  </div>
45
41
  <div className="flex items-center gap-2 shrink-0">
46
42
  {actions}
47
- <LanguagePicker variant="icon" />
48
43
  <AgentToggleButton />
49
44
  </div>
50
45
  </header>
@@ -101,6 +101,8 @@ export function useRecordingsCount(
101
101
  { ...args, countOnly: true } as any,
102
102
  {
103
103
  select: (data: any) => (typeof data?.total === "number" ? data.total : 0),
104
+ retry: false,
105
+ throwOnError: false,
104
106
  },
105
107
  );
106
108
  }
@@ -630,7 +630,7 @@ export default function SettingsIndexRoute() {
630
630
  </h1>
631
631
  </PageHeader>
632
632
  <div className="mx-auto w-full max-w-6xl p-6">
633
- <div className="grid gap-6 2xl:grid-cols-[minmax(0,1fr)_360px]">
633
+ <div className="space-y-6">
634
634
  <div className="min-w-0 space-y-6">
635
635
  <p className="text-sm text-muted-foreground">
636
636
  {t("settings.intro")}
@@ -1248,6 +1248,8 @@ export default function SettingsIndexRoute() {
1248
1248
  </Button>
1249
1249
  </div>
1250
1250
  </div>
1251
+ </div>
1252
+ <div className="mt-6">
1251
1253
  <CompactChangelogAside />
1252
1254
  </div>
1253
1255
  </div>
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-24
4
+ ---
5
+
6
+ Archive and spaces navigation is more resilient when sidebar count loading fails.
@@ -3,7 +3,6 @@ import type { ReactNode } from "react";
3
3
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
4
4
  import {
5
5
  AgentToggleButton,
6
- LanguagePicker,
7
6
  NotificationsBell,
8
7
  } from "@agent-native/core/client";
9
8
 
@@ -42,7 +41,6 @@ export function Header({ sidebarTrigger }: HeaderProps) {
42
41
  </div>
43
42
  <div className="flex items-center gap-2 shrink-0">
44
43
  {actions}
45
- <LanguagePicker variant="icon" />
46
44
  <NotificationsBell />
47
45
  <AgentToggleButton />
48
46
  </div>
@@ -1,9 +1,5 @@
1
1
  import { useLocation } from "react-router";
2
- import {
3
- LanguagePicker,
4
- useActionQuery,
5
- useT,
6
- } from "@agent-native/core/client";
2
+ import { useActionQuery, useT } from "@agent-native/core/client";
7
3
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
8
4
  import { AgentToggleButton } from "@agent-native/core/client";
9
5
  import { RunsTray } from "@agent-native/core/client/progress";
@@ -54,7 +50,6 @@ export function Header() {
54
50
  </div>
55
51
  <div className="flex items-center gap-2 shrink-0">
56
52
  {actions}
57
- <LanguagePicker variant="icon" />
58
53
  <RunsTray pollMs={1500} />
59
54
  <AgentToggleButton />
60
55
  </div>
@@ -1,10 +1,6 @@
1
1
  import { useLocation } from "react-router";
2
2
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
3
- import {
4
- AgentToggleButton,
5
- LanguagePicker,
6
- useT,
7
- } from "@agent-native/core/client";
3
+ import { AgentToggleButton, useT } from "@agent-native/core/client";
8
4
 
9
5
  const pageTitles: Record<string, string> = {
10
6
  "/": "header.forms",
@@ -42,7 +38,6 @@ export function Header() {
42
38
  </div>
43
39
  <div className="flex items-center gap-2 shrink-0">
44
40
  {actions}
45
- <LanguagePicker variant="icon" />
46
41
  <AgentToggleButton />
47
42
  </div>
48
43
  </header>
@@ -1,10 +1,6 @@
1
1
  import { useLocation } from "react-router";
2
2
  import { IconMenu2 } from "@tabler/icons-react";
3
- import {
4
- AgentToggleButton,
5
- LanguagePicker,
6
- useT,
7
- } from "@agent-native/core/client";
3
+ import { AgentToggleButton, useT } from "@agent-native/core/client";
8
4
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
9
5
 
10
6
  const pageTitles: Record<string, string> = {
@@ -49,7 +45,6 @@ export function Header({ onOpenSidebar }: HeaderProps) {
49
45
  </div>
50
46
  <div className="flex shrink-0 items-center gap-2">
51
47
  {actions}
52
- <LanguagePicker variant="icon" />
53
48
  <AgentToggleButton />
54
49
  </div>
55
50
  </header>
@@ -7,6 +7,7 @@ import {
7
7
  SelectTrigger,
8
8
  SelectValue,
9
9
  } from "@/components/ui/select";
10
+ import { useT } from "@agent-native/core/client";
10
11
 
11
12
  const LANGUAGES = [
12
13
  { value: "", label: "Plain text" },
@@ -34,6 +35,7 @@ interface CodeBlockLangPickerProps {
34
35
  }
35
36
 
36
37
  export function CodeBlockLangPicker({ editor }: CodeBlockLangPickerProps) {
38
+ const t = useT();
37
39
  const [position, setPosition] = useState<{
38
40
  top: number;
39
41
  right: number;
@@ -122,12 +124,12 @@ export function CodeBlockLangPicker({ editor }: CodeBlockLangPickerProps) {
122
124
  className="code-lang-select h-7 w-auto min-w-[100px] text-xs"
123
125
  onMouseDown={(e) => e.stopPropagation()}
124
126
  >
125
- <SelectValue placeholder="Plain text" />
127
+ <SelectValue placeholder={t("mail.compose.plainText")} />
126
128
  </SelectTrigger>
127
129
  <SelectContent>
128
130
  {LANGUAGES.map((l) => (
129
131
  <SelectItem key={l.value || "__plain"} value={l.value || "__plain"}>
130
- {l.label}
132
+ {l.value ? l.label : t("mail.compose.plainText")}
131
133
  </SelectItem>
132
134
  ))}
133
135
  </SelectContent>
@@ -9,6 +9,7 @@ import {
9
9
  IconLoader2,
10
10
  } from "@tabler/icons-react";
11
11
  import { cn, formatShortcut } from "@/lib/utils";
12
+ import { useT } from "@agent-native/core/client";
12
13
  import { useState, useEffect, useRef, useCallback } from "react";
13
14
  import {
14
15
  Tooltip,
@@ -51,6 +52,7 @@ export function ComposeBubbleToolbar({
51
52
  getCurrentDraftBody,
52
53
  sendToAgent,
53
54
  }: ComposeBubbleToolbarProps) {
55
+ const t = useT();
54
56
  const [visible, setVisible] = useState(false);
55
57
  const [position, setPosition] = useState({ top: 0, left: 0 });
56
58
  const [activeMarks, setActiveMarks] = useState({
@@ -244,32 +246,32 @@ export function ComposeBubbleToolbar({
244
246
  const items = [
245
247
  {
246
248
  icon: IconBold,
247
- title: "Bold",
249
+ title: t("mail.compose.bold"),
248
250
  action: () => (editor.chain().focus() as any).toggleBold().run(),
249
251
  active: activeMarks.bold,
250
252
  },
251
253
  {
252
254
  icon: IconItalic,
253
- title: "Italic",
255
+ title: t("mail.compose.italic"),
254
256
  action: () => (editor.chain().focus() as any).toggleItalic().run(),
255
257
  active: activeMarks.italic,
256
258
  },
257
259
  {
258
260
  icon: IconStrikethrough,
259
- title: "Strikethrough",
261
+ title: t("mail.compose.strikethrough"),
260
262
  action: () => (editor.chain().focus() as any).toggleStrike().run(),
261
263
  active: activeMarks.strike,
262
264
  },
263
265
  {
264
266
  icon: IconCode,
265
- title: "Code",
267
+ title: t("mail.compose.code"),
266
268
  action: () => (editor.chain().focus() as any).toggleCode().run(),
267
269
  active: activeMarks.code,
268
270
  },
269
271
  { type: "divider" as const },
270
272
  {
271
273
  icon: IconLink,
272
- title: "Link",
274
+ title: t("mail.compose.link"),
273
275
  action: toggleLink,
274
276
  active: activeMarks.link,
275
277
  },
@@ -292,7 +294,7 @@ export function ComposeBubbleToolbar({
292
294
  <input
293
295
  autoFocus
294
296
  type="url"
295
- placeholder="Paste link..."
297
+ placeholder={t("mail.compose.pasteLink")}
296
298
  value={linkUrl}
297
299
  onChange={(e) => setLinkUrl(e.target.value)}
298
300
  onKeyDown={(e) => {
@@ -308,7 +310,7 @@ export function ComposeBubbleToolbar({
308
310
  onClick={handleSetLink}
309
311
  className="text-xs text-blue-400 hover:text-blue-300 px-1.5 py-0.5 font-medium"
310
312
  >
311
- Apply
313
+ {t("mail.compose.apply")}
312
314
  </button>
313
315
  </div>
314
316
  ) : showAiInput || isGenerating ? (
@@ -316,13 +318,15 @@ export function ComposeBubbleToolbar({
316
318
  {isGenerating ? (
317
319
  <>
318
320
  <IconLoader2 size={14} className="animate-spin text-gray-400" />
319
- <span className="text-xs text-gray-400 px-1">Generating…</span>
321
+ <span className="text-xs text-gray-400 px-1">
322
+ {t("mail.compose.generating")}
323
+ </span>
320
324
  </>
321
325
  ) : (
322
326
  <>
323
327
  <textarea
324
328
  autoFocus
325
- placeholder="e.g. make more formal..."
329
+ placeholder={t("mail.compose.aiAssistPlaceholder")}
326
330
  value={aiPrompt}
327
331
  rows={2}
328
332
  onChange={(e) => setAiPrompt(e.target.value)}
@@ -346,11 +350,13 @@ export function ComposeBubbleToolbar({
346
350
  onClick={() => void handleAiAssist()}
347
351
  className="text-xs text-blue-400 hover:text-blue-300 px-1.5 py-0.5 font-medium shrink-0 self-end pb-1"
348
352
  >
349
- Generate
353
+ {t("mail.compose.generate")}
350
354
  </button>
351
355
  </TooltipTrigger>
352
356
  <TooltipContent>
353
- Generate ({formatShortcut("cmd+enter")})
357
+ {t("mail.compose.generateShortcut", {
358
+ shortcut: formatShortcut("cmd+enter"),
359
+ })}
354
360
  </TooltipContent>
355
361
  </Tooltip>
356
362
  </>
@@ -409,7 +415,7 @@ export function ComposeBubbleToolbar({
409
415
  <IconPencil size={14} strokeWidth={2.5} />
410
416
  </button>
411
417
  </TooltipTrigger>
412
- <TooltipContent>AI Assist</TooltipContent>
418
+ <TooltipContent>{t("mail.compose.aiAssist")}</TooltipContent>
413
419
  </Tooltip>
414
420
  </div>
415
421
  )}
@@ -30,6 +30,7 @@ import {
30
30
  } from "@/components/ui/dialog";
31
31
  import { Button } from "@/components/ui/button";
32
32
  import { Input } from "@/components/ui/input";
33
+ import { useT } from "@agent-native/core/client";
33
34
 
34
35
  const lowlight = createLowlight(common);
35
36
 
@@ -76,6 +77,7 @@ export const ComposeEditor = forwardRef<
76
77
  },
77
78
  ref,
78
79
  ) {
80
+ const t = useT();
79
81
  const isSettingContent = useRef(false);
80
82
  // Last time the user actually typed (not merely had focus). Used to let an
81
83
  // external/agent edit reconcile in even while the editor is focused but idle,
@@ -105,7 +107,7 @@ export const ComposeEditor = forwardRef<
105
107
  allowBase64: true,
106
108
  }),
107
109
  Placeholder.configure({
108
- placeholder: "Write your message...",
110
+ placeholder: t("mail.compose.writeMessagePlaceholder"),
109
111
  showOnlyWhenEditable: true,
110
112
  showOnlyCurrent: true,
111
113
  }),
@@ -267,8 +269,10 @@ export const ComposeEditor = forwardRef<
267
269
  <Dialog open={showLinkDialog} onOpenChange={setShowLinkDialog}>
268
270
  <DialogContent>
269
271
  <DialogHeader>
270
- <DialogTitle>Insert link</DialogTitle>
271
- <DialogDescription>Enter the URL for the link.</DialogDescription>
272
+ <DialogTitle>{t("mail.compose.insertLink")}</DialogTitle>
273
+ <DialogDescription>
274
+ {t("mail.compose.enterLinkUrl")}
275
+ </DialogDescription>
272
276
  </DialogHeader>
273
277
  <Input
274
278
  autoFocus
@@ -284,10 +288,10 @@ export const ComposeEditor = forwardRef<
284
288
  />
285
289
  <DialogFooter>
286
290
  <Button variant="outline" onClick={() => setShowLinkDialog(false)}>
287
- Cancel
291
+ {t("mail.compose.cancel")}
288
292
  </Button>
289
293
  <Button onClick={applyLink} disabled={!linkUrl.trim()}>
290
- Apply
294
+ {t("mail.compose.apply")}
291
295
  </Button>
292
296
  </DialogFooter>
293
297
  </DialogContent>
@@ -42,7 +42,7 @@ import { useUpdateQueuedDraft } from "@/hooks/use-draft-queue";
42
42
  import { useScheduleEmail } from "@/hooks/use-scheduled-jobs";
43
43
  import { SendLaterButton } from "./SendLaterButton";
44
44
  import { expandAliasTokens } from "@/lib/alias-utils";
45
- import { useAgentChatGenerating } from "@agent-native/core/client";
45
+ import { useAgentChatGenerating, useT } from "@agent-native/core/client";
46
46
  import { toast } from "sonner";
47
47
  import type { ComposeState } from "@shared/types";
48
48
  import {
@@ -152,6 +152,7 @@ export function ComposeModal({
152
152
  onReopen,
153
153
  onInitialExpandedConsumed,
154
154
  }: ComposeModalProps) {
155
+ const t = useT();
155
156
  const isMobile = useIsMobile();
156
157
  const [minimized, setMinimized] = useState(false);
157
158
  const [isExpanded, setIsExpanded] = useState(false);
@@ -570,7 +571,7 @@ export function ComposeModal({
570
571
  <IconPlus className="h-3 w-3" />
571
572
  </button>
572
573
  </TooltipTrigger>
573
- <TooltipContent>New draft</TooltipContent>
574
+ <TooltipContent>{t("mail.compose.newDraft")}</TooltipContent>
574
575
  </Tooltip>
575
576
  </div>
576
577
 
@@ -582,7 +583,11 @@ export function ComposeModal({
582
583
  variant="ghost"
583
584
  size="icon"
584
585
  className="h-7 w-7"
585
- aria-label={minimized ? "Restore compose" : "Minimize compose"}
586
+ aria-label={
587
+ minimized
588
+ ? t("mail.compose.restoreCompose")
589
+ : t("mail.compose.minimizeCompose")
590
+ }
586
591
  onClick={() => {
587
592
  setIsExpanded(false);
588
593
  setMinimized(!minimized);
@@ -592,7 +597,9 @@ export function ComposeModal({
592
597
  </Button>
593
598
  </TooltipTrigger>
594
599
  <TooltipContent>
595
- {minimized ? "Restore" : "Minimize"}
600
+ {minimized
601
+ ? t("mail.compose.restore")
602
+ : t("mail.compose.minimize")}
596
603
  </TooltipContent>
597
604
  </Tooltip>
598
605
  {!minimized && (
@@ -603,7 +610,9 @@ export function ComposeModal({
603
610
  size="icon"
604
611
  className="h-7 w-7"
605
612
  aria-label={
606
- isExpanded ? "Restore compose size" : "Full screen compose"
613
+ isExpanded
614
+ ? t("mail.compose.restoreComposeSize")
615
+ : t("mail.compose.fullScreenCompose")
607
616
  }
608
617
  aria-pressed={isExpanded}
609
618
  onClick={() => {
@@ -619,7 +628,9 @@ export function ComposeModal({
619
628
  </Button>
620
629
  </TooltipTrigger>
621
630
  <TooltipContent>
622
- {isExpanded ? "Restore size" : "Full screen"}
631
+ {isExpanded
632
+ ? t("mail.compose.restoreSize")
633
+ : t("mail.compose.fullScreen")}
623
634
  </TooltipContent>
624
635
  </Tooltip>
625
636
  )}
@@ -714,7 +725,7 @@ export function ComposeModal({
714
725
  onChange={(e) =>
715
726
  onUpdate(activeId!, { subject: e.target.value })
716
727
  }
717
- placeholder="Subject"
728
+ placeholder={t("mail.compose.subject")}
718
729
  className="flex-1 bg-transparent py-2 text-sm outline-none placeholder:text-muted-foreground"
719
730
  />
720
731
  </div>
@@ -759,7 +770,7 @@ export function ComposeModal({
759
770
  <IconBold className="h-3.5 w-3.5" />
760
771
  </Button>
761
772
  </TooltipTrigger>
762
- <TooltipContent>Bold</TooltipContent>
773
+ <TooltipContent>{t("mail.compose.bold")}</TooltipContent>
763
774
  </Tooltip>
764
775
  <Tooltip>
765
776
  <TooltipTrigger asChild>
@@ -772,7 +783,7 @@ export function ComposeModal({
772
783
  <IconItalic className="h-3.5 w-3.5" />
773
784
  </Button>
774
785
  </TooltipTrigger>
775
- <TooltipContent>Italic</TooltipContent>
786
+ <TooltipContent>{t("mail.compose.italic")}</TooltipContent>
776
787
  </Tooltip>
777
788
  <Tooltip>
778
789
  <TooltipTrigger asChild>
@@ -785,7 +796,7 @@ export function ComposeModal({
785
796
  <IconLink className="h-3.5 w-3.5" />
786
797
  </Button>
787
798
  </TooltipTrigger>
788
- <TooltipContent>Insert link</TooltipContent>
799
+ <TooltipContent>{t("mail.compose.insertLink")}</TooltipContent>
789
800
  </Tooltip>
790
801
  <Tooltip>
791
802
  <TooltipTrigger asChild>
@@ -798,7 +809,7 @@ export function ComposeModal({
798
809
  <IconPaperclip className="h-3.5 w-3.5" />
799
810
  </Button>
800
811
  </TooltipTrigger>
801
- <TooltipContent>Attach file</TooltipContent>
812
+ <TooltipContent>{t("mail.compose.attachFile")}</TooltipContent>
802
813
  </Tooltip>
803
814
 
804
815
  <div className="mx-1 h-4 w-px bg-border" />
@@ -806,7 +817,7 @@ export function ComposeModal({
806
817
  {isGenerating ? (
807
818
  <div className="flex items-center gap-1.5 px-2 text-xs text-muted-foreground">
808
819
  <IconLoader2 className="h-3.5 w-3.5 animate-spin" />
809
- <span>Generating…</span>
820
+ <span>{t("mail.compose.generating")}</span>
810
821
  </div>
811
822
  ) : (
812
823
  <Popover open={generateOpen} onOpenChange={setGenerateOpen}>
@@ -816,13 +827,13 @@ export function ComposeModal({
816
827
  size="sm"
817
828
  className="h-7 gap-1.5 px-2 text-xs"
818
829
  >
819
- Generate
830
+ {t("mail.compose.generate")}
820
831
  </Button>
821
832
  </PopoverTrigger>
822
833
  <PopoverContent side="top" align="start" className="w-80 p-3">
823
834
  <div className="flex flex-col gap-2">
824
835
  <label className="text-xs font-medium text-muted-foreground">
825
- What should the agent write?
836
+ {t("mail.compose.agentPromptLabel")}
826
837
  </label>
827
838
  <textarea
828
839
  ref={promptRef}
@@ -838,13 +849,14 @@ export function ComposeModal({
838
849
  setGenerateOpen(false);
839
850
  }
840
851
  }}
841
- placeholder="e.g. Write a polite follow-up..."
852
+ placeholder={t("mail.compose.agentPromptPlaceholder")}
842
853
  className="min-h-[60px] w-full resize-none rounded-md border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground focus:ring-1 focus:ring-ring"
843
854
  autoFocus
844
855
  />
845
856
  <div className="flex items-center justify-between">
846
857
  <span className="text-[10px] text-muted-foreground">
847
- <kbd className="kbd-hint">↵</kbd> to submit
858
+ <kbd className="kbd-hint">↵</kbd>{" "}
859
+ {t("mail.compose.toSubmit")}
848
860
  </span>
849
861
  <Button
850
862
  size="sm"
@@ -852,7 +864,7 @@ export function ComposeModal({
852
864
  disabled={!generatePrompt.trim()}
853
865
  className="h-7 gap-1.5 px-3 text-xs"
854
866
  >
855
- Generate
867
+ {t("mail.compose.generate")}
856
868
  </Button>
857
869
  </div>
858
870
  </div>
@@ -871,7 +883,7 @@ export function ComposeModal({
871
883
  <IconTrash className="h-4 w-4" />
872
884
  </button>
873
885
  </TooltipTrigger>
874
- <TooltipContent>Delete draft</TooltipContent>
886
+ <TooltipContent>{t("mail.compose.deleteDraft")}</TooltipContent>
875
887
  </Tooltip>
876
888
  <SendLaterButton
877
889
  onSend={handleSend}
@@ -924,6 +936,7 @@ function ComposeBody({
924
936
  setShowQuoted: (show: boolean) => void;
925
937
  signature?: string;
926
938
  }) {
939
+ const t = useT();
927
940
  const [editableContent, quotedContent] = useMemo(
928
941
  () => splitQuotedContent(activeDraft.body),
929
942
  [activeDraft.body],
@@ -994,7 +1007,11 @@ function ComposeBody({
994
1007
  <>
995
1008
  <button
996
1009
  type="button"
997
- aria-label={showQuoted ? "Hide quoted text" : "Show quoted text"}
1010
+ aria-label={
1011
+ showQuoted
1012
+ ? t("mail.thread.hideQuotedText")
1013
+ : t("mail.thread.showQuotedText")
1014
+ }
998
1015
  onClick={() => setShowQuoted(!showQuoted)}
999
1016
  className="mt-1 inline-flex h-6 w-6 items-center justify-center rounded text-muted-foreground/50 transition-colors hover:bg-accent hover:text-muted-foreground"
1000
1017
  >