27 files changed
+4521
-466
lib/core/components/app_text_field.dart
+10
-7
@@ -1,4 +1,5 @@
1
import 'package:flutter/material.dart';
2
+import 'package:localmind/l10n/app_localizations.dart';
3
4
import 'app_sizes.dart';
5
@@ -112,10 +113,11 @@ class AppDialog {
113
required BuildContext context,
114
required String title,
115
String? message,
115
- String confirmLabel = 'Confirm',
116
- String cancelLabel = 'Cancel',
116
+ String? confirmLabel,
117
+ String? cancelLabel,
118
bool destructive = false,
119
}) {
120
+ final l10n = AppLocalizations.of(context)!;
121
return showDialog<T>(
122
context: context,
123
builder: (ctx) => AlertDialog(
@@ -124,14 +126,14 @@ class AppDialog {
126
actions: [
127
TextButton(
128
onPressed: () => Navigator.pop(ctx),
127
- child: Text(cancelLabel),
129
+ child: Text(cancelLabel ?? l10n.cancel),
130
),
131
TextButton(
132
onPressed: () => Navigator.pop(ctx, true as T),
133
style: destructive
134
? TextButton.styleFrom(foregroundColor: Colors.red)
135
: null,
134
- child: Text(confirmLabel),
136
+ child: Text(confirmLabel ?? l10n.confirm),
137
),
138
],
139
),
@@ -143,8 +145,9 @@ class AppDialog {
145
required String title,
146
String? initialValue,
147
String? hintText,
146
- String confirmLabel = 'Save',
148
+ String? confirmLabel,
149
}) {
150
+ final l10n = AppLocalizations.of(context)!;
151
final controller = TextEditingController(text: initialValue);
152
return showDialog<String>(
153
context: context,
@@ -161,11 +164,11 @@ class AppDialog {
164
actions: [
165
TextButton(
166
onPressed: () => Navigator.pop(ctx),
164
- child: const Text('Cancel'),
167
+ child: Text(l10n.cancel),
168
),
169
TextButton(
170
onPressed: () => Navigator.pop(ctx, controller.text.trim()),
168
- child: Text(confirmLabel),
171
+ child: Text(confirmLabel ?? l10n.save),
172
),
173
],
174
),
lib/features/chat/views/chat_screen.dart
+259
-141
@@ -167,49 +167,82 @@ class _ChatScreenState extends ConsumerState<ChatScreen>
167
child: Column(
168
mainAxisSize: MainAxisSize.min,
169
children: [
170
- Center(child: Container(
171
- width: 40, height: 4,
172
- decoration: BoxDecoration(
173
- color: isDark ? Colors.grey[600] : Colors.grey[300],
174
- borderRadius: BorderRadius.circular(2),
170
+ Center(
171
+ child: Container(
172
+ width: 40,
173
+ height: 4,
174
+ decoration: BoxDecoration(
175
+ color: isDark ? Colors.grey[600] : Colors.grey[300],
176
+ borderRadius: BorderRadius.circular(2),
177
+ ),
178
),
176
- )),
179
+ ),
180
const SizedBox(height: 16),
178
- Text(sheetL10n.select_persona, style: TextStyle(
179
- fontSize: 18, fontWeight: FontWeight.bold,
180
- color: isDark ? Colors.white : Colors.black,
181
- )),
181
+ Text(
182
+ sheetL10n.select_persona,
183
+ style: TextStyle(
184
+ fontSize: 18,
185
+ fontWeight: FontWeight.bold,
186
+ color: isDark ? Colors.white : Colors.black,
187
+ ),
188
+ ),
189
const SizedBox(height: 8),
183
- Flexible(child: ListView.builder(
184
- shrinkWrap: true,
185
- itemCount: personas.length,
186
- itemBuilder: (context, index) {
187
- final p = personas[index];
188
- final isSelected = p.id == currentPersonaId;
189
- final accent = isDark ? AppColors.darkAccent : AppColors.lightAccent;
190
- return ListTile(
191
- leading: Text(p.emoji, style: const TextStyle(fontSize: 22)),
192
- title: Text(p.name, style: TextStyle(
193
- fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
194
- color: isDark ? Colors.white : Colors.black,
195
- )),
196
- subtitle: p.description != null
197
- ? Text(p.description!, style: TextStyle(
198
- fontSize: 12,
199
- color: isDark ? AppColors.darkMutedText : AppColors.lightMutedText,
200
- ), maxLines: 1, overflow: TextOverflow.ellipsis)
201
- : null,
202
- trailing: isSelected ? Icon(Icons.check_circle, color: accent) : null,
203
- onTap: () {
204
- if (activeConv != null) {
205
- ref.read(conv.conversationsProvider.notifier)
206
- .updatePersona(activeConv.id, p.id, p.systemPrompt);
207
- }
208
- Navigator.pop(ctx);
209
- },
210
- );
211
- },
212
- )),
190
+ Flexible(
191
+ child: ListView.builder(
192
+ shrinkWrap: true,
193
+ itemCount: personas.length,
194
+ itemBuilder: (context, index) {
195
+ final p = personas[index];
196
+ final isSelected = p.id == currentPersonaId;
197
+ final accent = isDark
198
+ ? AppColors.darkAccent
199
+ : AppColors.lightAccent;
200
+ return ListTile(
201
+ leading: Text(
202
+ p.emoji,
203
+ style: const TextStyle(fontSize: 22),
204
+ ),
205
+ title: Text(
206
+ p.name,
207
+ style: TextStyle(
208
+ fontWeight: isSelected
209
+ ? FontWeight.w600
210
+ : FontWeight.normal,
211
+ color: isDark ? Colors.white : Colors.black,
212
+ ),
213
+ ),
214
+ subtitle: p.description != null
215
+ ? Text(
216
+ p.description!,
217
+ style: TextStyle(
218
+ fontSize: 12,
219
+ color: isDark
220
+ ? AppColors.darkMutedText
221
+ : AppColors.lightMutedText,
222
+ ),
223
+ maxLines: 1,
224
+ overflow: TextOverflow.ellipsis,
225
+ )
226
+ : null,
227
+ trailing: isSelected
228
+ ? Icon(Icons.check_circle, color: accent)
229
+ : null,
230
+ onTap: () {
231
+ if (activeConv != null) {
232
+ ref
233
+ .read(conv.conversationsProvider.notifier)
234
+ .updatePersona(
235
+ activeConv.id,
236
+ p.id,
237
+ p.systemPrompt,
238
+ );
239
+ }
240
+ Navigator.pop(ctx);
241
+ },
242
+ );
243
+ },
244
+ ),
245
+ ),
246
],
247
),
248
),
@@ -218,22 +251,27 @@ class _ChatScreenState extends ConsumerState<ChatScreen>
251
);
252
}
253
221
- void _showToolApprovalDialog(BuildContext context, PendingToolApproval approval) {
254
+ void _showToolApprovalDialog(
255
+ BuildContext context,
256
+ PendingToolApproval approval,
257
+ ) {
258
setState(() => _isApprovalDialogOpen = true);
259
+ final l10n = AppLocalizations.of(context)!;
260
261
showShadDialog<bool>(
262
context: context,
263
barrierDismissible: false,
264
builder: (context) => ShadDialog.alert(
228
- title: Text('Execute Tool: ${approval.toolCall.name}?'),
265
+ title: Text('${l10n.execute_tool_title}: ${approval.toolCall.name}?'),
266
description: Column(
267
crossAxisAlignment: CrossAxisAlignment.start,
268
mainAxisSize: MainAxisSize.min,
269
children: [
233
- const Text('The model is requesting to execute the following tool:'),
270
+ Text(l10n.execute_tool_request_desc),
271
const SizedBox(height: 8),
272
Container(
236
- width: double.infinity, padding: const EdgeInsets.all(8),
273
+ width: double.infinity,
274
+ padding: const EdgeInsets.all(8),
275
decoration: BoxDecoration(
276
color: Theme.of(context).colorScheme.surfaceContainer,
277
borderRadius: BorderRadius.circular(8),
@@ -241,7 +279,9 @@ class _ChatScreenState extends ConsumerState<ChatScreen>
279
child: SingleChildScrollView(
280
scrollDirection: Axis.horizontal,
281
child: Text(
244
- const JsonEncoder.withIndent(' ').convert(approval.toolCall.arguments),
282
+ const JsonEncoder.withIndent(
283
+ ' ',
284
+ ).convert(approval.toolCall.arguments),
285
style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
286
),
287
),
@@ -250,11 +290,11 @@ class _ChatScreenState extends ConsumerState<ChatScreen>
290
),
291
actions: [
292
ShadButton.outline(
253
- child: const Text('Reject'),
293
+ child: Text(l10n.reject),
294
onPressed: () => Navigator.of(context).pop(false),
295
),
296
ShadButton(
257
- child: const Text('Approve'),
297
+ child: Text(l10n.approve),
298
onPressed: () => Navigator.of(context).pop(true),
299
),
300
],
@@ -302,7 +342,9 @@ class _ChatBody extends ConsumerWidget {
342
: null;
343
final keyboardBottomInset = bottomKeyboardInset(context);
344
final systemBottomInset = bottomSystemInset(context);
305
- final effectiveBottomInset = keyboardBottomInset > 0 ? 0.0 : systemBottomInset;
345
+ final effectiveBottomInset = keyboardBottomInset > 0
346
+ ? 0.0
347
+ : systemBottomInset;
348
349
final needsScroll = autoScroll.checkAndUpdate(
350
messageCount: messages.length,
@@ -311,7 +353,8 @@ class _ChatBody extends ConsumerWidget {
353
);
354
if (needsScroll) {
355
autoScroll.scheduleAutoScroll(
314
- controller: scrollController, streaming: isStreaming,
356
+ controller: scrollController,
357
+ streaming: isStreaming,
358
);
359
}
360
@@ -337,7 +380,8 @@ class _ChatBody extends ConsumerWidget {
380
onRemove: () {
381
final activeConv = ref.read(conv.activeConversationProvider);
382
if (activeConv != null) {
340
- ref.read(conv.conversationsProvider.notifier)
383
+ ref
384
+ .read(conv.conversationsProvider.notifier)
385
.updatePersona(activeConv.id, null, null);
386
}
387
},
@@ -389,49 +433,82 @@ void _openPersonaPicker(BuildContext context, WidgetRef ref) {
433
child: Column(
434
mainAxisSize: MainAxisSize.min,
435
children: [
392
- Center(child: Container(
393
- width: 40, height: 4,
394
- decoration: BoxDecoration(
395
- color: isDark ? Colors.grey[600] : Colors.grey[300],
396
- borderRadius: BorderRadius.circular(2),
436
+ Center(
437
+ child: Container(
438
+ width: 40,
439
+ height: 4,
440
+ decoration: BoxDecoration(
441
+ color: isDark ? Colors.grey[600] : Colors.grey[300],
442
+ borderRadius: BorderRadius.circular(2),
443
+ ),
444
),
398
- )),
445
+ ),
446
const SizedBox(height: 16),
400
- Text(sheetL10n.select_persona, style: TextStyle(
401
- fontSize: 18, fontWeight: FontWeight.bold,
402
- color: isDark ? Colors.white : Colors.black,
403
- )),
447
+ Text(
448
+ sheetL10n.select_persona,
449
+ style: TextStyle(
450
+ fontSize: 18,
451
+ fontWeight: FontWeight.bold,
452
+ color: isDark ? Colors.white : Colors.black,
453
+ ),
454
+ ),
455
const SizedBox(height: 8),
405
- Flexible(child: ListView.builder(
406
- shrinkWrap: true,
407
- itemCount: personas.length,
408
- itemBuilder: (context, index) {
409
- final p = personas[index];
410
- final isSelected = p.id == currentPersonaId;
411
- final accent = isDark ? AppColors.darkAccent : AppColors.lightAccent;
412
- return ListTile(
413
- leading: Text(p.emoji, style: const TextStyle(fontSize: 22)),
414
- title: Text(p.name, style: TextStyle(
415
- fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
416
- color: isDark ? Colors.white : Colors.black,
417
- )),
418
- subtitle: p.description != null
419
- ? Text(p.description!, style: TextStyle(
420
- fontSize: 12,
421
- color: isDark ? AppColors.darkMutedText : AppColors.lightMutedText,
422
- ), maxLines: 1, overflow: TextOverflow.ellipsis)
423
- : null,
424
- trailing: isSelected ? Icon(Icons.check_circle, color: accent) : null,
425
- onTap: () {
426
- if (activeConv != null) {
427
- ref.read(conv.conversationsProvider.notifier)
428
- .updatePersona(activeConv.id, p.id, p.systemPrompt);
429
- }
430
- Navigator.pop(ctx);
431
- },
432
- );
433
- },
434
- )),
456
+ Flexible(
457
+ child: ListView.builder(
458
+ shrinkWrap: true,
459
+ itemCount: personas.length,
460
+ itemBuilder: (context, index) {
461
+ final p = personas[index];
462
+ final isSelected = p.id == currentPersonaId;
463
+ final accent = isDark
464
+ ? AppColors.darkAccent
465
+ : AppColors.lightAccent;
466
+ return ListTile(
467
+ leading: Text(
468
+ p.emoji,
469
+ style: const TextStyle(fontSize: 22),
470
+ ),
471
+ title: Text(
472
+ p.name,
473
+ style: TextStyle(
474
+ fontWeight: isSelected
475
+ ? FontWeight.w600
476
+ : FontWeight.normal,
477
+ color: isDark ? Colors.white : Colors.black,
478
+ ),
479
+ ),
480
+ subtitle: p.description != null
481
+ ? Text(
482
+ p.description!,
483
+ style: TextStyle(
484
+ fontSize: 12,
485
+ color: isDark
486
+ ? AppColors.darkMutedText
487
+ : AppColors.lightMutedText,
488
+ ),
489
+ maxLines: 1,
490
+ overflow: TextOverflow.ellipsis,
491
+ )
492
+ : null,
493
+ trailing: isSelected
494
+ ? Icon(Icons.check_circle, color: accent)
495
+ : null,
496
+ onTap: () {
497
+ if (activeConv != null) {
498
+ ref
499
+ .read(conv.conversationsProvider.notifier)
500
+ .updatePersona(
501
+ activeConv.id,
502
+ p.id,
503
+ p.systemPrompt,
504
+ );
505
+ }
506
+ Navigator.pop(ctx);
507
+ },
508
+ );
509
+ },
510
+ ),
511
+ ),
512
],
513
),
514
),
@@ -546,46 +623,74 @@ void _openPersonaPickerForPreselection(BuildContext context, WidgetRef ref) {
623
child: Column(
624
mainAxisSize: MainAxisSize.min,
625
children: [
549
- Center(child: Container(
550
- width: 40, height: 4,
551
- decoration: BoxDecoration(
552
- color: isDark ? Colors.grey[600] : Colors.grey[300],
553
- borderRadius: BorderRadius.circular(2),
626
+ Center(
627
+ child: Container(
628
+ width: 40,
629
+ height: 4,
630
+ decoration: BoxDecoration(
631
+ color: isDark ? Colors.grey[600] : Colors.grey[300],
632
+ borderRadius: BorderRadius.circular(2),
633
+ ),
634
),
555
- )),
635
+ ),
636
const SizedBox(height: 16),
557
- Text(sheetL10n.select_persona, style: TextStyle(
558
- fontSize: 18, fontWeight: FontWeight.bold,
559
- color: isDark ? Colors.white : Colors.black,
560
- )),
637
+ Text(
638
+ sheetL10n.select_persona,
639
+ style: TextStyle(
640
+ fontSize: 18,
641
+ fontWeight: FontWeight.bold,
642
+ color: isDark ? Colors.white : Colors.black,
643
+ ),
644
+ ),
645
const SizedBox(height: 8),
562
- Flexible(child: ListView.builder(
563
- shrinkWrap: true,
564
- itemCount: personas.length,
565
- itemBuilder: (context, index) {
566
- final p = personas[index];
567
- final isSelected = p.id == currentPersona?.id;
568
- final accent = isDark ? AppColors.darkAccent : AppColors.lightAccent;
569
- return ListTile(
570
- leading: Text(p.emoji, style: const TextStyle(fontSize: 22)),
571
- title: Text(p.name, style: TextStyle(
572
- fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
573
- color: isDark ? Colors.white : Colors.black,
574
- )),
575
- subtitle: p.description != null
576
- ? Text(p.description!, style: TextStyle(
577
- fontSize: 12,
578
- color: isDark ? AppColors.darkMutedText : AppColors.lightMutedText,
579
- ), maxLines: 1, overflow: TextOverflow.ellipsis)
580
- : null,
581
- trailing: isSelected ? Icon(Icons.check_circle, color: accent) : null,
582
- onTap: () {
583
- ref.read(selectedPersonaProvider.notifier).select(p);
584
- Navigator.pop(ctx);
585
- },
586
- );
587
- },
588
- )),
646
+ Flexible(
647
+ child: ListView.builder(
648
+ shrinkWrap: true,
649
+ itemCount: personas.length,
650
+ itemBuilder: (context, index) {
651
+ final p = personas[index];
652
+ final isSelected = p.id == currentPersona?.id;
653
+ final accent = isDark
654
+ ? AppColors.darkAccent
655
+ : AppColors.lightAccent;
656
+ return ListTile(
657
+ leading: Text(
658
+ p.emoji,
659
+ style: const TextStyle(fontSize: 22),
660
+ ),
661
+ title: Text(
662
+ p.name,
663
+ style: TextStyle(
664
+ fontWeight: isSelected
665
+ ? FontWeight.w600
666
+ : FontWeight.normal,
667
+ color: isDark ? Colors.white : Colors.black,
668
+ ),
669
+ ),
670
+ subtitle: p.description != null
671
+ ? Text(
672
+ p.description!,
673
+ style: TextStyle(
674
+ fontSize: 12,
675
+ color: isDark
676
+ ? AppColors.darkMutedText
677
+ : AppColors.lightMutedText,
678
+ ),
679
+ maxLines: 1,
680
+ overflow: TextOverflow.ellipsis,
681
+ )
682
+ : null,
683
+ trailing: isSelected
684
+ ? Icon(Icons.check_circle, color: accent)
685
+ : null,
686
+ onTap: () {
687
+ ref.read(selectedPersonaProvider.notifier).select(p);
688
+ Navigator.pop(ctx);
689
+ },
690
+ );
691
+ },
692
+ ),
693
+ ),
694
],
695
),
696
),
@@ -625,7 +730,8 @@ class _ScreenAppBar extends ConsumerWidget {
730
children: [
731
ShadResponsiveBuilder(
732
builder: (context, breakpoint) {
628
- final isDesktop = breakpoint >= ShadTheme.of(context).breakpoints.md;
733
+ final isDesktop =
734
+ breakpoint >= ShadTheme.of(context).breakpoints.md;
735
if (isDesktop) return const SizedBox.shrink();
736
return IconButton(
737
icon: const Icon(Icons.menu),
@@ -643,15 +749,20 @@ class _ScreenAppBar extends ConsumerWidget {
749
],
750
Text(
751
activeServer?.name ?? l10n.chat_title,
646
- style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
752
+ style: const TextStyle(
753
+ fontSize: 18,
754
+ fontWeight: FontWeight.bold,
755
+ ),
756
),
757
const SizedBox(width: 8),
758
Container(
650
- width: 8, height: 8,
759
+ width: 8,
760
+ height: 8,
761
decoration: BoxDecoration(
762
shape: BoxShape.circle,
763
color: connectionStatus == ConnectionStatus.connected
654
- ? Colors.green : Colors.grey,
764
+ ? Colors.green
765
+ : Colors.grey,
766
),
767
),
768
],
@@ -665,11 +776,13 @@ class _ScreenAppBar extends ConsumerWidget {
776
size: 24,
777
color: isDark ? Colors.white70 : Colors.black87,
778
),
668
- onPressed: () => showChatSettingsSheet(context, initialTab: 'parameters'),
779
+ onPressed: () =>
780
+ showChatSettingsSheet(context, initialTab: 'parameters'),
781
tooltip: l10n.chat_parameters_tooltip,
782
),
783
PositionedDirectional(
672
- top: 4, end: 0,
784
+ top: 4,
785
+ end: 0,
786
child: Container(
787
padding: const EdgeInsets.all(2),
788
decoration: BoxDecoration(
@@ -678,7 +791,8 @@ class _ScreenAppBar extends ConsumerWidget {
791
),
792
child: const HugeIcon(
793
icon: HugeIcons.strokeRoundedTools,
681
- size: 10, color: Colors.white,
794
+ size: 10,
795
+ color: Colors.white,
796
),
797
),
798
),
@@ -699,10 +813,14 @@ class _ScreenAppBar extends ConsumerWidget {
813
PopupMenuItem(
814
value: 'persona',
815
child: ListTile(
702
- leading: Icon(persona != null
703
- ? Icons.swap_horiz : Icons.smart_toy_outlined),
704
- title: Text(persona != null
705
- ? l10n.change_persona : l10n.set_persona),
816
+ leading: Icon(
817
+ persona != null
818
+ ? Icons.swap_horiz
819
+ : Icons.smart_toy_outlined,
820
+ ),
821
+ title: Text(
822
+ persona != null ? l10n.change_persona : l10n.set_persona,
823
+ ),
824
contentPadding: EdgeInsets.zero,
825
),
826
),
@@ -788,9 +906,9 @@ class _ChatBottomBar extends ConsumerWidget {
906
focusNode: inputFocusNode,
907
isStreaming: isStreaming,
908
onSend: (message, {attachments}) {
791
- ref.read(chatProvider.notifier).sendMessage(
792
- message, attachments: attachments,
793
- );
909
+ ref
910
+ .read(chatProvider.notifier)
911
+ .sendMessage(message, attachments: attachments);
912
},
913
onStop: () => ref.read(chatProvider.notifier).cancelStream(),
914
),
lib/features/chat/views/components/chat_bubble/tool_bubble/tool_row.dart
+77
-37
@@ -3,6 +3,7 @@ import 'package:localmind/core/theme/colors.dart';
3
import 'package:localmind/features/chat/data/tools/tool_event.dart';
4
import 'package:localmind/features/chat/data/tools/tool_definition.dart';
5
import 'package:localmind/features/chat/data/models/grouped_tool_call.dart';
6
+import 'package:localmind/l10n/app_localizations.dart';
7
import 'tool_inline_badge.dart';
8
9
class ToolRowWidget extends StatefulWidget {
@@ -27,7 +28,8 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
28
@override
29
void initState() {
30
super.initState();
30
- _isExpanded = widget.call.status == ToolEventStatus.running ||
31
+ _isExpanded =
32
+ widget.call.status == ToolEventStatus.running ||
33
widget.call.status == ToolEventStatus.failed ||
34
widget.call.status == ToolEventStatus.requested ||
35
widget.call.status == ToolEventStatus.approved;
@@ -50,27 +52,31 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
52
53
@override
54
Widget build(BuildContext context) {
55
+ final l10n = AppLocalizations.of(context)!;
56
final call = widget.call;
57
final isDark = widget.isDark;
58
final isMcpTool = call.providerType == ToolProviderType.mcp;
59
60
final iconColor = switch (call.status) {
61
ToolEventStatus.completed => const Color(0xFF22C55E),
59
- ToolEventStatus.failed || ToolEventStatus.rejected => const Color(0xFFEF4444),
62
+ ToolEventStatus.failed ||
63
+ ToolEventStatus.rejected => const Color(0xFFEF4444),
64
ToolEventStatus.running => AppColors.darkAccent,
61
- ToolEventStatus.requested || ToolEventStatus.approved => const Color(0xFFF59E0B),
65
+ ToolEventStatus.requested ||
66
+ ToolEventStatus.approved => const Color(0xFFF59E0B),
67
};
68
69
final statusLabel = switch (call.status) {
65
- ToolEventStatus.requested => 'Requested',
66
- ToolEventStatus.approved => 'Approved',
67
- ToolEventStatus.rejected => 'Rejected',
68
- ToolEventStatus.running => 'Running',
69
- ToolEventStatus.completed => 'Done',
70
- ToolEventStatus.failed => 'Failed',
70
+ ToolEventStatus.requested => l10n.tool_status_requested,
71
+ ToolEventStatus.approved => l10n.tool_status_approved,
72
+ ToolEventStatus.rejected => l10n.tool_status_rejected,
73
+ ToolEventStatus.running => l10n.tool_status_running,
74
+ ToolEventStatus.completed => l10n.tool_status_done,
75
+ ToolEventStatus.failed => l10n.tool_status_failed,
76
};
77
73
- final showCodeBlock = (call.arguments != null && call.arguments!.isNotEmpty) ||
78
+ final showCodeBlock =
79
+ (call.arguments != null && call.arguments!.isNotEmpty) ||
80
(call.result != null && call.result!.isNotEmpty) ||
81
(call.error != null && call.error!.isNotEmpty);
82
@@ -94,8 +100,10 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
100
else
101
Icon(
102
switch (call.status) {
97
- ToolEventStatus.requested => Icons.hourglass_empty_rounded,
98
- ToolEventStatus.approved => Icons.check_circle_outline_rounded,
103
+ ToolEventStatus.requested =>
104
+ Icons.hourglass_empty_rounded,
105
+ ToolEventStatus.approved =>
106
+ Icons.check_circle_outline_rounded,
107
ToolEventStatus.rejected => Icons.block_flipped,
108
ToolEventStatus.running => Icons.cached_rounded,
109
ToolEventStatus.completed => Icons.check_circle_rounded,
@@ -124,26 +132,41 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
132
if (isMcpTool) ...[
133
InlineToolBadge(
134
label: 'MCP',
127
- backgroundColor: Colors.purple.withValues(alpha: isDark ? 0.2 : 0.1),
128
- textColor: isDark ? const Color(0xFFC084FC) : const Color(0xFF7E22CE),
135
+ backgroundColor: Colors.purple.withValues(
136
+ alpha: isDark ? 0.2 : 0.1,
137
+ ),
138
+ textColor: isDark
139
+ ? const Color(0xFFC084FC)
140
+ : const Color(0xFF7E22CE),
141
),
130
- ] else if (call.providerType == ToolProviderType.lmStudioServer) ...[
142
+ ] else if (call.providerType ==
143
+ ToolProviderType.lmStudioServer) ...[
144
InlineToolBadge(
145
label: 'LM Studio',
133
- backgroundColor: Colors.orange.withValues(alpha: isDark ? 0.2 : 0.1),
134
- textColor: isDark ? const Color(0xFFF97316) : const Color(0xFFC2410C),
146
+ backgroundColor: Colors.orange.withValues(
147
+ alpha: isDark ? 0.2 : 0.1,
148
+ ),
149
+ textColor: isDark
150
+ ? const Color(0xFFF97316)
151
+ : const Color(0xFFC2410C),
152
),
153
] else ...[
154
InlineToolBadge(
138
- label: 'LOCAL',
139
- backgroundColor: Colors.blue.withValues(alpha: isDark ? 0.2 : 0.1),
140
- textColor: isDark ? const Color(0xFF60A5FA) : const Color(0xFF1D4ED8),
155
+ label: l10n.local_label,
156
+ backgroundColor: Colors.blue.withValues(
157
+ alpha: isDark ? 0.2 : 0.1,
158
+ ),
159
+ textColor: isDark
160
+ ? const Color(0xFF60A5FA)
161
+ : const Color(0xFF1D4ED8),
162
),
163
],
164
const SizedBox(width: 6),
165
InlineToolBadge(
166
label: statusLabel,
146
- backgroundColor: iconColor.withValues(alpha: isDark ? 0.15 : 0.1),
167
+ backgroundColor: iconColor.withValues(
168
+ alpha: isDark ? 0.15 : 0.1,
169
+ ),
170
textColor: iconColor,
171
),
172
],
@@ -155,7 +178,9 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
178
'${call.durationMs}ms',
179
style: TextStyle(
180
fontSize: 10,
158
- color: isDark ? AppColors.darkMutedText : AppColors.lightMutedText,
181
+ color: isDark
182
+ ? AppColors.darkMutedText
183
+ : AppColors.lightMutedText,
184
),
185
),
186
],
@@ -166,7 +191,9 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
191
? Icons.keyboard_arrow_up_rounded
192
: Icons.keyboard_arrow_down_rounded,
193
size: 16,
169
- color: isDark ? AppColors.darkMutedText : AppColors.lightMutedText,
194
+ color: isDark
195
+ ? AppColors.darkMutedText
196
+ : AppColors.lightMutedText,
197
),
198
],
199
],
@@ -180,22 +207,29 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
207
width: double.infinity,
208
padding: const EdgeInsets.all(8),
209
decoration: BoxDecoration(
183
- color: isDark ? const Color(0xFF0F172A) : const Color(0xFFF1F5F9),
210
+ color: isDark
211
+ ? const Color(0xFF0F172A)
212
+ : const Color(0xFFF1F5F9),
213
borderRadius: BorderRadius.circular(8),
214
border: Border.all(
186
- color: isDark ? const Color(0xFF1E293B) : const Color(0xFFE2E8F0),
215
+ color: isDark
216
+ ? const Color(0xFF1E293B)
217
+ : const Color(0xFFE2E8F0),
218
),
219
),
220
child: Column(
221
crossAxisAlignment: CrossAxisAlignment.start,
222
children: [
192
- if (call.arguments != null && call.arguments!.isNotEmpty) ...[
223
+ if (call.arguments != null &&
224
+ call.arguments!.isNotEmpty) ...[
225
Text(
226
'Arguments:',
227
style: TextStyle(
228
fontSize: 9,
229
fontWeight: FontWeight.bold,
198
- color: isDark ? const Color(0xFF38BDF8) : const Color(0xFF0284C7),
230
+ color: isDark
231
+ ? const Color(0xFF38BDF8)
232
+ : const Color(0xFF0284C7),
233
fontFamily: 'monospace',
234
),
235
),
@@ -204,7 +238,9 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
238
widget.formatArgs(call.arguments!),
239
style: TextStyle(
240
fontSize: 10.5,
207
- color: isDark ? const Color(0xFFCBD5E1) : const Color(0xFF475569),
241
+ color: isDark
242
+ ? const Color(0xFFCBD5E1)
243
+ : const Color(0xFF475569),
244
fontFamily: 'monospace',
245
height: 1.3,
246
),
@@ -218,7 +254,9 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
254
style: TextStyle(
255
fontSize: 9,
256
fontWeight: FontWeight.bold,
221
- color: isDark ? const Color(0xFF4ADE80) : const Color(0xFF16A34A),
257
+ color: isDark
258
+ ? const Color(0xFF4ADE80)
259
+ : const Color(0xFF16A34A),
260
fontFamily: 'monospace',
261
),
262
),
@@ -227,7 +265,9 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
265
call.result!,
266
style: TextStyle(
267
fontSize: 10.5,
230
- color: isDark ? const Color(0xFFF8FAFC) : const Color(0xFF0F172A),
268
+ color: isDark
269
+ ? const Color(0xFFF8FAFC)
270
+ : const Color(0xFF0F172A),
271
fontFamily: 'monospace',
272
height: 1.3,
273
),
@@ -241,7 +281,9 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
281
style: TextStyle(
282
fontSize: 9,
283
fontWeight: FontWeight.bold,
244
- color: isDark ? const Color(0xFFF87171) : const Color(0xFFDC2626),
284
+ color: isDark
285
+ ? const Color(0xFFF87171)
286
+ : const Color(0xFFDC2626),
287
fontFamily: 'monospace',
288
),
289
),
@@ -250,7 +292,9 @@ class _ToolRowWidgetState extends State<ToolRowWidget> {
292
call.error!,
293
style: TextStyle(
294
fontSize: 10.5,
253
- color: isDark ? const Color(0xFFFCA5A5) : const Color(0xFF991B1B),
295
+ color: isDark
296
+ ? const Color(0xFFFCA5A5)
297
+ : const Color(0xFF991B1B),
298
fontFamily: 'monospace',
299
height: 1.3,
300
),
@@ -297,11 +341,7 @@ class _AnimatedRunningIconState extends State<_AnimatedRunningIcon>
341
Widget build(BuildContext context) {
342
return RotationTransition(
343
turns: _controller,
300
- child: Icon(
301
- Icons.cached_rounded,
302
- size: 14,
303
- color: widget.color,
304
- ),
344
+ child: Icon(Icons.cached_rounded, size: 14, color: widget.color),
345
);
346
}
347
}
lib/features/mcp/views/mcp_tools_screen.dart
+86
-81
@@ -2,6 +2,7 @@ import "package:localmind/core/theme/colors.dart";
2
import 'package:flutter/material.dart';
3
import 'package:flutter_riverpod/flutter_riverpod.dart';
4
import 'package:hugeicons/hugeicons.dart';
5
+import 'package:localmind/l10n/app_localizations.dart';
6
import 'package:shadcn_ui/shadcn_ui.dart';
7
8
import '../../chat/data/mcp_server_manager.dart';
@@ -47,6 +48,7 @@ class _McpToolsScreenState extends ConsumerState<McpToolsScreen> {
48
49
@override
50
Widget build(BuildContext context) {
51
+ final l10n = AppLocalizations.of(context)!;
52
final theme = Theme.of(context);
53
final isDark = theme.brightness == Brightness.dark;
54
final manager = ref.watch(mcpServerManagerProvider);
@@ -62,95 +64,94 @@ class _McpToolsScreenState extends ConsumerState<McpToolsScreen> {
64
top: topPadding + 8,
65
bottom: 16,
66
),
65
- decoration: BoxDecoration(
66
- color: isDark ? const Color(0xFF0A0A0A) : const Color(0xFFFAFAFA),
67
- border: Border(
68
- bottom: BorderSide(
69
- color: isDark
70
- ? const Color(0xFF2A2A2A)
71
- : const Color(0xFFE5E5E5),
72
- ),
67
+ decoration: BoxDecoration(
68
+ color: isDark ? const Color(0xFF0A0A0A) : const Color(0xFFFAFAFA),
69
+ border: Border(
70
+ bottom: BorderSide(
71
+ color: isDark
72
+ ? const Color(0xFF2A2A2A)
73
+ : const Color(0xFFE5E5E5),
74
),
75
),
75
- child: Row(
76
+ ),
77
+ child: Row(
78
+ children: [
79
+ Builder(
80
+ builder: (context) => IconButton(
81
+ icon: const Icon(Icons.menu),
82
+ onPressed: () => Scaffold.of(context).openDrawer(),
83
+ ),
84
+ ),
85
+ const SizedBox(width: 8),
86
+ Text(
87
+ l10n.mcp_tools_title,
88
+ style: TextStyle(
89
+ fontSize: 20,
90
+ fontWeight: FontWeight.bold,
91
+ color: isDark ? Colors.white : Colors.black,
92
+ ),
93
+ ),
94
+ ],
95
+ ),
96
+ ),
97
+ Expanded(
98
+ child: RefreshIndicator(
99
+ onRefresh: () async => _refreshTools(),
100
+ child: ListView(
101
+ padding: const EdgeInsets.all(16),
102
children: [
77
- Builder(
78
- builder: (context) => IconButton(
79
- icon: const Icon(Icons.menu),
80
- onPressed: () => Scaffold.of(context).openDrawer(),
81
- ),
103
+ _ExampleServerPanel(
104
+ enabled: hasExampleServer,
105
+ onToggle: _toggleExampleServer,
106
),
83
- const SizedBox(width: 8),
107
+ const SizedBox(height: 20),
108
Text(
85
- 'MCP Tools',
86
- style: TextStyle(
87
- fontSize: 20,
88
- fontWeight: FontWeight.bold,
89
- color: isDark ? Colors.white : Colors.black,
109
+ l10n.available_tools,
110
+ style: theme.textTheme.titleMedium?.copyWith(
111
+ fontWeight: FontWeight.w700,
112
),
113
),
92
- ],
93
- ),
94
- ),
95
- Expanded(
96
- child: RefreshIndicator(
97
- onRefresh: () async => _refreshTools(),
98
- child: ListView(
99
- padding: const EdgeInsets.all(16),
100
- children: [
101
- _ExampleServerPanel(
102
- enabled: hasExampleServer,
103
- onToggle: _toggleExampleServer,
104
- ),
105
- const SizedBox(height: 20),
106
- Text(
107
- 'Available tools',
108
- style: theme.textTheme.titleMedium?.copyWith(
109
- fontWeight: FontWeight.w700,
110
- ),
111
- ),
112
- const SizedBox(height: 12),
113
- FutureBuilder<List<ToolDefinition>>(
114
- future: _toolsFuture,
115
- builder: (context, snapshot) {
116
- if (snapshot.connectionState == ConnectionState.waiting) {
117
- return const Center(
118
- child: Padding(
119
- padding: EdgeInsets.all(32),
120
- child: CircularProgressIndicator(),
121
- ),
122
- );
123
- }
124
-
125
- if (snapshot.hasError) {
126
- return _StatusPanel(
127
- icon: Icons.error_outline,
128
- title: 'Unable to load tools',
129
- body: snapshot.error.toString(),
130
- );
131
- }
114
+ const SizedBox(height: 12),
115
+ FutureBuilder<List<ToolDefinition>>(
116
+ future: _toolsFuture,
117
+ builder: (context, snapshot) {
118
+ if (snapshot.connectionState == ConnectionState.waiting) {
119
+ return const Center(
120
+ child: Padding(
121
+ padding: EdgeInsets.all(32),
122
+ child: CircularProgressIndicator(),
123
+ ),
124
+ );
125
+ }
126
133
- final tools = snapshot.data ?? const <ToolDefinition>[];
134
- if (tools.isEmpty) {
135
- return const _StatusPanel(
136
- icon: Icons.extension_outlined,
137
- title: 'No tools registered',
138
- body:
139
- 'Enable the example MCP server or add MCP integrations from chat settings.',
140
- );
141
- }
127
+ if (snapshot.hasError) {
128
+ return _StatusPanel(
129
+ icon: Icons.error_outline,
130
+ title: l10n.unable_load_tools,
131
+ body: snapshot.error.toString(),
132
+ );
133
+ }
134
143
- return Column(
144
- children: tools
145
- .map((tool) => _ToolRow(tool: tool))
146
- .toList(growable: false),
135
+ final tools = snapshot.data ?? const <ToolDefinition>[];
136
+ if (tools.isEmpty) {
137
+ return _StatusPanel(
138
+ icon: Icons.extension_outlined,
139
+ title: l10n.no_tools_registered,
140
+ body: l10n.no_tools_registered_desc,
141
);
148
- },
149
- ),
150
- ],
151
- ),
142
+ }
143
+
144
+ return Column(
145
+ children: tools
146
+ .map((tool) => _ToolRow(tool: tool))
147
+ .toList(growable: false),
148
+ );
149
+ },
150
+ ),
151
+ ],
152
),
153
),
154
+ ),
155
],
156
);
157
}
@@ -164,6 +165,7 @@ class _ExampleServerPanel extends StatelessWidget {
165
166
@override
167
Widget build(BuildContext context) {
168
+ final l10n = AppLocalizations.of(context)!;
169
final theme = Theme.of(context);
170
final isDark = theme.brightness == Brightness.dark;
171
@@ -202,14 +204,14 @@ class _ExampleServerPanel extends StatelessWidget {
204
crossAxisAlignment: CrossAxisAlignment.start,
205
children: [
206
Text(
205
- 'Example MCP server',
207
+ l10n.example_mcp_server_title,
208
style: theme.textTheme.titleMedium?.copyWith(
209
fontWeight: FontWeight.w700,
210
),
211
),
212
const SizedBox(height: 4),
213
Text(
212
- 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.',
214
+ l10n.example_mcp_server_desc,
215
style: theme.textTheme.bodyMedium?.copyWith(
216
color: theme.colorScheme.onSurfaceVariant,
217
),
@@ -224,7 +226,9 @@ class _ExampleServerPanel extends StatelessWidget {
226
onPressed: onToggle,
227
leading: Icon(enabled ? Icons.power_settings_new : Icons.add),
228
child: Text(
227
- enabled ? 'Disable example server' : 'Enable example server',
229
+ enabled
230
+ ? l10n.disable_example_server
231
+ : l10n.enable_example_server,
232
),
233
),
234
],
@@ -241,6 +245,7 @@ class _ToolRow extends StatelessWidget {
245
@override
246
Widget build(BuildContext context) {
247
final theme = Theme.of(context);
248
+ final l10n = AppLocalizations.of(context)!;
249
final isMcp = tool.providerType == ToolProviderType.mcp;
250
final isDark = theme.brightness == Brightness.dark;
251
@@ -290,7 +295,7 @@ class _ToolRow extends StatelessWidget {
295
runSpacing: 8,
296
children: [
297
_ToolBadge(
293
- label: isMcp ? 'MCP' : 'Built-in',
298
+ label: isMcp ? 'MCP' : l10n.built_in_label,
299
color: isMcp
300
? theme.colorScheme.primary
301
: theme.colorScheme.outline,
lib/features/on_device/components/on_device_picker_section.dart
+8
-5
@@ -124,9 +124,9 @@ class OnDevicePickerSection extends ConsumerWidget {
124
children: [
125
if (importedModels.isNotEmpty) ...[
126
const SizedBox(height: 4),
127
- const _PickerSectionLabel(
128
- title: 'Imported GGUF',
129
- subtitle: 'Already available on this device',
127
+ _PickerSectionLabel(
128
+ title: l10n.gguf_imported_section_label,
129
+ subtitle: l10n.gguf_already_available,
130
),
131
...importedModels.map(buildTile),
132
const SizedBox(height: 8),
@@ -134,7 +134,7 @@ class OnDevicePickerSection extends ConsumerWidget {
134
if (downloadableModels.isNotEmpty) ...[
135
_PickerSectionLabel(
136
title: l10n.available_models,
137
- subtitle: 'Curated on-device models',
137
+ subtitle: l10n.gguf_curated_models_short,
138
),
139
...downloadableModels.map(buildTile),
140
],
@@ -357,7 +357,10 @@ class _OnDeviceModelTile extends ConsumerWidget {
357
isDark: isDark,
358
),
359
if (model.format == OnDeviceModelFormat.gguf)
360
- MetadataChip(label: 'GGUF', isDark: isDark),
360
+ MetadataChip(
361
+ label: l10n.gguf_format_label,
362
+ isDark: isDark,
363
+ ),
364
if (model.runtime == OnDeviceModelRuntime.llamaCpp)
365
MetadataChip(label: 'llama.cpp', isDark: isDark),
366
if (!model.isImported)
lib/features/on_device/views/model_manager_screen.dart
+126
-63
@@ -76,10 +76,10 @@ class _OnDeviceModelManagerScreenState
76
),
77
const SizedBox(height: 4),
78
_SectionHeader(
79
- title: 'Imported GGUF models',
79
+ title: l10n.gguf_imported_models_title,
80
subtitle: importedModels.isEmpty
81
- ? 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.'
82
- : '${importedModels.length} imported model${importedModels.length == 1 ? '' : 's'} ready for local inference.',
81
+ ? l10n.gguf_imported_models_empty_subtitle
82
+ : '${importedModels.length} ${l10n.gguf_imported_models_ready}',
83
),
84
if (importedModels.isEmpty)
85
_EmptyImportedModelsCard(
@@ -99,8 +99,7 @@ class _OnDeviceModelManagerScreenState
99
const SizedBox(height: 8),
100
_SectionHeader(
101
title: l10n.available_models,
102
- subtitle:
103
- 'Curated on-device models you can download and manage inside LocalMind.',
102
+ subtitle: l10n.gguf_curated_models_subtitle,
103
),
104
const SizedBox(height: 4),
105
...curatedModels.map(
@@ -121,6 +120,7 @@ class _OnDeviceModelManagerScreenState
120
121
Future<void> _importLocalGguf(BuildContext context) async {
122
final messenger = ScaffoldMessenger.of(context);
123
+ final l10n = AppLocalizations.of(context)!;
124
try {
125
final result = await FilePicker.pickFiles(
126
type: FileType.custom,
@@ -131,9 +131,7 @@ class _OnDeviceModelManagerScreenState
131
final path = result.files.single.path;
132
if (path == null || !path.toLowerCase().endsWith('.gguf')) {
133
messenger.showSnackBar(
134
- const SnackBar(
135
- content: Text('Only GGUF models are supported for this import.'),
136
- ),
134
+ SnackBar(content: Text(l10n.gguf_only_supported)),
135
);
136
return;
137
}
@@ -142,17 +140,24 @@ class _OnDeviceModelManagerScreenState
140
.read(importedGgufModelsProvider.notifier)
141
.importModel(path);
142
messenger.showSnackBar(
145
- SnackBar(content: Text('${model.name} imported from local file.')),
143
+ SnackBar(
144
+ content: Text('${model.name} ${l10n.gguf_imported_from_local_file}'),
145
+ ),
146
);
147
} catch (e) {
148
messenger.showSnackBar(
149
- SnackBar(content: Text('Failed to import GGUF model: $e')),
149
+ SnackBar(
150
+ content: Text(
151
+ '${l10n.gguf_import_failed}: ${_friendlyErrorForL10n(l10n, e)}',
152
+ ),
153
+ ),
154
);
155
}
156
}
157
158
Future<void> _importFromHuggingFace(BuildContext context) async {
159
final messenger = ScaffoldMessenger.of(context);
160
+ final l10n = AppLocalizations.of(context)!;
161
final importedModel = await showDialog<OnDeviceModel>(
162
context: context,
163
barrierDismissible: false,
@@ -162,10 +167,41 @@ class _OnDeviceModelManagerScreenState
167
if (!mounted || importedModel == null) return;
168
messenger.showSnackBar(
169
SnackBar(
165
- content: Text('${importedModel.name} imported from Hugging Face.'),
170
+ content: Text(
171
+ '${importedModel.name} ${l10n.gguf_imported_from_huggingface}',
172
+ ),
173
),
174
);
175
}
176
+
177
+ String _friendlyErrorForL10n(AppLocalizations l10n, Object error) {
178
+ final message = error.toString();
179
+ final normalized = message
180
+ .replaceFirst('HttpException: ', '')
181
+ .replaceFirst('FormatException: ', '')
182
+ .replaceFirst('FileSystemException: ', '');
183
+
184
+ switch (normalized) {
185
+ case 'GGUF import canceled.':
186
+ return l10n.gguf_import_canceled;
187
+ case 'Enter a Hugging Face GGUF URL.':
188
+ return l10n.gguf_enter_huggingface_url;
189
+ case 'Only official Hugging Face GGUF URLs are supported.':
190
+ return l10n.gguf_only_official_huggingface_urls;
191
+ case 'Use an HTTPS Hugging Face URL for GGUF import.':
192
+ return l10n.gguf_use_https_url;
193
+ case 'The Hugging Face URL must point directly to a .gguf file.':
194
+ return l10n.gguf_url_must_point_to_file;
195
+ case 'Unable to determine the GGUF file name.':
196
+ return l10n.gguf_unable_to_detect_file_name;
197
+ case 'The downloaded GGUF file was empty or missing.':
198
+ return l10n.gguf_download_empty;
199
+ case 'Selected model file does not exist':
200
+ return l10n.gguf_selected_file_missing;
201
+ default:
202
+ return normalized;
203
+ }
204
+ }
205
}
206
207
class _ManagerHeader extends StatelessWidget {
@@ -228,7 +264,7 @@ class _ManagerHeader extends StatelessWidget {
264
if (defaultTargetPlatform == TargetPlatform.android ||
265
defaultTargetPlatform == TargetPlatform.iOS)
266
PopupMenuButton<_ImportAction>(
231
- tooltip: 'Import GGUF',
267
+ tooltip: l10n.gguf_import_action,
268
onSelected: (value) {
269
switch (value) {
270
case _ImportAction.localFile:
@@ -237,23 +273,23 @@ class _ManagerHeader extends StatelessWidget {
273
onImportFromHuggingFace();
274
}
275
},
240
- itemBuilder: (context) => const [
276
+ itemBuilder: (context) => [
277
PopupMenuItem<_ImportAction>(
278
value: _ImportAction.localFile,
279
child: ListTile(
280
contentPadding: EdgeInsets.zero,
245
- leading: Icon(Icons.folder_open_outlined),
246
- title: Text('Import local GGUF'),
247
- subtitle: Text('Copy a .gguf file from this device'),
281
+ leading: const Icon(Icons.folder_open_outlined),
282
+ title: Text(l10n.gguf_import_local_title),
283
+ subtitle: Text(l10n.gguf_import_local_subtitle),
284
),
285
),
286
PopupMenuItem<_ImportAction>(
287
value: _ImportAction.huggingFace,
288
child: ListTile(
289
contentPadding: EdgeInsets.zero,
254
- leading: Icon(Icons.cloud_download_outlined),
255
- title: Text('Import from Hugging Face'),
256
- subtitle: Text('Paste a GGUF URL or repo path'),
290
+ leading: const Icon(Icons.cloud_download_outlined),
291
+ title: Text(l10n.gguf_import_huggingface_title),
292
+ subtitle: Text(l10n.gguf_import_huggingface_subtitle),
293
),
294
),
295
],
@@ -277,7 +313,7 @@ class _ManagerHeader extends StatelessWidget {
313
color: theme.colorScheme.primary,
314
),
315
const SizedBox(width: 8),
280
- const Text('Import GGUF'),
316
+ Text(l10n.gguf_import_action),
317
],
318
),
319
),
@@ -302,6 +338,7 @@ class _ImportOverviewCard extends StatelessWidget {
338
@override
339
Widget build(BuildContext context) {
340
final theme = Theme.of(context);
341
+ final l10n = AppLocalizations.of(context)!;
342
final localImports = importedModels
343
.where((model) => model.isImportedFromLocalFile)
344
.length;
@@ -342,14 +379,14 @@ class _ImportOverviewCard extends StatelessWidget {
379
crossAxisAlignment: CrossAxisAlignment.start,
380
children: [
381
Text(
345
- 'Bring your own GGUF models',
382
+ l10n.gguf_overview_title,
383
style: theme.textTheme.titleMedium?.copyWith(
384
fontWeight: FontWeight.bold,
385
),
386
),
387
const SizedBox(height: 4),
388
Text(
352
- 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.',
389
+ l10n.gguf_overview_subtitle,
390
style: theme.textTheme.bodySmall?.copyWith(
391
color: theme.colorScheme.onSurface.withValues(
392
alpha: 0.7,
@@ -368,15 +405,16 @@ class _ImportOverviewCard extends StatelessWidget {
405
children: [
406
_SummaryPill(
407
icon: Icons.layers_outlined,
371
- label: '${importedModels.length} imported',
408
+ label:
409
+ '${importedModels.length} ${l10n.gguf_imported_count_label}',
410
),
411
_SummaryPill(
412
icon: Icons.folder_open_outlined,
375
- label: '$localImports local files',
413
+ label: '$localImports ${l10n.gguf_local_files_label}',
414
),
415
_SummaryPill(
416
icon: Icons.cloud_download_outlined,
379
- label: '$huggingFaceImports Hugging Face',
417
+ label: '$huggingFaceImports ${l10n.gguf_huggingface_label}',
418
),
419
],
420
),
@@ -388,12 +426,12 @@ class _ImportOverviewCard extends StatelessWidget {
426
OutlinedButton.icon(
427
onPressed: onImportLocalGguf,
428
icon: const Icon(Icons.folder_open_outlined),
391
- label: const Text('Import local GGUF'),
429
+ label: Text(l10n.gguf_import_local_title),
430
),
431
OutlinedButton.icon(
432
onPressed: onImportFromHuggingFace,
433
icon: const Icon(Icons.cloud_download_outlined),
396
- label: const Text('Import from Hugging Face'),
434
+ label: Text(l10n.gguf_import_huggingface_title),
435
),
436
],
437
),
@@ -483,6 +521,7 @@ class _EmptyImportedModelsCard extends StatelessWidget {
521
@override
522
Widget build(BuildContext context) {
523
final theme = Theme.of(context);
524
+ final l10n = AppLocalizations.of(context)!;
525
return Container(
526
margin: const EdgeInsets.only(bottom: 16),
527
padding: const EdgeInsets.all(18),
@@ -497,14 +536,14 @@ class _EmptyImportedModelsCard extends StatelessWidget {
536
crossAxisAlignment: CrossAxisAlignment.start,
537
children: [
538
Text(
500
- 'No imported GGUF models yet',
539
+ l10n.gguf_no_imported_title,
540
style: theme.textTheme.titleSmall?.copyWith(
541
fontWeight: FontWeight.w700,
542
),
543
),
544
const SizedBox(height: 6),
545
Text(
507
- 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.',
546
+ l10n.gguf_no_imported_subtitle,
547
style: theme.textTheme.bodySmall?.copyWith(
548
color: theme.colorScheme.onSurface.withValues(alpha: 0.7),
549
),
@@ -517,12 +556,12 @@ class _EmptyImportedModelsCard extends StatelessWidget {
556
OutlinedButton.icon(
557
onPressed: onImportLocalGguf,
558
icon: const Icon(Icons.folder_open_outlined),
520
- label: const Text('Import local GGUF'),
559
+ label: Text(l10n.gguf_import_local_title),
560
),
561
OutlinedButton.icon(
562
onPressed: onImportFromHuggingFace,
563
icon: const Icon(Icons.cloud_download_outlined),
525
- label: const Text('Import from Hugging Face'),
564
+ label: Text(l10n.gguf_import_huggingface_title),
565
),
566
],
567
),
@@ -594,7 +633,7 @@ class _HuggingFaceGgufImportDialogState
633
),
634
),
635
const SizedBox(width: 12),
597
- const Expanded(child: Text('Import GGUF from Hugging Face')),
636
+ Expanded(child: Text(l10n.gguf_import_huggingface_dialog_title)),
637
],
638
),
639
content: SizedBox(
@@ -605,7 +644,7 @@ class _HuggingFaceGgufImportDialogState
644
crossAxisAlignment: CrossAxisAlignment.start,
645
children: [
646
Text(
608
- 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.',
647
+ l10n.gguf_import_huggingface_dialog_subtitle,
648
style: theme.textTheme.bodySmall?.copyWith(
649
color: theme.colorScheme.onSurface.withValues(alpha: 0.72),
650
),
@@ -631,7 +670,7 @@ class _HuggingFaceGgufImportDialogState
670
}
671
},
672
decoration: InputDecoration(
634
- labelText: 'GGUF URL or repo path',
673
+ labelText: l10n.gguf_url_or_repo_path,
674
hintText:
675
'owner/repo/blob/main/model.gguf\nhttps://huggingface.co/owner/repo/resolve/main/model.gguf',
676
border: const OutlineInputBorder(),
@@ -646,21 +685,21 @@ class _HuggingFaceGgufImportDialogState
685
OutlinedButton.icon(
686
onPressed: _isImporting ? null : _pasteFromClipboard,
687
icon: const Icon(Icons.content_paste_rounded, size: 18),
649
- label: const Text('Paste'),
688
+ label: Text(l10n.paste),
689
),
690
OutlinedButton.icon(
691
onPressed: _isImporting || input.isEmpty
692
? null
693
: _clearInput,
694
icon: const Icon(Icons.close_rounded, size: 18),
656
- label: const Text('Clear'),
695
+ label: Text(l10n.clear_huggingface_token),
696
),
697
OutlinedButton.icon(
698
onPressed: _isImporting
699
? null
700
: () => _openHuggingFace(context),
701
icon: const Icon(Icons.open_in_new_rounded, size: 18),
663
- label: const Text('Browse GGUFs'),
702
+ label: Text(l10n.gguf_browse),
703
),
704
],
705
),
@@ -698,8 +737,8 @@ class _HuggingFaceGgufImportDialogState
737
children: [
738
Text(
739
hasHuggingFaceToken
701
- ? 'Hugging Face token ready'
702
- : 'Token optional but recommended',
740
+ ? l10n.gguf_huggingface_token_ready
741
+ : l10n.gguf_huggingface_token_optional,
742
style: theme.textTheme.labelLarge?.copyWith(
743
fontWeight: FontWeight.w700,
744
),
@@ -707,8 +746,8 @@ class _HuggingFaceGgufImportDialogState
746
const SizedBox(height: 4),
747
Text(
748
hasHuggingFaceToken
710
- ? 'Your saved token will be used automatically for gated or private repositories.'
711
- : '${l10n.model_requires_huggingface_token} Add one in Settings if this GGUF is gated or private.',
749
+ ? l10n.gguf_huggingface_token_ready_desc
750
+ : l10n.gguf_huggingface_token_optional_desc,
751
style: theme.textTheme.bodySmall,
752
),
753
],
@@ -736,7 +775,7 @@ class _HuggingFaceGgufImportDialogState
775
children: [
776
Expanded(
777
child: Text(
739
- preview?.fileName ?? 'Downloading GGUF',
778
+ preview?.fileName ?? l10n.gguf_downloading,
779
maxLines: 1,
780
overflow: TextOverflow.ellipsis,
781
style: theme.textTheme.labelLarge?.copyWith(
@@ -758,7 +797,7 @@ class _HuggingFaceGgufImportDialogState
797
),
798
child: Text(
799
progress == null
761
- ? 'Preparing'
800
+ ? l10n.gguf_preparing
801
: '${(progress * 100).toStringAsFixed(1)}%',
802
style: theme.textTheme.labelMedium?.copyWith(
803
color: theme.colorScheme.primary,
@@ -774,7 +813,7 @@ class _HuggingFaceGgufImportDialogState
813
Text(
814
progress != null
815
? '${_formatBytes(_receivedBytes)} / ${_formatBytes(_totalBytes)}'
777
- : 'Preparing download...',
816
+ : l10n.gguf_preparing_download,
817
style: theme.textTheme.bodySmall?.copyWith(
818
color: theme.colorScheme.onSurface.withValues(
819
alpha: 0.70,
@@ -832,12 +871,12 @@ class _HuggingFaceGgufImportDialogState
871
Navigator.of(context).pop();
872
}
873
: () => Navigator.of(context).pop(),
835
- child: Text(_isImporting ? 'Cancel import' : l10n.cancel),
874
+ child: Text(_isImporting ? l10n.gguf_cancel_import : l10n.cancel),
875
),
876
ElevatedButton.icon(
877
onPressed: _isImporting || input.isEmpty ? null : _startImport,
878
icon: const Icon(Icons.download_rounded, size: 18),
840
- label: const Text('Import GGUF'),
879
+ label: Text(l10n.gguf_import_action),
880
),
881
],
882
);
@@ -848,9 +887,9 @@ class _HuggingFaceGgufImportDialogState
887
final text = data?.text?.trim();
888
if (!mounted) return;
889
if (text == null || text.isEmpty) {
851
- ScaffoldMessenger.of(
852
- context,
853
- ).showSnackBar(const SnackBar(content: Text('Clipboard is empty.')));
890
+ ScaffoldMessenger.of(context).showSnackBar(
891
+ SnackBar(content: Text(AppLocalizations.of(context)!.clipboard_empty)),
892
+ );
893
return;
894
}
895
setState(() {
@@ -874,7 +913,11 @@ class _HuggingFaceGgufImportDialogState
913
);
914
if (!launched && context.mounted) {
915
messenger.showSnackBar(
877
- const SnackBar(content: Text('Could not open Hugging Face.')),
916
+ SnackBar(
917
+ content: Text(
918
+ AppLocalizations.of(context)!.could_not_open_huggingface,
919
+ ),
920
+ ),
921
);
922
}
923
}
@@ -883,7 +926,7 @@ class _HuggingFaceGgufImportDialogState
926
final sourceUrl = _urlController.text.trim();
927
if (sourceUrl.isEmpty) {
928
setState(() {
886
- _error = 'Paste a Hugging Face GGUF URL or repo path.';
929
+ _error = AppLocalizations.of(context)!.gguf_paste_url_error;
930
});
931
return;
932
}
@@ -928,17 +971,33 @@ class _HuggingFaceGgufImportDialogState
971
}
972
973
String _friendlyError(Object error) {
974
+ final l10n = AppLocalizations.of(context)!;
975
final message = error.toString();
932
- if (message.startsWith('HttpException: ')) {
933
- return message.substring('HttpException: '.length);
976
+ final normalized = message
977
+ .replaceFirst('HttpException: ', '')
978
+ .replaceFirst('FormatException: ', '')
979
+ .replaceFirst('Exception: ', '')
980
+ .replaceFirst('FileSystemException: ', '');
981
+ switch (normalized) {
982
+ case 'GGUF import canceled.':
983
+ return l10n.gguf_import_canceled;
984
+ case 'Enter a Hugging Face GGUF URL.':
985
+ return l10n.gguf_enter_huggingface_url;
986
+ case 'Only official Hugging Face GGUF URLs are supported.':
987
+ return l10n.gguf_only_official_huggingface_urls;
988
+ case 'Use an HTTPS Hugging Face URL for GGUF import.':
989
+ return l10n.gguf_use_https_url;
990
+ case 'The Hugging Face URL must point directly to a .gguf file.':
991
+ return l10n.gguf_url_must_point_to_file;
992
+ case 'Unable to determine the GGUF file name.':
993
+ return l10n.gguf_unable_to_detect_file_name;
994
+ case 'The downloaded GGUF file was empty or missing.':
995
+ return l10n.gguf_download_empty;
996
+ case 'Selected model file does not exist':
997
+ return l10n.gguf_selected_file_missing;
998
+ default:
999
+ return normalized;
1000
}
935
- if (message.startsWith('FormatException: ')) {
936
- return message.substring('FormatException: '.length);
937
- }
938
- if (message.startsWith('Exception: ')) {
939
- return message.substring('Exception: '.length);
940
- }
941
- return message;
1001
}
1002
1003
String _formatBytes(int bytes) {
@@ -960,6 +1019,7 @@ class _ImportPreviewCard extends StatelessWidget {
1019
@override
1020
Widget build(BuildContext context) {
1021
final theme = Theme.of(context);
1022
+ final l10n = AppLocalizations.of(context)!;
1023
1024
return Container(
1025
width: double.infinity,
@@ -985,7 +1045,7 @@ class _ImportPreviewCard extends StatelessWidget {
1045
? Icons.sync_alt_rounded
1046
: Icons.link_rounded,
1047
label: preview.isBlobLink
988
- ? 'Blob link'
1048
+ ? l10n.gguf_blob_link
1049
: preview.inputStyleLabel,
1050
),
1051
if (preview.fileName != null)
@@ -997,10 +1057,13 @@ class _ImportPreviewCard extends StatelessWidget {
1057
),
1058
const SizedBox(height: 10),
1059
if (preview.repoPath != null)
1000
- _PreviewRow(label: 'Repository', value: preview.repoPath!),
1060
+ _PreviewRow(
1061
+ label: l10n.gguf_repository_label,
1062
+ value: preview.repoPath!,
1063
+ ),
1064
if (preview.normalizedDisplay != null)
1065
_PreviewRow(
1003
- label: 'Detected path',
1066
+ label: l10n.gguf_detected_path_label,
1067
value: preview.normalizedDisplay!,
1068
),
1069
],
lib/features/servers/views/add_server_screen.dart
+8
-9
@@ -284,7 +284,7 @@ class _AddServerScreenState extends ConsumerState<AddServerScreen> {
284
_buildSectionCard(
285
context,
286
title: l10n.server_type_label,
287
- subtitle: 'Pick the provider before filling connection details.',
287
+ subtitle: l10n.server_type_help,
288
child: ServerTypeSelector(
289
selectedType: _selectedType,
290
onChanged: _onTypeChanged,
@@ -293,9 +293,8 @@ class _AddServerScreenState extends ConsumerState<AddServerScreen> {
293
const SizedBox(height: 12),
294
_buildSectionCard(
295
context,
296
- title: 'Identity',
297
- subtitle:
298
- 'Name this server and choose how it appears in the list.',
296
+ title: l10n.server_identity_title,
297
+ subtitle: l10n.server_identity_desc,
298
child: Column(
299
children: [
300
GestureDetector(
@@ -384,8 +383,8 @@ class _AddServerScreenState extends ConsumerState<AddServerScreen> {
383
const SizedBox(height: 12),
384
_buildSectionCard(
385
context,
387
- title: 'Connection',
388
- subtitle: 'Use the address and port exposed by your server.',
386
+ title: l10n.server_connection_title,
387
+ subtitle: l10n.server_connection_desc,
388
child: Column(
389
children: [
390
TextFormField(
@@ -419,10 +418,10 @@ class _AddServerScreenState extends ConsumerState<AddServerScreen> {
418
const SizedBox(height: 12),
419
_buildSectionCard(
420
context,
422
- title: 'Authentication',
421
+ title: l10n.server_authentication_title,
422
subtitle: _requiresMandatoryApiKey
424
- ? 'OpenRouter requires an API key before testing.'
425
- : 'Leave the API key empty if this server does not require one.',
423
+ ? l10n.server_authentication_required_desc
424
+ : l10n.server_authentication_optional_desc,
425
child: TextFormField(
426
controller: _apiKeyController,
427
decoration: InputDecoration(
lib/features/settings/views/settings_screen.dart
+5
-12
@@ -736,7 +736,7 @@ class _AboutPanel extends StatelessWidget {
736
.toList(),
737
),
738
const SizedBox(height: 12),
739
- _AboutLabel(label: 'Highlights'),
739
+ _AboutLabel(label: l10n.highlights_label),
740
const SizedBox(height: 8),
741
Wrap(
742
spacing: 6,
@@ -751,7 +751,7 @@ class _AboutPanel extends StatelessWidget {
751
.toList(),
752
),
753
const SizedBox(height: 12),
754
- _AboutLabel(label: 'Built with'),
754
+ _AboutLabel(label: l10n.built_with_label),
755
const SizedBox(height: 8),
756
Wrap(
757
spacing: 6,
@@ -1927,8 +1927,7 @@ class _HuggingFaceTokenSetting extends StatelessWidget {
1927
child: Text(l10n.clear_huggingface_token),
1928
),
1929
TextButton(
1930
- onPressed: () =>
1931
- Navigator.of(ctx).pop(controller.text.trim()),
1930
+ onPressed: () => Navigator.of(ctx).pop(controller.text.trim()),
1931
child: Text(l10n.save),
1932
),
1933
],
@@ -1970,9 +1969,7 @@ class _HuggingFaceTokenSetting extends StatelessWidget {
1969
vertical: 12,
1970
),
1971
child: Text(
1973
- _hasToken
1974
- ? _maskedToken(currentToken!)
1975
- : '—',
1972
+ _hasToken ? _maskedToken(currentToken!) : '—',
1973
style: theme.textTheme.bodyMedium?.copyWith(
1974
fontFamily: 'monospace',
1975
color: _hasToken
@@ -1986,11 +1983,7 @@ class _HuggingFaceTokenSetting extends StatelessWidget {
1983
const SizedBox(width: 10),
1984
ShadButton.outline(
1985
onPressed: () => _editToken(context),
1989
- child: Text(
1990
- _hasToken
1991
- ? l10n.edit
1992
- : l10n.set_huggingface_token,
1993
- ),
1986
+ child: Text(_hasToken ? l10n.edit : l10n.set_huggingface_token),
1987
),
1988
if (_hasToken) ...[
1989
const SizedBox(width: 6),
lib/features/sidebar/sidebar_widget.dart
+1
-1
@@ -96,7 +96,7 @@ class SidebarWidget extends ConsumerWidget {
96
),
97
DrawerNavItem(
98
iconData: HugeIcons.strokeRoundedMcpServer,
99
- label: 'MCP Tools',
99
+ label: l10n.mcp_tools_title,
100
isSelected: isMcpTools,
101
onTap: () {
102
if (Scaffold.maybeOf(context)?.isDrawerOpen ?? false) {
lib/l10n/app_ar.arb
+97
-2
@@ -507,5 +507,100 @@
507
"tts_supports_background": "يدعم التشغيل في الخلفية كصوت أصلي",
508
"tts_other_services_background_note": "ملاحظة: تدعم خدمات TTS الأخرى التشغيل في الخلفية كصوت أصلي.",
509
"start_listening_tooltip": "بدء الاستماع",
510
- "stop_listening_tooltip": "إيقاف الاستماع"
511
-}
\ No newline at end of file
510
+ "stop_listening_tooltip": "إيقاف الاستماع",
511
+ "settings_huggingface_token": "رمز Hugging Face (اختياري)",
512
+ "settings_huggingface_token_desc": "مطلوب فقط للنماذج المقيّدة (مثل Gemma). احصل على رمز من huggingface.co/settings/tokens.",
513
+ "settings_huggingface_token_set": "تم حفظ الرمز",
514
+ "settings_huggingface_token_cleared": "تم مسح الرمز",
515
+ "model_requires_huggingface_token": "يتطلب رمز Hugging Face",
516
+ "model_missing_huggingface_token": "هذا النموذج مقيّد على Hugging Face. أضف رمزاً في الإعدادات ← الاستدلال المحلي لتنزيله.",
517
+ "set_huggingface_token": "تعيين الرمز",
518
+ "clear_huggingface_token": "مسح",
519
+ "edit_huggingface_token_dialog_title": "رمز وصول Hugging Face",
520
+ "huggingface_token_dialog_hint": "hf_…",
521
+ "server_type_ollama_desc": "محرك ذكاء اصطناعي محلي. لا يتطلب مفتاح API.",
522
+ "server_type_on_device_desc": "يعمل على هاتفك. بعض النماذج تحتاج إلى رمز Hugging Face.",
523
+ "server_type_lm_studio_desc": "خادم API محلي. لا يتطلب مفتاح API.",
524
+ "gguf_imported_models_title": "Imported GGUF models",
525
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
526
+ "gguf_imported_models_ready": "imported models ready for local inference.",
527
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
528
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
529
+ "gguf_imported_from_local_file": "imported from local file.",
530
+ "gguf_import_failed": "Failed to import GGUF model",
531
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
532
+ "gguf_import_canceled": "GGUF import canceled.",
533
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
534
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
535
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
536
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
537
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
538
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
539
+ "gguf_selected_file_missing": "Selected model file does not exist.",
540
+ "gguf_import_action": "Import GGUF",
541
+ "gguf_overview_title": "Bring your own GGUF models",
542
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
543
+ "gguf_imported_count_label": "imported",
544
+ "gguf_local_files_label": "local files",
545
+ "gguf_huggingface_label": "Hugging Face",
546
+ "gguf_import_local_title": "Import local GGUF",
547
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
548
+ "gguf_import_huggingface_title": "Import from Hugging Face",
549
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
550
+ "gguf_no_imported_title": "No imported GGUF models yet",
551
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
552
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
553
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
554
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
555
+ "paste": "Paste",
556
+ "gguf_browse": "Browse GGUFs",
557
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
558
+ "gguf_huggingface_token_optional": "Token optional but recommended",
559
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
560
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
561
+ "gguf_downloading": "Downloading GGUF",
562
+ "gguf_preparing": "Preparing",
563
+ "gguf_preparing_download": "Preparing download...",
564
+ "gguf_cancel_import": "Cancel import",
565
+ "clipboard_empty": "Clipboard is empty.",
566
+ "could_not_open_huggingface": "Could not open Hugging Face.",
567
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
568
+ "gguf_blob_link": "Blob link",
569
+ "gguf_repository_label": "Repository",
570
+ "gguf_detected_path_label": "Detected path",
571
+ "gguf_imported_section_label": "Imported GGUF",
572
+ "gguf_already_available": "Already available on this device",
573
+ "gguf_curated_models_short": "Curated on-device models",
574
+ "execute_tool_title": "Execute Tool",
575
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
576
+ "reject": "Reject",
577
+ "approve": "Approve",
578
+ "server_type_help": "Pick the provider before filling connection details.",
579
+ "server_identity_title": "Identity",
580
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
581
+ "server_connection_title": "Connection",
582
+ "server_connection_desc": "Use the address and port exposed by your server.",
583
+ "server_authentication_title": "Authentication",
584
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
585
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
586
+ "mcp_tools_title": "MCP Tools",
587
+ "available_tools": "Available tools",
588
+ "unable_load_tools": "Unable to load tools",
589
+ "no_tools_registered": "No tools registered",
590
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
591
+ "example_mcp_server_title": "Example MCP server",
592
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
593
+ "disable_example_server": "Disable example server",
594
+ "enable_example_server": "Enable example server",
595
+ "built_in_label": "Built-in",
596
+ "highlights_label": "Highlights",
597
+ "built_with_label": "Built with",
598
+ "local_label": "Local",
599
+ "gguf_format_label": "GGUF",
600
+ "tool_status_requested": "Requested",
601
+ "tool_status_approved": "Approved",
602
+ "tool_status_rejected": "Rejected",
603
+ "tool_status_running": "Running",
604
+ "tool_status_done": "Done",
605
+ "tool_status_failed": "Failed"
606
+}
lib/l10n/app_bn.arb
+97
-2
@@ -507,5 +507,100 @@
507
"tts_supports_background": "নেটিভ অডিও হিসাবে ব্যাকগ্রাউন্ড প্লেব্যাক সমর্থন করে",
508
"tts_other_services_background_note": "দ্রষ্টব্য: অন্যান্য টিটিএস পরিষেবাগুলি নেটিভ অডিও হিসাবে ব্যাকগ্রাউন্ড প্লেব্যাক সমর্থন করে।",
509
"start_listening_tooltip": "শোনা শুরু করুন",
510
- "stop_listening_tooltip": "শোনা বন্ধ করুন"
511
-}
\ No newline at end of file
510
+ "stop_listening_tooltip": "শোনা বন্ধ করুন",
511
+ "settings_huggingface_token": "Hugging Face টোকেন (ঐচ্ছিক)",
512
+ "settings_huggingface_token_desc": "শুধু gated মডেলের জন্য প্রয়োজন (যেমন Gemma)। huggingface.co/settings/tokens থেকে একটি টোকেন নিন।",
513
+ "settings_huggingface_token_set": "টোকেন সংরক্ষিত হয়েছে",
514
+ "settings_huggingface_token_cleared": "টোকেন মুছে ফেলা হয়েছে",
515
+ "model_requires_huggingface_token": "Hugging Face টোকেন প্রয়োজন",
516
+ "model_missing_huggingface_token": "এই মডেলটি Hugging Face-এ gated। এটি ডাউনলোড করতে Settings → On-Device Inference-এ একটি টোকেন যোগ করুন।",
517
+ "set_huggingface_token": "টোকেন সেট করুন",
518
+ "clear_huggingface_token": "মুছুন",
519
+ "edit_huggingface_token_dialog_title": "Hugging Face অ্যাক্সেস টোকেন",
520
+ "huggingface_token_dialog_hint": "hf_…",
521
+ "server_type_ollama_desc": "লোকাল AI ইঞ্জিন। API key প্রয়োজন নেই।",
522
+ "server_type_on_device_desc": "আপনার ফোনে চলে। কিছু মডেলের জন্য Hugging Face টোকেন লাগে।",
523
+ "server_type_lm_studio_desc": "লোকাল API সার্ভার। API key প্রয়োজন নেই।",
524
+ "gguf_imported_models_title": "Imported GGUF models",
525
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
526
+ "gguf_imported_models_ready": "imported models ready for local inference.",
527
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
528
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
529
+ "gguf_imported_from_local_file": "imported from local file.",
530
+ "gguf_import_failed": "Failed to import GGUF model",
531
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
532
+ "gguf_import_canceled": "GGUF import canceled.",
533
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
534
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
535
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
536
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
537
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
538
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
539
+ "gguf_selected_file_missing": "Selected model file does not exist.",
540
+ "gguf_import_action": "Import GGUF",
541
+ "gguf_overview_title": "Bring your own GGUF models",
542
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
543
+ "gguf_imported_count_label": "imported",
544
+ "gguf_local_files_label": "local files",
545
+ "gguf_huggingface_label": "Hugging Face",
546
+ "gguf_import_local_title": "Import local GGUF",
547
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
548
+ "gguf_import_huggingface_title": "Import from Hugging Face",
549
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
550
+ "gguf_no_imported_title": "No imported GGUF models yet",
551
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
552
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
553
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
554
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
555
+ "paste": "Paste",
556
+ "gguf_browse": "Browse GGUFs",
557
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
558
+ "gguf_huggingface_token_optional": "Token optional but recommended",
559
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
560
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
561
+ "gguf_downloading": "Downloading GGUF",
562
+ "gguf_preparing": "Preparing",
563
+ "gguf_preparing_download": "Preparing download...",
564
+ "gguf_cancel_import": "Cancel import",
565
+ "clipboard_empty": "Clipboard is empty.",
566
+ "could_not_open_huggingface": "Could not open Hugging Face.",
567
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
568
+ "gguf_blob_link": "Blob link",
569
+ "gguf_repository_label": "Repository",
570
+ "gguf_detected_path_label": "Detected path",
571
+ "gguf_imported_section_label": "Imported GGUF",
572
+ "gguf_already_available": "Already available on this device",
573
+ "gguf_curated_models_short": "Curated on-device models",
574
+ "execute_tool_title": "Execute Tool",
575
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
576
+ "reject": "Reject",
577
+ "approve": "Approve",
578
+ "server_type_help": "Pick the provider before filling connection details.",
579
+ "server_identity_title": "Identity",
580
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
581
+ "server_connection_title": "Connection",
582
+ "server_connection_desc": "Use the address and port exposed by your server.",
583
+ "server_authentication_title": "Authentication",
584
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
585
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
586
+ "mcp_tools_title": "MCP Tools",
587
+ "available_tools": "Available tools",
588
+ "unable_load_tools": "Unable to load tools",
589
+ "no_tools_registered": "No tools registered",
590
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
591
+ "example_mcp_server_title": "Example MCP server",
592
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
593
+ "disable_example_server": "Disable example server",
594
+ "enable_example_server": "Enable example server",
595
+ "built_in_label": "Built-in",
596
+ "highlights_label": "Highlights",
597
+ "built_with_label": "Built with",
598
+ "local_label": "Local",
599
+ "gguf_format_label": "GGUF",
600
+ "tool_status_requested": "Requested",
601
+ "tool_status_approved": "Approved",
602
+ "tool_status_rejected": "Rejected",
603
+ "tool_status_running": "Running",
604
+ "tool_status_done": "Done",
605
+ "tool_status_failed": "Failed"
606
+}
lib/l10n/app_en.arb
+84
-2
@@ -2373,5 +2373,87 @@
2373
"tts_other_services_background_note": "Note: The other TTS services support background playback as native audio.",
2374
"@tts_other_services_background_note": {
2375
"description": "TTS background playback support status"
2376
- }
2377
-}
\ No newline at end of file
2376
+ },
2377
+ "gguf_imported_models_title": "Imported GGUF models",
2378
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
2379
+ "gguf_imported_models_ready": "imported models ready for local inference.",
2380
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
2381
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
2382
+ "gguf_imported_from_local_file": "imported from local file.",
2383
+ "gguf_import_failed": "Failed to import GGUF model",
2384
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
2385
+ "gguf_import_canceled": "GGUF import canceled.",
2386
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
2387
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
2388
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
2389
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
2390
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
2391
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
2392
+ "gguf_selected_file_missing": "Selected model file does not exist.",
2393
+ "gguf_import_action": "Import GGUF",
2394
+ "gguf_overview_title": "Bring your own GGUF models",
2395
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
2396
+ "gguf_imported_count_label": "imported",
2397
+ "gguf_local_files_label": "local files",
2398
+ "gguf_huggingface_label": "Hugging Face",
2399
+ "gguf_import_local_title": "Import local GGUF",
2400
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
2401
+ "gguf_import_huggingface_title": "Import from Hugging Face",
2402
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
2403
+ "gguf_no_imported_title": "No imported GGUF models yet",
2404
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
2405
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
2406
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
2407
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
2408
+ "paste": "Paste",
2409
+ "gguf_browse": "Browse GGUFs",
2410
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
2411
+ "gguf_huggingface_token_optional": "Token optional but recommended",
2412
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
2413
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
2414
+ "gguf_downloading": "Downloading GGUF",
2415
+ "gguf_preparing": "Preparing",
2416
+ "gguf_preparing_download": "Preparing download...",
2417
+ "gguf_cancel_import": "Cancel import",
2418
+ "clipboard_empty": "Clipboard is empty.",
2419
+ "could_not_open_huggingface": "Could not open Hugging Face.",
2420
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
2421
+ "gguf_blob_link": "Blob link",
2422
+ "gguf_repository_label": "Repository",
2423
+ "gguf_detected_path_label": "Detected path",
2424
+ "gguf_imported_section_label": "Imported GGUF",
2425
+ "gguf_already_available": "Already available on this device",
2426
+ "gguf_curated_models_short": "Curated on-device models",
2427
+ "execute_tool_title": "Execute Tool",
2428
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
2429
+ "reject": "Reject",
2430
+ "approve": "Approve",
2431
+ "server_type_help": "Pick the provider before filling connection details.",
2432
+ "server_identity_title": "Identity",
2433
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
2434
+ "server_connection_title": "Connection",
2435
+ "server_connection_desc": "Use the address and port exposed by your server.",
2436
+ "server_authentication_title": "Authentication",
2437
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
2438
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
2439
+ "mcp_tools_title": "MCP Tools",
2440
+ "available_tools": "Available tools",
2441
+ "unable_load_tools": "Unable to load tools",
2442
+ "no_tools_registered": "No tools registered",
2443
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
2444
+ "example_mcp_server_title": "Example MCP server",
2445
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
2446
+ "disable_example_server": "Disable example server",
2447
+ "enable_example_server": "Enable example server",
2448
+ "built_in_label": "Built-in",
2449
+ "highlights_label": "Highlights",
2450
+ "built_with_label": "Built with",
2451
+ "local_label": "Local",
2452
+ "gguf_format_label": "GGUF",
2453
+ "tool_status_requested": "Requested",
2454
+ "tool_status_approved": "Approved",
2455
+ "tool_status_rejected": "Rejected",
2456
+ "tool_status_running": "Running",
2457
+ "tool_status_done": "Done",
2458
+ "tool_status_failed": "Failed"
2459
+}
lib/l10n/app_es.arb
+97
-2
@@ -507,5 +507,100 @@
507
"tts_supports_background": "Soporta reproducción en segundo plano como audio nativo",
508
"tts_other_services_background_note": "Nota: Los otros servicios de TTS soportan reproducción en segundo plano como audio nativo.",
509
"start_listening_tooltip": "Iniciar escucha",
510
- "stop_listening_tooltip": "Detener escucha"
511
-}
\ No newline at end of file
510
+ "stop_listening_tooltip": "Detener escucha",
511
+ "settings_huggingface_token": "Token de Hugging Face (Opcional)",
512
+ "settings_huggingface_token_desc": "Solo se requiere para modelos restringidos (p. ej., Gemma). Obtenga un token en huggingface.co/settings/tokens.",
513
+ "settings_huggingface_token_set": "Token guardado",
514
+ "settings_huggingface_token_cleared": "Token eliminado",
515
+ "model_requires_huggingface_token": "Requiere un token de Hugging Face",
516
+ "model_missing_huggingface_token": "Este modelo está restringido en Hugging Face. Añada un token en Ajustes → Inferencia en el dispositivo para descargarlo.",
517
+ "set_huggingface_token": "Configurar token",
518
+ "clear_huggingface_token": "Borrar",
519
+ "edit_huggingface_token_dialog_title": "Token de acceso de Hugging Face",
520
+ "huggingface_token_dialog_hint": "hf_…",
521
+ "server_type_ollama_desc": "Motor de IA local. No requiere clave API.",
522
+ "server_type_on_device_desc": "Se ejecuta en su teléfono. Algunos modelos necesitan un token de Hugging Face.",
523
+ "server_type_lm_studio_desc": "Servidor API local. No requiere clave API.",
524
+ "gguf_imported_models_title": "Imported GGUF models",
525
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
526
+ "gguf_imported_models_ready": "imported models ready for local inference.",
527
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
528
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
529
+ "gguf_imported_from_local_file": "imported from local file.",
530
+ "gguf_import_failed": "Failed to import GGUF model",
531
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
532
+ "gguf_import_canceled": "GGUF import canceled.",
533
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
534
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
535
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
536
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
537
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
538
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
539
+ "gguf_selected_file_missing": "Selected model file does not exist.",
540
+ "gguf_import_action": "Import GGUF",
541
+ "gguf_overview_title": "Bring your own GGUF models",
542
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
543
+ "gguf_imported_count_label": "imported",
544
+ "gguf_local_files_label": "local files",
545
+ "gguf_huggingface_label": "Hugging Face",
546
+ "gguf_import_local_title": "Import local GGUF",
547
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
548
+ "gguf_import_huggingface_title": "Import from Hugging Face",
549
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
550
+ "gguf_no_imported_title": "No imported GGUF models yet",
551
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
552
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
553
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
554
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
555
+ "paste": "Paste",
556
+ "gguf_browse": "Browse GGUFs",
557
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
558
+ "gguf_huggingface_token_optional": "Token optional but recommended",
559
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
560
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
561
+ "gguf_downloading": "Downloading GGUF",
562
+ "gguf_preparing": "Preparing",
563
+ "gguf_preparing_download": "Preparing download...",
564
+ "gguf_cancel_import": "Cancel import",
565
+ "clipboard_empty": "Clipboard is empty.",
566
+ "could_not_open_huggingface": "Could not open Hugging Face.",
567
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
568
+ "gguf_blob_link": "Blob link",
569
+ "gguf_repository_label": "Repository",
570
+ "gguf_detected_path_label": "Detected path",
571
+ "gguf_imported_section_label": "Imported GGUF",
572
+ "gguf_already_available": "Already available on this device",
573
+ "gguf_curated_models_short": "Curated on-device models",
574
+ "execute_tool_title": "Execute Tool",
575
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
576
+ "reject": "Reject",
577
+ "approve": "Approve",
578
+ "server_type_help": "Pick the provider before filling connection details.",
579
+ "server_identity_title": "Identity",
580
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
581
+ "server_connection_title": "Connection",
582
+ "server_connection_desc": "Use the address and port exposed by your server.",
583
+ "server_authentication_title": "Authentication",
584
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
585
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
586
+ "mcp_tools_title": "MCP Tools",
587
+ "available_tools": "Available tools",
588
+ "unable_load_tools": "Unable to load tools",
589
+ "no_tools_registered": "No tools registered",
590
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
591
+ "example_mcp_server_title": "Example MCP server",
592
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
593
+ "disable_example_server": "Disable example server",
594
+ "enable_example_server": "Enable example server",
595
+ "built_in_label": "Built-in",
596
+ "highlights_label": "Highlights",
597
+ "built_with_label": "Built with",
598
+ "local_label": "Local",
599
+ "gguf_format_label": "GGUF",
600
+ "tool_status_requested": "Requested",
601
+ "tool_status_approved": "Approved",
602
+ "tool_status_rejected": "Rejected",
603
+ "tool_status_running": "Running",
604
+ "tool_status_done": "Done",
605
+ "tool_status_failed": "Failed"
606
+}
lib/l10n/app_hi.arb
+97
-2
@@ -507,5 +507,100 @@
507
"tts_supports_background": "मूल ऑडियो के रूप में पृष्ठभूमि प्लेबैक का समर्थन करता है",
508
"tts_other_services_background_note": "नोट: अन्य टीटीएस सेवाएं मूल ऑडियो के रूप में पृष्ठभूमि प्लेबैक का समर्थन करती हैं।",
509
"start_listening_tooltip": "सुनना शुरू करें",
510
- "stop_listening_tooltip": "सुनना बंद करें"
511
-}
\ No newline at end of file
510
+ "stop_listening_tooltip": "सुनना बंद करें",
511
+ "settings_huggingface_token": "Hugging Face टोकन (वैकल्पिक)",
512
+ "settings_huggingface_token_desc": "केवल gated मॉडलों के लिए आवश्यक (जैसे Gemma)। huggingface.co/settings/tokens पर टोकन प्राप्त करें।",
513
+ "settings_huggingface_token_set": "टोकन सहेजा गया",
514
+ "settings_huggingface_token_cleared": "टोकन साफ़ किया गया",
515
+ "model_requires_huggingface_token": "Hugging Face टोकन आवश्यक है",
516
+ "model_missing_huggingface_token": "यह मॉडल Hugging Face पर gated है। इसे डाउनलोड करने के लिए Settings → On-Device Inference में एक टोकन जोड़ें।",
517
+ "set_huggingface_token": "टोकन सेट करें",
518
+ "clear_huggingface_token": "साफ़ करें",
519
+ "edit_huggingface_token_dialog_title": "Hugging Face एक्सेस टोकन",
520
+ "huggingface_token_dialog_hint": "hf_…",
521
+ "server_type_ollama_desc": "लोकल AI इंजन। API key की आवश्यकता नहीं है।",
522
+ "server_type_on_device_desc": "आपके फ़ोन पर चलता है। कुछ मॉडलों के लिए Hugging Face टोकन चाहिए।",
523
+ "server_type_lm_studio_desc": "लोकल API सर्वर। API key की आवश्यकता नहीं है।",
524
+ "gguf_imported_models_title": "Imported GGUF models",
525
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
526
+ "gguf_imported_models_ready": "imported models ready for local inference.",
527
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
528
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
529
+ "gguf_imported_from_local_file": "imported from local file.",
530
+ "gguf_import_failed": "Failed to import GGUF model",
531
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
532
+ "gguf_import_canceled": "GGUF import canceled.",
533
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
534
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
535
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
536
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
537
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
538
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
539
+ "gguf_selected_file_missing": "Selected model file does not exist.",
540
+ "gguf_import_action": "Import GGUF",
541
+ "gguf_overview_title": "Bring your own GGUF models",
542
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
543
+ "gguf_imported_count_label": "imported",
544
+ "gguf_local_files_label": "local files",
545
+ "gguf_huggingface_label": "Hugging Face",
546
+ "gguf_import_local_title": "Import local GGUF",
547
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
548
+ "gguf_import_huggingface_title": "Import from Hugging Face",
549
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
550
+ "gguf_no_imported_title": "No imported GGUF models yet",
551
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
552
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
553
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
554
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
555
+ "paste": "Paste",
556
+ "gguf_browse": "Browse GGUFs",
557
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
558
+ "gguf_huggingface_token_optional": "Token optional but recommended",
559
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
560
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
561
+ "gguf_downloading": "Downloading GGUF",
562
+ "gguf_preparing": "Preparing",
563
+ "gguf_preparing_download": "Preparing download...",
564
+ "gguf_cancel_import": "Cancel import",
565
+ "clipboard_empty": "Clipboard is empty.",
566
+ "could_not_open_huggingface": "Could not open Hugging Face.",
567
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
568
+ "gguf_blob_link": "Blob link",
569
+ "gguf_repository_label": "Repository",
570
+ "gguf_detected_path_label": "Detected path",
571
+ "gguf_imported_section_label": "Imported GGUF",
572
+ "gguf_already_available": "Already available on this device",
573
+ "gguf_curated_models_short": "Curated on-device models",
574
+ "execute_tool_title": "Execute Tool",
575
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
576
+ "reject": "Reject",
577
+ "approve": "Approve",
578
+ "server_type_help": "Pick the provider before filling connection details.",
579
+ "server_identity_title": "Identity",
580
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
581
+ "server_connection_title": "Connection",
582
+ "server_connection_desc": "Use the address and port exposed by your server.",
583
+ "server_authentication_title": "Authentication",
584
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
585
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
586
+ "mcp_tools_title": "MCP Tools",
587
+ "available_tools": "Available tools",
588
+ "unable_load_tools": "Unable to load tools",
589
+ "no_tools_registered": "No tools registered",
590
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
591
+ "example_mcp_server_title": "Example MCP server",
592
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
593
+ "disable_example_server": "Disable example server",
594
+ "enable_example_server": "Enable example server",
595
+ "built_in_label": "Built-in",
596
+ "highlights_label": "Highlights",
597
+ "built_with_label": "Built with",
598
+ "local_label": "Local",
599
+ "gguf_format_label": "GGUF",
600
+ "tool_status_requested": "Requested",
601
+ "tool_status_approved": "Approved",
602
+ "tool_status_rejected": "Rejected",
603
+ "tool_status_running": "Running",
604
+ "tool_status_done": "Done",
605
+ "tool_status_failed": "Failed"
606
+}
lib/l10n/app_it.arb
+97
-2
@@ -507,5 +507,100 @@
507
"tts_supports_background": "Supporta la riproduzione in background come audio nativo",
508
"tts_other_services_background_note": "Nota: Gli altri servizi TTS supportano la riproduzione in background come audio nativo.",
509
"start_listening_tooltip": "Avvia ascolto",
510
- "stop_listening_tooltip": "Interrompi ascolto"
511
-}
\ No newline at end of file
510
+ "stop_listening_tooltip": "Interrompi ascolto",
511
+ "settings_huggingface_token": "Token Hugging Face (Opzionale)",
512
+ "settings_huggingface_token_desc": "Richiesto solo per i modelli con accesso limitato (ad es. Gemma). Ottieni un token su huggingface.co/settings/tokens.",
513
+ "settings_huggingface_token_set": "Token salvato",
514
+ "settings_huggingface_token_cleared": "Token cancellato",
515
+ "model_requires_huggingface_token": "Richiede un token Hugging Face",
516
+ "model_missing_huggingface_token": "Questo modello ha accesso limitato su Hugging Face. Aggiungi un token in Impostazioni → Inferenza sul dispositivo per scaricarlo.",
517
+ "set_huggingface_token": "Imposta token",
518
+ "clear_huggingface_token": "Cancella",
519
+ "edit_huggingface_token_dialog_title": "Token di accesso Hugging Face",
520
+ "huggingface_token_dialog_hint": "hf_…",
521
+ "server_type_ollama_desc": "Motore AI locale. Nessuna chiave API richiesta.",
522
+ "server_type_on_device_desc": "Funziona sul tuo telefono. Alcuni modelli richiedono un token Hugging Face.",
523
+ "server_type_lm_studio_desc": "Server API locale. Nessuna chiave API richiesta.",
524
+ "gguf_imported_models_title": "Imported GGUF models",
525
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
526
+ "gguf_imported_models_ready": "imported models ready for local inference.",
527
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
528
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
529
+ "gguf_imported_from_local_file": "imported from local file.",
530
+ "gguf_import_failed": "Failed to import GGUF model",
531
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
532
+ "gguf_import_canceled": "GGUF import canceled.",
533
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
534
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
535
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
536
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
537
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
538
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
539
+ "gguf_selected_file_missing": "Selected model file does not exist.",
540
+ "gguf_import_action": "Import GGUF",
541
+ "gguf_overview_title": "Bring your own GGUF models",
542
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
543
+ "gguf_imported_count_label": "imported",
544
+ "gguf_local_files_label": "local files",
545
+ "gguf_huggingface_label": "Hugging Face",
546
+ "gguf_import_local_title": "Import local GGUF",
547
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
548
+ "gguf_import_huggingface_title": "Import from Hugging Face",
549
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
550
+ "gguf_no_imported_title": "No imported GGUF models yet",
551
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
552
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
553
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
554
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
555
+ "paste": "Paste",
556
+ "gguf_browse": "Browse GGUFs",
557
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
558
+ "gguf_huggingface_token_optional": "Token optional but recommended",
559
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
560
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
561
+ "gguf_downloading": "Downloading GGUF",
562
+ "gguf_preparing": "Preparing",
563
+ "gguf_preparing_download": "Preparing download...",
564
+ "gguf_cancel_import": "Cancel import",
565
+ "clipboard_empty": "Clipboard is empty.",
566
+ "could_not_open_huggingface": "Could not open Hugging Face.",
567
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
568
+ "gguf_blob_link": "Blob link",
569
+ "gguf_repository_label": "Repository",
570
+ "gguf_detected_path_label": "Detected path",
571
+ "gguf_imported_section_label": "Imported GGUF",
572
+ "gguf_already_available": "Already available on this device",
573
+ "gguf_curated_models_short": "Curated on-device models",
574
+ "execute_tool_title": "Execute Tool",
575
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
576
+ "reject": "Reject",
577
+ "approve": "Approve",
578
+ "server_type_help": "Pick the provider before filling connection details.",
579
+ "server_identity_title": "Identity",
580
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
581
+ "server_connection_title": "Connection",
582
+ "server_connection_desc": "Use the address and port exposed by your server.",
583
+ "server_authentication_title": "Authentication",
584
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
585
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
586
+ "mcp_tools_title": "MCP Tools",
587
+ "available_tools": "Available tools",
588
+ "unable_load_tools": "Unable to load tools",
589
+ "no_tools_registered": "No tools registered",
590
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
591
+ "example_mcp_server_title": "Example MCP server",
592
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
593
+ "disable_example_server": "Disable example server",
594
+ "enable_example_server": "Enable example server",
595
+ "built_in_label": "Built-in",
596
+ "highlights_label": "Highlights",
597
+ "built_with_label": "Built with",
598
+ "local_label": "Local",
599
+ "gguf_format_label": "GGUF",
600
+ "tool_status_requested": "Requested",
601
+ "tool_status_approved": "Approved",
602
+ "tool_status_rejected": "Rejected",
603
+ "tool_status_running": "Running",
604
+ "tool_status_done": "Done",
605
+ "tool_status_failed": "Failed"
606
+}
lib/l10n/app_ja.arb
+97
-2
@@ -507,5 +507,100 @@
507
"tts_supports_background": "ネイティブオーディオとしてバックグラウンド再生をサポート",
508
"tts_other_services_background_note": "注意: 他のTTSサービスはネイティブオーディオとしてバックグラウンド再生をサポートしています。",
509
"start_listening_tooltip": "聞き取りを開始",
510
- "stop_listening_tooltip": "聞き取りを停止"
511
-}
\ No newline at end of file
510
+ "stop_listening_tooltip": "聞き取りを停止",
511
+ "settings_huggingface_token": "Hugging Faceトークン(任意)",
512
+ "settings_huggingface_token_desc": "制限付きモデル(例: Gemma)でのみ必要です。トークンは huggingface.co/settings/tokens で取得できます。",
513
+ "settings_huggingface_token_set": "トークンを保存しました",
514
+ "settings_huggingface_token_cleared": "トークンを消去しました",
515
+ "model_requires_huggingface_token": "Hugging Faceトークンが必要です",
516
+ "model_missing_huggingface_token": "このモデルはHugging Faceで制限されています。ダウンロードするには、設定 → 端末内推論 にトークンを追加してください。",
517
+ "set_huggingface_token": "トークンを設定",
518
+ "clear_huggingface_token": "クリア",
519
+ "edit_huggingface_token_dialog_title": "Hugging Faceアクセストークン",
520
+ "huggingface_token_dialog_hint": "hf_…",
521
+ "server_type_ollama_desc": "ローカルAIエンジン。APIキーは不要です。",
522
+ "server_type_on_device_desc": "スマートフォン上で動作します。一部のモデルにはHugging Faceトークンが必要です。",
523
+ "server_type_lm_studio_desc": "ローカルAPIサーバー。APIキーは不要です。",
524
+ "gguf_imported_models_title": "Imported GGUF models",
525
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
526
+ "gguf_imported_models_ready": "imported models ready for local inference.",
527
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
528
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
529
+ "gguf_imported_from_local_file": "imported from local file.",
530
+ "gguf_import_failed": "Failed to import GGUF model",
531
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
532
+ "gguf_import_canceled": "GGUF import canceled.",
533
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
534
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
535
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
536
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
537
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
538
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
539
+ "gguf_selected_file_missing": "Selected model file does not exist.",
540
+ "gguf_import_action": "Import GGUF",
541
+ "gguf_overview_title": "Bring your own GGUF models",
542
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
543
+ "gguf_imported_count_label": "imported",
544
+ "gguf_local_files_label": "local files",
545
+ "gguf_huggingface_label": "Hugging Face",
546
+ "gguf_import_local_title": "Import local GGUF",
547
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
548
+ "gguf_import_huggingface_title": "Import from Hugging Face",
549
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
550
+ "gguf_no_imported_title": "No imported GGUF models yet",
551
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
552
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
553
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
554
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
555
+ "paste": "Paste",
556
+ "gguf_browse": "Browse GGUFs",
557
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
558
+ "gguf_huggingface_token_optional": "Token optional but recommended",
559
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
560
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
561
+ "gguf_downloading": "Downloading GGUF",
562
+ "gguf_preparing": "Preparing",
563
+ "gguf_preparing_download": "Preparing download...",
564
+ "gguf_cancel_import": "Cancel import",
565
+ "clipboard_empty": "Clipboard is empty.",
566
+ "could_not_open_huggingface": "Could not open Hugging Face.",
567
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
568
+ "gguf_blob_link": "Blob link",
569
+ "gguf_repository_label": "Repository",
570
+ "gguf_detected_path_label": "Detected path",
571
+ "gguf_imported_section_label": "Imported GGUF",
572
+ "gguf_already_available": "Already available on this device",
573
+ "gguf_curated_models_short": "Curated on-device models",
574
+ "execute_tool_title": "Execute Tool",
575
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
576
+ "reject": "Reject",
577
+ "approve": "Approve",
578
+ "server_type_help": "Pick the provider before filling connection details.",
579
+ "server_identity_title": "Identity",
580
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
581
+ "server_connection_title": "Connection",
582
+ "server_connection_desc": "Use the address and port exposed by your server.",
583
+ "server_authentication_title": "Authentication",
584
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
585
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
586
+ "mcp_tools_title": "MCP Tools",
587
+ "available_tools": "Available tools",
588
+ "unable_load_tools": "Unable to load tools",
589
+ "no_tools_registered": "No tools registered",
590
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
591
+ "example_mcp_server_title": "Example MCP server",
592
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
593
+ "disable_example_server": "Disable example server",
594
+ "enable_example_server": "Enable example server",
595
+ "built_in_label": "Built-in",
596
+ "highlights_label": "Highlights",
597
+ "built_with_label": "Built with",
598
+ "local_label": "Local",
599
+ "gguf_format_label": "GGUF",
600
+ "tool_status_requested": "Requested",
601
+ "tool_status_approved": "Approved",
602
+ "tool_status_rejected": "Rejected",
603
+ "tool_status_running": "Running",
604
+ "tool_status_done": "Done",
605
+ "tool_status_failed": "Failed"
606
+}
lib/l10n/app_localizations.dart
+492
@@ -3218,6 +3218,498 @@ abstract class AppLocalizations {
3218
/// In en, this message translates to:
3219
/// **'Note: The other TTS services support background playback as native audio.'**
3220
String get tts_other_services_background_note;
3221
+
3222
+ /// No description provided for @gguf_imported_models_title.
3223
+ ///
3224
+ /// In en, this message translates to:
3225
+ /// **'Imported GGUF models'**
3226
+ String get gguf_imported_models_title;
3227
+
3228
+ /// No description provided for @gguf_imported_models_empty_subtitle.
3229
+ ///
3230
+ /// In en, this message translates to:
3231
+ /// **'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.'**
3232
+ String get gguf_imported_models_empty_subtitle;
3233
+
3234
+ /// No description provided for @gguf_imported_models_ready.
3235
+ ///
3236
+ /// In en, this message translates to:
3237
+ /// **'imported models ready for local inference.'**
3238
+ String get gguf_imported_models_ready;
3239
+
3240
+ /// No description provided for @gguf_curated_models_subtitle.
3241
+ ///
3242
+ /// In en, this message translates to:
3243
+ /// **'Curated on-device models you can download and manage inside LocalMind.'**
3244
+ String get gguf_curated_models_subtitle;
3245
+
3246
+ /// No description provided for @gguf_only_supported.
3247
+ ///
3248
+ /// In en, this message translates to:
3249
+ /// **'Only GGUF models are supported for this import.'**
3250
+ String get gguf_only_supported;
3251
+
3252
+ /// No description provided for @gguf_imported_from_local_file.
3253
+ ///
3254
+ /// In en, this message translates to:
3255
+ /// **'imported from local file.'**
3256
+ String get gguf_imported_from_local_file;
3257
+
3258
+ /// No description provided for @gguf_import_failed.
3259
+ ///
3260
+ /// In en, this message translates to:
3261
+ /// **'Failed to import GGUF model'**
3262
+ String get gguf_import_failed;
3263
+
3264
+ /// No description provided for @gguf_imported_from_huggingface.
3265
+ ///
3266
+ /// In en, this message translates to:
3267
+ /// **'imported from Hugging Face.'**
3268
+ String get gguf_imported_from_huggingface;
3269
+
3270
+ /// No description provided for @gguf_import_canceled.
3271
+ ///
3272
+ /// In en, this message translates to:
3273
+ /// **'GGUF import canceled.'**
3274
+ String get gguf_import_canceled;
3275
+
3276
+ /// No description provided for @gguf_enter_huggingface_url.
3277
+ ///
3278
+ /// In en, this message translates to:
3279
+ /// **'Enter a Hugging Face GGUF URL.'**
3280
+ String get gguf_enter_huggingface_url;
3281
+
3282
+ /// No description provided for @gguf_only_official_huggingface_urls.
3283
+ ///
3284
+ /// In en, this message translates to:
3285
+ /// **'Only official Hugging Face GGUF URLs are supported.'**
3286
+ String get gguf_only_official_huggingface_urls;
3287
+
3288
+ /// No description provided for @gguf_use_https_url.
3289
+ ///
3290
+ /// In en, this message translates to:
3291
+ /// **'Use an HTTPS Hugging Face URL for GGUF import.'**
3292
+ String get gguf_use_https_url;
3293
+
3294
+ /// No description provided for @gguf_url_must_point_to_file.
3295
+ ///
3296
+ /// In en, this message translates to:
3297
+ /// **'The Hugging Face URL must point directly to a .gguf file.'**
3298
+ String get gguf_url_must_point_to_file;
3299
+
3300
+ /// No description provided for @gguf_unable_to_detect_file_name.
3301
+ ///
3302
+ /// In en, this message translates to:
3303
+ /// **'Unable to determine the GGUF file name.'**
3304
+ String get gguf_unable_to_detect_file_name;
3305
+
3306
+ /// No description provided for @gguf_download_empty.
3307
+ ///
3308
+ /// In en, this message translates to:
3309
+ /// **'The downloaded GGUF file was empty or missing.'**
3310
+ String get gguf_download_empty;
3311
+
3312
+ /// No description provided for @gguf_selected_file_missing.
3313
+ ///
3314
+ /// In en, this message translates to:
3315
+ /// **'Selected model file does not exist.'**
3316
+ String get gguf_selected_file_missing;
3317
+
3318
+ /// No description provided for @gguf_import_action.
3319
+ ///
3320
+ /// In en, this message translates to:
3321
+ /// **'Import GGUF'**
3322
+ String get gguf_import_action;
3323
+
3324
+ /// No description provided for @gguf_overview_title.
3325
+ ///
3326
+ /// In en, this message translates to:
3327
+ /// **'Bring your own GGUF models'**
3328
+ String get gguf_overview_title;
3329
+
3330
+ /// No description provided for @gguf_overview_subtitle.
3331
+ ///
3332
+ /// In en, this message translates to:
3333
+ /// **'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.'**
3334
+ String get gguf_overview_subtitle;
3335
+
3336
+ /// No description provided for @gguf_imported_count_label.
3337
+ ///
3338
+ /// In en, this message translates to:
3339
+ /// **'imported'**
3340
+ String get gguf_imported_count_label;
3341
+
3342
+ /// No description provided for @gguf_local_files_label.
3343
+ ///
3344
+ /// In en, this message translates to:
3345
+ /// **'local files'**
3346
+ String get gguf_local_files_label;
3347
+
3348
+ /// No description provided for @gguf_huggingface_label.
3349
+ ///
3350
+ /// In en, this message translates to:
3351
+ /// **'Hugging Face'**
3352
+ String get gguf_huggingface_label;
3353
+
3354
+ /// No description provided for @gguf_import_local_title.
3355
+ ///
3356
+ /// In en, this message translates to:
3357
+ /// **'Import local GGUF'**
3358
+ String get gguf_import_local_title;
3359
+
3360
+ /// No description provided for @gguf_import_local_subtitle.
3361
+ ///
3362
+ /// In en, this message translates to:
3363
+ /// **'Copy a .gguf file from this device'**
3364
+ String get gguf_import_local_subtitle;
3365
+
3366
+ /// No description provided for @gguf_import_huggingface_title.
3367
+ ///
3368
+ /// In en, this message translates to:
3369
+ /// **'Import from Hugging Face'**
3370
+ String get gguf_import_huggingface_title;
3371
+
3372
+ /// No description provided for @gguf_import_huggingface_subtitle.
3373
+ ///
3374
+ /// In en, this message translates to:
3375
+ /// **'Paste a GGUF URL or repo path'**
3376
+ String get gguf_import_huggingface_subtitle;
3377
+
3378
+ /// No description provided for @gguf_no_imported_title.
3379
+ ///
3380
+ /// In en, this message translates to:
3381
+ /// **'No imported GGUF models yet'**
3382
+ String get gguf_no_imported_title;
3383
+
3384
+ /// No description provided for @gguf_no_imported_subtitle.
3385
+ ///
3386
+ /// In en, this message translates to:
3387
+ /// **'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.'**
3388
+ String get gguf_no_imported_subtitle;
3389
+
3390
+ /// No description provided for @gguf_import_huggingface_dialog_title.
3391
+ ///
3392
+ /// In en, this message translates to:
3393
+ /// **'Import GGUF from Hugging Face'**
3394
+ String get gguf_import_huggingface_dialog_title;
3395
+
3396
+ /// No description provided for @gguf_import_huggingface_dialog_subtitle.
3397
+ ///
3398
+ /// In en, this message translates to:
3399
+ /// **'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.'**
3400
+ String get gguf_import_huggingface_dialog_subtitle;
3401
+
3402
+ /// No description provided for @gguf_url_or_repo_path.
3403
+ ///
3404
+ /// In en, this message translates to:
3405
+ /// **'GGUF URL or repo path'**
3406
+ String get gguf_url_or_repo_path;
3407
+
3408
+ /// No description provided for @paste.
3409
+ ///
3410
+ /// In en, this message translates to:
3411
+ /// **'Paste'**
3412
+ String get paste;
3413
+
3414
+ /// No description provided for @gguf_browse.
3415
+ ///
3416
+ /// In en, this message translates to:
3417
+ /// **'Browse GGUFs'**
3418
+ String get gguf_browse;
3419
+
3420
+ /// No description provided for @gguf_huggingface_token_ready.
3421
+ ///
3422
+ /// In en, this message translates to:
3423
+ /// **'Hugging Face token ready'**
3424
+ String get gguf_huggingface_token_ready;
3425
+
3426
+ /// No description provided for @gguf_huggingface_token_optional.
3427
+ ///
3428
+ /// In en, this message translates to:
3429
+ /// **'Token optional but recommended'**
3430
+ String get gguf_huggingface_token_optional;
3431
+
3432
+ /// No description provided for @gguf_huggingface_token_ready_desc.
3433
+ ///
3434
+ /// In en, this message translates to:
3435
+ /// **'Your saved token will be used automatically for gated or private repositories.'**
3436
+ String get gguf_huggingface_token_ready_desc;
3437
+
3438
+ /// No description provided for @gguf_huggingface_token_optional_desc.
3439
+ ///
3440
+ /// In en, this message translates to:
3441
+ /// **'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.'**
3442
+ String get gguf_huggingface_token_optional_desc;
3443
+
3444
+ /// No description provided for @gguf_downloading.
3445
+ ///
3446
+ /// In en, this message translates to:
3447
+ /// **'Downloading GGUF'**
3448
+ String get gguf_downloading;
3449
+
3450
+ /// No description provided for @gguf_preparing.
3451
+ ///
3452
+ /// In en, this message translates to:
3453
+ /// **'Preparing'**
3454
+ String get gguf_preparing;
3455
+
3456
+ /// No description provided for @gguf_preparing_download.
3457
+ ///
3458
+ /// In en, this message translates to:
3459
+ /// **'Preparing download...'**
3460
+ String get gguf_preparing_download;
3461
+
3462
+ /// No description provided for @gguf_cancel_import.
3463
+ ///
3464
+ /// In en, this message translates to:
3465
+ /// **'Cancel import'**
3466
+ String get gguf_cancel_import;
3467
+
3468
+ /// No description provided for @clipboard_empty.
3469
+ ///
3470
+ /// In en, this message translates to:
3471
+ /// **'Clipboard is empty.'**
3472
+ String get clipboard_empty;
3473
+
3474
+ /// No description provided for @could_not_open_huggingface.
3475
+ ///
3476
+ /// In en, this message translates to:
3477
+ /// **'Could not open Hugging Face.'**
3478
+ String get could_not_open_huggingface;
3479
+
3480
+ /// No description provided for @gguf_paste_url_error.
3481
+ ///
3482
+ /// In en, this message translates to:
3483
+ /// **'Paste a Hugging Face GGUF URL or repo path.'**
3484
+ String get gguf_paste_url_error;
3485
+
3486
+ /// No description provided for @gguf_blob_link.
3487
+ ///
3488
+ /// In en, this message translates to:
3489
+ /// **'Blob link'**
3490
+ String get gguf_blob_link;
3491
+
3492
+ /// No description provided for @gguf_repository_label.
3493
+ ///
3494
+ /// In en, this message translates to:
3495
+ /// **'Repository'**
3496
+ String get gguf_repository_label;
3497
+
3498
+ /// No description provided for @gguf_detected_path_label.
3499
+ ///
3500
+ /// In en, this message translates to:
3501
+ /// **'Detected path'**
3502
+ String get gguf_detected_path_label;
3503
+
3504
+ /// No description provided for @gguf_imported_section_label.
3505
+ ///
3506
+ /// In en, this message translates to:
3507
+ /// **'Imported GGUF'**
3508
+ String get gguf_imported_section_label;
3509
+
3510
+ /// No description provided for @gguf_already_available.
3511
+ ///
3512
+ /// In en, this message translates to:
3513
+ /// **'Already available on this device'**
3514
+ String get gguf_already_available;
3515
+
3516
+ /// No description provided for @gguf_curated_models_short.
3517
+ ///
3518
+ /// In en, this message translates to:
3519
+ /// **'Curated on-device models'**
3520
+ String get gguf_curated_models_short;
3521
+
3522
+ /// No description provided for @execute_tool_title.
3523
+ ///
3524
+ /// In en, this message translates to:
3525
+ /// **'Execute Tool'**
3526
+ String get execute_tool_title;
3527
+
3528
+ /// No description provided for @execute_tool_request_desc.
3529
+ ///
3530
+ /// In en, this message translates to:
3531
+ /// **'The model is requesting to execute the following tool:'**
3532
+ String get execute_tool_request_desc;
3533
+
3534
+ /// No description provided for @reject.
3535
+ ///
3536
+ /// In en, this message translates to:
3537
+ /// **'Reject'**
3538
+ String get reject;
3539
+
3540
+ /// No description provided for @approve.
3541
+ ///
3542
+ /// In en, this message translates to:
3543
+ /// **'Approve'**
3544
+ String get approve;
3545
+
3546
+ /// No description provided for @server_type_help.
3547
+ ///
3548
+ /// In en, this message translates to:
3549
+ /// **'Pick the provider before filling connection details.'**
3550
+ String get server_type_help;
3551
+
3552
+ /// No description provided for @server_identity_title.
3553
+ ///
3554
+ /// In en, this message translates to:
3555
+ /// **'Identity'**
3556
+ String get server_identity_title;
3557
+
3558
+ /// No description provided for @server_identity_desc.
3559
+ ///
3560
+ /// In en, this message translates to:
3561
+ /// **'Name this server and choose how it appears in the list.'**
3562
+ String get server_identity_desc;
3563
+
3564
+ /// No description provided for @server_connection_title.
3565
+ ///
3566
+ /// In en, this message translates to:
3567
+ /// **'Connection'**
3568
+ String get server_connection_title;
3569
+
3570
+ /// No description provided for @server_connection_desc.
3571
+ ///
3572
+ /// In en, this message translates to:
3573
+ /// **'Use the address and port exposed by your server.'**
3574
+ String get server_connection_desc;
3575
+
3576
+ /// No description provided for @server_authentication_title.
3577
+ ///
3578
+ /// In en, this message translates to:
3579
+ /// **'Authentication'**
3580
+ String get server_authentication_title;
3581
+
3582
+ /// No description provided for @server_authentication_required_desc.
3583
+ ///
3584
+ /// In en, this message translates to:
3585
+ /// **'OpenRouter requires an API key before testing.'**
3586
+ String get server_authentication_required_desc;
3587
+
3588
+ /// No description provided for @server_authentication_optional_desc.
3589
+ ///
3590
+ /// In en, this message translates to:
3591
+ /// **'Leave the API key empty if this server does not require one.'**
3592
+ String get server_authentication_optional_desc;
3593
+
3594
+ /// No description provided for @mcp_tools_title.
3595
+ ///
3596
+ /// In en, this message translates to:
3597
+ /// **'MCP Tools'**
3598
+ String get mcp_tools_title;
3599
+
3600
+ /// No description provided for @available_tools.
3601
+ ///
3602
+ /// In en, this message translates to:
3603
+ /// **'Available tools'**
3604
+ String get available_tools;
3605
+
3606
+ /// No description provided for @unable_load_tools.
3607
+ ///
3608
+ /// In en, this message translates to:
3609
+ /// **'Unable to load tools'**
3610
+ String get unable_load_tools;
3611
+
3612
+ /// No description provided for @no_tools_registered.
3613
+ ///
3614
+ /// In en, this message translates to:
3615
+ /// **'No tools registered'**
3616
+ String get no_tools_registered;
3617
+
3618
+ /// No description provided for @no_tools_registered_desc.
3619
+ ///
3620
+ /// In en, this message translates to:
3621
+ /// **'Enable the example MCP server or add MCP integrations from chat settings.'**
3622
+ String get no_tools_registered_desc;
3623
+
3624
+ /// No description provided for @example_mcp_server_title.
3625
+ ///
3626
+ /// In en, this message translates to:
3627
+ /// **'Example MCP server'**
3628
+ String get example_mcp_server_title;
3629
+
3630
+ /// No description provided for @example_mcp_server_desc.
3631
+ ///
3632
+ /// In en, this message translates to:
3633
+ /// **'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.'**
3634
+ String get example_mcp_server_desc;
3635
+
3636
+ /// No description provided for @disable_example_server.
3637
+ ///
3638
+ /// In en, this message translates to:
3639
+ /// **'Disable example server'**
3640
+ String get disable_example_server;
3641
+
3642
+ /// No description provided for @enable_example_server.
3643
+ ///
3644
+ /// In en, this message translates to:
3645
+ /// **'Enable example server'**
3646
+ String get enable_example_server;
3647
+
3648
+ /// No description provided for @built_in_label.
3649
+ ///
3650
+ /// In en, this message translates to:
3651
+ /// **'Built-in'**
3652
+ String get built_in_label;
3653
+
3654
+ /// No description provided for @highlights_label.
3655
+ ///
3656
+ /// In en, this message translates to:
3657
+ /// **'Highlights'**
3658
+ String get highlights_label;
3659
+
3660
+ /// No description provided for @built_with_label.
3661
+ ///
3662
+ /// In en, this message translates to:
3663
+ /// **'Built with'**
3664
+ String get built_with_label;
3665
+
3666
+ /// No description provided for @local_label.
3667
+ ///
3668
+ /// In en, this message translates to:
3669
+ /// **'Local'**
3670
+ String get local_label;
3671
+
3672
+ /// No description provided for @gguf_format_label.
3673
+ ///
3674
+ /// In en, this message translates to:
3675
+ /// **'GGUF'**
3676
+ String get gguf_format_label;
3677
+
3678
+ /// No description provided for @tool_status_requested.
3679
+ ///
3680
+ /// In en, this message translates to:
3681
+ /// **'Requested'**
3682
+ String get tool_status_requested;
3683
+
3684
+ /// No description provided for @tool_status_approved.
3685
+ ///
3686
+ /// In en, this message translates to:
3687
+ /// **'Approved'**
3688
+ String get tool_status_approved;
3689
+
3690
+ /// No description provided for @tool_status_rejected.
3691
+ ///
3692
+ /// In en, this message translates to:
3693
+ /// **'Rejected'**
3694
+ String get tool_status_rejected;
3695
+
3696
+ /// No description provided for @tool_status_running.
3697
+ ///
3698
+ /// In en, this message translates to:
3699
+ /// **'Running'**
3700
+ String get tool_status_running;
3701
+
3702
+ /// No description provided for @tool_status_done.
3703
+ ///
3704
+ /// In en, this message translates to:
3705
+ /// **'Done'**
3706
+ String get tool_status_done;
3707
+
3708
+ /// No description provided for @tool_status_failed.
3709
+ ///
3710
+ /// In en, this message translates to:
3711
+ /// **'Failed'**
3712
+ String get tool_status_failed;
3713
}
3714
3715
class _AppLocalizationsDelegate
lib/l10n/app_localizations_ar.dart
+286
-14
@@ -1371,48 +1371,47 @@ class AppLocalizationsAr extends AppLocalizations {
1371
String get on_device_models_title => 'النماذج المحلية';
1372
1373
@override
1374
- String get settings_huggingface_token => 'Hugging Face Token (Optional)';
1374
+ String get settings_huggingface_token => 'رمز Hugging Face (اختياري)';
1375
1376
@override
1377
String get settings_huggingface_token_desc =>
1378
- 'Required only for gated models (e.g. Gemma). Get a token at huggingface.co/settings/tokens.';
1378
+ 'مطلوب فقط للنماذج المقيّدة (مثل Gemma). احصل على رمز من huggingface.co/settings/tokens.';
1379
1380
@override
1381
- String get settings_huggingface_token_set => 'Token saved';
1381
+ String get settings_huggingface_token_set => 'تم حفظ الرمز';
1382
1383
@override
1384
- String get settings_huggingface_token_cleared => 'Token cleared';
1384
+ String get settings_huggingface_token_cleared => 'تم مسح الرمز';
1385
1386
@override
1387
- String get model_requires_huggingface_token =>
1388
- 'Requires a Hugging Face token';
1387
+ String get model_requires_huggingface_token => 'يتطلب رمز Hugging Face';
1388
1389
@override
1390
String get model_missing_huggingface_token =>
1392
- 'This model is gated on Hugging Face. Add a token in Settings → On-Device Inference to download it.';
1391
+ 'هذا النموذج مقيّد على Hugging Face. أضف رمزاً في الإعدادات ← الاستدلال المحلي لتنزيله.';
1392
1393
@override
1395
- String get set_huggingface_token => 'Set token';
1394
+ String get set_huggingface_token => 'تعيين الرمز';
1395
1396
@override
1398
- String get clear_huggingface_token => 'Clear';
1397
+ String get clear_huggingface_token => 'مسح';
1398
1399
@override
1401
- String get edit_huggingface_token_dialog_title => 'Hugging Face Access Token';
1400
+ String get edit_huggingface_token_dialog_title => 'رمز وصول Hugging Face';
1401
1402
@override
1403
String get huggingface_token_dialog_hint => 'hf_…';
1404
1405
@override
1407
- String get server_type_ollama_desc => 'Local AI engine. No API key required.';
1406
+ String get server_type_ollama_desc =>
1407
+ 'محرك ذكاء اصطناعي محلي. لا يتطلب مفتاح API.';
1408
1409
@override
1410
String get server_type_on_device_desc =>
1411
- 'Runs on your phone. Some models need a Hugging Face token.';
1411
+ 'يعمل على هاتفك. بعض النماذج تحتاج إلى رمز Hugging Face.';
1412
1413
@override
1414
- String get server_type_lm_studio_desc =>
1415
- 'Local API server. No API key required.';
1414
+ String get server_type_lm_studio_desc => 'خادم API محلي. لا يتطلب مفتاح API.';
1415
1416
@override
1417
String get available_models => 'النماذج المتاحة';
@@ -1676,4 +1675,277 @@ class AppLocalizationsAr extends AppLocalizations {
1675
@override
1676
String get tts_other_services_background_note =>
1677
'ملاحظة: تدعم خدمات TTS الأخرى التشغيل في الخلفية كصوت أصلي.';
1678
+
1679
+ @override
1680
+ String get gguf_imported_models_title => 'Imported GGUF models';
1681
+
1682
+ @override
1683
+ String get gguf_imported_models_empty_subtitle =>
1684
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
1685
+
1686
+ @override
1687
+ String get gguf_imported_models_ready =>
1688
+ 'imported models ready for local inference.';
1689
+
1690
+ @override
1691
+ String get gguf_curated_models_subtitle =>
1692
+ 'Curated on-device models you can download and manage inside LocalMind.';
1693
+
1694
+ @override
1695
+ String get gguf_only_supported =>
1696
+ 'Only GGUF models are supported for this import.';
1697
+
1698
+ @override
1699
+ String get gguf_imported_from_local_file => 'imported from local file.';
1700
+
1701
+ @override
1702
+ String get gguf_import_failed => 'Failed to import GGUF model';
1703
+
1704
+ @override
1705
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
1706
+
1707
+ @override
1708
+ String get gguf_import_canceled => 'GGUF import canceled.';
1709
+
1710
+ @override
1711
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
1712
+
1713
+ @override
1714
+ String get gguf_only_official_huggingface_urls =>
1715
+ 'Only official Hugging Face GGUF URLs are supported.';
1716
+
1717
+ @override
1718
+ String get gguf_use_https_url =>
1719
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
1720
+
1721
+ @override
1722
+ String get gguf_url_must_point_to_file =>
1723
+ 'The Hugging Face URL must point directly to a .gguf file.';
1724
+
1725
+ @override
1726
+ String get gguf_unable_to_detect_file_name =>
1727
+ 'Unable to determine the GGUF file name.';
1728
+
1729
+ @override
1730
+ String get gguf_download_empty =>
1731
+ 'The downloaded GGUF file was empty or missing.';
1732
+
1733
+ @override
1734
+ String get gguf_selected_file_missing =>
1735
+ 'Selected model file does not exist.';
1736
+
1737
+ @override
1738
+ String get gguf_import_action => 'Import GGUF';
1739
+
1740
+ @override
1741
+ String get gguf_overview_title => 'Bring your own GGUF models';
1742
+
1743
+ @override
1744
+ String get gguf_overview_subtitle =>
1745
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
1746
+
1747
+ @override
1748
+ String get gguf_imported_count_label => 'imported';
1749
+
1750
+ @override
1751
+ String get gguf_local_files_label => 'local files';
1752
+
1753
+ @override
1754
+ String get gguf_huggingface_label => 'Hugging Face';
1755
+
1756
+ @override
1757
+ String get gguf_import_local_title => 'Import local GGUF';
1758
+
1759
+ @override
1760
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
1761
+
1762
+ @override
1763
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
1764
+
1765
+ @override
1766
+ String get gguf_import_huggingface_subtitle =>
1767
+ 'Paste a GGUF URL or repo path';
1768
+
1769
+ @override
1770
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
1771
+
1772
+ @override
1773
+ String get gguf_no_imported_subtitle =>
1774
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
1775
+
1776
+ @override
1777
+ String get gguf_import_huggingface_dialog_title =>
1778
+ 'Import GGUF from Hugging Face';
1779
+
1780
+ @override
1781
+ String get gguf_import_huggingface_dialog_subtitle =>
1782
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
1783
+
1784
+ @override
1785
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
1786
+
1787
+ @override
1788
+ String get paste => 'Paste';
1789
+
1790
+ @override
1791
+ String get gguf_browse => 'Browse GGUFs';
1792
+
1793
+ @override
1794
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
1795
+
1796
+ @override
1797
+ String get gguf_huggingface_token_optional =>
1798
+ 'Token optional but recommended';
1799
+
1800
+ @override
1801
+ String get gguf_huggingface_token_ready_desc =>
1802
+ 'Your saved token will be used automatically for gated or private repositories.';
1803
+
1804
+ @override
1805
+ String get gguf_huggingface_token_optional_desc =>
1806
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
1807
+
1808
+ @override
1809
+ String get gguf_downloading => 'Downloading GGUF';
1810
+
1811
+ @override
1812
+ String get gguf_preparing => 'Preparing';
1813
+
1814
+ @override
1815
+ String get gguf_preparing_download => 'Preparing download...';
1816
+
1817
+ @override
1818
+ String get gguf_cancel_import => 'Cancel import';
1819
+
1820
+ @override
1821
+ String get clipboard_empty => 'Clipboard is empty.';
1822
+
1823
+ @override
1824
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
1825
+
1826
+ @override
1827
+ String get gguf_paste_url_error =>
1828
+ 'Paste a Hugging Face GGUF URL or repo path.';
1829
+
1830
+ @override
1831
+ String get gguf_blob_link => 'Blob link';
1832
+
1833
+ @override
1834
+ String get gguf_repository_label => 'Repository';
1835
+
1836
+ @override
1837
+ String get gguf_detected_path_label => 'Detected path';
1838
+
1839
+ @override
1840
+ String get gguf_imported_section_label => 'Imported GGUF';
1841
+
1842
+ @override
1843
+ String get gguf_already_available => 'Already available on this device';
1844
+
1845
+ @override
1846
+ String get gguf_curated_models_short => 'Curated on-device models';
1847
+
1848
+ @override
1849
+ String get execute_tool_title => 'Execute Tool';
1850
+
1851
+ @override
1852
+ String get execute_tool_request_desc =>
1853
+ 'The model is requesting to execute the following tool:';
1854
+
1855
+ @override
1856
+ String get reject => 'Reject';
1857
+
1858
+ @override
1859
+ String get approve => 'Approve';
1860
+
1861
+ @override
1862
+ String get server_type_help =>
1863
+ 'Pick the provider before filling connection details.';
1864
+
1865
+ @override
1866
+ String get server_identity_title => 'Identity';
1867
+
1868
+ @override
1869
+ String get server_identity_desc =>
1870
+ 'Name this server and choose how it appears in the list.';
1871
+
1872
+ @override
1873
+ String get server_connection_title => 'Connection';
1874
+
1875
+ @override
1876
+ String get server_connection_desc =>
1877
+ 'Use the address and port exposed by your server.';
1878
+
1879
+ @override
1880
+ String get server_authentication_title => 'Authentication';
1881
+
1882
+ @override
1883
+ String get server_authentication_required_desc =>
1884
+ 'OpenRouter requires an API key before testing.';
1885
+
1886
+ @override
1887
+ String get server_authentication_optional_desc =>
1888
+ 'Leave the API key empty if this server does not require one.';
1889
+
1890
+ @override
1891
+ String get mcp_tools_title => 'MCP Tools';
1892
+
1893
+ @override
1894
+ String get available_tools => 'Available tools';
1895
+
1896
+ @override
1897
+ String get unable_load_tools => 'Unable to load tools';
1898
+
1899
+ @override
1900
+ String get no_tools_registered => 'No tools registered';
1901
+
1902
+ @override
1903
+ String get no_tools_registered_desc =>
1904
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
1905
+
1906
+ @override
1907
+ String get example_mcp_server_title => 'Example MCP server';
1908
+
1909
+ @override
1910
+ String get example_mcp_server_desc =>
1911
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
1912
+
1913
+ @override
1914
+ String get disable_example_server => 'Disable example server';
1915
+
1916
+ @override
1917
+ String get enable_example_server => 'Enable example server';
1918
+
1919
+ @override
1920
+ String get built_in_label => 'Built-in';
1921
+
1922
+ @override
1923
+ String get highlights_label => 'Highlights';
1924
+
1925
+ @override
1926
+ String get built_with_label => 'Built with';
1927
+
1928
+ @override
1929
+ String get local_label => 'Local';
1930
+
1931
+ @override
1932
+ String get gguf_format_label => 'GGUF';
1933
+
1934
+ @override
1935
+ String get tool_status_requested => 'Requested';
1936
+
1937
+ @override
1938
+ String get tool_status_approved => 'Approved';
1939
+
1940
+ @override
1941
+ String get tool_status_rejected => 'Rejected';
1942
+
1943
+ @override
1944
+ String get tool_status_running => 'Running';
1945
+
1946
+ @override
1947
+ String get tool_status_done => 'Done';
1948
+
1949
+ @override
1950
+ String get tool_status_failed => 'Failed';
1951
}
lib/l10n/app_localizations_bn.dart
+287
-13
@@ -1377,48 +1377,49 @@ class AppLocalizationsBn extends AppLocalizations {
1377
String get on_device_models_title => 'অন-ডিভাইস মডেলসমূহ';
1378
1379
@override
1380
- String get settings_huggingface_token => 'Hugging Face Token (Optional)';
1380
+ String get settings_huggingface_token => 'Hugging Face টোকেন (ঐচ্ছিক)';
1381
1382
@override
1383
String get settings_huggingface_token_desc =>
1384
- 'Required only for gated models (e.g. Gemma). Get a token at huggingface.co/settings/tokens.';
1384
+ 'শুধু gated মডেলের জন্য প্রয়োজন (যেমন Gemma)। huggingface.co/settings/tokens থেকে একটি টোকেন নিন।';
1385
1386
@override
1387
- String get settings_huggingface_token_set => 'Token saved';
1387
+ String get settings_huggingface_token_set => 'টোকেন সংরক্ষিত হয়েছে';
1388
1389
@override
1390
- String get settings_huggingface_token_cleared => 'Token cleared';
1390
+ String get settings_huggingface_token_cleared => 'টোকেন মুছে ফেলা হয়েছে';
1391
1392
@override
1393
- String get model_requires_huggingface_token =>
1394
- 'Requires a Hugging Face token';
1393
+ String get model_requires_huggingface_token => 'Hugging Face টোকেন প্রয়োজন';
1394
1395
@override
1396
String get model_missing_huggingface_token =>
1398
- 'This model is gated on Hugging Face. Add a token in Settings → On-Device Inference to download it.';
1397
+ 'এই মডেলটি Hugging Face-এ gated। এটি ডাউনলোড করতে Settings → On-Device Inference-এ একটি টোকেন যোগ করুন।';
1398
1399
@override
1401
- String get set_huggingface_token => 'Set token';
1400
+ String get set_huggingface_token => 'টোকেন সেট করুন';
1401
1402
@override
1404
- String get clear_huggingface_token => 'Clear';
1403
+ String get clear_huggingface_token => 'মুছুন';
1404
1405
@override
1407
- String get edit_huggingface_token_dialog_title => 'Hugging Face Access Token';
1406
+ String get edit_huggingface_token_dialog_title =>
1407
+ 'Hugging Face অ্যাক্সেস টোকেন';
1408
1409
@override
1410
String get huggingface_token_dialog_hint => 'hf_…';
1411
1412
@override
1413
- String get server_type_ollama_desc => 'Local AI engine. No API key required.';
1413
+ String get server_type_ollama_desc =>
1414
+ 'লোকাল AI ইঞ্জিন। API key প্রয়োজন নেই।';
1415
1416
@override
1417
String get server_type_on_device_desc =>
1417
- 'Runs on your phone. Some models need a Hugging Face token.';
1418
+ 'আপনার ফোনে চলে। কিছু মডেলের জন্য Hugging Face টোকেন লাগে।';
1419
1420
@override
1421
String get server_type_lm_studio_desc =>
1421
- 'Local API server. No API key required.';
1422
+ 'লোকাল API সার্ভার। API key প্রয়োজন নেই।';
1423
1424
@override
1425
String get available_models => 'উপলব্ধ মডেলসমূহ';
@@ -1687,4 +1688,277 @@ class AppLocalizationsBn extends AppLocalizations {
1688
@override
1689
String get tts_other_services_background_note =>
1690
'দ্রষ্টব্য: অন্যান্য টিটিএস পরিষেবাগুলি নেটিভ অডিও হিসাবে ব্যাকগ্রাউন্ড প্লেব্যাক সমর্থন করে।';
1691
+
1692
+ @override
1693
+ String get gguf_imported_models_title => 'Imported GGUF models';
1694
+
1695
+ @override
1696
+ String get gguf_imported_models_empty_subtitle =>
1697
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
1698
+
1699
+ @override
1700
+ String get gguf_imported_models_ready =>
1701
+ 'imported models ready for local inference.';
1702
+
1703
+ @override
1704
+ String get gguf_curated_models_subtitle =>
1705
+ 'Curated on-device models you can download and manage inside LocalMind.';
1706
+
1707
+ @override
1708
+ String get gguf_only_supported =>
1709
+ 'Only GGUF models are supported for this import.';
1710
+
1711
+ @override
1712
+ String get gguf_imported_from_local_file => 'imported from local file.';
1713
+
1714
+ @override
1715
+ String get gguf_import_failed => 'Failed to import GGUF model';
1716
+
1717
+ @override
1718
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
1719
+
1720
+ @override
1721
+ String get gguf_import_canceled => 'GGUF import canceled.';
1722
+
1723
+ @override
1724
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
1725
+
1726
+ @override
1727
+ String get gguf_only_official_huggingface_urls =>
1728
+ 'Only official Hugging Face GGUF URLs are supported.';
1729
+
1730
+ @override
1731
+ String get gguf_use_https_url =>
1732
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
1733
+
1734
+ @override
1735
+ String get gguf_url_must_point_to_file =>
1736
+ 'The Hugging Face URL must point directly to a .gguf file.';
1737
+
1738
+ @override
1739
+ String get gguf_unable_to_detect_file_name =>
1740
+ 'Unable to determine the GGUF file name.';
1741
+
1742
+ @override
1743
+ String get gguf_download_empty =>
1744
+ 'The downloaded GGUF file was empty or missing.';
1745
+
1746
+ @override
1747
+ String get gguf_selected_file_missing =>
1748
+ 'Selected model file does not exist.';
1749
+
1750
+ @override
1751
+ String get gguf_import_action => 'Import GGUF';
1752
+
1753
+ @override
1754
+ String get gguf_overview_title => 'Bring your own GGUF models';
1755
+
1756
+ @override
1757
+ String get gguf_overview_subtitle =>
1758
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
1759
+
1760
+ @override
1761
+ String get gguf_imported_count_label => 'imported';
1762
+
1763
+ @override
1764
+ String get gguf_local_files_label => 'local files';
1765
+
1766
+ @override
1767
+ String get gguf_huggingface_label => 'Hugging Face';
1768
+
1769
+ @override
1770
+ String get gguf_import_local_title => 'Import local GGUF';
1771
+
1772
+ @override
1773
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
1774
+
1775
+ @override
1776
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
1777
+
1778
+ @override
1779
+ String get gguf_import_huggingface_subtitle =>
1780
+ 'Paste a GGUF URL or repo path';
1781
+
1782
+ @override
1783
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
1784
+
1785
+ @override
1786
+ String get gguf_no_imported_subtitle =>
1787
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
1788
+
1789
+ @override
1790
+ String get gguf_import_huggingface_dialog_title =>
1791
+ 'Import GGUF from Hugging Face';
1792
+
1793
+ @override
1794
+ String get gguf_import_huggingface_dialog_subtitle =>
1795
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
1796
+
1797
+ @override
1798
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
1799
+
1800
+ @override
1801
+ String get paste => 'Paste';
1802
+
1803
+ @override
1804
+ String get gguf_browse => 'Browse GGUFs';
1805
+
1806
+ @override
1807
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
1808
+
1809
+ @override
1810
+ String get gguf_huggingface_token_optional =>
1811
+ 'Token optional but recommended';
1812
+
1813
+ @override
1814
+ String get gguf_huggingface_token_ready_desc =>
1815
+ 'Your saved token will be used automatically for gated or private repositories.';
1816
+
1817
+ @override
1818
+ String get gguf_huggingface_token_optional_desc =>
1819
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
1820
+
1821
+ @override
1822
+ String get gguf_downloading => 'Downloading GGUF';
1823
+
1824
+ @override
1825
+ String get gguf_preparing => 'Preparing';
1826
+
1827
+ @override
1828
+ String get gguf_preparing_download => 'Preparing download...';
1829
+
1830
+ @override
1831
+ String get gguf_cancel_import => 'Cancel import';
1832
+
1833
+ @override
1834
+ String get clipboard_empty => 'Clipboard is empty.';
1835
+
1836
+ @override
1837
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
1838
+
1839
+ @override
1840
+ String get gguf_paste_url_error =>
1841
+ 'Paste a Hugging Face GGUF URL or repo path.';
1842
+
1843
+ @override
1844
+ String get gguf_blob_link => 'Blob link';
1845
+
1846
+ @override
1847
+ String get gguf_repository_label => 'Repository';
1848
+
1849
+ @override
1850
+ String get gguf_detected_path_label => 'Detected path';
1851
+
1852
+ @override
1853
+ String get gguf_imported_section_label => 'Imported GGUF';
1854
+
1855
+ @override
1856
+ String get gguf_already_available => 'Already available on this device';
1857
+
1858
+ @override
1859
+ String get gguf_curated_models_short => 'Curated on-device models';
1860
+
1861
+ @override
1862
+ String get execute_tool_title => 'Execute Tool';
1863
+
1864
+ @override
1865
+ String get execute_tool_request_desc =>
1866
+ 'The model is requesting to execute the following tool:';
1867
+
1868
+ @override
1869
+ String get reject => 'Reject';
1870
+
1871
+ @override
1872
+ String get approve => 'Approve';
1873
+
1874
+ @override
1875
+ String get server_type_help =>
1876
+ 'Pick the provider before filling connection details.';
1877
+
1878
+ @override
1879
+ String get server_identity_title => 'Identity';
1880
+
1881
+ @override
1882
+ String get server_identity_desc =>
1883
+ 'Name this server and choose how it appears in the list.';
1884
+
1885
+ @override
1886
+ String get server_connection_title => 'Connection';
1887
+
1888
+ @override
1889
+ String get server_connection_desc =>
1890
+ 'Use the address and port exposed by your server.';
1891
+
1892
+ @override
1893
+ String get server_authentication_title => 'Authentication';
1894
+
1895
+ @override
1896
+ String get server_authentication_required_desc =>
1897
+ 'OpenRouter requires an API key before testing.';
1898
+
1899
+ @override
1900
+ String get server_authentication_optional_desc =>
1901
+ 'Leave the API key empty if this server does not require one.';
1902
+
1903
+ @override
1904
+ String get mcp_tools_title => 'MCP Tools';
1905
+
1906
+ @override
1907
+ String get available_tools => 'Available tools';
1908
+
1909
+ @override
1910
+ String get unable_load_tools => 'Unable to load tools';
1911
+
1912
+ @override
1913
+ String get no_tools_registered => 'No tools registered';
1914
+
1915
+ @override
1916
+ String get no_tools_registered_desc =>
1917
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
1918
+
1919
+ @override
1920
+ String get example_mcp_server_title => 'Example MCP server';
1921
+
1922
+ @override
1923
+ String get example_mcp_server_desc =>
1924
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
1925
+
1926
+ @override
1927
+ String get disable_example_server => 'Disable example server';
1928
+
1929
+ @override
1930
+ String get enable_example_server => 'Enable example server';
1931
+
1932
+ @override
1933
+ String get built_in_label => 'Built-in';
1934
+
1935
+ @override
1936
+ String get highlights_label => 'Highlights';
1937
+
1938
+ @override
1939
+ String get built_with_label => 'Built with';
1940
+
1941
+ @override
1942
+ String get local_label => 'Local';
1943
+
1944
+ @override
1945
+ String get gguf_format_label => 'GGUF';
1946
+
1947
+ @override
1948
+ String get tool_status_requested => 'Requested';
1949
+
1950
+ @override
1951
+ String get tool_status_approved => 'Approved';
1952
+
1953
+ @override
1954
+ String get tool_status_rejected => 'Rejected';
1955
+
1956
+ @override
1957
+ String get tool_status_running => 'Running';
1958
+
1959
+ @override
1960
+ String get tool_status_done => 'Done';
1961
+
1962
+ @override
1963
+ String get tool_status_failed => 'Failed';
1964
}
lib/l10n/app_localizations_en.dart
+273
@@ -1680,4 +1680,277 @@ class AppLocalizationsEn extends AppLocalizations {
1680
@override
1681
String get tts_other_services_background_note =>
1682
'Note: The other TTS services support background playback as native audio.';
1683
+
1684
+ @override
1685
+ String get gguf_imported_models_title => 'Imported GGUF models';
1686
+
1687
+ @override
1688
+ String get gguf_imported_models_empty_subtitle =>
1689
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
1690
+
1691
+ @override
1692
+ String get gguf_imported_models_ready =>
1693
+ 'imported models ready for local inference.';
1694
+
1695
+ @override
1696
+ String get gguf_curated_models_subtitle =>
1697
+ 'Curated on-device models you can download and manage inside LocalMind.';
1698
+
1699
+ @override
1700
+ String get gguf_only_supported =>
1701
+ 'Only GGUF models are supported for this import.';
1702
+
1703
+ @override
1704
+ String get gguf_imported_from_local_file => 'imported from local file.';
1705
+
1706
+ @override
1707
+ String get gguf_import_failed => 'Failed to import GGUF model';
1708
+
1709
+ @override
1710
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
1711
+
1712
+ @override
1713
+ String get gguf_import_canceled => 'GGUF import canceled.';
1714
+
1715
+ @override
1716
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
1717
+
1718
+ @override
1719
+ String get gguf_only_official_huggingface_urls =>
1720
+ 'Only official Hugging Face GGUF URLs are supported.';
1721
+
1722
+ @override
1723
+ String get gguf_use_https_url =>
1724
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
1725
+
1726
+ @override
1727
+ String get gguf_url_must_point_to_file =>
1728
+ 'The Hugging Face URL must point directly to a .gguf file.';
1729
+
1730
+ @override
1731
+ String get gguf_unable_to_detect_file_name =>
1732
+ 'Unable to determine the GGUF file name.';
1733
+
1734
+ @override
1735
+ String get gguf_download_empty =>
1736
+ 'The downloaded GGUF file was empty or missing.';
1737
+
1738
+ @override
1739
+ String get gguf_selected_file_missing =>
1740
+ 'Selected model file does not exist.';
1741
+
1742
+ @override
1743
+ String get gguf_import_action => 'Import GGUF';
1744
+
1745
+ @override
1746
+ String get gguf_overview_title => 'Bring your own GGUF models';
1747
+
1748
+ @override
1749
+ String get gguf_overview_subtitle =>
1750
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
1751
+
1752
+ @override
1753
+ String get gguf_imported_count_label => 'imported';
1754
+
1755
+ @override
1756
+ String get gguf_local_files_label => 'local files';
1757
+
1758
+ @override
1759
+ String get gguf_huggingface_label => 'Hugging Face';
1760
+
1761
+ @override
1762
+ String get gguf_import_local_title => 'Import local GGUF';
1763
+
1764
+ @override
1765
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
1766
+
1767
+ @override
1768
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
1769
+
1770
+ @override
1771
+ String get gguf_import_huggingface_subtitle =>
1772
+ 'Paste a GGUF URL or repo path';
1773
+
1774
+ @override
1775
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
1776
+
1777
+ @override
1778
+ String get gguf_no_imported_subtitle =>
1779
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
1780
+
1781
+ @override
1782
+ String get gguf_import_huggingface_dialog_title =>
1783
+ 'Import GGUF from Hugging Face';
1784
+
1785
+ @override
1786
+ String get gguf_import_huggingface_dialog_subtitle =>
1787
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
1788
+
1789
+ @override
1790
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
1791
+
1792
+ @override
1793
+ String get paste => 'Paste';
1794
+
1795
+ @override
1796
+ String get gguf_browse => 'Browse GGUFs';
1797
+
1798
+ @override
1799
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
1800
+
1801
+ @override
1802
+ String get gguf_huggingface_token_optional =>
1803
+ 'Token optional but recommended';
1804
+
1805
+ @override
1806
+ String get gguf_huggingface_token_ready_desc =>
1807
+ 'Your saved token will be used automatically for gated or private repositories.';
1808
+
1809
+ @override
1810
+ String get gguf_huggingface_token_optional_desc =>
1811
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
1812
+
1813
+ @override
1814
+ String get gguf_downloading => 'Downloading GGUF';
1815
+
1816
+ @override
1817
+ String get gguf_preparing => 'Preparing';
1818
+
1819
+ @override
1820
+ String get gguf_preparing_download => 'Preparing download...';
1821
+
1822
+ @override
1823
+ String get gguf_cancel_import => 'Cancel import';
1824
+
1825
+ @override
1826
+ String get clipboard_empty => 'Clipboard is empty.';
1827
+
1828
+ @override
1829
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
1830
+
1831
+ @override
1832
+ String get gguf_paste_url_error =>
1833
+ 'Paste a Hugging Face GGUF URL or repo path.';
1834
+
1835
+ @override
1836
+ String get gguf_blob_link => 'Blob link';
1837
+
1838
+ @override
1839
+ String get gguf_repository_label => 'Repository';
1840
+
1841
+ @override
1842
+ String get gguf_detected_path_label => 'Detected path';
1843
+
1844
+ @override
1845
+ String get gguf_imported_section_label => 'Imported GGUF';
1846
+
1847
+ @override
1848
+ String get gguf_already_available => 'Already available on this device';
1849
+
1850
+ @override
1851
+ String get gguf_curated_models_short => 'Curated on-device models';
1852
+
1853
+ @override
1854
+ String get execute_tool_title => 'Execute Tool';
1855
+
1856
+ @override
1857
+ String get execute_tool_request_desc =>
1858
+ 'The model is requesting to execute the following tool:';
1859
+
1860
+ @override
1861
+ String get reject => 'Reject';
1862
+
1863
+ @override
1864
+ String get approve => 'Approve';
1865
+
1866
+ @override
1867
+ String get server_type_help =>
1868
+ 'Pick the provider before filling connection details.';
1869
+
1870
+ @override
1871
+ String get server_identity_title => 'Identity';
1872
+
1873
+ @override
1874
+ String get server_identity_desc =>
1875
+ 'Name this server and choose how it appears in the list.';
1876
+
1877
+ @override
1878
+ String get server_connection_title => 'Connection';
1879
+
1880
+ @override
1881
+ String get server_connection_desc =>
1882
+ 'Use the address and port exposed by your server.';
1883
+
1884
+ @override
1885
+ String get server_authentication_title => 'Authentication';
1886
+
1887
+ @override
1888
+ String get server_authentication_required_desc =>
1889
+ 'OpenRouter requires an API key before testing.';
1890
+
1891
+ @override
1892
+ String get server_authentication_optional_desc =>
1893
+ 'Leave the API key empty if this server does not require one.';
1894
+
1895
+ @override
1896
+ String get mcp_tools_title => 'MCP Tools';
1897
+
1898
+ @override
1899
+ String get available_tools => 'Available tools';
1900
+
1901
+ @override
1902
+ String get unable_load_tools => 'Unable to load tools';
1903
+
1904
+ @override
1905
+ String get no_tools_registered => 'No tools registered';
1906
+
1907
+ @override
1908
+ String get no_tools_registered_desc =>
1909
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
1910
+
1911
+ @override
1912
+ String get example_mcp_server_title => 'Example MCP server';
1913
+
1914
+ @override
1915
+ String get example_mcp_server_desc =>
1916
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
1917
+
1918
+ @override
1919
+ String get disable_example_server => 'Disable example server';
1920
+
1921
+ @override
1922
+ String get enable_example_server => 'Enable example server';
1923
+
1924
+ @override
1925
+ String get built_in_label => 'Built-in';
1926
+
1927
+ @override
1928
+ String get highlights_label => 'Highlights';
1929
+
1930
+ @override
1931
+ String get built_with_label => 'Built with';
1932
+
1933
+ @override
1934
+ String get local_label => 'Local';
1935
+
1936
+ @override
1937
+ String get gguf_format_label => 'GGUF';
1938
+
1939
+ @override
1940
+ String get tool_status_requested => 'Requested';
1941
+
1942
+ @override
1943
+ String get tool_status_approved => 'Approved';
1944
+
1945
+ @override
1946
+ String get tool_status_rejected => 'Rejected';
1947
+
1948
+ @override
1949
+ String get tool_status_running => 'Running';
1950
+
1951
+ @override
1952
+ String get tool_status_done => 'Done';
1953
+
1954
+ @override
1955
+ String get tool_status_failed => 'Failed';
1956
}
lib/l10n/app_localizations_es.dart
+287
-12
@@ -1381,48 +1381,50 @@ class AppLocalizationsEs extends AppLocalizations {
1381
String get on_device_models_title => 'Modelos locales';
1382
1383
@override
1384
- String get settings_huggingface_token => 'Hugging Face Token (Optional)';
1384
+ String get settings_huggingface_token => 'Token de Hugging Face (Opcional)';
1385
1386
@override
1387
String get settings_huggingface_token_desc =>
1388
- 'Required only for gated models (e.g. Gemma). Get a token at huggingface.co/settings/tokens.';
1388
+ 'Solo se requiere para modelos restringidos (p. ej., Gemma). Obtenga un token en huggingface.co/settings/tokens.';
1389
1390
@override
1391
- String get settings_huggingface_token_set => 'Token saved';
1391
+ String get settings_huggingface_token_set => 'Token guardado';
1392
1393
@override
1394
- String get settings_huggingface_token_cleared => 'Token cleared';
1394
+ String get settings_huggingface_token_cleared => 'Token eliminado';
1395
1396
@override
1397
String get model_requires_huggingface_token =>
1398
- 'Requires a Hugging Face token';
1398
+ 'Requiere un token de Hugging Face';
1399
1400
@override
1401
String get model_missing_huggingface_token =>
1402
- 'This model is gated on Hugging Face. Add a token in Settings → On-Device Inference to download it.';
1402
+ 'Este modelo está restringido en Hugging Face. Añada un token en Ajustes → Inferencia en el dispositivo para descargarlo.';
1403
1404
@override
1405
- String get set_huggingface_token => 'Set token';
1405
+ String get set_huggingface_token => 'Configurar token';
1406
1407
@override
1408
- String get clear_huggingface_token => 'Clear';
1408
+ String get clear_huggingface_token => 'Borrar';
1409
1410
@override
1411
- String get edit_huggingface_token_dialog_title => 'Hugging Face Access Token';
1411
+ String get edit_huggingface_token_dialog_title =>
1412
+ 'Token de acceso de Hugging Face';
1413
1414
@override
1415
String get huggingface_token_dialog_hint => 'hf_…';
1416
1417
@override
1417
- String get server_type_ollama_desc => 'Local AI engine. No API key required.';
1418
+ String get server_type_ollama_desc =>
1419
+ 'Motor de IA local. No requiere clave API.';
1420
1421
@override
1422
String get server_type_on_device_desc =>
1421
- 'Runs on your phone. Some models need a Hugging Face token.';
1423
+ 'Se ejecuta en su teléfono. Algunos modelos necesitan un token de Hugging Face.';
1424
1425
@override
1426
String get server_type_lm_studio_desc =>
1425
- 'Local API server. No API key required.';
1427
+ 'Servidor API local. No requiere clave API.';
1428
1429
@override
1430
String get available_models => 'Modelos disponibles';
@@ -1693,4 +1695,277 @@ class AppLocalizationsEs extends AppLocalizations {
1695
@override
1696
String get tts_other_services_background_note =>
1697
'Nota: Los otros servicios de TTS soportan reproducción en segundo plano como audio nativo.';
1698
+
1699
+ @override
1700
+ String get gguf_imported_models_title => 'Imported GGUF models';
1701
+
1702
+ @override
1703
+ String get gguf_imported_models_empty_subtitle =>
1704
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
1705
+
1706
+ @override
1707
+ String get gguf_imported_models_ready =>
1708
+ 'imported models ready for local inference.';
1709
+
1710
+ @override
1711
+ String get gguf_curated_models_subtitle =>
1712
+ 'Curated on-device models you can download and manage inside LocalMind.';
1713
+
1714
+ @override
1715
+ String get gguf_only_supported =>
1716
+ 'Only GGUF models are supported for this import.';
1717
+
1718
+ @override
1719
+ String get gguf_imported_from_local_file => 'imported from local file.';
1720
+
1721
+ @override
1722
+ String get gguf_import_failed => 'Failed to import GGUF model';
1723
+
1724
+ @override
1725
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
1726
+
1727
+ @override
1728
+ String get gguf_import_canceled => 'GGUF import canceled.';
1729
+
1730
+ @override
1731
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
1732
+
1733
+ @override
1734
+ String get gguf_only_official_huggingface_urls =>
1735
+ 'Only official Hugging Face GGUF URLs are supported.';
1736
+
1737
+ @override
1738
+ String get gguf_use_https_url =>
1739
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
1740
+
1741
+ @override
1742
+ String get gguf_url_must_point_to_file =>
1743
+ 'The Hugging Face URL must point directly to a .gguf file.';
1744
+
1745
+ @override
1746
+ String get gguf_unable_to_detect_file_name =>
1747
+ 'Unable to determine the GGUF file name.';
1748
+
1749
+ @override
1750
+ String get gguf_download_empty =>
1751
+ 'The downloaded GGUF file was empty or missing.';
1752
+
1753
+ @override
1754
+ String get gguf_selected_file_missing =>
1755
+ 'Selected model file does not exist.';
1756
+
1757
+ @override
1758
+ String get gguf_import_action => 'Import GGUF';
1759
+
1760
+ @override
1761
+ String get gguf_overview_title => 'Bring your own GGUF models';
1762
+
1763
+ @override
1764
+ String get gguf_overview_subtitle =>
1765
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
1766
+
1767
+ @override
1768
+ String get gguf_imported_count_label => 'imported';
1769
+
1770
+ @override
1771
+ String get gguf_local_files_label => 'local files';
1772
+
1773
+ @override
1774
+ String get gguf_huggingface_label => 'Hugging Face';
1775
+
1776
+ @override
1777
+ String get gguf_import_local_title => 'Import local GGUF';
1778
+
1779
+ @override
1780
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
1781
+
1782
+ @override
1783
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
1784
+
1785
+ @override
1786
+ String get gguf_import_huggingface_subtitle =>
1787
+ 'Paste a GGUF URL or repo path';
1788
+
1789
+ @override
1790
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
1791
+
1792
+ @override
1793
+ String get gguf_no_imported_subtitle =>
1794
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
1795
+
1796
+ @override
1797
+ String get gguf_import_huggingface_dialog_title =>
1798
+ 'Import GGUF from Hugging Face';
1799
+
1800
+ @override
1801
+ String get gguf_import_huggingface_dialog_subtitle =>
1802
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
1803
+
1804
+ @override
1805
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
1806
+
1807
+ @override
1808
+ String get paste => 'Paste';
1809
+
1810
+ @override
1811
+ String get gguf_browse => 'Browse GGUFs';
1812
+
1813
+ @override
1814
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
1815
+
1816
+ @override
1817
+ String get gguf_huggingface_token_optional =>
1818
+ 'Token optional but recommended';
1819
+
1820
+ @override
1821
+ String get gguf_huggingface_token_ready_desc =>
1822
+ 'Your saved token will be used automatically for gated or private repositories.';
1823
+
1824
+ @override
1825
+ String get gguf_huggingface_token_optional_desc =>
1826
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
1827
+
1828
+ @override
1829
+ String get gguf_downloading => 'Downloading GGUF';
1830
+
1831
+ @override
1832
+ String get gguf_preparing => 'Preparing';
1833
+
1834
+ @override
1835
+ String get gguf_preparing_download => 'Preparing download...';
1836
+
1837
+ @override
1838
+ String get gguf_cancel_import => 'Cancel import';
1839
+
1840
+ @override
1841
+ String get clipboard_empty => 'Clipboard is empty.';
1842
+
1843
+ @override
1844
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
1845
+
1846
+ @override
1847
+ String get gguf_paste_url_error =>
1848
+ 'Paste a Hugging Face GGUF URL or repo path.';
1849
+
1850
+ @override
1851
+ String get gguf_blob_link => 'Blob link';
1852
+
1853
+ @override
1854
+ String get gguf_repository_label => 'Repository';
1855
+
1856
+ @override
1857
+ String get gguf_detected_path_label => 'Detected path';
1858
+
1859
+ @override
1860
+ String get gguf_imported_section_label => 'Imported GGUF';
1861
+
1862
+ @override
1863
+ String get gguf_already_available => 'Already available on this device';
1864
+
1865
+ @override
1866
+ String get gguf_curated_models_short => 'Curated on-device models';
1867
+
1868
+ @override
1869
+ String get execute_tool_title => 'Execute Tool';
1870
+
1871
+ @override
1872
+ String get execute_tool_request_desc =>
1873
+ 'The model is requesting to execute the following tool:';
1874
+
1875
+ @override
1876
+ String get reject => 'Reject';
1877
+
1878
+ @override
1879
+ String get approve => 'Approve';
1880
+
1881
+ @override
1882
+ String get server_type_help =>
1883
+ 'Pick the provider before filling connection details.';
1884
+
1885
+ @override
1886
+ String get server_identity_title => 'Identity';
1887
+
1888
+ @override
1889
+ String get server_identity_desc =>
1890
+ 'Name this server and choose how it appears in the list.';
1891
+
1892
+ @override
1893
+ String get server_connection_title => 'Connection';
1894
+
1895
+ @override
1896
+ String get server_connection_desc =>
1897
+ 'Use the address and port exposed by your server.';
1898
+
1899
+ @override
1900
+ String get server_authentication_title => 'Authentication';
1901
+
1902
+ @override
1903
+ String get server_authentication_required_desc =>
1904
+ 'OpenRouter requires an API key before testing.';
1905
+
1906
+ @override
1907
+ String get server_authentication_optional_desc =>
1908
+ 'Leave the API key empty if this server does not require one.';
1909
+
1910
+ @override
1911
+ String get mcp_tools_title => 'MCP Tools';
1912
+
1913
+ @override
1914
+ String get available_tools => 'Available tools';
1915
+
1916
+ @override
1917
+ String get unable_load_tools => 'Unable to load tools';
1918
+
1919
+ @override
1920
+ String get no_tools_registered => 'No tools registered';
1921
+
1922
+ @override
1923
+ String get no_tools_registered_desc =>
1924
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
1925
+
1926
+ @override
1927
+ String get example_mcp_server_title => 'Example MCP server';
1928
+
1929
+ @override
1930
+ String get example_mcp_server_desc =>
1931
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
1932
+
1933
+ @override
1934
+ String get disable_example_server => 'Disable example server';
1935
+
1936
+ @override
1937
+ String get enable_example_server => 'Enable example server';
1938
+
1939
+ @override
1940
+ String get built_in_label => 'Built-in';
1941
+
1942
+ @override
1943
+ String get highlights_label => 'Highlights';
1944
+
1945
+ @override
1946
+ String get built_with_label => 'Built with';
1947
+
1948
+ @override
1949
+ String get local_label => 'Local';
1950
+
1951
+ @override
1952
+ String get gguf_format_label => 'GGUF';
1953
+
1954
+ @override
1955
+ String get tool_status_requested => 'Requested';
1956
+
1957
+ @override
1958
+ String get tool_status_approved => 'Approved';
1959
+
1960
+ @override
1961
+ String get tool_status_rejected => 'Rejected';
1962
+
1963
+ @override
1964
+ String get tool_status_running => 'Running';
1965
+
1966
+ @override
1967
+ String get tool_status_done => 'Done';
1968
+
1969
+ @override
1970
+ String get tool_status_failed => 'Failed';
1971
}
lib/l10n/app_localizations_hi.dart
+286
-13
@@ -1375,48 +1375,48 @@ class AppLocalizationsHi extends AppLocalizations {
1375
String get on_device_models_title => 'ऑन-डिवाइस मॉडल';
1376
1377
@override
1378
- String get settings_huggingface_token => 'Hugging Face Token (Optional)';
1378
+ String get settings_huggingface_token => 'Hugging Face टोकन (वैकल्पिक)';
1379
1380
@override
1381
String get settings_huggingface_token_desc =>
1382
- 'Required only for gated models (e.g. Gemma). Get a token at huggingface.co/settings/tokens.';
1382
+ 'केवल gated मॉडलों के लिए आवश्यक (जैसे Gemma)। huggingface.co/settings/tokens पर टोकन प्राप्त करें।';
1383
1384
@override
1385
- String get settings_huggingface_token_set => 'Token saved';
1385
+ String get settings_huggingface_token_set => 'टोकन सहेजा गया';
1386
1387
@override
1388
- String get settings_huggingface_token_cleared => 'Token cleared';
1388
+ String get settings_huggingface_token_cleared => 'टोकन साफ़ किया गया';
1389
1390
@override
1391
- String get model_requires_huggingface_token =>
1392
- 'Requires a Hugging Face token';
1391
+ String get model_requires_huggingface_token => 'Hugging Face टोकन आवश्यक है';
1392
1393
@override
1394
String get model_missing_huggingface_token =>
1396
- 'This model is gated on Hugging Face. Add a token in Settings → On-Device Inference to download it.';
1395
+ 'यह मॉडल Hugging Face पर gated है। इसे डाउनलोड करने के लिए Settings → On-Device Inference में एक टोकन जोड़ें।';
1396
1397
@override
1399
- String get set_huggingface_token => 'Set token';
1398
+ String get set_huggingface_token => 'टोकन सेट करें';
1399
1400
@override
1402
- String get clear_huggingface_token => 'Clear';
1401
+ String get clear_huggingface_token => 'साफ़ करें';
1402
1403
@override
1405
- String get edit_huggingface_token_dialog_title => 'Hugging Face Access Token';
1404
+ String get edit_huggingface_token_dialog_title => 'Hugging Face एक्सेस टोकन';
1405
1406
@override
1407
String get huggingface_token_dialog_hint => 'hf_…';
1408
1409
@override
1411
- String get server_type_ollama_desc => 'Local AI engine. No API key required.';
1410
+ String get server_type_ollama_desc =>
1411
+ 'लोकल AI इंजन। API key की आवश्यकता नहीं है।';
1412
1413
@override
1414
String get server_type_on_device_desc =>
1415
- 'Runs on your phone. Some models need a Hugging Face token.';
1415
+ 'आपके फ़ोन पर चलता है। कुछ मॉडलों के लिए Hugging Face टोकन चाहिए।';
1416
1417
@override
1418
String get server_type_lm_studio_desc =>
1419
- 'Local API server. No API key required.';
1419
+ 'लोकल API सर्वर। API key की आवश्यकता नहीं है।';
1420
1421
@override
1422
String get available_models => 'उपलब्ध मॉडल';
@@ -1684,4 +1684,277 @@ class AppLocalizationsHi extends AppLocalizations {
1684
@override
1685
String get tts_other_services_background_note =>
1686
'नोट: अन्य टीटीएस सेवाएं मूल ऑडियो के रूप में पृष्ठभूमि प्लेबैक का समर्थन करती हैं।';
1687
+
1688
+ @override
1689
+ String get gguf_imported_models_title => 'Imported GGUF models';
1690
+
1691
+ @override
1692
+ String get gguf_imported_models_empty_subtitle =>
1693
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
1694
+
1695
+ @override
1696
+ String get gguf_imported_models_ready =>
1697
+ 'imported models ready for local inference.';
1698
+
1699
+ @override
1700
+ String get gguf_curated_models_subtitle =>
1701
+ 'Curated on-device models you can download and manage inside LocalMind.';
1702
+
1703
+ @override
1704
+ String get gguf_only_supported =>
1705
+ 'Only GGUF models are supported for this import.';
1706
+
1707
+ @override
1708
+ String get gguf_imported_from_local_file => 'imported from local file.';
1709
+
1710
+ @override
1711
+ String get gguf_import_failed => 'Failed to import GGUF model';
1712
+
1713
+ @override
1714
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
1715
+
1716
+ @override
1717
+ String get gguf_import_canceled => 'GGUF import canceled.';
1718
+
1719
+ @override
1720
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
1721
+
1722
+ @override
1723
+ String get gguf_only_official_huggingface_urls =>
1724
+ 'Only official Hugging Face GGUF URLs are supported.';
1725
+
1726
+ @override
1727
+ String get gguf_use_https_url =>
1728
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
1729
+
1730
+ @override
1731
+ String get gguf_url_must_point_to_file =>
1732
+ 'The Hugging Face URL must point directly to a .gguf file.';
1733
+
1734
+ @override
1735
+ String get gguf_unable_to_detect_file_name =>
1736
+ 'Unable to determine the GGUF file name.';
1737
+
1738
+ @override
1739
+ String get gguf_download_empty =>
1740
+ 'The downloaded GGUF file was empty or missing.';
1741
+
1742
+ @override
1743
+ String get gguf_selected_file_missing =>
1744
+ 'Selected model file does not exist.';
1745
+
1746
+ @override
1747
+ String get gguf_import_action => 'Import GGUF';
1748
+
1749
+ @override
1750
+ String get gguf_overview_title => 'Bring your own GGUF models';
1751
+
1752
+ @override
1753
+ String get gguf_overview_subtitle =>
1754
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
1755
+
1756
+ @override
1757
+ String get gguf_imported_count_label => 'imported';
1758
+
1759
+ @override
1760
+ String get gguf_local_files_label => 'local files';
1761
+
1762
+ @override
1763
+ String get gguf_huggingface_label => 'Hugging Face';
1764
+
1765
+ @override
1766
+ String get gguf_import_local_title => 'Import local GGUF';
1767
+
1768
+ @override
1769
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
1770
+
1771
+ @override
1772
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
1773
+
1774
+ @override
1775
+ String get gguf_import_huggingface_subtitle =>
1776
+ 'Paste a GGUF URL or repo path';
1777
+
1778
+ @override
1779
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
1780
+
1781
+ @override
1782
+ String get gguf_no_imported_subtitle =>
1783
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
1784
+
1785
+ @override
1786
+ String get gguf_import_huggingface_dialog_title =>
1787
+ 'Import GGUF from Hugging Face';
1788
+
1789
+ @override
1790
+ String get gguf_import_huggingface_dialog_subtitle =>
1791
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
1792
+
1793
+ @override
1794
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
1795
+
1796
+ @override
1797
+ String get paste => 'Paste';
1798
+
1799
+ @override
1800
+ String get gguf_browse => 'Browse GGUFs';
1801
+
1802
+ @override
1803
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
1804
+
1805
+ @override
1806
+ String get gguf_huggingface_token_optional =>
1807
+ 'Token optional but recommended';
1808
+
1809
+ @override
1810
+ String get gguf_huggingface_token_ready_desc =>
1811
+ 'Your saved token will be used automatically for gated or private repositories.';
1812
+
1813
+ @override
1814
+ String get gguf_huggingface_token_optional_desc =>
1815
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
1816
+
1817
+ @override
1818
+ String get gguf_downloading => 'Downloading GGUF';
1819
+
1820
+ @override
1821
+ String get gguf_preparing => 'Preparing';
1822
+
1823
+ @override
1824
+ String get gguf_preparing_download => 'Preparing download...';
1825
+
1826
+ @override
1827
+ String get gguf_cancel_import => 'Cancel import';
1828
+
1829
+ @override
1830
+ String get clipboard_empty => 'Clipboard is empty.';
1831
+
1832
+ @override
1833
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
1834
+
1835
+ @override
1836
+ String get gguf_paste_url_error =>
1837
+ 'Paste a Hugging Face GGUF URL or repo path.';
1838
+
1839
+ @override
1840
+ String get gguf_blob_link => 'Blob link';
1841
+
1842
+ @override
1843
+ String get gguf_repository_label => 'Repository';
1844
+
1845
+ @override
1846
+ String get gguf_detected_path_label => 'Detected path';
1847
+
1848
+ @override
1849
+ String get gguf_imported_section_label => 'Imported GGUF';
1850
+
1851
+ @override
1852
+ String get gguf_already_available => 'Already available on this device';
1853
+
1854
+ @override
1855
+ String get gguf_curated_models_short => 'Curated on-device models';
1856
+
1857
+ @override
1858
+ String get execute_tool_title => 'Execute Tool';
1859
+
1860
+ @override
1861
+ String get execute_tool_request_desc =>
1862
+ 'The model is requesting to execute the following tool:';
1863
+
1864
+ @override
1865
+ String get reject => 'Reject';
1866
+
1867
+ @override
1868
+ String get approve => 'Approve';
1869
+
1870
+ @override
1871
+ String get server_type_help =>
1872
+ 'Pick the provider before filling connection details.';
1873
+
1874
+ @override
1875
+ String get server_identity_title => 'Identity';
1876
+
1877
+ @override
1878
+ String get server_identity_desc =>
1879
+ 'Name this server and choose how it appears in the list.';
1880
+
1881
+ @override
1882
+ String get server_connection_title => 'Connection';
1883
+
1884
+ @override
1885
+ String get server_connection_desc =>
1886
+ 'Use the address and port exposed by your server.';
1887
+
1888
+ @override
1889
+ String get server_authentication_title => 'Authentication';
1890
+
1891
+ @override
1892
+ String get server_authentication_required_desc =>
1893
+ 'OpenRouter requires an API key before testing.';
1894
+
1895
+ @override
1896
+ String get server_authentication_optional_desc =>
1897
+ 'Leave the API key empty if this server does not require one.';
1898
+
1899
+ @override
1900
+ String get mcp_tools_title => 'MCP Tools';
1901
+
1902
+ @override
1903
+ String get available_tools => 'Available tools';
1904
+
1905
+ @override
1906
+ String get unable_load_tools => 'Unable to load tools';
1907
+
1908
+ @override
1909
+ String get no_tools_registered => 'No tools registered';
1910
+
1911
+ @override
1912
+ String get no_tools_registered_desc =>
1913
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
1914
+
1915
+ @override
1916
+ String get example_mcp_server_title => 'Example MCP server';
1917
+
1918
+ @override
1919
+ String get example_mcp_server_desc =>
1920
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
1921
+
1922
+ @override
1923
+ String get disable_example_server => 'Disable example server';
1924
+
1925
+ @override
1926
+ String get enable_example_server => 'Enable example server';
1927
+
1928
+ @override
1929
+ String get built_in_label => 'Built-in';
1930
+
1931
+ @override
1932
+ String get highlights_label => 'Highlights';
1933
+
1934
+ @override
1935
+ String get built_with_label => 'Built with';
1936
+
1937
+ @override
1938
+ String get local_label => 'Local';
1939
+
1940
+ @override
1941
+ String get gguf_format_label => 'GGUF';
1942
+
1943
+ @override
1944
+ String get tool_status_requested => 'Requested';
1945
+
1946
+ @override
1947
+ String get tool_status_approved => 'Approved';
1948
+
1949
+ @override
1950
+ String get tool_status_rejected => 'Rejected';
1951
+
1952
+ @override
1953
+ String get tool_status_running => 'Running';
1954
+
1955
+ @override
1956
+ String get tool_status_done => 'Done';
1957
+
1958
+ @override
1959
+ String get tool_status_failed => 'Failed';
1960
}
lib/l10n/app_localizations_it.dart
+287
-12
@@ -1380,48 +1380,50 @@ class AppLocalizationsIt extends AppLocalizations {
1380
String get on_device_models_title => 'Modelli sul dispositivo';
1381
1382
@override
1383
- String get settings_huggingface_token => 'Hugging Face Token (Optional)';
1383
+ String get settings_huggingface_token => 'Token Hugging Face (Opzionale)';
1384
1385
@override
1386
String get settings_huggingface_token_desc =>
1387
- 'Required only for gated models (e.g. Gemma). Get a token at huggingface.co/settings/tokens.';
1387
+ 'Richiesto solo per i modelli con accesso limitato (ad es. Gemma). Ottieni un token su huggingface.co/settings/tokens.';
1388
1389
@override
1390
- String get settings_huggingface_token_set => 'Token saved';
1390
+ String get settings_huggingface_token_set => 'Token salvato';
1391
1392
@override
1393
- String get settings_huggingface_token_cleared => 'Token cleared';
1393
+ String get settings_huggingface_token_cleared => 'Token cancellato';
1394
1395
@override
1396
String get model_requires_huggingface_token =>
1397
- 'Requires a Hugging Face token';
1397
+ 'Richiede un token Hugging Face';
1398
1399
@override
1400
String get model_missing_huggingface_token =>
1401
- 'This model is gated on Hugging Face. Add a token in Settings → On-Device Inference to download it.';
1401
+ 'Questo modello ha accesso limitato su Hugging Face. Aggiungi un token in Impostazioni → Inferenza sul dispositivo per scaricarlo.';
1402
1403
@override
1404
- String get set_huggingface_token => 'Set token';
1404
+ String get set_huggingface_token => 'Imposta token';
1405
1406
@override
1407
- String get clear_huggingface_token => 'Clear';
1407
+ String get clear_huggingface_token => 'Cancella';
1408
1409
@override
1410
- String get edit_huggingface_token_dialog_title => 'Hugging Face Access Token';
1410
+ String get edit_huggingface_token_dialog_title =>
1411
+ 'Token di accesso Hugging Face';
1412
1413
@override
1414
String get huggingface_token_dialog_hint => 'hf_…';
1415
1416
@override
1416
- String get server_type_ollama_desc => 'Local AI engine. No API key required.';
1417
+ String get server_type_ollama_desc =>
1418
+ 'Motore AI locale. Nessuna chiave API richiesta.';
1419
1420
@override
1421
String get server_type_on_device_desc =>
1420
- 'Runs on your phone. Some models need a Hugging Face token.';
1422
+ 'Funziona sul tuo telefono. Alcuni modelli richiedono un token Hugging Face.';
1423
1424
@override
1425
String get server_type_lm_studio_desc =>
1424
- 'Local API server. No API key required.';
1426
+ 'Server API locale. Nessuna chiave API richiesta.';
1427
1428
@override
1429
String get available_models => 'Modelli disponibili';
@@ -1693,4 +1695,277 @@ class AppLocalizationsIt extends AppLocalizations {
1695
@override
1696
String get tts_other_services_background_note =>
1697
'Nota: Gli altri servizi TTS supportano la riproduzione in background come audio nativo.';
1698
+
1699
+ @override
1700
+ String get gguf_imported_models_title => 'Imported GGUF models';
1701
+
1702
+ @override
1703
+ String get gguf_imported_models_empty_subtitle =>
1704
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
1705
+
1706
+ @override
1707
+ String get gguf_imported_models_ready =>
1708
+ 'imported models ready for local inference.';
1709
+
1710
+ @override
1711
+ String get gguf_curated_models_subtitle =>
1712
+ 'Curated on-device models you can download and manage inside LocalMind.';
1713
+
1714
+ @override
1715
+ String get gguf_only_supported =>
1716
+ 'Only GGUF models are supported for this import.';
1717
+
1718
+ @override
1719
+ String get gguf_imported_from_local_file => 'imported from local file.';
1720
+
1721
+ @override
1722
+ String get gguf_import_failed => 'Failed to import GGUF model';
1723
+
1724
+ @override
1725
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
1726
+
1727
+ @override
1728
+ String get gguf_import_canceled => 'GGUF import canceled.';
1729
+
1730
+ @override
1731
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
1732
+
1733
+ @override
1734
+ String get gguf_only_official_huggingface_urls =>
1735
+ 'Only official Hugging Face GGUF URLs are supported.';
1736
+
1737
+ @override
1738
+ String get gguf_use_https_url =>
1739
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
1740
+
1741
+ @override
1742
+ String get gguf_url_must_point_to_file =>
1743
+ 'The Hugging Face URL must point directly to a .gguf file.';
1744
+
1745
+ @override
1746
+ String get gguf_unable_to_detect_file_name =>
1747
+ 'Unable to determine the GGUF file name.';
1748
+
1749
+ @override
1750
+ String get gguf_download_empty =>
1751
+ 'The downloaded GGUF file was empty or missing.';
1752
+
1753
+ @override
1754
+ String get gguf_selected_file_missing =>
1755
+ 'Selected model file does not exist.';
1756
+
1757
+ @override
1758
+ String get gguf_import_action => 'Import GGUF';
1759
+
1760
+ @override
1761
+ String get gguf_overview_title => 'Bring your own GGUF models';
1762
+
1763
+ @override
1764
+ String get gguf_overview_subtitle =>
1765
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
1766
+
1767
+ @override
1768
+ String get gguf_imported_count_label => 'imported';
1769
+
1770
+ @override
1771
+ String get gguf_local_files_label => 'local files';
1772
+
1773
+ @override
1774
+ String get gguf_huggingface_label => 'Hugging Face';
1775
+
1776
+ @override
1777
+ String get gguf_import_local_title => 'Import local GGUF';
1778
+
1779
+ @override
1780
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
1781
+
1782
+ @override
1783
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
1784
+
1785
+ @override
1786
+ String get gguf_import_huggingface_subtitle =>
1787
+ 'Paste a GGUF URL or repo path';
1788
+
1789
+ @override
1790
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
1791
+
1792
+ @override
1793
+ String get gguf_no_imported_subtitle =>
1794
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
1795
+
1796
+ @override
1797
+ String get gguf_import_huggingface_dialog_title =>
1798
+ 'Import GGUF from Hugging Face';
1799
+
1800
+ @override
1801
+ String get gguf_import_huggingface_dialog_subtitle =>
1802
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
1803
+
1804
+ @override
1805
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
1806
+
1807
+ @override
1808
+ String get paste => 'Paste';
1809
+
1810
+ @override
1811
+ String get gguf_browse => 'Browse GGUFs';
1812
+
1813
+ @override
1814
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
1815
+
1816
+ @override
1817
+ String get gguf_huggingface_token_optional =>
1818
+ 'Token optional but recommended';
1819
+
1820
+ @override
1821
+ String get gguf_huggingface_token_ready_desc =>
1822
+ 'Your saved token will be used automatically for gated or private repositories.';
1823
+
1824
+ @override
1825
+ String get gguf_huggingface_token_optional_desc =>
1826
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
1827
+
1828
+ @override
1829
+ String get gguf_downloading => 'Downloading GGUF';
1830
+
1831
+ @override
1832
+ String get gguf_preparing => 'Preparing';
1833
+
1834
+ @override
1835
+ String get gguf_preparing_download => 'Preparing download...';
1836
+
1837
+ @override
1838
+ String get gguf_cancel_import => 'Cancel import';
1839
+
1840
+ @override
1841
+ String get clipboard_empty => 'Clipboard is empty.';
1842
+
1843
+ @override
1844
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
1845
+
1846
+ @override
1847
+ String get gguf_paste_url_error =>
1848
+ 'Paste a Hugging Face GGUF URL or repo path.';
1849
+
1850
+ @override
1851
+ String get gguf_blob_link => 'Blob link';
1852
+
1853
+ @override
1854
+ String get gguf_repository_label => 'Repository';
1855
+
1856
+ @override
1857
+ String get gguf_detected_path_label => 'Detected path';
1858
+
1859
+ @override
1860
+ String get gguf_imported_section_label => 'Imported GGUF';
1861
+
1862
+ @override
1863
+ String get gguf_already_available => 'Already available on this device';
1864
+
1865
+ @override
1866
+ String get gguf_curated_models_short => 'Curated on-device models';
1867
+
1868
+ @override
1869
+ String get execute_tool_title => 'Execute Tool';
1870
+
1871
+ @override
1872
+ String get execute_tool_request_desc =>
1873
+ 'The model is requesting to execute the following tool:';
1874
+
1875
+ @override
1876
+ String get reject => 'Reject';
1877
+
1878
+ @override
1879
+ String get approve => 'Approve';
1880
+
1881
+ @override
1882
+ String get server_type_help =>
1883
+ 'Pick the provider before filling connection details.';
1884
+
1885
+ @override
1886
+ String get server_identity_title => 'Identity';
1887
+
1888
+ @override
1889
+ String get server_identity_desc =>
1890
+ 'Name this server and choose how it appears in the list.';
1891
+
1892
+ @override
1893
+ String get server_connection_title => 'Connection';
1894
+
1895
+ @override
1896
+ String get server_connection_desc =>
1897
+ 'Use the address and port exposed by your server.';
1898
+
1899
+ @override
1900
+ String get server_authentication_title => 'Authentication';
1901
+
1902
+ @override
1903
+ String get server_authentication_required_desc =>
1904
+ 'OpenRouter requires an API key before testing.';
1905
+
1906
+ @override
1907
+ String get server_authentication_optional_desc =>
1908
+ 'Leave the API key empty if this server does not require one.';
1909
+
1910
+ @override
1911
+ String get mcp_tools_title => 'MCP Tools';
1912
+
1913
+ @override
1914
+ String get available_tools => 'Available tools';
1915
+
1916
+ @override
1917
+ String get unable_load_tools => 'Unable to load tools';
1918
+
1919
+ @override
1920
+ String get no_tools_registered => 'No tools registered';
1921
+
1922
+ @override
1923
+ String get no_tools_registered_desc =>
1924
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
1925
+
1926
+ @override
1927
+ String get example_mcp_server_title => 'Example MCP server';
1928
+
1929
+ @override
1930
+ String get example_mcp_server_desc =>
1931
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
1932
+
1933
+ @override
1934
+ String get disable_example_server => 'Disable example server';
1935
+
1936
+ @override
1937
+ String get enable_example_server => 'Enable example server';
1938
+
1939
+ @override
1940
+ String get built_in_label => 'Built-in';
1941
+
1942
+ @override
1943
+ String get highlights_label => 'Highlights';
1944
+
1945
+ @override
1946
+ String get built_with_label => 'Built with';
1947
+
1948
+ @override
1949
+ String get local_label => 'Local';
1950
+
1951
+ @override
1952
+ String get gguf_format_label => 'GGUF';
1953
+
1954
+ @override
1955
+ String get tool_status_requested => 'Requested';
1956
+
1957
+ @override
1958
+ String get tool_status_approved => 'Approved';
1959
+
1960
+ @override
1961
+ String get tool_status_rejected => 'Rejected';
1962
+
1963
+ @override
1964
+ String get tool_status_running => 'Running';
1965
+
1966
+ @override
1967
+ String get tool_status_done => 'Done';
1968
+
1969
+ @override
1970
+ String get tool_status_failed => 'Failed';
1971
}
lib/l10n/app_localizations_ja.dart
+285
-14
@@ -1358,48 +1358,46 @@ class AppLocalizationsJa extends AppLocalizations {
1358
String get on_device_models_title => 'ローカルモデル';
1359
1360
@override
1361
- String get settings_huggingface_token => 'Hugging Face Token (Optional)';
1361
+ String get settings_huggingface_token => 'Hugging Faceトークン(任意)';
1362
1363
@override
1364
String get settings_huggingface_token_desc =>
1365
- 'Required only for gated models (e.g. Gemma). Get a token at huggingface.co/settings/tokens.';
1365
+ '制限付きモデル(例: Gemma)でのみ必要です。トークンは huggingface.co/settings/tokens で取得できます。';
1366
1367
@override
1368
- String get settings_huggingface_token_set => 'Token saved';
1368
+ String get settings_huggingface_token_set => 'トークンを保存しました';
1369
1370
@override
1371
- String get settings_huggingface_token_cleared => 'Token cleared';
1371
+ String get settings_huggingface_token_cleared => 'トークンを消去しました';
1372
1373
@override
1374
- String get model_requires_huggingface_token =>
1375
- 'Requires a Hugging Face token';
1374
+ String get model_requires_huggingface_token => 'Hugging Faceトークンが必要です';
1375
1376
@override
1377
String get model_missing_huggingface_token =>
1379
- 'This model is gated on Hugging Face. Add a token in Settings → On-Device Inference to download it.';
1378
+ 'このモデルはHugging Faceで制限されています。ダウンロードするには、設定 → 端末内推論 にトークンを追加してください。';
1379
1380
@override
1382
- String get set_huggingface_token => 'Set token';
1381
+ String get set_huggingface_token => 'トークンを設定';
1382
1383
@override
1385
- String get clear_huggingface_token => 'Clear';
1384
+ String get clear_huggingface_token => 'クリア';
1385
1386
@override
1388
- String get edit_huggingface_token_dialog_title => 'Hugging Face Access Token';
1387
+ String get edit_huggingface_token_dialog_title => 'Hugging Faceアクセストークン';
1388
1389
@override
1390
String get huggingface_token_dialog_hint => 'hf_…';
1391
1392
@override
1394
- String get server_type_ollama_desc => 'Local AI engine. No API key required.';
1393
+ String get server_type_ollama_desc => 'ローカルAIエンジン。APIキーは不要です。';
1394
1395
@override
1396
String get server_type_on_device_desc =>
1398
- 'Runs on your phone. Some models need a Hugging Face token.';
1397
+ 'スマートフォン上で動作します。一部のモデルにはHugging Faceトークンが必要です。';
1398
1399
@override
1401
- String get server_type_lm_studio_desc =>
1402
- 'Local API server. No API key required.';
1400
+ String get server_type_lm_studio_desc => 'ローカルAPIサーバー。APIキーは不要です。';
1401
1402
@override
1403
String get available_models => '利用可能なモデル';
@@ -1659,4 +1657,277 @@ class AppLocalizationsJa extends AppLocalizations {
1657
@override
1658
String get tts_other_services_background_note =>
1659
'注意: 他のTTSサービスはネイティブオーディオとしてバックグラウンド再生をサポートしています。';
1660
+
1661
+ @override
1662
+ String get gguf_imported_models_title => 'Imported GGUF models';
1663
+
1664
+ @override
1665
+ String get gguf_imported_models_empty_subtitle =>
1666
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
1667
+
1668
+ @override
1669
+ String get gguf_imported_models_ready =>
1670
+ 'imported models ready for local inference.';
1671
+
1672
+ @override
1673
+ String get gguf_curated_models_subtitle =>
1674
+ 'Curated on-device models you can download and manage inside LocalMind.';
1675
+
1676
+ @override
1677
+ String get gguf_only_supported =>
1678
+ 'Only GGUF models are supported for this import.';
1679
+
1680
+ @override
1681
+ String get gguf_imported_from_local_file => 'imported from local file.';
1682
+
1683
+ @override
1684
+ String get gguf_import_failed => 'Failed to import GGUF model';
1685
+
1686
+ @override
1687
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
1688
+
1689
+ @override
1690
+ String get gguf_import_canceled => 'GGUF import canceled.';
1691
+
1692
+ @override
1693
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
1694
+
1695
+ @override
1696
+ String get gguf_only_official_huggingface_urls =>
1697
+ 'Only official Hugging Face GGUF URLs are supported.';
1698
+
1699
+ @override
1700
+ String get gguf_use_https_url =>
1701
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
1702
+
1703
+ @override
1704
+ String get gguf_url_must_point_to_file =>
1705
+ 'The Hugging Face URL must point directly to a .gguf file.';
1706
+
1707
+ @override
1708
+ String get gguf_unable_to_detect_file_name =>
1709
+ 'Unable to determine the GGUF file name.';
1710
+
1711
+ @override
1712
+ String get gguf_download_empty =>
1713
+ 'The downloaded GGUF file was empty or missing.';
1714
+
1715
+ @override
1716
+ String get gguf_selected_file_missing =>
1717
+ 'Selected model file does not exist.';
1718
+
1719
+ @override
1720
+ String get gguf_import_action => 'Import GGUF';
1721
+
1722
+ @override
1723
+ String get gguf_overview_title => 'Bring your own GGUF models';
1724
+
1725
+ @override
1726
+ String get gguf_overview_subtitle =>
1727
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
1728
+
1729
+ @override
1730
+ String get gguf_imported_count_label => 'imported';
1731
+
1732
+ @override
1733
+ String get gguf_local_files_label => 'local files';
1734
+
1735
+ @override
1736
+ String get gguf_huggingface_label => 'Hugging Face';
1737
+
1738
+ @override
1739
+ String get gguf_import_local_title => 'Import local GGUF';
1740
+
1741
+ @override
1742
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
1743
+
1744
+ @override
1745
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
1746
+
1747
+ @override
1748
+ String get gguf_import_huggingface_subtitle =>
1749
+ 'Paste a GGUF URL or repo path';
1750
+
1751
+ @override
1752
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
1753
+
1754
+ @override
1755
+ String get gguf_no_imported_subtitle =>
1756
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
1757
+
1758
+ @override
1759
+ String get gguf_import_huggingface_dialog_title =>
1760
+ 'Import GGUF from Hugging Face';
1761
+
1762
+ @override
1763
+ String get gguf_import_huggingface_dialog_subtitle =>
1764
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
1765
+
1766
+ @override
1767
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
1768
+
1769
+ @override
1770
+ String get paste => 'Paste';
1771
+
1772
+ @override
1773
+ String get gguf_browse => 'Browse GGUFs';
1774
+
1775
+ @override
1776
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
1777
+
1778
+ @override
1779
+ String get gguf_huggingface_token_optional =>
1780
+ 'Token optional but recommended';
1781
+
1782
+ @override
1783
+ String get gguf_huggingface_token_ready_desc =>
1784
+ 'Your saved token will be used automatically for gated or private repositories.';
1785
+
1786
+ @override
1787
+ String get gguf_huggingface_token_optional_desc =>
1788
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
1789
+
1790
+ @override
1791
+ String get gguf_downloading => 'Downloading GGUF';
1792
+
1793
+ @override
1794
+ String get gguf_preparing => 'Preparing';
1795
+
1796
+ @override
1797
+ String get gguf_preparing_download => 'Preparing download...';
1798
+
1799
+ @override
1800
+ String get gguf_cancel_import => 'Cancel import';
1801
+
1802
+ @override
1803
+ String get clipboard_empty => 'Clipboard is empty.';
1804
+
1805
+ @override
1806
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
1807
+
1808
+ @override
1809
+ String get gguf_paste_url_error =>
1810
+ 'Paste a Hugging Face GGUF URL or repo path.';
1811
+
1812
+ @override
1813
+ String get gguf_blob_link => 'Blob link';
1814
+
1815
+ @override
1816
+ String get gguf_repository_label => 'Repository';
1817
+
1818
+ @override
1819
+ String get gguf_detected_path_label => 'Detected path';
1820
+
1821
+ @override
1822
+ String get gguf_imported_section_label => 'Imported GGUF';
1823
+
1824
+ @override
1825
+ String get gguf_already_available => 'Already available on this device';
1826
+
1827
+ @override
1828
+ String get gguf_curated_models_short => 'Curated on-device models';
1829
+
1830
+ @override
1831
+ String get execute_tool_title => 'Execute Tool';
1832
+
1833
+ @override
1834
+ String get execute_tool_request_desc =>
1835
+ 'The model is requesting to execute the following tool:';
1836
+
1837
+ @override
1838
+ String get reject => 'Reject';
1839
+
1840
+ @override
1841
+ String get approve => 'Approve';
1842
+
1843
+ @override
1844
+ String get server_type_help =>
1845
+ 'Pick the provider before filling connection details.';
1846
+
1847
+ @override
1848
+ String get server_identity_title => 'Identity';
1849
+
1850
+ @override
1851
+ String get server_identity_desc =>
1852
+ 'Name this server and choose how it appears in the list.';
1853
+
1854
+ @override
1855
+ String get server_connection_title => 'Connection';
1856
+
1857
+ @override
1858
+ String get server_connection_desc =>
1859
+ 'Use the address and port exposed by your server.';
1860
+
1861
+ @override
1862
+ String get server_authentication_title => 'Authentication';
1863
+
1864
+ @override
1865
+ String get server_authentication_required_desc =>
1866
+ 'OpenRouter requires an API key before testing.';
1867
+
1868
+ @override
1869
+ String get server_authentication_optional_desc =>
1870
+ 'Leave the API key empty if this server does not require one.';
1871
+
1872
+ @override
1873
+ String get mcp_tools_title => 'MCP Tools';
1874
+
1875
+ @override
1876
+ String get available_tools => 'Available tools';
1877
+
1878
+ @override
1879
+ String get unable_load_tools => 'Unable to load tools';
1880
+
1881
+ @override
1882
+ String get no_tools_registered => 'No tools registered';
1883
+
1884
+ @override
1885
+ String get no_tools_registered_desc =>
1886
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
1887
+
1888
+ @override
1889
+ String get example_mcp_server_title => 'Example MCP server';
1890
+
1891
+ @override
1892
+ String get example_mcp_server_desc =>
1893
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
1894
+
1895
+ @override
1896
+ String get disable_example_server => 'Disable example server';
1897
+
1898
+ @override
1899
+ String get enable_example_server => 'Enable example server';
1900
+
1901
+ @override
1902
+ String get built_in_label => 'Built-in';
1903
+
1904
+ @override
1905
+ String get highlights_label => 'Highlights';
1906
+
1907
+ @override
1908
+ String get built_with_label => 'Built with';
1909
+
1910
+ @override
1911
+ String get local_label => 'Local';
1912
+
1913
+ @override
1914
+ String get gguf_format_label => 'GGUF';
1915
+
1916
+ @override
1917
+ String get tool_status_requested => 'Requested';
1918
+
1919
+ @override
1920
+ String get tool_status_approved => 'Approved';
1921
+
1922
+ @override
1923
+ String get tool_status_rejected => 'Rejected';
1924
+
1925
+ @override
1926
+ String get tool_status_running => 'Running';
1927
+
1928
+ @override
1929
+ String get tool_status_done => 'Done';
1930
+
1931
+ @override
1932
+ String get tool_status_failed => 'Failed';
1933
}
lib/l10n/app_localizations_zh.dart
+599
-15
@@ -1353,48 +1353,45 @@ class AppLocalizationsZh extends AppLocalizations {
1353
String get on_device_models_title => '设备端模型';
1354
1355
@override
1356
- String get settings_huggingface_token => 'Hugging Face Token (Optional)';
1356
+ String get settings_huggingface_token => 'Hugging Face 令牌(可选)';
1357
1358
@override
1359
String get settings_huggingface_token_desc =>
1360
- 'Required only for gated models (e.g. Gemma). Get a token at huggingface.co/settings/tokens.';
1360
+ '仅对受限模型必需(例如 Gemma)。可在 huggingface.co/settings/tokens 获取令牌。';
1361
1362
@override
1363
- String get settings_huggingface_token_set => 'Token saved';
1363
+ String get settings_huggingface_token_set => '令牌已保存';
1364
1365
@override
1366
- String get settings_huggingface_token_cleared => 'Token cleared';
1366
+ String get settings_huggingface_token_cleared => '令牌已清除';
1367
1368
@override
1369
- String get model_requires_huggingface_token =>
1370
- 'Requires a Hugging Face token';
1369
+ String get model_requires_huggingface_token => '需要 Hugging Face 令牌';
1370
1371
@override
1372
String get model_missing_huggingface_token =>
1374
- 'This model is gated on Hugging Face. Add a token in Settings → On-Device Inference to download it.';
1373
+ '此模型在 Hugging Face 上受限。请在“设置 → 设备端推理”中添加令牌后再下载。';
1374
1375
@override
1377
- String get set_huggingface_token => 'Set token';
1376
+ String get set_huggingface_token => '设置令牌';
1377
1378
@override
1380
- String get clear_huggingface_token => 'Clear';
1379
+ String get clear_huggingface_token => '清除';
1380
1381
@override
1383
- String get edit_huggingface_token_dialog_title => 'Hugging Face Access Token';
1382
+ String get edit_huggingface_token_dialog_title => 'Hugging Face 访问令牌';
1383
1384
@override
1385
String get huggingface_token_dialog_hint => 'hf_…';
1386
1387
@override
1389
- String get server_type_ollama_desc => 'Local AI engine. No API key required.';
1388
+ String get server_type_ollama_desc => '本地 AI 引擎。无需 API 密钥。';
1389
1390
@override
1392
- String get server_type_on_device_desc =>
1393
- 'Runs on your phone. Some models need a Hugging Face token.';
1391
+ String get server_type_on_device_desc => '在您的手机上运行。某些模型需要 Hugging Face 令牌。';
1392
1393
@override
1396
- String get server_type_lm_studio_desc =>
1397
- 'Local API server. No API key required.';
1394
+ String get server_type_lm_studio_desc => '本地 API 服务器。无需 API 密钥。';
1395
1396
@override
1397
String get available_models => '可用模型';
@@ -1653,6 +1650,279 @@ class AppLocalizationsZh extends AppLocalizations {
1650
1651
@override
1652
String get tts_other_services_background_note => '注意:其他TTS服务支持后台播放(原生音频格式)。';
1653
+
1654
+ @override
1655
+ String get gguf_imported_models_title => 'Imported GGUF models';
1656
+
1657
+ @override
1658
+ String get gguf_imported_models_empty_subtitle =>
1659
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
1660
+
1661
+ @override
1662
+ String get gguf_imported_models_ready =>
1663
+ 'imported models ready for local inference.';
1664
+
1665
+ @override
1666
+ String get gguf_curated_models_subtitle =>
1667
+ 'Curated on-device models you can download and manage inside LocalMind.';
1668
+
1669
+ @override
1670
+ String get gguf_only_supported =>
1671
+ 'Only GGUF models are supported for this import.';
1672
+
1673
+ @override
1674
+ String get gguf_imported_from_local_file => 'imported from local file.';
1675
+
1676
+ @override
1677
+ String get gguf_import_failed => 'Failed to import GGUF model';
1678
+
1679
+ @override
1680
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
1681
+
1682
+ @override
1683
+ String get gguf_import_canceled => 'GGUF import canceled.';
1684
+
1685
+ @override
1686
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
1687
+
1688
+ @override
1689
+ String get gguf_only_official_huggingface_urls =>
1690
+ 'Only official Hugging Face GGUF URLs are supported.';
1691
+
1692
+ @override
1693
+ String get gguf_use_https_url =>
1694
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
1695
+
1696
+ @override
1697
+ String get gguf_url_must_point_to_file =>
1698
+ 'The Hugging Face URL must point directly to a .gguf file.';
1699
+
1700
+ @override
1701
+ String get gguf_unable_to_detect_file_name =>
1702
+ 'Unable to determine the GGUF file name.';
1703
+
1704
+ @override
1705
+ String get gguf_download_empty =>
1706
+ 'The downloaded GGUF file was empty or missing.';
1707
+
1708
+ @override
1709
+ String get gguf_selected_file_missing =>
1710
+ 'Selected model file does not exist.';
1711
+
1712
+ @override
1713
+ String get gguf_import_action => 'Import GGUF';
1714
+
1715
+ @override
1716
+ String get gguf_overview_title => 'Bring your own GGUF models';
1717
+
1718
+ @override
1719
+ String get gguf_overview_subtitle =>
1720
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
1721
+
1722
+ @override
1723
+ String get gguf_imported_count_label => 'imported';
1724
+
1725
+ @override
1726
+ String get gguf_local_files_label => 'local files';
1727
+
1728
+ @override
1729
+ String get gguf_huggingface_label => 'Hugging Face';
1730
+
1731
+ @override
1732
+ String get gguf_import_local_title => 'Import local GGUF';
1733
+
1734
+ @override
1735
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
1736
+
1737
+ @override
1738
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
1739
+
1740
+ @override
1741
+ String get gguf_import_huggingface_subtitle =>
1742
+ 'Paste a GGUF URL or repo path';
1743
+
1744
+ @override
1745
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
1746
+
1747
+ @override
1748
+ String get gguf_no_imported_subtitle =>
1749
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
1750
+
1751
+ @override
1752
+ String get gguf_import_huggingface_dialog_title =>
1753
+ 'Import GGUF from Hugging Face';
1754
+
1755
+ @override
1756
+ String get gguf_import_huggingface_dialog_subtitle =>
1757
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
1758
+
1759
+ @override
1760
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
1761
+
1762
+ @override
1763
+ String get paste => 'Paste';
1764
+
1765
+ @override
1766
+ String get gguf_browse => 'Browse GGUFs';
1767
+
1768
+ @override
1769
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
1770
+
1771
+ @override
1772
+ String get gguf_huggingface_token_optional =>
1773
+ 'Token optional but recommended';
1774
+
1775
+ @override
1776
+ String get gguf_huggingface_token_ready_desc =>
1777
+ 'Your saved token will be used automatically for gated or private repositories.';
1778
+
1779
+ @override
1780
+ String get gguf_huggingface_token_optional_desc =>
1781
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
1782
+
1783
+ @override
1784
+ String get gguf_downloading => 'Downloading GGUF';
1785
+
1786
+ @override
1787
+ String get gguf_preparing => 'Preparing';
1788
+
1789
+ @override
1790
+ String get gguf_preparing_download => 'Preparing download...';
1791
+
1792
+ @override
1793
+ String get gguf_cancel_import => 'Cancel import';
1794
+
1795
+ @override
1796
+ String get clipboard_empty => 'Clipboard is empty.';
1797
+
1798
+ @override
1799
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
1800
+
1801
+ @override
1802
+ String get gguf_paste_url_error =>
1803
+ 'Paste a Hugging Face GGUF URL or repo path.';
1804
+
1805
+ @override
1806
+ String get gguf_blob_link => 'Blob link';
1807
+
1808
+ @override
1809
+ String get gguf_repository_label => 'Repository';
1810
+
1811
+ @override
1812
+ String get gguf_detected_path_label => 'Detected path';
1813
+
1814
+ @override
1815
+ String get gguf_imported_section_label => 'Imported GGUF';
1816
+
1817
+ @override
1818
+ String get gguf_already_available => 'Already available on this device';
1819
+
1820
+ @override
1821
+ String get gguf_curated_models_short => 'Curated on-device models';
1822
+
1823
+ @override
1824
+ String get execute_tool_title => 'Execute Tool';
1825
+
1826
+ @override
1827
+ String get execute_tool_request_desc =>
1828
+ 'The model is requesting to execute the following tool:';
1829
+
1830
+ @override
1831
+ String get reject => 'Reject';
1832
+
1833
+ @override
1834
+ String get approve => 'Approve';
1835
+
1836
+ @override
1837
+ String get server_type_help =>
1838
+ 'Pick the provider before filling connection details.';
1839
+
1840
+ @override
1841
+ String get server_identity_title => 'Identity';
1842
+
1843
+ @override
1844
+ String get server_identity_desc =>
1845
+ 'Name this server and choose how it appears in the list.';
1846
+
1847
+ @override
1848
+ String get server_connection_title => 'Connection';
1849
+
1850
+ @override
1851
+ String get server_connection_desc =>
1852
+ 'Use the address and port exposed by your server.';
1853
+
1854
+ @override
1855
+ String get server_authentication_title => 'Authentication';
1856
+
1857
+ @override
1858
+ String get server_authentication_required_desc =>
1859
+ 'OpenRouter requires an API key before testing.';
1860
+
1861
+ @override
1862
+ String get server_authentication_optional_desc =>
1863
+ 'Leave the API key empty if this server does not require one.';
1864
+
1865
+ @override
1866
+ String get mcp_tools_title => 'MCP Tools';
1867
+
1868
+ @override
1869
+ String get available_tools => 'Available tools';
1870
+
1871
+ @override
1872
+ String get unable_load_tools => 'Unable to load tools';
1873
+
1874
+ @override
1875
+ String get no_tools_registered => 'No tools registered';
1876
+
1877
+ @override
1878
+ String get no_tools_registered_desc =>
1879
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
1880
+
1881
+ @override
1882
+ String get example_mcp_server_title => 'Example MCP server';
1883
+
1884
+ @override
1885
+ String get example_mcp_server_desc =>
1886
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
1887
+
1888
+ @override
1889
+ String get disable_example_server => 'Disable example server';
1890
+
1891
+ @override
1892
+ String get enable_example_server => 'Enable example server';
1893
+
1894
+ @override
1895
+ String get built_in_label => 'Built-in';
1896
+
1897
+ @override
1898
+ String get highlights_label => 'Highlights';
1899
+
1900
+ @override
1901
+ String get built_with_label => 'Built with';
1902
+
1903
+ @override
1904
+ String get local_label => 'Local';
1905
+
1906
+ @override
1907
+ String get gguf_format_label => 'GGUF';
1908
+
1909
+ @override
1910
+ String get tool_status_requested => 'Requested';
1911
+
1912
+ @override
1913
+ String get tool_status_approved => 'Approved';
1914
+
1915
+ @override
1916
+ String get tool_status_rejected => 'Rejected';
1917
+
1918
+ @override
1919
+ String get tool_status_running => 'Running';
1920
+
1921
+ @override
1922
+ String get tool_status_done => 'Done';
1923
+
1924
+ @override
1925
+ String get tool_status_failed => 'Failed';
1926
}
1927
1928
/// The translations for Chinese, as used in Taiwan (`zh_TW`).
@@ -3003,6 +3273,47 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
3273
@override
3274
String get on_device_models_title => '裝置端模型';
3275
3276
+ @override
3277
+ String get settings_huggingface_token => 'Hugging Face 權杖(選用)';
3278
+
3279
+ @override
3280
+ String get settings_huggingface_token_desc =>
3281
+ '僅限受限制模型需要(例如 Gemma)。可在 huggingface.co/settings/tokens 取得權杖。';
3282
+
3283
+ @override
3284
+ String get settings_huggingface_token_set => '權杖已儲存';
3285
+
3286
+ @override
3287
+ String get settings_huggingface_token_cleared => '權杖已清除';
3288
+
3289
+ @override
3290
+ String get model_requires_huggingface_token => '需要 Hugging Face 權杖';
3291
+
3292
+ @override
3293
+ String get model_missing_huggingface_token =>
3294
+ '此模型在 Hugging Face 上受限制。請在「設定 → 裝置端推論」中加入權杖後再下載。';
3295
+
3296
+ @override
3297
+ String get set_huggingface_token => '設定權杖';
3298
+
3299
+ @override
3300
+ String get clear_huggingface_token => '清除';
3301
+
3302
+ @override
3303
+ String get edit_huggingface_token_dialog_title => 'Hugging Face 存取權杖';
3304
+
3305
+ @override
3306
+ String get huggingface_token_dialog_hint => 'hf_…';
3307
+
3308
+ @override
3309
+ String get server_type_ollama_desc => '本機 AI 引擎。不需要 API 金鑰。';
3310
+
3311
+ @override
3312
+ String get server_type_on_device_desc => '在您的手機上執行。某些模型需要 Hugging Face 權杖。';
3313
+
3314
+ @override
3315
+ String get server_type_lm_studio_desc => '本機 API 伺服器。不需要 API 金鑰。';
3316
+
3317
@override
3318
String get available_models => '可用模型';
3319
@@ -3261,4 +3572,277 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
3572
@override
3573
String get tts_other_services_background_note =>
3574
'注意:其他 TTS 服務支援背景播放(原生音訊格式)。';
3575
+
3576
+ @override
3577
+ String get gguf_imported_models_title => 'Imported GGUF models';
3578
+
3579
+ @override
3580
+ String get gguf_imported_models_empty_subtitle =>
3581
+ 'Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.';
3582
+
3583
+ @override
3584
+ String get gguf_imported_models_ready =>
3585
+ 'imported models ready for local inference.';
3586
+
3587
+ @override
3588
+ String get gguf_curated_models_subtitle =>
3589
+ 'Curated on-device models you can download and manage inside LocalMind.';
3590
+
3591
+ @override
3592
+ String get gguf_only_supported =>
3593
+ 'Only GGUF models are supported for this import.';
3594
+
3595
+ @override
3596
+ String get gguf_imported_from_local_file => 'imported from local file.';
3597
+
3598
+ @override
3599
+ String get gguf_import_failed => 'Failed to import GGUF model';
3600
+
3601
+ @override
3602
+ String get gguf_imported_from_huggingface => 'imported from Hugging Face.';
3603
+
3604
+ @override
3605
+ String get gguf_import_canceled => 'GGUF import canceled.';
3606
+
3607
+ @override
3608
+ String get gguf_enter_huggingface_url => 'Enter a Hugging Face GGUF URL.';
3609
+
3610
+ @override
3611
+ String get gguf_only_official_huggingface_urls =>
3612
+ 'Only official Hugging Face GGUF URLs are supported.';
3613
+
3614
+ @override
3615
+ String get gguf_use_https_url =>
3616
+ 'Use an HTTPS Hugging Face URL for GGUF import.';
3617
+
3618
+ @override
3619
+ String get gguf_url_must_point_to_file =>
3620
+ 'The Hugging Face URL must point directly to a .gguf file.';
3621
+
3622
+ @override
3623
+ String get gguf_unable_to_detect_file_name =>
3624
+ 'Unable to determine the GGUF file name.';
3625
+
3626
+ @override
3627
+ String get gguf_download_empty =>
3628
+ 'The downloaded GGUF file was empty or missing.';
3629
+
3630
+ @override
3631
+ String get gguf_selected_file_missing =>
3632
+ 'Selected model file does not exist.';
3633
+
3634
+ @override
3635
+ String get gguf_import_action => 'Import GGUF';
3636
+
3637
+ @override
3638
+ String get gguf_overview_title => 'Bring your own GGUF models';
3639
+
3640
+ @override
3641
+ String get gguf_overview_subtitle =>
3642
+ 'Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.';
3643
+
3644
+ @override
3645
+ String get gguf_imported_count_label => 'imported';
3646
+
3647
+ @override
3648
+ String get gguf_local_files_label => 'local files';
3649
+
3650
+ @override
3651
+ String get gguf_huggingface_label => 'Hugging Face';
3652
+
3653
+ @override
3654
+ String get gguf_import_local_title => 'Import local GGUF';
3655
+
3656
+ @override
3657
+ String get gguf_import_local_subtitle => 'Copy a .gguf file from this device';
3658
+
3659
+ @override
3660
+ String get gguf_import_huggingface_title => 'Import from Hugging Face';
3661
+
3662
+ @override
3663
+ String get gguf_import_huggingface_subtitle =>
3664
+ 'Paste a GGUF URL or repo path';
3665
+
3666
+ @override
3667
+ String get gguf_no_imported_title => 'No imported GGUF models yet';
3668
+
3669
+ @override
3670
+ String get gguf_no_imported_subtitle =>
3671
+ 'You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.';
3672
+
3673
+ @override
3674
+ String get gguf_import_huggingface_dialog_title =>
3675
+ 'Import GGUF from Hugging Face';
3676
+
3677
+ @override
3678
+ String get gguf_import_huggingface_dialog_subtitle =>
3679
+ 'Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.';
3680
+
3681
+ @override
3682
+ String get gguf_url_or_repo_path => 'GGUF URL or repo path';
3683
+
3684
+ @override
3685
+ String get paste => 'Paste';
3686
+
3687
+ @override
3688
+ String get gguf_browse => 'Browse GGUFs';
3689
+
3690
+ @override
3691
+ String get gguf_huggingface_token_ready => 'Hugging Face token ready';
3692
+
3693
+ @override
3694
+ String get gguf_huggingface_token_optional =>
3695
+ 'Token optional but recommended';
3696
+
3697
+ @override
3698
+ String get gguf_huggingface_token_ready_desc =>
3699
+ 'Your saved token will be used automatically for gated or private repositories.';
3700
+
3701
+ @override
3702
+ String get gguf_huggingface_token_optional_desc =>
3703
+ 'Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.';
3704
+
3705
+ @override
3706
+ String get gguf_downloading => 'Downloading GGUF';
3707
+
3708
+ @override
3709
+ String get gguf_preparing => 'Preparing';
3710
+
3711
+ @override
3712
+ String get gguf_preparing_download => 'Preparing download...';
3713
+
3714
+ @override
3715
+ String get gguf_cancel_import => 'Cancel import';
3716
+
3717
+ @override
3718
+ String get clipboard_empty => 'Clipboard is empty.';
3719
+
3720
+ @override
3721
+ String get could_not_open_huggingface => 'Could not open Hugging Face.';
3722
+
3723
+ @override
3724
+ String get gguf_paste_url_error =>
3725
+ 'Paste a Hugging Face GGUF URL or repo path.';
3726
+
3727
+ @override
3728
+ String get gguf_blob_link => 'Blob link';
3729
+
3730
+ @override
3731
+ String get gguf_repository_label => 'Repository';
3732
+
3733
+ @override
3734
+ String get gguf_detected_path_label => 'Detected path';
3735
+
3736
+ @override
3737
+ String get gguf_imported_section_label => 'Imported GGUF';
3738
+
3739
+ @override
3740
+ String get gguf_already_available => 'Already available on this device';
3741
+
3742
+ @override
3743
+ String get gguf_curated_models_short => 'Curated on-device models';
3744
+
3745
+ @override
3746
+ String get execute_tool_title => 'Execute Tool';
3747
+
3748
+ @override
3749
+ String get execute_tool_request_desc =>
3750
+ 'The model is requesting to execute the following tool:';
3751
+
3752
+ @override
3753
+ String get reject => 'Reject';
3754
+
3755
+ @override
3756
+ String get approve => 'Approve';
3757
+
3758
+ @override
3759
+ String get server_type_help =>
3760
+ 'Pick the provider before filling connection details.';
3761
+
3762
+ @override
3763
+ String get server_identity_title => 'Identity';
3764
+
3765
+ @override
3766
+ String get server_identity_desc =>
3767
+ 'Name this server and choose how it appears in the list.';
3768
+
3769
+ @override
3770
+ String get server_connection_title => 'Connection';
3771
+
3772
+ @override
3773
+ String get server_connection_desc =>
3774
+ 'Use the address and port exposed by your server.';
3775
+
3776
+ @override
3777
+ String get server_authentication_title => 'Authentication';
3778
+
3779
+ @override
3780
+ String get server_authentication_required_desc =>
3781
+ 'OpenRouter requires an API key before testing.';
3782
+
3783
+ @override
3784
+ String get server_authentication_optional_desc =>
3785
+ 'Leave the API key empty if this server does not require one.';
3786
+
3787
+ @override
3788
+ String get mcp_tools_title => 'MCP Tools';
3789
+
3790
+ @override
3791
+ String get available_tools => 'Available tools';
3792
+
3793
+ @override
3794
+ String get unable_load_tools => 'Unable to load tools';
3795
+
3796
+ @override
3797
+ String get no_tools_registered => 'No tools registered';
3798
+
3799
+ @override
3800
+ String get no_tools_registered_desc =>
3801
+ 'Enable the example MCP server or add MCP integrations from chat settings.';
3802
+
3803
+ @override
3804
+ String get example_mcp_server_title => 'Example MCP server';
3805
+
3806
+ @override
3807
+ String get example_mcp_server_desc =>
3808
+ 'Registers example.echo and example.word_count through the same MCP tool provider used by external servers.';
3809
+
3810
+ @override
3811
+ String get disable_example_server => 'Disable example server';
3812
+
3813
+ @override
3814
+ String get enable_example_server => 'Enable example server';
3815
+
3816
+ @override
3817
+ String get built_in_label => 'Built-in';
3818
+
3819
+ @override
3820
+ String get highlights_label => 'Highlights';
3821
+
3822
+ @override
3823
+ String get built_with_label => 'Built with';
3824
+
3825
+ @override
3826
+ String get local_label => 'Local';
3827
+
3828
+ @override
3829
+ String get gguf_format_label => 'GGUF';
3830
+
3831
+ @override
3832
+ String get tool_status_requested => 'Requested';
3833
+
3834
+ @override
3835
+ String get tool_status_approved => 'Approved';
3836
+
3837
+ @override
3838
+ String get tool_status_rejected => 'Rejected';
3839
+
3840
+ @override
3841
+ String get tool_status_running => 'Running';
3842
+
3843
+ @override
3844
+ String get tool_status_done => 'Done';
3845
+
3846
+ @override
3847
+ String get tool_status_failed => 'Failed';
3848
}
lib/l10n/app_zh.arb
+97
-2
@@ -507,5 +507,100 @@
507
"tts_supports_background": "支持后台播放(原生音频格式)",
508
"tts_other_services_background_note": "注意:其他TTS服务支持后台播放(原生音频格式)。",
509
"start_listening_tooltip": "开始聆听",
510
- "stop_listening_tooltip": "停止聆听"
511
-}
\ No newline at end of file
510
+ "stop_listening_tooltip": "停止聆听",
511
+ "settings_huggingface_token": "Hugging Face 令牌(可选)",
512
+ "settings_huggingface_token_desc": "仅对受限模型必需(例如 Gemma)。可在 huggingface.co/settings/tokens 获取令牌。",
513
+ "settings_huggingface_token_set": "令牌已保存",
514
+ "settings_huggingface_token_cleared": "令牌已清除",
515
+ "model_requires_huggingface_token": "需要 Hugging Face 令牌",
516
+ "model_missing_huggingface_token": "此模型在 Hugging Face 上受限。请在“设置 → 设备端推理”中添加令牌后再下载。",
517
+ "set_huggingface_token": "设置令牌",
518
+ "clear_huggingface_token": "清除",
519
+ "edit_huggingface_token_dialog_title": "Hugging Face 访问令牌",
520
+ "huggingface_token_dialog_hint": "hf_…",
521
+ "server_type_ollama_desc": "本地 AI 引擎。无需 API 密钥。",
522
+ "server_type_on_device_desc": "在您的手机上运行。某些模型需要 Hugging Face 令牌。",
523
+ "server_type_lm_studio_desc": "本地 API 服务器。无需 API 密钥。",
524
+ "gguf_imported_models_title": "Imported GGUF models",
525
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
526
+ "gguf_imported_models_ready": "imported models ready for local inference.",
527
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
528
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
529
+ "gguf_imported_from_local_file": "imported from local file.",
530
+ "gguf_import_failed": "Failed to import GGUF model",
531
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
532
+ "gguf_import_canceled": "GGUF import canceled.",
533
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
534
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
535
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
536
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
537
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
538
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
539
+ "gguf_selected_file_missing": "Selected model file does not exist.",
540
+ "gguf_import_action": "Import GGUF",
541
+ "gguf_overview_title": "Bring your own GGUF models",
542
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
543
+ "gguf_imported_count_label": "imported",
544
+ "gguf_local_files_label": "local files",
545
+ "gguf_huggingface_label": "Hugging Face",
546
+ "gguf_import_local_title": "Import local GGUF",
547
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
548
+ "gguf_import_huggingface_title": "Import from Hugging Face",
549
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
550
+ "gguf_no_imported_title": "No imported GGUF models yet",
551
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
552
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
553
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
554
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
555
+ "paste": "Paste",
556
+ "gguf_browse": "Browse GGUFs",
557
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
558
+ "gguf_huggingface_token_optional": "Token optional but recommended",
559
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
560
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
561
+ "gguf_downloading": "Downloading GGUF",
562
+ "gguf_preparing": "Preparing",
563
+ "gguf_preparing_download": "Preparing download...",
564
+ "gguf_cancel_import": "Cancel import",
565
+ "clipboard_empty": "Clipboard is empty.",
566
+ "could_not_open_huggingface": "Could not open Hugging Face.",
567
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
568
+ "gguf_blob_link": "Blob link",
569
+ "gguf_repository_label": "Repository",
570
+ "gguf_detected_path_label": "Detected path",
571
+ "gguf_imported_section_label": "Imported GGUF",
572
+ "gguf_already_available": "Already available on this device",
573
+ "gguf_curated_models_short": "Curated on-device models",
574
+ "execute_tool_title": "Execute Tool",
575
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
576
+ "reject": "Reject",
577
+ "approve": "Approve",
578
+ "server_type_help": "Pick the provider before filling connection details.",
579
+ "server_identity_title": "Identity",
580
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
581
+ "server_connection_title": "Connection",
582
+ "server_connection_desc": "Use the address and port exposed by your server.",
583
+ "server_authentication_title": "Authentication",
584
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
585
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
586
+ "mcp_tools_title": "MCP Tools",
587
+ "available_tools": "Available tools",
588
+ "unable_load_tools": "Unable to load tools",
589
+ "no_tools_registered": "No tools registered",
590
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
591
+ "example_mcp_server_title": "Example MCP server",
592
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
593
+ "disable_example_server": "Disable example server",
594
+ "enable_example_server": "Enable example server",
595
+ "built_in_label": "Built-in",
596
+ "highlights_label": "Highlights",
597
+ "built_with_label": "Built with",
598
+ "local_label": "Local",
599
+ "gguf_format_label": "GGUF",
600
+ "tool_status_requested": "Requested",
601
+ "tool_status_approved": "Approved",
602
+ "tool_status_rejected": "Rejected",
603
+ "tool_status_running": "Running",
604
+ "tool_status_done": "Done",
605
+ "tool_status_failed": "Failed"
606
+}
lib/l10n/app_zh_TW.arb
+96
-1
@@ -507,5 +507,100 @@
507
"tts_supports_background": "支援背景播放(原生音訊格式)",
508
"tts_other_services_background_note": "注意:其他 TTS 服務支援背景播放(原生音訊格式)。",
509
"start_listening_tooltip": "開始聆聽",
510
- "stop_listening_tooltip": "停止聆聽"
510
+ "stop_listening_tooltip": "停止聆聽",
511
+ "settings_huggingface_token": "Hugging Face 權杖(選用)",
512
+ "settings_huggingface_token_desc": "僅限受限制模型需要(例如 Gemma)。可在 huggingface.co/settings/tokens 取得權杖。",
513
+ "settings_huggingface_token_set": "權杖已儲存",
514
+ "settings_huggingface_token_cleared": "權杖已清除",
515
+ "model_requires_huggingface_token": "需要 Hugging Face 權杖",
516
+ "model_missing_huggingface_token": "此模型在 Hugging Face 上受限制。請在「設定 → 裝置端推論」中加入權杖後再下載。",
517
+ "set_huggingface_token": "設定權杖",
518
+ "clear_huggingface_token": "清除",
519
+ "edit_huggingface_token_dialog_title": "Hugging Face 存取權杖",
520
+ "huggingface_token_dialog_hint": "hf_…",
521
+ "server_type_ollama_desc": "本機 AI 引擎。不需要 API 金鑰。",
522
+ "server_type_on_device_desc": "在您的手機上執行。某些模型需要 Hugging Face 權杖。",
523
+ "server_type_lm_studio_desc": "本機 API 伺服器。不需要 API 金鑰。",
524
+ "gguf_imported_models_title": "Imported GGUF models",
525
+ "gguf_imported_models_empty_subtitle": "Import a GGUF from your device or add one from Hugging Face. Imported models run locally with llama.cpp.",
526
+ "gguf_imported_models_ready": "imported models ready for local inference.",
527
+ "gguf_curated_models_subtitle": "Curated on-device models you can download and manage inside LocalMind.",
528
+ "gguf_only_supported": "Only GGUF models are supported for this import.",
529
+ "gguf_imported_from_local_file": "imported from local file.",
530
+ "gguf_import_failed": "Failed to import GGUF model",
531
+ "gguf_imported_from_huggingface": "imported from Hugging Face.",
532
+ "gguf_import_canceled": "GGUF import canceled.",
533
+ "gguf_enter_huggingface_url": "Enter a Hugging Face GGUF URL.",
534
+ "gguf_only_official_huggingface_urls": "Only official Hugging Face GGUF URLs are supported.",
535
+ "gguf_use_https_url": "Use an HTTPS Hugging Face URL for GGUF import.",
536
+ "gguf_url_must_point_to_file": "The Hugging Face URL must point directly to a .gguf file.",
537
+ "gguf_unable_to_detect_file_name": "Unable to determine the GGUF file name.",
538
+ "gguf_download_empty": "The downloaded GGUF file was empty or missing.",
539
+ "gguf_selected_file_missing": "Selected model file does not exist.",
540
+ "gguf_import_action": "Import GGUF",
541
+ "gguf_overview_title": "Bring your own GGUF models",
542
+ "gguf_overview_subtitle": "Import a .gguf from local storage or download one straight from Hugging Face. Imported models stay on this device and load with llama.cpp.",
543
+ "gguf_imported_count_label": "imported",
544
+ "gguf_local_files_label": "local files",
545
+ "gguf_huggingface_label": "Hugging Face",
546
+ "gguf_import_local_title": "Import local GGUF",
547
+ "gguf_import_local_subtitle": "Copy a .gguf file from this device",
548
+ "gguf_import_huggingface_title": "Import from Hugging Face",
549
+ "gguf_import_huggingface_subtitle": "Paste a GGUF URL or repo path",
550
+ "gguf_no_imported_title": "No imported GGUF models yet",
551
+ "gguf_no_imported_subtitle": "You can bring your own GGUF file from device storage or paste a Hugging Face URL or repo path that points to a .gguf file.",
552
+ "gguf_import_huggingface_dialog_title": "Import GGUF from Hugging Face",
553
+ "gguf_import_huggingface_dialog_subtitle": "Paste a direct GGUF URL or a Hugging Face repo path like `owner/repo/blob/main/model.gguf`. Blob links are converted automatically.",
554
+ "gguf_url_or_repo_path": "GGUF URL or repo path",
555
+ "paste": "Paste",
556
+ "gguf_browse": "Browse GGUFs",
557
+ "gguf_huggingface_token_ready": "Hugging Face token ready",
558
+ "gguf_huggingface_token_optional": "Token optional but recommended",
559
+ "gguf_huggingface_token_ready_desc": "Your saved token will be used automatically for gated or private repositories.",
560
+ "gguf_huggingface_token_optional_desc": "Requires a Hugging Face token. Add one in Settings if this GGUF is gated or private.",
561
+ "gguf_downloading": "Downloading GGUF",
562
+ "gguf_preparing": "Preparing",
563
+ "gguf_preparing_download": "Preparing download...",
564
+ "gguf_cancel_import": "Cancel import",
565
+ "clipboard_empty": "Clipboard is empty.",
566
+ "could_not_open_huggingface": "Could not open Hugging Face.",
567
+ "gguf_paste_url_error": "Paste a Hugging Face GGUF URL or repo path.",
568
+ "gguf_blob_link": "Blob link",
569
+ "gguf_repository_label": "Repository",
570
+ "gguf_detected_path_label": "Detected path",
571
+ "gguf_imported_section_label": "Imported GGUF",
572
+ "gguf_already_available": "Already available on this device",
573
+ "gguf_curated_models_short": "Curated on-device models",
574
+ "execute_tool_title": "Execute Tool",
575
+ "execute_tool_request_desc": "The model is requesting to execute the following tool:",
576
+ "reject": "Reject",
577
+ "approve": "Approve",
578
+ "server_type_help": "Pick the provider before filling connection details.",
579
+ "server_identity_title": "Identity",
580
+ "server_identity_desc": "Name this server and choose how it appears in the list.",
581
+ "server_connection_title": "Connection",
582
+ "server_connection_desc": "Use the address and port exposed by your server.",
583
+ "server_authentication_title": "Authentication",
584
+ "server_authentication_required_desc": "OpenRouter requires an API key before testing.",
585
+ "server_authentication_optional_desc": "Leave the API key empty if this server does not require one.",
586
+ "mcp_tools_title": "MCP Tools",
587
+ "available_tools": "Available tools",
588
+ "unable_load_tools": "Unable to load tools",
589
+ "no_tools_registered": "No tools registered",
590
+ "no_tools_registered_desc": "Enable the example MCP server or add MCP integrations from chat settings.",
591
+ "example_mcp_server_title": "Example MCP server",
592
+ "example_mcp_server_desc": "Registers example.echo and example.word_count through the same MCP tool provider used by external servers.",
593
+ "disable_example_server": "Disable example server",
594
+ "enable_example_server": "Enable example server",
595
+ "built_in_label": "Built-in",
596
+ "highlights_label": "Highlights",
597
+ "built_with_label": "Built with",
598
+ "local_label": "Local",
599
+ "gguf_format_label": "GGUF",
600
+ "tool_status_requested": "Requested",
601
+ "tool_status_approved": "Approved",
602
+ "tool_status_rejected": "Rejected",
603
+ "tool_status_running": "Running",
604
+ "tool_status_done": "Done",
605
+ "tool_status_failed": "Failed"
606
}