tabby-ai-assistant 1.0.8 → 1.0.10

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 (54) hide show
  1. package/dist/components/chat/ai-sidebar.component.d.ts +16 -3
  2. package/dist/components/chat/chat-input.component.d.ts +4 -0
  3. package/dist/components/chat/chat-interface.component.d.ts +22 -1
  4. package/dist/components/chat/chat-settings.component.d.ts +21 -11
  5. package/dist/components/settings/ai-settings-tab.component.d.ts +14 -4
  6. package/dist/components/settings/general-settings.component.d.ts +43 -12
  7. package/dist/components/settings/provider-config.component.d.ts +110 -5
  8. package/dist/components/settings/security-settings.component.d.ts +14 -4
  9. package/dist/i18n/index.d.ts +48 -0
  10. package/dist/i18n/translations/en-US.d.ts +5 -0
  11. package/dist/i18n/translations/ja-JP.d.ts +5 -0
  12. package/dist/i18n/translations/zh-CN.d.ts +5 -0
  13. package/dist/i18n/types.d.ts +198 -0
  14. package/dist/index.js +1 -1
  15. package/dist/services/chat/ai-sidebar.service.d.ts +23 -1
  16. package/dist/services/core/theme.service.d.ts +53 -0
  17. package/dist/services/core/toast.service.d.ts +15 -0
  18. package/package.json +1 -1
  19. package/src/components/chat/ai-sidebar.component.scss +468 -0
  20. package/src/components/chat/ai-sidebar.component.ts +47 -344
  21. package/src/components/chat/chat-input.component.scss +2 -2
  22. package/src/components/chat/chat-input.component.ts +16 -5
  23. package/src/components/chat/chat-interface.component.html +11 -11
  24. package/src/components/chat/chat-interface.component.scss +410 -4
  25. package/src/components/chat/chat-interface.component.ts +105 -14
  26. package/src/components/chat/chat-message.component.scss +3 -3
  27. package/src/components/chat/chat-message.component.ts +3 -2
  28. package/src/components/chat/chat-settings.component.html +95 -61
  29. package/src/components/chat/chat-settings.component.scss +224 -50
  30. package/src/components/chat/chat-settings.component.ts +56 -30
  31. package/src/components/security/risk-confirm-dialog.component.scss +7 -7
  32. package/src/components/settings/ai-settings-tab.component.html +27 -27
  33. package/src/components/settings/ai-settings-tab.component.scss +34 -20
  34. package/src/components/settings/ai-settings-tab.component.ts +59 -20
  35. package/src/components/settings/general-settings.component.html +69 -40
  36. package/src/components/settings/general-settings.component.scss +151 -58
  37. package/src/components/settings/general-settings.component.ts +168 -55
  38. package/src/components/settings/provider-config.component.html +183 -60
  39. package/src/components/settings/provider-config.component.scss +332 -153
  40. package/src/components/settings/provider-config.component.ts +268 -19
  41. package/src/components/settings/security-settings.component.html +70 -39
  42. package/src/components/settings/security-settings.component.scss +104 -8
  43. package/src/components/settings/security-settings.component.ts +48 -10
  44. package/src/i18n/index.ts +129 -0
  45. package/src/i18n/translations/en-US.ts +193 -0
  46. package/src/i18n/translations/ja-JP.ts +193 -0
  47. package/src/i18n/translations/zh-CN.ts +193 -0
  48. package/src/i18n/types.ts +224 -0
  49. package/src/index.ts +6 -0
  50. package/src/services/chat/ai-sidebar.service.ts +157 -5
  51. package/src/services/core/theme.service.ts +480 -0
  52. package/src/services/core/toast.service.ts +36 -0
  53. package/src/styles/ai-assistant.scss +8 -88
  54. package/src/styles/themes.scss +161 -0
@@ -1,13 +1,18 @@
1
- import { Component, OnInit } from '@angular/core';
1
+ import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core';
2
+ import { Subject } from 'rxjs';
3
+ import { takeUntil } from 'rxjs/operators';
2
4
  import { ConfigProviderService } from '../../services/core/config-provider.service';
3
5
  import { LoggerService } from '../../services/core/logger.service';
6
+ import { ThemeService, ThemeType } from '../../services/core/theme.service';
7
+ import { TranslateService } from '../../i18n';
4
8
 
5
9
  @Component({
6
10
  selector: 'app-chat-settings',
7
11
  templateUrl: './chat-settings.component.html',
8
- styleUrls: ['./chat-settings.component.scss']
12
+ styleUrls: ['./chat-settings.component.scss'],
13
+ encapsulation: ViewEncapsulation.None
9
14
  })
10
- export class ChatSettingsComponent implements OnInit {
15
+ export class ChatSettingsComponent implements OnInit, OnDestroy {
11
16
  settings: {
12
17
  chatHistoryEnabled: boolean;
13
18
  maxChatHistory: number;
@@ -32,23 +37,59 @@ export class ChatSettingsComponent implements OnInit {
32
37
  soundEnabled: true
33
38
  };
34
39
 
35
- themes = [
36
- { value: 'auto', label: '跟随系统' },
37
- { value: 'light', label: '浅色主题' },
38
- { value: 'dark', label: '深色主题' }
39
- ];
40
+ // 翻译对象
41
+ t: any;
40
42
 
41
43
  fontSizes = [12, 14, 16, 18, 20];
42
44
 
45
+ private destroy$ = new Subject<void>();
46
+
43
47
  constructor(
44
48
  private config: ConfigProviderService,
45
- private logger: LoggerService
46
- ) {}
49
+ private logger: LoggerService,
50
+ private translate: TranslateService,
51
+ private themeService: ThemeService
52
+ ) {
53
+ this.t = this.translate.t;
54
+ }
47
55
 
48
56
  ngOnInit(): void {
57
+ // 监听语言变化
58
+ this.translate.translation$.pipe(
59
+ takeUntil(this.destroy$)
60
+ ).subscribe(translation => {
61
+ this.t = translation;
62
+ this.updateThemeLabels();
63
+ });
64
+
49
65
  this.loadSettings();
50
66
  }
51
67
 
68
+ ngOnDestroy(): void {
69
+ this.destroy$.next();
70
+ this.destroy$.complete();
71
+ }
72
+
73
+ /**
74
+ * 更新主题标签翻译
75
+ */
76
+ private updateThemeLabels(): void {
77
+ this.settings.theme = this.config.get('theme', 'auto') ?? 'auto';
78
+ }
79
+
80
+ /**
81
+ * 获取主题选项
82
+ */
83
+ get themes() {
84
+ return [
85
+ { value: 'auto', label: this.t.general.themeAuto },
86
+ { value: 'light', label: this.t.general.themeLight },
87
+ { value: 'dark', label: this.t.general.themeDark },
88
+ { value: 'pixel', label: this.t.general.themePixel || '像素复古' },
89
+ { value: 'tech', label: this.t.general.themeTech || '赛博科技' }
90
+ ];
91
+ }
92
+
52
93
  /**
53
94
  * 加载设置
54
95
  */
@@ -83,22 +124,7 @@ export class ChatSettingsComponent implements OnInit {
83
124
  updateTheme(theme: string): void {
84
125
  this.settings.theme = theme;
85
126
  this.saveSetting('theme', theme);
86
- this.applyTheme(theme);
87
- }
88
-
89
- /**
90
- * 应用主题
91
- */
92
- private applyTheme(theme: string): void {
93
- const body = document.body;
94
- body.classList.remove('light-theme', 'dark-theme');
95
-
96
- if (theme === 'light') {
97
- body.classList.add('light-theme');
98
- } else if (theme === 'dark') {
99
- body.classList.add('dark-theme');
100
- }
101
- // 'auto' 主题由系统决定
127
+ this.themeService.applyTheme(theme as ThemeType);
102
128
  }
103
129
 
104
130
  /**
@@ -123,10 +149,10 @@ export class ChatSettingsComponent implements OnInit {
123
149
  * 清空聊天历史
124
150
  */
125
151
  clearChatHistory(): void {
126
- if (confirm('确定要清空所有聊天记录吗?此操作不可恢复。')) {
152
+ if (confirm(this.t.chatSettings.clearHistoryConfirm)) {
127
153
  localStorage.removeItem('ai-assistant-chat-history');
128
154
  this.logger.info('Chat history cleared');
129
- alert('聊天记录已清空');
155
+ alert(this.t.providers.configDeleted);
130
156
  }
131
157
  }
132
158
 
@@ -152,7 +178,7 @@ export class ChatSettingsComponent implements OnInit {
152
178
  * 重置为默认设置
153
179
  */
154
180
  resetToDefaults(): void {
155
- if (confirm('确定要重置所有设置为默认值吗?')) {
181
+ if (confirm(this.t.chatSettings.resetConfirm)) {
156
182
  this.settings = {
157
183
  chatHistoryEnabled: true,
158
184
  maxChatHistory: 100,
@@ -173,7 +199,7 @@ export class ChatSettingsComponent implements OnInit {
173
199
  });
174
200
 
175
201
  this.logger.info('Chat settings reset to defaults');
176
- alert('设置已重置为默认值');
202
+ alert(this.t.providers.configSaved);
177
203
  }
178
204
  }
179
205
  }
@@ -26,7 +26,7 @@
26
26
  }
27
27
 
28
28
  span {
29
- color: var(--ai-dark);
29
+ color: var(--ai-text-primary);
30
30
  }
31
31
  }
32
32
 
@@ -45,7 +45,7 @@
45
45
 
46
46
  &:hover {
47
47
  background-color: var(--ai-border);
48
- color: var(--ai-dark);
48
+ color: var(--ai-text-primary);
49
49
  }
50
50
  }
51
51
  }
@@ -120,7 +120,7 @@
120
120
  display: block;
121
121
  font-weight: 600;
122
122
  margin-bottom: 0.5rem;
123
- color: var(--ai-dark);
123
+ color: var(--ai-text-primary);
124
124
  font-size: 0.875rem;
125
125
  }
126
126
 
@@ -137,7 +137,7 @@
137
137
  flex: 1;
138
138
  font-family: 'Courier New', Courier, monospace;
139
139
  font-size: 0.875rem;
140
- color: var(--ai-dark);
140
+ color: var(--ai-text-primary);
141
141
  word-break: break-all;
142
142
  }
143
143
 
@@ -156,7 +156,7 @@
156
156
 
157
157
  &:hover {
158
158
  background-color: var(--ai-border);
159
- color: var(--ai-dark);
159
+ color: var(--ai-text-primary);
160
160
  }
161
161
  }
162
162
  }
@@ -169,7 +169,7 @@
169
169
  border-radius: 0.375rem;
170
170
  font-size: 0.875rem;
171
171
  line-height: 1.6;
172
- color: var(--ai-dark);
172
+ color: var(--ai-text-primary);
173
173
  }
174
174
 
175
175
  .suggestions-list {
@@ -201,7 +201,7 @@
201
201
  flex: 1;
202
202
  font-size: 0.875rem;
203
203
  line-height: 1.5;
204
- color: var(--ai-dark);
204
+ color: var(--ai-text-primary);
205
205
  }
206
206
  }
207
207
  }
@@ -4,30 +4,30 @@
4
4
  <div class="header-content">
5
5
  <h2>
6
6
  <i class="fa fa-robot"></i>
7
- AI助手设置
7
+ {{ t.chatInterface.title }}{{ t.settings.title }}
8
8
  </h2>
9
9
  <div class="header-status">
10
10
  <div class="status-indicator" [class.enabled]="isEnabled">
11
11
  <i class="fa fa-power-off"></i>
12
- <span>{{ isEnabled ? '已启用' : '已禁用' }}</span>
12
+ <span>{{ isEnabled ? t.common.enabled : t.common.disabled }}</span>
13
13
  </div>
14
14
  <div class="provider-info" *ngIf="isEnabled">
15
15
  <i class="fa fa-cloud"></i>
16
- <span>当前提供商: {{ currentProvider }}</span>
16
+ <span>{{ t.advancedSettings.currentProvider }}: {{ currentProvider }}</span>
17
17
  </div>
18
18
  </div>
19
19
  </div>
20
20
  <div class="header-actions">
21
- <button class="btn-icon" (click)="toggleEnabled()" [title]="isEnabled ? '禁用AI助手' : '启用AI助手'">
21
+ <button class="btn-icon" (click)="toggleEnabled()" [title]="isEnabled ? t.common.disabled : t.common.enabled">
22
22
  <i [class]="isEnabled ? 'fa fa-pause' : 'fa fa-play'"></i>
23
23
  </button>
24
- <button class="btn-icon" (click)="refreshProviderStatus()" title="刷新状态">
24
+ <button class="btn-icon" (click)="refreshProviderStatus()" [title]="t.general.shortcutGenerate">
25
25
  <i class="fa fa-refresh"></i>
26
26
  </button>
27
- <button class="btn-icon" (click)="exportConfig()" title="导出配置">
27
+ <button class="btn-icon" (click)="exportConfig()" [title]="t.chatInterface.exportChat">
28
28
  <i class="fa fa-download"></i>
29
29
  </button>
30
- <button class="btn-icon" (click)="importConfig()" title="导入配置">
30
+ <button class="btn-icon" (click)="importConfig()" [title]="t.common.add">
31
31
  <i class="fa fa-upload"></i>
32
32
  </button>
33
33
  </div>
@@ -38,7 +38,7 @@
38
38
  <button *ngFor="let tab of tabs" class="tab-button" [class.active]="activeTab === tab.id"
39
39
  (click)="switchTab(tab.id)">
40
40
  <i [class]="tab.icon"></i>
41
- <span>{{ tab.label }}</span>
41
+ <span>{{ t[tab.labelKey.split('.')[0]][tab.labelKey.split('.')[1]] }}</span>
42
42
  </button>
43
43
  </div>
44
44
 
@@ -69,50 +69,50 @@
69
69
  <!-- 高级设置 -->
70
70
  <div *ngIf="activeTab === 'advanced'" class="tab-content">
71
71
  <div class="advanced-settings">
72
- <h3>高级设置</h3>
72
+ <h3>{{ t.advancedSettings.title }}</h3>
73
73
 
74
74
  <!-- 配置验证 -->
75
75
  <div class="settings-section">
76
- <h4>配置管理</h4>
76
+ <h4>{{ t.advancedSettings.configManagement }}</h4>
77
77
  <button class="btn btn-primary" (click)="validateConfig()">
78
78
  <i class="fa fa-check"></i>
79
- 验证配置
79
+ {{ t.advancedSettings.validateConfig }}
80
80
  </button>
81
81
  <button class="btn btn-warning" (click)="resetToDefaults()">
82
82
  <i class="fa fa-refresh"></i>
83
- 重置为默认
83
+ {{ t.advancedSettings.resetDefaults }}
84
84
  </button>
85
85
  </div>
86
86
 
87
87
  <!-- 日志设置 -->
88
88
  <div class="settings-section">
89
- <h4>日志设置</h4>
89
+ <h4>{{ t.advancedSettings.logSettings }}</h4>
90
90
  <div class="log-level-selector">
91
- <label>日志级别</label>
91
+ <label>{{ t.advancedSettings.logLevel }}</label>
92
92
  <select class="form-control" [(ngModel)]="config.logLevel"
93
93
  (change)="config.setLogLevel(config.logLevel)">
94
- <option value="debug">Debug (详细)</option>
95
- <option value="info">Info (信息)</option>
96
- <option value="warn">Warn (警告)</option>
97
- <option value="error">Error (错误)</option>
94
+ <option value="debug">{{ t.advancedSettings.logLevels.debug }}</option>
95
+ <option value="info">{{ t.advancedSettings.logLevels.info }}</option>
96
+ <option value="warn">{{ t.advancedSettings.logLevels.warn }}</option>
97
+ <option value="error">{{ t.advancedSettings.logLevels.error }}</option>
98
98
  </select>
99
99
  </div>
100
100
  </div>
101
101
 
102
102
  <!-- 系统信息 -->
103
103
  <div class="settings-section">
104
- <h4>系统信息</h4>
104
+ <h4>{{ t.advancedSettings.systemInfo }}</h4>
105
105
  <div class="system-info">
106
106
  <div class="info-item">
107
- <label>插件版本:</label>
108
- <span>1.0.0</span>
107
+ <label>{{ t.advancedSettings.pluginVersion }}:</label>
108
+ <span>{{ pluginVersion }}</span>
109
109
  </div>
110
110
  <div class="info-item">
111
- <label>支持的提供商:</label>
111
+ <label>{{ t.advancedSettings.supportedProviders }}:</label>
112
112
  <span>{{ providerStatus.count }}</span>
113
113
  </div>
114
114
  <div class="info-item">
115
- <label>当前提供商:</label>
115
+ <label>{{ t.advancedSettings.currentProvider }}:</label>
116
116
  <span>{{ currentProvider }}</span>
117
117
  </div>
118
118
  </div>
@@ -125,12 +125,12 @@
125
125
  <div class="disabled-message" *ngIf="!isEnabled">
126
126
  <div class="message-content">
127
127
  <i class="fa fa-pause-circle fa-3x"></i>
128
- <h3>AI助手已禁用</h3>
129
- <p>点击上方按钮启用AI助手功能</p>
128
+ <h3>{{ t.chatInterface.title }} {{ t.common.disabled }}</h3>
129
+ <p>{{ t.general.enableAssistantDesc }}</p>
130
130
  <button class="btn btn-primary" (click)="toggleEnabled()">
131
131
  <i class="fa fa-play"></i>
132
- 启用AI助手
132
+ {{ t.general.enableAssistant }}
133
133
  </button>
134
134
  </div>
135
135
  </div>
136
- </div>
136
+ </div>
@@ -24,7 +24,7 @@
24
24
  display: flex;
25
25
  align-items: center;
26
26
  gap: 0.5rem;
27
- color: var(--ai-dark);
27
+ color: var(--ai-text-primary);
28
28
 
29
29
  .icon-robot {
30
30
  font-size: 1.75rem;
@@ -58,12 +58,12 @@
58
58
  }
59
59
 
60
60
  &:not(.enabled) {
61
- color: var(--ai-secondary);
61
+ color: var(--ai-text-secondary);
62
62
  }
63
63
  }
64
64
 
65
65
  .provider-info {
66
- color: var(--ai-secondary);
66
+ color: var(--ai-text-secondary);
67
67
  }
68
68
  }
69
69
  }
@@ -83,11 +83,11 @@
83
83
  justify-content: center;
84
84
  cursor: pointer;
85
85
  transition: all 0.2s;
86
- color: var(--ai-secondary);
86
+ color: var(--ai-text-secondary);
87
87
 
88
88
  &:hover {
89
89
  background-color: var(--ai-border);
90
- color: var(--ai-dark);
90
+ color: var(--ai-text-primary);
91
91
  }
92
92
 
93
93
  .icon-refresh {
@@ -114,13 +114,13 @@
114
114
  gap: 0.5rem;
115
115
  cursor: pointer;
116
116
  transition: all 0.2s;
117
- color: var(--ai-secondary);
117
+ color: var(--ai-text-secondary);
118
118
  white-space: nowrap;
119
119
  font-size: 0.875rem;
120
120
  font-weight: 500;
121
121
 
122
122
  &:hover {
123
- color: var(--ai-dark);
123
+ color: var(--ai-text-primary);
124
124
  background-color: rgba(0, 0, 0, 0.05);
125
125
  }
126
126
 
@@ -158,7 +158,7 @@
158
158
  margin: 0 0 1.5rem 0;
159
159
  font-size: 1.25rem;
160
160
  font-weight: 600;
161
- color: var(--ai-dark);
161
+ color: var(--ai-text-primary);
162
162
  }
163
163
 
164
164
  .settings-section {
@@ -172,7 +172,7 @@
172
172
  margin: 0 0 1rem 0;
173
173
  font-size: 1.125rem;
174
174
  font-weight: 600;
175
- color: var(--ai-dark);
175
+ color: var(--ai-text-primary);
176
176
  }
177
177
 
178
178
  .btn {
@@ -200,7 +200,7 @@
200
200
 
201
201
  &.btn-warning {
202
202
  background-color: var(--ai-warning);
203
- color: var(--ai-dark);
203
+ color: var(--ai-text-primary);
204
204
 
205
205
  &:hover {
206
206
  background-color: #e0a800;
@@ -213,20 +213,34 @@
213
213
  display: block;
214
214
  font-weight: 500;
215
215
  margin-bottom: 0.5rem;
216
- color: var(--ai-dark);
216
+ color: var(--ai-text-primary);
217
217
  }
218
218
 
219
219
  .form-control {
220
220
  width: 200px;
221
- padding: 0.5rem 0.75rem;
222
- border: 1px solid var(--ai-border);
221
+ padding: 0.5rem 2rem 0.5rem 0.75rem;
222
+ border: 2px solid var(--ai-border);
223
223
  border-radius: 0.375rem;
224
- background-color: var(--ai-bg-primary);
225
- color: var(--ai-dark);
224
+ background-color: var(--ai-bg-secondary);
225
+ color: var(--ai-text-primary);
226
+ font-size: 0.875rem;
227
+ appearance: none;
228
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23adb5bd' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
229
+ background-repeat: no-repeat;
230
+ background-position: right 0.75rem center;
231
+ cursor: pointer;
226
232
 
227
233
  &:focus {
228
234
  outline: none;
229
235
  border-color: var(--ai-primary);
236
+ box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
237
+ }
238
+
239
+ // 下拉选项样式
240
+ option {
241
+ background-color: var(--ai-bg-secondary);
242
+ color: var(--ai-text-primary);
243
+ padding: 0.5rem;
230
244
  }
231
245
  }
232
246
  }
@@ -244,11 +258,11 @@
244
258
 
245
259
  label {
246
260
  font-weight: 500;
247
- color: var(--ai-dark);
261
+ color: var(--ai-text-primary);
248
262
  }
249
263
 
250
264
  span {
251
- color: var(--ai-secondary);
265
+ color: var(--ai-text-secondary);
252
266
  }
253
267
  }
254
268
  }
@@ -269,7 +283,7 @@
269
283
 
270
284
  .icon-pause-circle {
271
285
  font-size: 4rem;
272
- color: var(--ai-secondary);
286
+ color: var(--ai-text-secondary);
273
287
  margin-bottom: 1rem;
274
288
  }
275
289
 
@@ -277,12 +291,12 @@
277
291
  margin: 0 0 0.75rem 0;
278
292
  font-size: 1.5rem;
279
293
  font-weight: 600;
280
- color: var(--ai-dark);
294
+ color: var(--ai-text-primary);
281
295
  }
282
296
 
283
297
  p {
284
298
  margin: 0 0 2rem 0;
285
- color: var(--ai-secondary);
299
+ color: var(--ai-text-secondary);
286
300
  font-size: 1rem;
287
301
  }
288
302
 
@@ -1,38 +1,77 @@
1
- import { Component, OnInit } from '@angular/core';
1
+ import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core';
2
+ import { Subject } from 'rxjs';
3
+ import { takeUntil } from 'rxjs/operators';
2
4
  import { AiAssistantService } from '../../services/core/ai-assistant.service';
3
5
  import { ConfigProviderService } from '../../services/core/config-provider.service';
4
6
  import { LoggerService } from '../../services/core/logger.service';
7
+ import { TranslateService } from '../../i18n';
8
+
9
+ // 动态读取 package.json 中的版本号
10
+ declare const require: (path: string) => any;
11
+ const packageJson = require('../../../package.json');
12
+ const PLUGIN_VERSION = packageJson.version;
5
13
 
6
14
  @Component({
7
15
  selector: 'app-ai-settings-tab',
8
16
  templateUrl: './ai-settings-tab.component.html',
9
- styleUrls: ['./ai-settings-tab.component.scss']
17
+ styleUrls: ['./ai-settings-tab.component.scss'],
18
+ encapsulation: ViewEncapsulation.None
10
19
  })
11
- export class AiSettingsTabComponent implements OnInit {
20
+ export class AiSettingsTabComponent implements OnInit, OnDestroy {
12
21
  activeTab = 'general';
13
22
  isEnabled = true;
14
23
  currentProvider = '';
15
24
  providerStatus: any = {};
25
+ pluginVersion: string = PLUGIN_VERSION;
26
+
27
+ // 翻译对象
28
+ t: any;
29
+
30
+ // Tab 定义(使用翻译 key)
31
+ tabs: { id: string; labelKey: string; icon: string }[] = [];
16
32
 
17
- tabs = [
18
- { id: 'general', label: '基本设置', icon: 'fa fa-cog' },
19
- { id: 'providers', label: 'AI提供商', icon: 'fa fa-cloud' },
20
- { id: 'security', label: '安全设置', icon: 'fa fa-shield' },
21
- { id: 'chat', label: '聊天设置', icon: 'fa fa-comments' },
22
- { id: 'advanced', label: '高级设置', icon: 'fa fa-sliders' }
23
- ];
33
+ private destroy$ = new Subject<void>();
24
34
 
25
35
  constructor(
26
36
  private aiService: AiAssistantService,
27
37
  private config: ConfigProviderService,
28
- private logger: LoggerService
29
- ) { }
38
+ private logger: LoggerService,
39
+ private translate: TranslateService
40
+ ) {
41
+ this.t = this.translate.t;
42
+ }
30
43
 
31
44
  ngOnInit(): void {
45
+ // 监听语言变化
46
+ this.translate.translation$.pipe(
47
+ takeUntil(this.destroy$)
48
+ ).subscribe(translation => {
49
+ this.t = translation;
50
+ this.updateTabLabels();
51
+ });
52
+
32
53
  this.loadSettings();
33
54
  this.loadProviderStatus();
34
55
  }
35
56
 
57
+ ngOnDestroy(): void {
58
+ this.destroy$.next();
59
+ this.destroy$.complete();
60
+ }
61
+
62
+ /**
63
+ * 更新 Tab 标签
64
+ */
65
+ private updateTabLabels(): void {
66
+ this.tabs = [
67
+ { id: 'general', labelKey: 'settings.generalTab', icon: 'fa fa-cog' },
68
+ { id: 'providers', labelKey: 'settings.providersTab', icon: 'fa fa-cloud' },
69
+ { id: 'security', labelKey: 'settings.securityTab', icon: 'fa fa-shield' },
70
+ { id: 'chat', labelKey: 'settings.chatTab', icon: 'fa fa-comments' },
71
+ { id: 'advanced', labelKey: 'settings.advancedTab', icon: 'fa fa-sliders' }
72
+ ];
73
+ }
74
+
36
75
  /**
37
76
  * 加载设置
38
77
  */
@@ -115,7 +154,7 @@ export class AiSettingsTabComponent implements OnInit {
115
154
  * 获取提供商状态文本
116
155
  */
117
156
  getProviderStatusText(healthy: boolean): string {
118
- return healthy ? '正常' : '异常';
157
+ return healthy ? this.t.common.enabled : this.t.common.disabled;
119
158
  }
120
159
 
121
160
  /**
@@ -127,13 +166,13 @@ export class AiSettingsTabComponent implements OnInit {
127
166
  const invalidProviders = results.filter(r => !r.valid);
128
167
 
129
168
  if (invalidProviders.length > 0) {
130
- alert(`发现 ${invalidProviders.length} 个配置问题,请检查AI提供商设置。`);
169
+ alert(`${this.t.advancedSettings.validateConfig}: ${invalidProviders.length} ${this.t.chatSettings.resetConfirm}`);
131
170
  } else {
132
- alert('所有配置验证通过!');
171
+ alert(this.t.providers.testSuccess);
133
172
  }
134
173
  } catch (error) {
135
174
  this.logger.error('Failed to validate config', error);
136
- alert('配置验证失败,请检查日志。');
175
+ alert(this.t.chatInterface.errorPrefix);
137
176
  }
138
177
  }
139
178
 
@@ -166,11 +205,11 @@ export class AiSettingsTabComponent implements OnInit {
166
205
  try {
167
206
  const config = e.target?.result as string;
168
207
  this.config.importConfig(config);
169
- alert('配置导入成功,请重启插件生效。');
208
+ alert(this.t.providers.configSaved);
170
209
  this.loadSettings();
171
210
  this.loadProviderStatus();
172
211
  } catch (error) {
173
- alert('配置导入失败,请检查文件格式。');
212
+ alert(this.t.chatInterface.errorPrefix);
174
213
  }
175
214
  };
176
215
  reader.readAsText(file);
@@ -183,11 +222,11 @@ export class AiSettingsTabComponent implements OnInit {
183
222
  * 重置为默认配置
184
223
  */
185
224
  resetToDefaults(): void {
186
- if (confirm('确定要重置所有设置为默认值吗?此操作不可恢复。')) {
225
+ if (confirm(this.t.chatSettings.resetConfirm)) {
187
226
  this.config.reset();
188
227
  this.loadSettings();
189
228
  this.loadProviderStatus();
190
- alert('配置已重置为默认值。');
229
+ alert(this.t.providers.configSaved);
191
230
  }
192
231
  }
193
232
  }