@djangocfg/ext-knowbase 1.0.21 → 1.0.22

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.
@@ -0,0 +1,59 @@
1
+ import * as _djangocfg_ext_base_i18n from '@djangocfg/ext-base/i18n';
2
+ import { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
3
+
4
+ /**
5
+ * Knowbase Extension I18n Types
6
+ */
7
+
8
+ /**
9
+ * All valid keys for knowbase translations (with namespace)
10
+ */
11
+ type KnowbaseKeys = ExtensionKeys<'knowbase', KnowbaseTranslations>;
12
+ /**
13
+ * Keys without namespace prefix (for createTypedExtensionT)
14
+ */
15
+ type KnowbaseLocalKeys = PathKeys<KnowbaseTranslations>;
16
+ interface KnowbaseTranslations {
17
+ /** Chat widget */
18
+ chat: {
19
+ title: string;
20
+ titleShort: string;
21
+ placeholder: string;
22
+ enterToSend: string;
23
+ thinking: string;
24
+ source: string;
25
+ startConversation: string;
26
+ startConversationDescription: string;
27
+ openChat: string;
28
+ };
29
+ /** Sessions */
30
+ sessions: {
31
+ title: string;
32
+ description: string;
33
+ noSessions: string;
34
+ noSessionsDescription: string;
35
+ untitled: string;
36
+ active: string;
37
+ archive: string;
38
+ delete: string;
39
+ loadingMore: string;
40
+ noMore: string;
41
+ newChat: string;
42
+ };
43
+ /** Actions */
44
+ actions: {
45
+ sessions: string;
46
+ collapse: string;
47
+ expand: string;
48
+ close: string;
49
+ };
50
+ }
51
+
52
+ /** Knowbase extension namespace */
53
+ declare const KNOWBASE_NAMESPACE: "knowbase";
54
+ declare const knowbaseI18n: _djangocfg_ext_base_i18n.ExtensionI18n<KnowbaseTranslations>;
55
+ declare const knowbaseTranslations: Record<string, {
56
+ [namespace: string]: KnowbaseTranslations;
57
+ }>;
58
+
59
+ export { KNOWBASE_NAMESPACE, type KnowbaseKeys, type KnowbaseLocalKeys, type KnowbaseTranslations, knowbaseI18n, knowbaseTranslations };
package/dist/i18n.d.ts ADDED
@@ -0,0 +1,59 @@
1
+ import * as _djangocfg_ext_base_i18n from '@djangocfg/ext-base/i18n';
2
+ import { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
3
+
4
+ /**
5
+ * Knowbase Extension I18n Types
6
+ */
7
+
8
+ /**
9
+ * All valid keys for knowbase translations (with namespace)
10
+ */
11
+ type KnowbaseKeys = ExtensionKeys<'knowbase', KnowbaseTranslations>;
12
+ /**
13
+ * Keys without namespace prefix (for createTypedExtensionT)
14
+ */
15
+ type KnowbaseLocalKeys = PathKeys<KnowbaseTranslations>;
16
+ interface KnowbaseTranslations {
17
+ /** Chat widget */
18
+ chat: {
19
+ title: string;
20
+ titleShort: string;
21
+ placeholder: string;
22
+ enterToSend: string;
23
+ thinking: string;
24
+ source: string;
25
+ startConversation: string;
26
+ startConversationDescription: string;
27
+ openChat: string;
28
+ };
29
+ /** Sessions */
30
+ sessions: {
31
+ title: string;
32
+ description: string;
33
+ noSessions: string;
34
+ noSessionsDescription: string;
35
+ untitled: string;
36
+ active: string;
37
+ archive: string;
38
+ delete: string;
39
+ loadingMore: string;
40
+ noMore: string;
41
+ newChat: string;
42
+ };
43
+ /** Actions */
44
+ actions: {
45
+ sessions: string;
46
+ collapse: string;
47
+ expand: string;
48
+ close: string;
49
+ };
50
+ }
51
+
52
+ /** Knowbase extension namespace */
53
+ declare const KNOWBASE_NAMESPACE: "knowbase";
54
+ declare const knowbaseI18n: _djangocfg_ext_base_i18n.ExtensionI18n<KnowbaseTranslations>;
55
+ declare const knowbaseTranslations: Record<string, {
56
+ [namespace: string]: KnowbaseTranslations;
57
+ }>;
58
+
59
+ export { KNOWBASE_NAMESPACE, type KnowbaseKeys, type KnowbaseLocalKeys, type KnowbaseTranslations, knowbaseI18n, knowbaseTranslations };
package/dist/i18n.js ADDED
@@ -0,0 +1,118 @@
1
+ // src/i18n/index.ts
2
+ import { createExtensionI18n } from "@djangocfg/ext-base/i18n";
3
+
4
+ // src/i18n/locales/en.ts
5
+ var en = {
6
+ chat: {
7
+ title: "Knowledge Assistant",
8
+ titleShort: "Support",
9
+ placeholder: "Ask me anything...",
10
+ enterToSend: "Press Enter to send, Shift+Enter for new line",
11
+ thinking: "Thinking...",
12
+ source: "Source {index}",
13
+ startConversation: "Start a Conversation",
14
+ startConversationDescription: "Ask me anything about the documentation, features, or get help with your project.",
15
+ openChat: "Open Support Chat"
16
+ },
17
+ sessions: {
18
+ title: "Chat Sessions",
19
+ description: "View and manage your chat history",
20
+ noSessions: "No Sessions Yet",
21
+ noSessionsDescription: "Start a new conversation to create your first session.",
22
+ untitled: "Untitled Session",
23
+ active: "Active",
24
+ archive: "Archive",
25
+ delete: "Delete",
26
+ loadingMore: "Loading more...",
27
+ noMore: "No more sessions",
28
+ newChat: "New Chat"
29
+ },
30
+ actions: {
31
+ sessions: "Sessions",
32
+ collapse: "Collapse",
33
+ expand: "Expand",
34
+ close: "Close"
35
+ }
36
+ };
37
+
38
+ // src/i18n/locales/ru.ts
39
+ var ru = {
40
+ chat: {
41
+ title: "\u0411\u0430\u0437\u0430 \u0437\u043D\u0430\u043D\u0438\u0439",
42
+ titleShort: "\u041F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0430",
43
+ placeholder: "\u0417\u0430\u0434\u0430\u0439\u0442\u0435 \u0432\u043E\u043F\u0440\u043E\u0441...",
44
+ enterToSend: "Enter \u0434\u043B\u044F \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438, Shift+Enter \u0434\u043B\u044F \u043D\u043E\u0432\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u0438",
45
+ thinking: "\u0414\u0443\u043C\u0430\u044E...",
46
+ source: "\u0418\u0441\u0442\u043E\u0447\u043D\u0438\u043A {index}",
47
+ startConversation: "\u041D\u0430\u0447\u0430\u0442\u044C \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440",
48
+ startConversationDescription: "\u0417\u0430\u0434\u0430\u0439\u0442\u0435 \u043B\u044E\u0431\u043E\u0439 \u0432\u043E\u043F\u0440\u043E\u0441 \u043E \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u0438, \u0444\u0443\u043D\u043A\u0446\u0438\u044F\u0445 \u0438\u043B\u0438 \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u043F\u043E\u043C\u043E\u0449\u044C \u0441 \u043F\u0440\u043E\u0435\u043A\u0442\u043E\u043C.",
49
+ openChat: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0447\u0430\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0438"
50
+ },
51
+ sessions: {
52
+ title: "\u0421\u0435\u0441\u0441\u0438\u0438 \u0447\u0430\u0442\u0430",
53
+ description: "\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u0438 \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0438\u0441\u0442\u043E\u0440\u0438\u0435\u0439 \u0447\u0430\u0442\u0430",
54
+ noSessions: "\u041D\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u0439",
55
+ noSessionsDescription: "\u041D\u0430\u0447\u043D\u0438\u0442\u0435 \u043D\u043E\u0432\u044B\u0439 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440, \u0447\u0442\u043E\u0431\u044B \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u043F\u0435\u0440\u0432\u0443\u044E \u0441\u0435\u0441\u0441\u0438\u044E.",
56
+ untitled: "\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F",
57
+ active: "\u0410\u043A\u0442\u0438\u0432\u043D\u0430\u044F",
58
+ archive: "\u0410\u0440\u0445\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
59
+ delete: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
60
+ loadingMore: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430...",
61
+ noMore: "\u0411\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u0439",
62
+ newChat: "\u041D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442"
63
+ },
64
+ actions: {
65
+ sessions: "\u0421\u0435\u0441\u0441\u0438\u0438",
66
+ collapse: "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
67
+ expand: "\u0420\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
68
+ close: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C"
69
+ }
70
+ };
71
+
72
+ // src/i18n/locales/ko.ts
73
+ var ko = {
74
+ chat: {
75
+ title: "\uC9C0\uC2DD \uB3C4\uC6B0\uBBF8",
76
+ titleShort: "\uC9C0\uC6D0",
77
+ placeholder: "\uBB34\uC5C7\uC774\uB4E0 \uBB3C\uC5B4\uBCF4\uC138\uC694...",
78
+ enterToSend: "Enter\uB85C \uC804\uC1A1, Shift+Enter\uB85C \uC904\uBC14\uAFC8",
79
+ thinking: "\uC0DD\uAC01 \uC911...",
80
+ source: "\uCD9C\uCC98 {index}",
81
+ startConversation: "\uB300\uD654 \uC2DC\uC791\uD558\uAE30",
82
+ startConversationDescription: "\uBB38\uC11C, \uAE30\uB2A5\uC5D0 \uB300\uD574 \uC9C8\uBB38\uD558\uAC70\uB098 \uD504\uB85C\uC81D\uD2B8 \uB3C4\uC6C0\uC744 \uBC1B\uC73C\uC138\uC694.",
83
+ openChat: "\uC9C0\uC6D0 \uCC44\uD305 \uC5F4\uAE30"
84
+ },
85
+ sessions: {
86
+ title: "\uCC44\uD305 \uC138\uC158",
87
+ description: "\uCC44\uD305 \uAE30\uB85D \uBCF4\uAE30 \uBC0F \uAD00\uB9AC",
88
+ noSessions: "\uC138\uC158 \uC5C6\uC74C",
89
+ noSessionsDescription: "\uC0C8 \uB300\uD654\uB97C \uC2DC\uC791\uD558\uC5EC \uCCAB \uBC88\uC9F8 \uC138\uC158\uC744 \uB9CC\uB4DC\uC138\uC694.",
90
+ untitled: "\uC81C\uBAA9 \uC5C6\uC74C",
91
+ active: "\uD65C\uC131",
92
+ archive: "\uBCF4\uAD00",
93
+ delete: "\uC0AD\uC81C",
94
+ loadingMore: "\uBD88\uB7EC\uC624\uB294 \uC911...",
95
+ noMore: "\uB354 \uC774\uC0C1 \uC138\uC158 \uC5C6\uC74C",
96
+ newChat: "\uC0C8 \uCC44\uD305"
97
+ },
98
+ actions: {
99
+ sessions: "\uC138\uC158",
100
+ collapse: "\uCD95\uC18C",
101
+ expand: "\uD655\uC7A5",
102
+ close: "\uB2EB\uAE30"
103
+ }
104
+ };
105
+
106
+ // src/i18n/index.ts
107
+ var KNOWBASE_NAMESPACE = "knowbase";
108
+ var knowbaseI18n = createExtensionI18n({
109
+ namespace: KNOWBASE_NAMESPACE,
110
+ defaultLocale: "en",
111
+ locales: { en, ru, ko }
112
+ });
113
+ var knowbaseTranslations = knowbaseI18n.getAllTranslations();
114
+ export {
115
+ KNOWBASE_NAMESPACE,
116
+ knowbaseI18n,
117
+ knowbaseTranslations
118
+ };
package/dist/index.cjs CHANGED
@@ -4369,7 +4369,7 @@ var apiKnowbase = api.createExtensionAPI(API);
4369
4369
  // package.json
4370
4370
  var package_default = {
4371
4371
  name: "@djangocfg/ext-knowbase",
4372
- version: "1.0.21",
4372
+ version: "1.0.22",
4373
4373
  description: "Knowledge base and chat extension for DjangoCFG",
4374
4374
  keywords: [
4375
4375
  "django",
@@ -4415,6 +4415,11 @@ var package_default = {
4415
4415
  types: "./dist/config.d.ts",
4416
4416
  import: "./dist/config.js",
4417
4417
  require: "./dist/config.cjs"
4418
+ },
4419
+ "./i18n": {
4420
+ types: "./dist/i18n.d.ts",
4421
+ import: "./dist/i18n.js",
4422
+ require: "./dist/i18n.cjs"
4418
4423
  }
4419
4424
  },
4420
4425
  files: [
@@ -4430,6 +4435,7 @@ var package_default = {
4430
4435
  peerDependencies: {
4431
4436
  "@djangocfg/api": "workspace:*",
4432
4437
  "@djangocfg/ext-base": "workspace:*",
4438
+ "@djangocfg/i18n": "workspace:*",
4433
4439
  "@djangocfg/ui-core": "workspace:*",
4434
4440
  "@djangocfg/ui-nextjs": "workspace:*",
4435
4441
  consola: "^3.4.2",
@@ -4446,6 +4452,7 @@ var package_default = {
4446
4452
  devDependencies: {
4447
4453
  "@djangocfg/api": "workspace:*",
4448
4454
  "@djangocfg/ext-base": "workspace:*",
4455
+ "@djangocfg/i18n": "workspace:*",
4449
4456
  "@djangocfg/ui-core": "workspace:*",
4450
4457
  "@djangocfg/typescript-config": "workspace:*",
4451
4458
  "@types/node": "^24.7.2",
package/dist/index.js CHANGED
@@ -4363,7 +4363,7 @@ var apiKnowbase = createExtensionAPI(API);
4363
4363
  // package.json
4364
4364
  var package_default = {
4365
4365
  name: "@djangocfg/ext-knowbase",
4366
- version: "1.0.21",
4366
+ version: "1.0.22",
4367
4367
  description: "Knowledge base and chat extension for DjangoCFG",
4368
4368
  keywords: [
4369
4369
  "django",
@@ -4409,6 +4409,11 @@ var package_default = {
4409
4409
  types: "./dist/config.d.ts",
4410
4410
  import: "./dist/config.js",
4411
4411
  require: "./dist/config.cjs"
4412
+ },
4413
+ "./i18n": {
4414
+ types: "./dist/i18n.d.ts",
4415
+ import: "./dist/i18n.js",
4416
+ require: "./dist/i18n.cjs"
4412
4417
  }
4413
4418
  },
4414
4419
  files: [
@@ -4424,6 +4429,7 @@ var package_default = {
4424
4429
  peerDependencies: {
4425
4430
  "@djangocfg/api": "workspace:*",
4426
4431
  "@djangocfg/ext-base": "workspace:*",
4432
+ "@djangocfg/i18n": "workspace:*",
4427
4433
  "@djangocfg/ui-core": "workspace:*",
4428
4434
  "@djangocfg/ui-nextjs": "workspace:*",
4429
4435
  consola: "^3.4.2",
@@ -4440,6 +4446,7 @@ var package_default = {
4440
4446
  devDependencies: {
4441
4447
  "@djangocfg/api": "workspace:*",
4442
4448
  "@djangocfg/ext-base": "workspace:*",
4449
+ "@djangocfg/i18n": "workspace:*",
4443
4450
  "@djangocfg/ui-core": "workspace:*",
4444
4451
  "@djangocfg/typescript-config": "workspace:*",
4445
4452
  "@types/node": "^24.7.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ext-knowbase",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "description": "Knowledge base and chat extension for DjangoCFG",
5
5
  "keywords": [
6
6
  "django",
@@ -46,6 +46,11 @@
46
46
  "types": "./dist/config.d.ts",
47
47
  "import": "./dist/config.js",
48
48
  "require": "./dist/config.cjs"
49
+ },
50
+ "./i18n": {
51
+ "types": "./dist/i18n.d.ts",
52
+ "import": "./dist/i18n.js",
53
+ "require": "./dist/i18n.cjs"
49
54
  }
50
55
  },
51
56
  "files": [
@@ -59,10 +64,11 @@
59
64
  "check": "tsc --noEmit"
60
65
  },
61
66
  "peerDependencies": {
62
- "@djangocfg/api": "^2.1.109",
63
- "@djangocfg/ext-base": "^1.0.16",
64
- "@djangocfg/ui-core": "^2.1.109",
65
- "@djangocfg/ui-nextjs": "^2.1.109",
67
+ "@djangocfg/api": "^2.1.111",
68
+ "@djangocfg/ext-base": "^1.0.17",
69
+ "@djangocfg/i18n": "^2.1.111",
70
+ "@djangocfg/ui-core": "^2.1.111",
71
+ "@djangocfg/ui-nextjs": "^2.1.111",
66
72
  "consola": "^3.4.2",
67
73
  "lucide-react": "^0.545.0",
68
74
  "next": "^16",
@@ -75,10 +81,11 @@
75
81
  "moment": "^2.30.1"
76
82
  },
77
83
  "devDependencies": {
78
- "@djangocfg/api": "^2.1.109",
79
- "@djangocfg/ext-base": "^1.0.16",
80
- "@djangocfg/ui-core": "^2.1.109",
81
- "@djangocfg/typescript-config": "^2.1.109",
84
+ "@djangocfg/api": "^2.1.111",
85
+ "@djangocfg/ext-base": "^1.0.17",
86
+ "@djangocfg/i18n": "^2.1.111",
87
+ "@djangocfg/ui-core": "^2.1.111",
88
+ "@djangocfg/typescript-config": "^2.1.111",
82
89
  "@types/node": "^24.7.2",
83
90
  "@types/react": "^19.0.0",
84
91
  "consola": "^3.4.2",
@@ -7,9 +7,12 @@
7
7
 
8
8
  import { List, Maximize2, MessageSquare, Minimize2, Plus, X } from 'lucide-react';
9
9
  import { usePathname } from 'next/navigation';
10
- import React, { useCallback, useEffect, useState } from 'react';
10
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
11
11
  import { createPortal } from 'react-dom';
12
12
 
13
+ import { createTypedExtensionT } from '@djangocfg/ext-base/i18n';
14
+ import { useT } from '@djangocfg/i18n';
15
+ import { KNOWBASE_NAMESPACE, type KnowbaseTranslations } from '../../i18n';
13
16
  import {
14
17
  Button, Card, CardContent, CardHeader,
15
18
  } from '@djangocfg/ui-nextjs';
@@ -37,6 +40,8 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
37
40
  onToggle,
38
41
  onMessage,
39
42
  }) => {
43
+ const baseT = useT();
44
+ const kt = createTypedExtensionT<typeof KNOWBASE_NAMESPACE, KnowbaseTranslations>(baseT, KNOWBASE_NAMESPACE);
40
45
  const { sendQuery, getChatHistory } = useKnowbaseChatContext();
41
46
  const { createSession, getSession } = useKnowbaseSessionsContext();
42
47
  const {
@@ -48,9 +53,21 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
48
53
  toggleTimestamps,
49
54
  } = useChatUI();
50
55
 
56
+ const labels = useMemo(() => ({
57
+ title: kt('chat.title'),
58
+ titleShort: kt('chat.titleShort'),
59
+ placeholder: kt('chat.placeholder'),
60
+ openChat: kt('chat.openChat'),
61
+ sessions: kt('actions.sessions'),
62
+ newChat: kt('sessions.newChat'),
63
+ collapse: kt('actions.collapse'),
64
+ expand: kt('actions.expand'),
65
+ close: kt('actions.close'),
66
+ }), [kt]);
67
+
51
68
  const pathname = usePathname();
52
69
  const isMobile = useIsMobile();
53
-
70
+
54
71
  const [isLoading, setIsLoading] = useState(false);
55
72
  const [showSessions, setShowSessions] = useState(false);
56
73
  const [mounted, setMounted] = useState(false);
@@ -233,7 +250,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
233
250
  <div className="flex items-center justify-between p-4 border-b bg-background shadow-sm">
234
251
  <div className="flex items-center gap-2">
235
252
  <MessageSquare className="h-5 w-5 text-primary" />
236
- <h2 className="font-semibold text-foreground">Knowledge Assistant</h2>
253
+ <h2 className="font-semibold text-foreground">{labels.title}</h2>
237
254
  </div>
238
255
 
239
256
  <div className="flex items-center gap-2">
@@ -242,7 +259,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
242
259
  size="sm"
243
260
  onClick={() => setShowSessions(true)}
244
261
  className="text-muted-foreground hover:text-foreground"
245
- title="Sessions"
262
+ title={labels.sessions}
246
263
  >
247
264
  <List className="h-5 w-5" />
248
265
  </Button>
@@ -252,7 +269,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
252
269
  size="sm"
253
270
  onClick={handleNewChat}
254
271
  className="text-muted-foreground hover:text-foreground"
255
- title="New Chat"
272
+ title={labels.newChat}
256
273
  >
257
274
  <Plus className="h-5 w-5" />
258
275
  </Button>
@@ -282,7 +299,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
282
299
  <MessageInput
283
300
  onSend={handleSendMessage}
284
301
  isLoading={isLoading}
285
- placeholder="Ask me anything..."
302
+ placeholder={labels.placeholder}
286
303
  />
287
304
  </div>
288
305
  </div>
@@ -342,7 +359,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
342
359
  <CardHeader className="flex-row items-center justify-between space-y-0 pb-3 border-b">
343
360
  <div className="flex items-center gap-2">
344
361
  <MessageSquare className="h-5 w-5 text-primary" />
345
- <h3 className="font-semibold text-foreground">Support</h3>
362
+ <h3 className="font-semibold text-foreground">{labels.titleShort}</h3>
346
363
  </div>
347
364
 
348
365
  <div className="flex items-center gap-1">
@@ -351,7 +368,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
351
368
  size="sm"
352
369
  onClick={() => setShowSessions(true)}
353
370
  className="h-8 w-8 p-0"
354
- title="Sessions"
371
+ title={labels.sessions}
355
372
  >
356
373
  <List className="h-4 w-4" />
357
374
  </Button>
@@ -361,7 +378,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
361
378
  size="sm"
362
379
  onClick={handleNewChat}
363
380
  className="h-8 w-8 p-0"
364
- title="New Chat"
381
+ title={labels.newChat}
365
382
  >
366
383
  <Plus className="h-4 w-4" />
367
384
  </Button>
@@ -371,7 +388,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
371
388
  size="sm"
372
389
  onClick={uiState.isExpanded ? collapseChat : expandChat}
373
390
  className="h-8 w-8 p-0"
374
- title={uiState.isExpanded ? 'Collapse' : 'Expand'}
391
+ title={uiState.isExpanded ? labels.collapse : labels.expand}
375
392
  >
376
393
  {uiState.isExpanded ? (
377
394
  <Minimize2 className="h-4 w-4" />
@@ -385,7 +402,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
385
402
  size="sm"
386
403
  onClick={toggleChat}
387
404
  className="h-8 w-8 p-0"
388
- title="Close"
405
+ title={labels.close}
389
406
  >
390
407
  <X className="h-4 w-4" />
391
408
  </Button>
@@ -406,7 +423,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
406
423
  <MessageInput
407
424
  onSend={handleSendMessage}
408
425
  isLoading={isLoading}
409
- placeholder="Ask me anything..."
426
+ placeholder={labels.placeholder}
410
427
  />
411
428
  </CardContent>
412
429
  </Card>
@@ -439,8 +456,8 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
439
456
  `}</style>
440
457
  <Button
441
458
  onClick={toggleChat}
442
- className="w-full h-full rounded-full shadow-2xl
443
- hover:scale-110 hover:rotate-12 active:scale-95
459
+ className="w-full h-full rounded-full shadow-2xl
460
+ hover:scale-110 hover:rotate-12 active:scale-95
444
461
  transition-all duration-300 ease-out
445
462
  flex items-center justify-center
446
463
  group"
@@ -449,8 +466,8 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({
449
466
  borderRadius: '50%',
450
467
  padding: 0,
451
468
  }}
452
- title="Open Support Chat"
453
- aria-label="Open Support Chat"
469
+ title={labels.openChat}
470
+ aria-label={labels.openChat}
454
471
  >
455
472
  <MessageSquare
456
473
  className="h-7 w-7 text-primary-foreground group-hover:scale-110 transition-transform duration-300"
@@ -6,8 +6,11 @@
6
6
  'use client';
7
7
 
8
8
  import { Loader2, Send } from 'lucide-react';
9
- import React, { useCallback, useEffect, useRef, useState } from 'react';
9
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
10
10
 
11
+ import { createTypedExtensionT } from '@djangocfg/ext-base/i18n';
12
+ import { useT } from '@djangocfg/i18n';
13
+ import { KNOWBASE_NAMESPACE, type KnowbaseTranslations } from '../../../i18n';
11
14
  import { Button, Textarea } from '@djangocfg/ui-nextjs';
12
15
 
13
16
  import { chatLogger } from '../../../utils/logger';
@@ -22,13 +25,20 @@ export const MessageInput: React.FC<MessageInputProps> = ({
22
25
  onSend,
23
26
  isLoading = false,
24
27
  disabled = false,
25
- placeholder = 'Ask me anything...',
28
+ placeholder,
26
29
  className = '',
27
30
  }) => {
31
+ const baseT = useT();
32
+ const kt = createTypedExtensionT<typeof KNOWBASE_NAMESPACE, KnowbaseTranslations>(baseT, KNOWBASE_NAMESPACE);
28
33
  const [message, setMessage] = useState('');
29
34
  const [rows, setRows] = useState(1);
30
35
  const textareaRef = useRef<HTMLTextAreaElement>(null);
31
36
 
37
+ const labels = useMemo(() => ({
38
+ placeholder: placeholder || kt('chat.placeholder'),
39
+ enterToSend: kt('chat.enterToSend'),
40
+ }), [kt, placeholder]);
41
+
32
42
  // Auto-resize textarea based on content
33
43
  useEffect(() => {
34
44
  if (textareaRef.current) {
@@ -95,19 +105,19 @@ export const MessageInput: React.FC<MessageInputProps> = ({
95
105
  value={message}
96
106
  onChange={(e) => setMessage(e.target.value)}
97
107
  onKeyDown={handleKeyDown}
98
- placeholder={placeholder}
108
+ placeholder={labels.placeholder}
99
109
  disabled={isDisabled}
100
110
  rows={rows}
101
- className="resize-none min-h-[40px] max-h-[120px] transition-all duration-200
111
+ className="resize-none min-h-[40px] max-h-[120px] transition-all duration-200
102
112
  focus:ring-2 focus:ring-primary/20"
103
113
  style={{ resize: 'none' }}
104
114
  />
105
-
115
+
106
116
  <Button
107
117
  type="submit"
108
118
  size="icon"
109
119
  disabled={!canSend}
110
- className="shrink-0 h-10 w-10 transition-all duration-200
120
+ className="shrink-0 h-10 w-10 transition-all duration-200
111
121
  hover:scale-110 active:scale-95 disabled:scale-100"
112
122
  >
113
123
  {isLoading ? (
@@ -117,9 +127,9 @@ export const MessageInput: React.FC<MessageInputProps> = ({
117
127
  )}
118
128
  </Button>
119
129
  </div>
120
-
130
+
121
131
  <p className="text-xs text-muted-foreground mt-2">
122
- Press Enter to send, Shift+Enter for new line
132
+ {labels.enterToSend}
123
133
  </p>
124
134
  </form>
125
135
  );
@@ -7,9 +7,12 @@
7
7
 
8
8
  import { Bot, ExternalLink, Loader2, User } from 'lucide-react';
9
9
  import moment from 'moment';
10
- import React, { useEffect, useRef } from 'react';
10
+ import React, { useEffect, useMemo, useRef } from 'react';
11
11
 
12
12
  import { useAuth } from '@djangocfg/api/auth';
13
+ import { createTypedExtensionT } from '@djangocfg/ext-base/i18n';
14
+ import { useT } from '@djangocfg/i18n';
15
+ import { KNOWBASE_NAMESPACE, type KnowbaseTranslations } from '../../../i18n';
13
16
  import {
14
17
  Avatar, AvatarFallback, AvatarImage, Badge, Card, CardContent, ScrollArea
15
18
  } from '@djangocfg/ui-nextjs';
@@ -29,9 +32,18 @@ export const MessageList: React.FC<MessageListProps> = ({
29
32
  autoScroll = true,
30
33
  className = '',
31
34
  }) => {
35
+ const baseT = useT();
36
+ const kt = createTypedExtensionT<typeof KNOWBASE_NAMESPACE, KnowbaseTranslations>(baseT, KNOWBASE_NAMESPACE);
32
37
  const scrollRef = useRef<HTMLDivElement>(null);
33
38
  const { user } = useAuth();
34
39
 
40
+ const labels = useMemo(() => ({
41
+ startConversation: kt('chat.startConversation'),
42
+ startConversationDescription: kt('chat.startConversationDescription'),
43
+ source: kt('chat.source'),
44
+ thinking: kt('chat.thinking'),
45
+ }), [kt]);
46
+
35
47
  // Auto-scroll to bottom on new messages
36
48
  useEffect(() => {
37
49
  if (autoScroll && scrollRef.current) {
@@ -58,10 +70,10 @@ export const MessageList: React.FC<MessageListProps> = ({
58
70
  <div className="flex flex-col items-center justify-center h-full text-center py-12">
59
71
  <Bot className="h-12 w-12 text-muted-foreground mb-4" />
60
72
  <h3 className="text-lg font-semibold text-foreground mb-2">
61
- Start a Conversation
73
+ {labels.startConversation}
62
74
  </h3>
63
75
  <p className="text-sm text-muted-foreground max-w-md">
64
- Ask me anything about the documentation, features, or get help with your project.
76
+ {labels.startConversationDescription}
65
77
  </p>
66
78
  </div>
67
79
  ) : (
@@ -123,12 +135,12 @@ export const MessageList: React.FC<MessageListProps> = ({
123
135
  <div key={idx}>
124
136
  <Badge
125
137
  variant="secondary"
126
- className="text-xs flex items-center gap-1 cursor-pointer
127
- hover:bg-secondary/80 hover:scale-105 active:scale-95
138
+ className="text-xs flex items-center gap-1 cursor-pointer
139
+ hover:bg-secondary/80 hover:scale-105 active:scale-95
128
140
  transition-all duration-200 animate-in fade-in zoom-in-95"
129
141
  style={{ animationDelay: `${(idx + 1) * 100}ms` }}
130
142
  >
131
- {source.document_title || `Source ${idx + 1}`}
143
+ {source.document_title || labels.source.replace('{index}', String(idx + 1))}
132
144
  <ExternalLink className="h-3 w-3" />
133
145
  </Badge>
134
146
  </div>
@@ -163,7 +175,7 @@ export const MessageList: React.FC<MessageListProps> = ({
163
175
  <CardContent className="p-3">
164
176
  <div className="flex items-center gap-2 text-sm text-muted-foreground">
165
177
  <Loader2 className="h-4 w-4 animate-spin" />
166
- <span className="animate-pulse">Thinking...</span>
178
+ <span className="animate-pulse">{labels.thinking}</span>
167
179
  </div>
168
180
  </CardContent>
169
181
  </Card>