hanbiro-react16-sdk 1.0.28 → 1.0.29

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 (43) hide show
  1. package/README.md +58 -5
  2. package/dist/components/ChatAIDraft/ChatInput.js +3 -1
  3. package/dist/components/ChatAIDraft/ChatList/MessageItem.js +3 -1
  4. package/dist/components/ChatAIDraft/CreatePanel/EmptyState.js +15 -15
  5. package/dist/components/ChatAIDraft/CreatePanel/index.js +3 -3
  6. package/dist/components/ChatAIDraft/ReplyPanel/ContextPreviewModal.js +3 -1
  7. package/dist/components/ChatAIDraft/ReplyPanel/EmptyState.js +10 -10
  8. package/dist/components/ChatAIDraft/ReplyPanel/Header/index.js +8 -4
  9. package/dist/components/ChatAIDraft/ReplyPanel/MailListSelect.js +12 -9
  10. package/dist/components/ChatAIDraft/ReplyPanel/index.js +7 -5
  11. package/dist/components/ChatAIDraft/SettingPopper/index.js +8 -6
  12. package/dist/components/ChatAIDraft/constants.d.ts +2 -2
  13. package/dist/components/ChatAIDraft/constants.js +16 -14
  14. package/dist/components/ChatAIDraft/index.d.ts +1 -0
  15. package/dist/components/ChatAIDraft/index.js +7 -1
  16. package/dist/components/Pagination/index.js +4 -2
  17. package/dist/components/SummaryAIEmails/FilterTabs.js +4 -2
  18. package/dist/components/SummaryAIEmails/SummaryItem.js +3 -1
  19. package/dist/components/SummaryAIEmails/index.d.ts +1 -0
  20. package/dist/components/SummaryAIEmails/index.js +11 -2
  21. package/dist/components/SummaryAIEmails/utils.d.ts +2 -1
  22. package/dist/components/SummaryAIEmails/utils.js +5 -4
  23. package/dist/hanbiro-react16-sdk.style.css +1 -1
  24. package/dist/hanbiro-react16-sdk.umd.js +241 -98
  25. package/dist/index.js +4 -3
  26. package/dist/lang/en.d.ts +3 -0
  27. package/dist/lang/en.js +66 -0
  28. package/dist/lang/index.d.ts +4 -0
  29. package/dist/lang/index.js +18 -0
  30. package/dist/lang/keyLang.d.ts +62 -0
  31. package/dist/lang/keyLang.js +66 -0
  32. package/dist/lang/ko.d.ts +3 -0
  33. package/dist/lang/ko.js +66 -0
  34. package/dist/lang/vi.d.ts +3 -0
  35. package/dist/lang/vi.js +66 -0
  36. package/dist/utils/index.d.ts +1 -1
  37. package/dist/utils/lang.d.ts +1 -0
  38. package/dist/utils/lang.js +30 -0
  39. package/dist/utils/storage.d.ts +8 -0
  40. package/dist/utils/storage.js +19 -0
  41. package/dist/utils/url.d.ts +2 -0
  42. package/dist/utils/url.js +8 -2
  43. package/package.json +1 -1
package/README.md CHANGED
@@ -40,11 +40,12 @@ import "hanbiro-react16-sdk/style.css";
40
40
 
41
41
  ## Exported Utils
42
42
 
43
- | Function | Description | Import path |
44
- | --------------------- | -------------------------------- | --------------------------- |
45
- | `initHanbiroReactSDK` | Initialize SDK (baseUrl, signer) | `hanbiro-react16-sdk/utils` |
46
- | `getBaseUrl` | Get the configured base URL | `hanbiro-react16-sdk/utils` |
47
- | `getGroupwareUrl` | Get the groupware URL | `hanbiro-react16-sdk/utils` |
43
+ | Function | Description | Import path |
44
+ | --------------------- | ------------------------------------------- | --------------------------- |
45
+ | `initHanbiroReactSDK` | Initialize SDK (baseUrl, signer) | `hanbiro-react16-sdk/utils` |
46
+ | `setLibLang` | Set the active language for SDK components | `hanbiro-react16-sdk/utils` |
47
+ | `getBaseUrl` | Get the configured base URL | `hanbiro-react16-sdk/utils` |
48
+ | `getGroupwareUrl` | Get the groupware URL | `hanbiro-react16-sdk/utils` |
48
49
 
49
50
  ---
50
51
 
@@ -63,6 +64,58 @@ initHanbiroReactSDK({
63
64
 
64
65
  ---
65
66
 
67
+ ## Language Configuration (`setLibLang`)
68
+
69
+ SDK components read their translations from a shared global config (`SDKConfig.lang`). Because some translation lookups happen at **module-load time** inside the bundled `.ts` files, the language **must be set before the SDK components are rendered** — passing it later (e.g. via a prop and `useEffect`) is too late for those module-level lookups.
70
+
71
+ Use `setLibLang` to configure the active language imperatively.
72
+
73
+ **Supported language codes:** `en`, `ko`, `vi` (defaults to `en`).
74
+
75
+ ### ES Module (npm)
76
+
77
+ ```ts
78
+ import { initHanbiroReactSDK, setLibLang } from "hanbiro-react16-sdk/utils";
79
+
80
+ // Call ONCE at app startup, before rendering any SDK component
81
+ initHanbiroReactSDK({
82
+ baseUrl: "https://vndev.hanbiro.com",
83
+ signer: null,
84
+ });
85
+ setLibLang("ko");
86
+ ```
87
+
88
+ ### Changing language at runtime
89
+
90
+ `setLibLang` only updates the global config — components already mounted will not re-translate module-level strings automatically. To apply a new language at runtime, set it **then** remount the SDK subtree (or reload the page):
91
+
92
+ ```tsx
93
+ import { setLibLang } from "hanbiro-react16-sdk/utils";
94
+
95
+ function App() {
96
+ const [lang, setLangState] = useState("ko");
97
+
98
+ const handleLangChange = (next: string) => {
99
+ setLibLang(next); // update SDK config first
100
+ setLangState(next); // then trigger remount via `key`
101
+ };
102
+
103
+ return <ChatAIDraft key={lang} onApply={...} />;
104
+ }
105
+ ```
106
+
107
+ ### UMD (script tag)
108
+
109
+ ```js
110
+ HanbiroReact16SDK.initHanbiroReactSDK({
111
+ baseUrl: "https://vndev.hanbiro.com",
112
+ signer: null,
113
+ });
114
+ HanbiroReact16SDK.setLibLang("ko");
115
+ ```
116
+
117
+ ---
118
+
66
119
  ## Usage: ES Module (npm)
67
120
 
68
121
  ```tsx
@@ -5,6 +5,8 @@ import * as React from "react";
5
5
  import { AI_LANG_FLAGS } from "../../constants/index.js";
6
6
  import CountryFlag from "../CountryFlag/index.js";
7
7
  import SettingPopper from "./SettingPopper/index.js";
8
+ import { t } from "../../lang/index.js";
9
+ import { LangKey } from "../../lang/keyLang.js";
8
10
  import ArrowUp from "../../node_modules/react-feather/dist/icons/arrow-up.js";
9
11
  class ChatInput extends React.Component {
10
12
  constructor(props) {
@@ -73,7 +75,7 @@ class ChatInput extends React.Component {
73
75
  ref: this.textareaRef,
74
76
  value: message,
75
77
  onChange: this.handleChange,
76
- placeholder: placeholder || "Describe your email...",
78
+ placeholder: placeholder || t(LangKey.CHAT_INPUT_PLACEHOLDER),
77
79
  name: "ai-content",
78
80
  onKeyDown: this.handleKeyDown,
79
81
  disabled: isSending,
@@ -24,6 +24,8 @@ import TypingText from "../TypingText.js";
24
24
  import AIAvatar from "./AIAvatar.js";
25
25
  import LoadingDots from "./LoadingDots.js";
26
26
  import { buildApplyHtml } from "./helpers.js";
27
+ import { t } from "../../../lang/index.js";
28
+ import { LangKey } from "../../../lang/keyLang.js";
27
29
  import Copy from "../../../node_modules/react-feather/dist/icons/copy.js";
28
30
  const MessageItem = ({
29
31
  item,
@@ -105,7 +107,7 @@ const MessageItem = ({
105
107
  padding: "8px 12px"
106
108
  }
107
109
  }
108
- ), /* @__PURE__ */ React.createElement("div", { style: { marginTop: 4 } }, /* @__PURE__ */ React.createElement(Tooltip, { title: "Apply content" }, /* @__PURE__ */ React.createElement(
110
+ ), /* @__PURE__ */ React.createElement("div", { style: { marginTop: 4 } }, /* @__PURE__ */ React.createElement(Tooltip, { title: t(LangKey.APPLY_CONTENT) }, /* @__PURE__ */ React.createElement(
109
111
  "button",
110
112
  {
111
113
  type: "button",
@@ -1,29 +1,31 @@
1
1
  import * as React from "react";
2
2
  import CustomAiIcon from "../CustomAIIcon.js";
3
+ import { t } from "../../../lang/index.js";
4
+ import { LangKey } from "../../../lang/keyLang.js";
3
5
  import MessageSquare from "../../../node_modules/react-feather/dist/icons/message-square.js";
4
6
  import MessageCircle from "../../../node_modules/react-feather/dist/icons/message-circle.js";
5
7
  import Check from "../../../node_modules/react-feather/dist/icons/check.js";
6
8
  const FEATURES = [
7
9
  {
8
10
  icon: /* @__PURE__ */ React.createElement(MessageCircle, { size: 16 }),
9
- title: "Request via message",
10
- desc: 'e.g., "Draft an email to Director Hong proposing a Q3 collaboration meeting (May 20, 3 PM)"'
11
+ title: t(LangKey.CREATE_FEATURE_1_TITLE),
12
+ desc: t(LangKey.CREATE_FEATURE_1_DESC)
11
13
  },
12
14
  {
13
15
  icon: /* @__PURE__ */ React.createElement(CustomAiIcon, { size: 16, stroke: 2 }),
14
- title: "AI generates a draft",
15
- desc: "Refine the draft freely with follow-ups like 'more polite' or 'add a deadline'."
16
+ title: t(LangKey.CREATE_FEATURE_2_TITLE),
17
+ desc: t(LangKey.CREATE_FEATURE_2_DESC)
16
18
  },
17
19
  {
18
20
  icon: /* @__PURE__ */ React.createElement(Check, { size: 16 }),
19
- title: "Apply to body",
20
- desc: "Insert the response you like into the email body and send."
21
+ title: t(LangKey.CREATE_FEATURE_3_TITLE),
22
+ desc: t(LangKey.CREATE_FEATURE_3_DESC)
21
23
  }
22
24
  ];
23
25
  const SUGGESTIONS = [
24
- "Propose a Q3 meeting to Director Hong (May 20, 3 PM)",
25
- "Notify client of payment schedule (Due May 30)",
26
- "Welcome message to new employee (Joining May 22)"
26
+ t(LangKey.CREATE_SUGGESTION_1),
27
+ t(LangKey.CREATE_SUGGESTION_2),
28
+ t(LangKey.CREATE_SUGGESTION_3)
27
29
  ];
28
30
  const EmptyState = ({
29
31
  onSelectPrompt
@@ -52,7 +54,7 @@ const EmptyState = ({
52
54
  lineHeight: 1.5
53
55
  }
54
56
  },
55
- "Let's draft a new email together from scratch."
57
+ t(LangKey.CREATE_EMPTY_TITLE)
56
58
  ), /* @__PURE__ */ React.createElement(
57
59
  "div",
58
60
  {
@@ -62,7 +64,7 @@ const EmptyState = ({
62
64
  marginTop: 4
63
65
  }
64
66
  },
65
- "Tell me what kind of email you'd like to write."
67
+ t(LangKey.CREATE_EMPTY_SUBTITLE)
66
68
  )),
67
69
  /* @__PURE__ */ React.createElement(
68
70
  "div",
@@ -92,9 +94,7 @@ const EmptyState = ({
92
94
  lineHeight: 1.6
93
95
  }
94
96
  },
95
- "Give me the recipient, purpose, and key points",
96
- /* @__PURE__ */ React.createElement("br", null),
97
- "and AI will generate a polished draft."
97
+ t(LangKey.CREATE_EMPTY_GUIDE).split("\n").map((line, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, line, /* @__PURE__ */ React.createElement("br", null)))
98
98
  )),
99
99
  /* @__PURE__ */ React.createElement(
100
100
  "div",
@@ -178,7 +178,7 @@ const EmptyState = ({
178
178
  marginBottom: 8
179
179
  }
180
180
  },
181
- "💡 Try these prompts to get a draft right away"
181
+ t(LangKey.CREATE_PROMPT_HINT)
182
182
  ),
183
183
  /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } }, SUGGESTIONS.map((s, i) => /* @__PURE__ */ React.createElement(
184
184
  "button",
@@ -43,7 +43,7 @@ import { callAI } from "../helper.js";
43
43
  import ChatList from "../ChatList/index.js";
44
44
  import ChatInput from "../ChatInput.js";
45
45
  import EmptyState from "./EmptyState.js";
46
- import { LENGTH_OPTIONS, TONE_OPTIONS } from "../constants.js";
46
+ import { getLengthOptions, getToneOptions } from "../constants.js";
47
47
  import { AI_LANG_FLAGS } from "../../../constants/index.js";
48
48
  import v4 from "../../../node_modules/uuid/dist/esm-browser/v4.js";
49
49
  class CreatePanel extends React.Component {
@@ -114,8 +114,8 @@ class CreatePanel extends React.Component {
114
114
  messages: [],
115
115
  isSending: false,
116
116
  lang,
117
- tone: TONE_OPTIONS[2],
118
- length: LENGTH_OPTIONS[2],
117
+ tone: getToneOptions()[2],
118
+ length: getLengthOptions()[2],
119
119
  conversationId: ""
120
120
  };
121
121
  }
@@ -1,6 +1,8 @@
1
1
  import * as React from "react";
2
2
  import { marked } from "../../../node_modules/marked/lib/marked.esm.js";
3
3
  import BaseModal from "./BaseModal.js";
4
+ import { t } from "../../../lang/index.js";
5
+ import { LangKey } from "../../../lang/keyLang.js";
4
6
  const renderMarkdown = (md) => {
5
7
  try {
6
8
  return marked.parse(md, { async: false });
@@ -22,7 +24,7 @@ const MailHeader = ({
22
24
  textOverflow: "ellipsis"
23
25
  }
24
26
  },
25
- mail.subject || "(no subject)"
27
+ mail.subject || t(LangKey.NO_SUBJECT)
26
28
  ), /* @__PURE__ */ React.createElement(
27
29
  "div",
28
30
  {
@@ -1,22 +1,24 @@
1
1
  import * as React from "react";
2
2
  import CustomAiIcon from "../CustomAIIcon.js";
3
+ import { t } from "../../../lang/index.js";
4
+ import { LangKey } from "../../../lang/keyLang.js";
3
5
  import Mail from "../../../node_modules/react-feather/dist/icons/mail.js";
4
6
  import MessageCircle from "../../../node_modules/react-feather/dist/icons/message-circle.js";
5
7
  const FEATURES = [
6
8
  {
7
9
  icon: /* @__PURE__ */ React.createElement(Mail, { size: 16 }),
8
- title: "Auto-include source",
9
- desc: "The email you are replying to is automatically added as context."
10
+ title: t(LangKey.REPLY_FEATURE_1_TITLE),
11
+ desc: t(LangKey.REPLY_FEATURE_1_DESC)
10
12
  },
11
13
  {
12
14
  icon: /* @__PURE__ */ React.createElement(CustomAiIcon, { size: 16, stroke: 2 }),
13
- title: "Add send history (optional)",
14
- desc: "Use '+ Add' to pick past emails and reference their tone."
15
+ title: t(LangKey.REPLY_FEATURE_2_TITLE),
16
+ desc: t(LangKey.REPLY_FEATURE_2_DESC)
15
17
  },
16
18
  {
17
19
  icon: /* @__PURE__ */ React.createElement(MessageCircle, { size: 16 }),
18
- title: "Refine with conversation",
19
- desc: "Get an AI draft, then adjust freely with chips or messages."
20
+ title: t(LangKey.REPLY_FEATURE_3_TITLE),
21
+ desc: t(LangKey.REPLY_FEATURE_3_DESC)
20
22
  }
21
23
  ];
22
24
  const EmptyState = () => {
@@ -44,9 +46,7 @@ const EmptyState = () => {
44
46
  lineHeight: 1.6
45
47
  }
46
48
  },
47
- "We'll draft a reply based on the received email.",
48
- /* @__PURE__ */ React.createElement("br", null),
49
- "Add send history if you want to match the tone."
49
+ t(LangKey.REPLY_EMPTY_TITLE).split("\n").map((line, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, line, /* @__PURE__ */ React.createElement("br", null)))
50
50
  )),
51
51
  /* @__PURE__ */ React.createElement(
52
52
  "div",
@@ -76,7 +76,7 @@ const EmptyState = () => {
76
76
  lineHeight: 1.6
77
77
  }
78
78
  },
79
- "The source is auto-included. Adjust tone and length through conversation."
79
+ t(LangKey.REPLY_EMPTY_GUIDE)
80
80
  )),
81
81
  /* @__PURE__ */ React.createElement(
82
82
  "div",
@@ -1,6 +1,8 @@
1
1
  import * as React from "react";
2
2
  import SourceCard from "./SourceCard.js";
3
3
  import SelectedChip from "./SelectedChip.js";
4
+ import { t } from "../../../../lang/index.js";
5
+ import { LangKey } from "../../../../lang/keyLang.js";
4
6
  import Lock from "../../../../node_modules/react-feather/dist/icons/lock.js";
5
7
  import Plus from "../../../../node_modules/react-feather/dist/icons/plus.js";
6
8
  const ContextHeader = ({
@@ -34,7 +36,7 @@ const ContextHeader = ({
34
36
  fontWeight: 600
35
37
  }
36
38
  },
37
- /* @__PURE__ */ React.createElement("span", null, "Source context"),
39
+ /* @__PURE__ */ React.createElement("span", null, t(LangKey.SOURCE_CONTEXT)),
38
40
  /* @__PURE__ */ React.createElement(
39
41
  "span",
40
42
  {
@@ -62,7 +64,8 @@ const ContextHeader = ({
62
64
  }
63
65
  },
64
66
  /* @__PURE__ */ React.createElement(Lock, { size: 11 }),
65
- " Auto"
67
+ " ",
68
+ t(LangKey.AUTO)
66
69
  )
67
70
  ), /* @__PURE__ */ React.createElement(
68
71
  SourceCard,
@@ -92,7 +95,7 @@ const ContextHeader = ({
92
95
  fontWeight: 600
93
96
  }
94
97
  },
95
- /* @__PURE__ */ React.createElement("span", null, "Selected context"),
98
+ /* @__PURE__ */ React.createElement("span", null, t(LangKey.SELECTED_CONTEXT)),
96
99
  /* @__PURE__ */ React.createElement(
97
100
  "span",
98
101
  {
@@ -116,7 +119,8 @@ const ContextHeader = ({
116
119
  className: "text-button primary"
117
120
  },
118
121
  /* @__PURE__ */ React.createElement(Plus, { size: 12 }),
119
- " Add"
122
+ " ",
123
+ t(LangKey.ADD)
120
124
  )
121
125
  ), selectedMails.length > 0 && /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 } }, selectedMails.map((m, i) => /* @__PURE__ */ React.createElement(
122
126
  SelectedChip,
@@ -26,7 +26,9 @@ import LoadingContainer from "../../LoadingContainer/index.js";
26
26
  import LoadingCircular from "../../LoadingCircular/index.js";
27
27
  import Pagination from "../../Pagination/index.js";
28
28
  import { fetchMailList } from "./helper.js";
29
+ import { t } from "../../../lang/index.js";
29
30
  import ArrowLeft from "../../../node_modules/react-feather/dist/icons/arrow-left.js";
31
+ import { LangKey } from "../../../lang/keyLang.js";
30
32
  import Paperclip from "../../../node_modules/react-feather/dist/icons/paperclip.js";
31
33
  const PAGE_SIZE = 6;
32
34
  const MAX_SELECTED = 5;
@@ -120,7 +122,8 @@ class MailListSelect extends React.Component {
120
122
  style: { alignSelf: "flex-start" }
121
123
  },
122
124
  /* @__PURE__ */ React.createElement(ArrowLeft, { size: 14 }),
123
- " Back"
125
+ " ",
126
+ t(LangKey.BACK)
124
127
  ),
125
128
  /* @__PURE__ */ React.createElement("div", { style: { marginTop: 8 } }, /* @__PURE__ */ React.createElement(
126
129
  "div",
@@ -131,7 +134,7 @@ class MailListSelect extends React.Component {
131
134
  color: "var(--text-primary)"
132
135
  }
133
136
  },
134
- "Add context from receive history"
137
+ t(LangKey.ADD_CONTEXT_TITLE)
135
138
  ), /* @__PURE__ */ React.createElement(
136
139
  "div",
137
140
  {
@@ -141,7 +144,7 @@ class MailListSelect extends React.Component {
141
144
  marginTop: 2
142
145
  }
143
146
  },
144
- "Select related emails to provide AI context."
147
+ t(LangKey.ADD_CONTEXT_DESC)
145
148
  )),
146
149
  /* @__PURE__ */ React.createElement(
147
150
  "div",
@@ -190,7 +193,7 @@ class MailListSelect extends React.Component {
190
193
  "/",
191
194
  MAX_SELECTED
192
195
  ),
193
- /* @__PURE__ */ React.createElement("span", null, "selected · up to ", MAX_SELECTED),
196
+ /* @__PURE__ */ React.createElement("span", null, t(LangKey.SELECTED_UP_TO), " ", MAX_SELECTED),
194
197
  selectedMids.length > 0 && /* @__PURE__ */ React.createElement(
195
198
  "button",
196
199
  {
@@ -201,10 +204,10 @@ class MailListSelect extends React.Component {
201
204
  },
202
205
  className: "text-button primary"
203
206
  },
204
- "Clear all"
207
+ t(LangKey.CLEAR_ALL)
205
208
  )
206
209
  ),
207
- /* @__PURE__ */ React.createElement("span", { style: { fontSize: 11, color: "var(--text-secondary)" } }, "Sort: latest")
210
+ /* @__PURE__ */ React.createElement("span", { style: { fontSize: 11, color: "var(--text-secondary)" } }, t(LangKey.SORT_LATEST))
208
211
  ),
209
212
  /* @__PURE__ */ React.createElement(
210
213
  "div",
@@ -227,7 +230,7 @@ class MailListSelect extends React.Component {
227
230
  fontSize: 12
228
231
  }
229
232
  },
230
- "No emails found."
233
+ t(LangKey.NO_EMAILS_FOUND)
231
234
  ) : items.map((it) => {
232
235
  const isChecked = selectedMids.includes(it.mid);
233
236
  const disabled = !isChecked && selectedMids.length >= MAX_SELECTED;
@@ -356,7 +359,7 @@ class MailListSelect extends React.Component {
356
359
  fontFamily: "inherit"
357
360
  }
358
361
  },
359
- "Cancel"
362
+ t(LangKey.CANCEL)
360
363
  ),
361
364
  /* @__PURE__ */ React.createElement(
362
365
  "button",
@@ -382,7 +385,7 @@ class MailListSelect extends React.Component {
382
385
  }
383
386
  },
384
387
  isConfirming && /* @__PURE__ */ React.createElement(LoadingCircular, { size: 16, color: "var(--primary-contrasttext)" }),
385
- /* @__PURE__ */ React.createElement("span", null, "Add ", selectedMids.length > 0 ? `${selectedMids.length} ` : "", "as context →")
388
+ /* @__PURE__ */ React.createElement("span", null, t(LangKey.ADD), " ", selectedMids.length > 0 ? `${selectedMids.length} ` : "", t(LangKey.ADD_AS_CONTEXT))
386
389
  )
387
390
  )
388
391
  );
@@ -47,9 +47,11 @@ import ContextHeader from "./Header/index.js";
47
47
  import MailListSelect from "./MailListSelect.js";
48
48
  import ContextPreviewModal from "./ContextPreviewModal.js";
49
49
  import { fetchMailView, fetchMailAiContext } from "./helper.js";
50
- import { LENGTH_OPTIONS, TONE_OPTIONS } from "../constants.js";
50
+ import { getLengthOptions, getToneOptions } from "../constants.js";
51
51
  import { AI_LANG_FLAGS } from "../../../constants/index.js";
52
+ import { t } from "../../../lang/index.js";
52
53
  import v4 from "../../../node_modules/uuid/dist/esm-browser/v4.js";
54
+ import { LangKey } from "../../../lang/keyLang.js";
53
55
  class ReplyPanel extends React.Component {
54
56
  constructor(props) {
55
57
  var _a;
@@ -191,8 +193,8 @@ class ReplyPanel extends React.Component {
191
193
  messages: [],
192
194
  isSending: false,
193
195
  lang,
194
- tone: TONE_OPTIONS[2],
195
- length: LENGTH_OPTIONS[2],
196
+ tone: getToneOptions()[2],
197
+ length: getLengthOptions()[2],
196
198
  conversationId: ""
197
199
  };
198
200
  }
@@ -270,7 +272,7 @@ class ReplyPanel extends React.Component {
270
272
  textAlign: "center"
271
273
  }
272
274
  },
273
- "Loading context..."
275
+ t(LangKey.REPLY_LOADING_CONTEXT)
274
276
  ),
275
277
  /* @__PURE__ */ React.createElement(
276
278
  ChatInput,
@@ -286,7 +288,7 @@ class ReplyPanel extends React.Component {
286
288
  length,
287
289
  setLength: this.setLength,
288
290
  parentRef: this.rootRef,
289
- placeholder: "Type a message..."
291
+ placeholder: t(LangKey.CHAT_INPUT_PLACEHOLDER_REPLY)
290
292
  }
291
293
  ),
292
294
  /* @__PURE__ */ React.createElement(
@@ -24,11 +24,13 @@ var __async = (__this, __arguments, generator) => {
24
24
  import * as React from "react";
25
25
  import * as ReactDOM from "react-dom";
26
26
  import { apiGet } from "../../../utils/api.js";
27
- import { TONE_OPTIONS, LENGTH_OPTIONS } from "../constants.js";
27
+ import { getToneOptions, getLengthOptions } from "../constants.js";
28
28
  import LanguageSelect from "./LanguageSelect.js";
29
29
  import ChipGroup from "./ChipGroup.js";
30
30
  import { TONE_ICONS, LENGTH_ICONS } from "./icons.js";
31
+ import { t } from "../../../lang/index.js";
31
32
  import Settings from "../../../node_modules/react-feather/dist/icons/settings.js";
33
+ import { LangKey } from "../../../lang/keyLang.js";
32
34
  class SettingPopper extends React.Component {
33
35
  constructor(props) {
34
36
  super(props);
@@ -130,7 +132,7 @@ class SettingPopper extends React.Component {
130
132
  {
131
133
  style: { display: "flex", flexDirection: "column", gap: 6 }
132
134
  },
133
- /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, fontWeight: 600 } }, "Language"),
135
+ /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, fontWeight: 600 } }, t(LangKey.SETTING_LANGUAGE)),
134
136
  /* @__PURE__ */ React.createElement(
135
137
  LanguageSelect,
136
138
  {
@@ -145,11 +147,11 @@ class SettingPopper extends React.Component {
145
147
  {
146
148
  style: { display: "flex", flexDirection: "column", gap: 6 }
147
149
  },
148
- /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, fontWeight: 600 } }, "Tone"),
150
+ /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, fontWeight: 600 } }, t(LangKey.SETTING_TONE)),
149
151
  /* @__PURE__ */ React.createElement(
150
152
  ChipGroup,
151
153
  {
152
- options: TONE_OPTIONS,
154
+ options: getToneOptions(),
153
155
  selected: tone,
154
156
  onSelect: (opt) => setTone(opt),
155
157
  iconMap: TONE_ICONS
@@ -161,11 +163,11 @@ class SettingPopper extends React.Component {
161
163
  {
162
164
  style: { display: "flex", flexDirection: "column", gap: 6 }
163
165
  },
164
- /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, fontWeight: 600 } }, "Length"),
166
+ /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, fontWeight: 600 } }, t(LangKey.SETTING_LENGTH)),
165
167
  /* @__PURE__ */ React.createElement(
166
168
  ChipGroup,
167
169
  {
168
- options: LENGTH_OPTIONS,
170
+ options: getLengthOptions(),
169
171
  selected: length,
170
172
  onSelect: (opt) => setLength(opt),
171
173
  iconMap: LENGTH_ICONS,
@@ -1,4 +1,4 @@
1
1
  import { LabelValue } from '../../types';
2
2
 
3
- export declare const TONE_OPTIONS: LabelValue[];
4
- export declare const LENGTH_OPTIONS: LabelValue[];
3
+ export declare const getToneOptions: () => LabelValue[];
4
+ export declare const getLengthOptions: () => LabelValue[];
@@ -1,18 +1,20 @@
1
- const TONE_OPTIONS = [
2
- { label: "Formal", value: "formal" },
3
- { label: "Polite", value: "polite" },
4
- { label: "Neutral", value: "neutral" },
5
- { label: "Friendly", value: "friendly" },
6
- { label: "Firm", value: "firm" },
7
- { label: "Apology", value: "apologetic" }
1
+ import { t } from "../../lang/index.js";
2
+ import { LangKey } from "../../lang/keyLang.js";
3
+ const getToneOptions = () => [
4
+ { label: t(LangKey.TONE_FORMAL), value: "formal" },
5
+ { label: t(LangKey.TONE_POLITE), value: "polite" },
6
+ { label: t(LangKey.TONE_NEUTRAL), value: "neutral" },
7
+ { label: t(LangKey.TONE_FRIENDLY), value: "friendly" },
8
+ { label: t(LangKey.TONE_FIRM), value: "firm" },
9
+ { label: t(LangKey.TONE_APOLOGY), value: "apologetic" }
8
10
  ];
9
- const LENGTH_OPTIONS = [
10
- { label: "Short", value: "short" },
11
- { label: "Medium", value: "medium" },
12
- { label: "Long", value: "long" },
13
- { label: "1-liner", value: "one_liner" }
11
+ const getLengthOptions = () => [
12
+ { label: t(LangKey.LENGTH_SHORT), value: "short" },
13
+ { label: t(LangKey.LENGTH_MEDIUM), value: "medium" },
14
+ { label: t(LangKey.LENGTH_LONG), value: "long" },
15
+ { label: t(LangKey.LENGTH_ONE_LINER), value: "one_liner" }
14
16
  ];
15
17
  export {
16
- LENGTH_OPTIONS,
17
- TONE_OPTIONS
18
+ getLengthOptions,
19
+ getToneOptions
18
20
  };
@@ -4,6 +4,7 @@ export interface ChatAIDraftProps {
4
4
  type?: ChatType;
5
5
  sourceMid?: string;
6
6
  defaultLang?: string;
7
+ userLang?: string;
7
8
  getEditorContent?: () => string;
8
9
  onApply: (params: {
9
10
  html: string;
@@ -29,8 +29,14 @@ var __objRest = (source, exclude) => {
29
29
  import * as React from "react";
30
30
  import CreatePanel from "./CreatePanel/index.js";
31
31
  import ReplyPanel from "./ReplyPanel/index.js";
32
+ import { SDKConfig } from "../../utils/url.js";
32
33
  const ChatAIDraft = (props) => {
33
- const _a = props, { type = "new", sourceMid } = _a, rest = __objRest(_a, ["type", "sourceMid"]);
34
+ const _a = props, { type = "new", sourceMid, userLang } = _a, rest = __objRest(_a, ["type", "sourceMid", "userLang"]);
35
+ React.useEffect(() => {
36
+ if (userLang) {
37
+ SDKConfig.lang = userLang;
38
+ }
39
+ }, [userLang]);
34
40
  if ((type === "reply" || type === "forward") && sourceMid) {
35
41
  return /* @__PURE__ */ React.createElement(ReplyPanel, __spreadValues({ type, sourceMid }, rest));
36
42
  }
@@ -2,6 +2,8 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import * as React from "react";
5
+ import { t } from "../../lang/index.js";
6
+ import { LangKey } from "../../lang/keyLang.js";
5
7
  import ChevronLeft from "../../node_modules/react-feather/dist/icons/chevron-left.js";
6
8
  import ChevronRight from "../../node_modules/react-feather/dist/icons/chevron-right.js";
7
9
  class Pagination extends React.Component {
@@ -51,7 +53,7 @@ class Pagination extends React.Component {
51
53
  borderTop: "1px solid var(--border-light)"
52
54
  }
53
55
  },
54
- /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, color: "var(--text-secondary)" } }, "Total ", total, " | Page ", page, " / ", totalPages),
56
+ /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, color: "var(--text-secondary)" } }, t(LangKey.PAGINATION_TOTAL), " ", total, " | ", t(LangKey.PAGINATION_PAGE_OF), " ", page, " / ", totalPages),
55
57
  /* @__PURE__ */ React.createElement(
56
58
  "div",
57
59
  {
@@ -90,7 +92,7 @@ class Pagination extends React.Component {
90
92
  marginLeft: 4
91
93
  }
92
94
  },
93
- "Page"
95
+ t(LangKey.PAGINATION_PAGE)
94
96
  ),
95
97
  /* @__PURE__ */ React.createElement(
96
98
  "input",
@@ -1,5 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { FILTERS } from "./utils.js";
3
+ import { t } from "../../lang/index.js";
4
+ import { LangKey } from "../../lang/keyLang.js";
3
5
  const FilterTabs = ({
4
6
  mailtype,
5
7
  onChangeFilter
@@ -14,7 +16,7 @@ const FilterTabs = ({
14
16
  gap: 8
15
17
  }
16
18
  },
17
- /* @__PURE__ */ React.createElement("span", { style: { fontSize: 13, color: "var(--text-secondary)" } }, "This is a summary compiled by AI · May contain some inaccuracies"),
19
+ /* @__PURE__ */ React.createElement("span", { style: { fontSize: 13, color: "var(--text-secondary)" } }, t(LangKey.SUMMARY_WARNING)),
18
20
  /* @__PURE__ */ React.createElement(
19
21
  "div",
20
22
  {
@@ -47,7 +49,7 @@ const FilterTabs = ({
47
49
  transition: "background 0.15s ease-in-out"
48
50
  }
49
51
  },
50
- f.label
52
+ t(f.label)
51
53
  );
52
54
  })
53
55
  )
@@ -1,7 +1,9 @@
1
1
  import * as React from "react";
2
2
  import { formatDate } from "./utils.js";
3
+ import { t } from "../../lang/index.js";
3
4
  import ArrowUp from "../../node_modules/react-feather/dist/icons/arrow-up.js";
4
5
  import ArrowDown from "../../node_modules/react-feather/dist/icons/arrow-down.js";
6
+ import { LangKey } from "../../lang/keyLang.js";
5
7
  const SummaryItem = ({ item }) => {
6
8
  const isSent = (item == null ? void 0 : item.direction) === "sent" || (item == null ? void 0 : item.sig) === "out";
7
9
  return /* @__PURE__ */ React.createElement(
@@ -41,7 +43,7 @@ const SummaryItem = ({ item }) => {
41
43
  }
42
44
  },
43
45
  isSent ? /* @__PURE__ */ React.createElement(ArrowUp, { size: 11 }) : /* @__PURE__ */ React.createElement(ArrowDown, { size: 11 }),
44
- isSent ? "Sent" : "Received"
46
+ t(isSent ? LangKey.SENT : LangKey.RECEIVED)
45
47
  )
46
48
  ),
47
49
  /* @__PURE__ */ React.createElement(