@tduncan / Cortana / commits / 7362420

chore: fixed translations

abdulmominsakib committed Jun 29, 2026 at 23:21 UTC 73624204e2406d9f6945e09ea7aad32441adca14
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 }