fix(stt): retry error_client with the other recognizer and explain STT errors #100
Devices without Google speech services (e.g. GrapheneOS) fail the default Android recognizer with error_client, which voice mode showed as "Speech recognition error: client". - Retry once after error_client; on Android the retry switches between the default and the on-device recognizer, and remembers what worked. - Report a missing recognizer as its own error instead of a microphone permission problem. - Share one localized STT error mapping between voice mode and the chat input bar, with an install hint for missing recognizers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
abdulmominsakib committed
Sep 28, 2026 at 20:04 UTC
d9663883ccc6dadc085151180899e5430737512f
40 files changed
+1151
-98
lib/features/chat/views/components/chat_input_bar.dart
+8
-44
@@ -15,6 +15,7 @@ import '../../../../l10n/app_localizations.dart';
15
import '../../../saved_messages/views/components/saved_message_picker_sheet.dart';
16
import '../../../servers/providers/server_providers.dart';
17
import '../../../stt/providers/stt_providers.dart';
18
+import '../../../stt/utils/stt_error_messages.dart';
19
import '../../../tts/providers/tts_providers.dart';
20
import '../../../voice_mode/providers/voice_mode_provider.dart';
21
import '../../providers/chat_providers.dart';
@@ -756,40 +757,6 @@ class ChatInputBarState extends ConsumerState<ChatInputBar>
757
);
758
}
759
759
- String? _mapSttError(String error) {
760
- switch (error) {
761
- case 'error_no_match':
762
- return 'No speech recognized. Please try speaking again and check your microphone.';
763
-
764
- case 'error_speech_timeout':
765
- return 'No speech detected. Timed out.';
766
-
767
- case 'error_permission':
768
- return 'Microphone permission denied.';
769
-
770
- case 'error_busy':
771
- return 'Speech recognition is busy. Please try again.';
772
-
773
- case 'error_network':
774
- case 'error_network_timeout':
775
- return 'Network error. Please check your connection and try again.';
776
-
777
- case 'error_audio':
778
- return 'Audio recording error. Please check your microphone.';
779
-
780
- default:
781
- if (error.startsWith('error_')) {
782
- final cleanName = error
783
- .replaceFirst('error_', '')
784
- .replaceAll('_', ' ');
785
-
786
- return 'Speech recognition error: $cleanName';
787
- }
788
-
789
- return error;
790
- }
791
- }
792
-
760
@override
761
Widget build(BuildContext context) {
762
final l10n = AppLocalizations.of(context)!;
@@ -844,16 +811,13 @@ class ChatInputBarState extends ConsumerState<ChatInputBar>
811
voiceState.isActive || voiceState.phase != VoiceModePhase.idle;
812
if (voiceActive) return;
813
847
- final message = _mapSttError(next);
848
-
849
- if (message != null) {
850
- WidgetsBinding.instance.addPostFrameCallback((_) {
851
- if (!mounted) return;
852
- ScaffoldMessenger.maybeOf(
853
- context,
854
- )?.showSnackBar(SnackBar(content: Text(message)));
855
- });
856
- }
814
+ final message = sttErrorMessage(AppLocalizations.of(context), next);
815
+ WidgetsBinding.instance.addPostFrameCallback((_) {
816
+ if (!mounted) return;
817
+ ScaffoldMessenger.maybeOf(
818
+ context,
819
+ )?.showSnackBar(SnackBar(content: Text(message)));
820
+ });
821
}
822
});
823
lib/features/stt/providers/stt_providers.dart
+88
-2
@@ -1,7 +1,12 @@
1
import 'dart:async';
2
+
3
+import 'package:flutter/foundation.dart';
4
+import 'package:flutter/services.dart';
5
import 'package:flutter_riverpod/flutter_riverpod.dart';
6
import 'package:speech_to_text/speech_to_text.dart';
7
+
8
import '../../../core/logger/app_logger.dart';
9
+import '../utils/stt_error_messages.dart';
10
11
/// Double in dB-ish units (iOS) or 0..1-ish (Android) reported by the
12
/// speech_to_text plugin via `onSoundLevelChange`. Higher = louder.
@@ -37,6 +42,14 @@ class SttState {
42
}
43
44
class SttNotifier extends Notifier<SttState> {
45
+ SttNotifier({SpeechToText Function()? speechFactory})
46
+ : _speechFactory = speechFactory ?? SpeechToText.new;
47
+
48
+ /// Delay before re-listening after an `error_client`, giving the platform
49
+ /// recognizer time to release the previous session.
50
+ static const clientErrorRetryDelay = Duration(milliseconds: 300);
51
+
52
+ final SpeechToText Function() _speechFactory;
53
late SpeechToText _speech;
54
bool _isInit = false;
55
Future<bool>? _initialization;
@@ -46,10 +59,19 @@ class SttNotifier extends Notifier<SttState> {
59
// Snapshot of the most recently issued session id. Set to -1 when no
60
// listen() is in flight.
61
int _activeSession = -1;
62
+ // Re-issues the current listen() with the same callbacks. Null when no
63
+ // listen is in flight.
64
+ Future<void> Function()? _relisten;
65
+ bool _retriedClientError = false;
66
+ // Android: use the on-device recognizer instead of the default service.
67
+ // Flipped after an `error_client`, which is what devices without Google
68
+ // speech services (e.g. GrapheneOS) report for the default one (#100).
69
+ bool _useOnDeviceRecognizer = false;
70
+ bool _switchedRecognizerForRetry = false;
71
72
@override
73
SttState build() {
52
- _speech = SpeechToText();
74
+ _speech = _speechFactory();
75
ref.onDispose(() {
76
try {
77
_speech.cancel();
@@ -71,6 +93,15 @@ class SttNotifier extends Notifier<SttState> {
93
onError: (val) {
94
if (!ref.mounted) return;
95
Log.error('STT error: ${val.errorMsg} - permanent: ${val.permanent}');
96
+ if (val.errorMsg == 'error_client' && _retryAfterClientError()) {
97
+ return;
98
+ }
99
+ if (_switchedRecognizerForRetry) {
100
+ // The other recognizer didn't help either; go back to the
101
+ // original one for the next attempt.
102
+ _useOnDeviceRecognizer = !_useOnDeviceRecognizer;
103
+ _switchedRecognizerForRetry = false;
104
+ }
105
state = state.copyWith(error: val.errorMsg, isListening: false);
106
},
107
onStatus: (val) {
@@ -97,7 +128,12 @@ class SttNotifier extends Notifier<SttState> {
128
} catch (e) {
129
if (!ref.mounted) return false;
130
Log.error('STT initialization failed: $e');
100
- state = state.copyWith(isAvailable: false, error: e.toString());
131
+ final noRecognizer =
132
+ e is PlatformException && e.code == 'recognizerNotAvailable';
133
+ state = state.copyWith(
134
+ isAvailable: false,
135
+ error: noRecognizer ? sttUnavailableCode : e.toString(),
136
+ );
137
return false;
138
} finally {
139
_initialization = null;
@@ -123,6 +159,21 @@ class SttNotifier extends Notifier<SttState> {
159
recognizedWords: '',
160
clearError: true,
161
);
162
+ _retriedClientError = false;
163
+ _switchedRecognizerForRetry = false;
164
+ _relisten = () => _listen(
165
+ onResult: onResult,
166
+ onFinal: onFinal,
167
+ onSoundLevelChange: onSoundLevelChange,
168
+ );
169
+ await _relisten!();
170
+ }
171
+
172
+ Future<void> _listen({
173
+ required void Function(String) onResult,
174
+ void Function(String)? onFinal,
175
+ SoundLevelChange? onSoundLevelChange,
176
+ }) async {
177
_session++;
178
_activeSession = _session;
179
@@ -148,6 +199,7 @@ class SttNotifier extends Notifier<SttState> {
199
pauseFor: const Duration(seconds: 5),
200
partialResults: true,
201
cancelOnError: true,
202
+ onDevice: _useOnDeviceRecognizer,
203
),
204
);
205
} catch (e) {
@@ -157,9 +209,42 @@ class SttNotifier extends Notifier<SttState> {
209
}
210
}
211
212
+ /// Retries the current listen once after an `error_client`. On Android the
213
+ /// retry switches between the default and the on-device recognizer.
214
+ /// Returns false when the error should be surfaced instead.
215
+ bool _retryAfterClientError() {
216
+ final relisten = _relisten;
217
+ if (relisten == null || _retriedClientError) return false;
218
+ _retriedClientError = true;
219
+ if (defaultTargetPlatform == TargetPlatform.android) {
220
+ _useOnDeviceRecognizer = !_useOnDeviceRecognizer;
221
+ _switchedRecognizerForRetry = true;
222
+ }
223
+ Log.warning(
224
+ 'STT error_client, retrying once '
225
+ '(onDevice: $_useOnDeviceRecognizer)',
226
+ );
227
+ final session = _session;
228
+ unawaited(() async {
229
+ try {
230
+ await _speech.cancel();
231
+ } catch (e) {
232
+ Log.error('STT cancel before retry failed: $e');
233
+ }
234
+ await Future<void>.delayed(clientErrorRetryDelay);
235
+ // Bail if the caller stopped or restarted listening meanwhile.
236
+ if (!ref.mounted || _session != session || _relisten != relisten) {
237
+ return;
238
+ }
239
+ await relisten();
240
+ }());
241
+ return true;
242
+ }
243
+
244
Future<void> stopListening() async {
245
// Invalidate the current session so any in-flight status callbacks
246
// are ignored.
247
+ _relisten = null;
248
_session++;
249
_activeSession = -1;
250
try {
@@ -172,6 +257,7 @@ class SttNotifier extends Notifier<SttState> {
257
}
258
259
Future<void> cancelListening() async {
260
+ _relisten = null;
261
_session++;
262
_activeSession = -1;
263
try {
lib/features/stt/utils/stt_error_messages.dart
new
+48
@@ -0,0 +1,48 @@
1
+import '../../../l10n/app_localizations.dart';
2
+
3
+/// Reported when the device has no speech recognition service at all.
4
+const sttUnavailableCode = 'stt_unavailable';
5
+
6
+/// Whether [error] means the recognizer ran but heard nothing usable.
7
+bool isNoSpeechSttError(String? error) =>
8
+ error == 'error_no_match' || error == 'error_speech_timeout';
9
+
10
+/// Maps a speech_to_text error code to a user-facing message. Anything that
11
+/// isn't a known code (e.g. an already-readable message) is returned as is.
12
+String sttErrorMessage(AppLocalizations? l10n, String error) {
13
+ if (l10n == null) return error;
14
+ switch (error) {
15
+ case sttUnavailableCode:
16
+ return l10n.stt_error_unavailable;
17
+ case 'error_no_match':
18
+ return l10n.stt_error_no_match;
19
+ case 'error_speech_timeout':
20
+ return l10n.stt_error_speech_timeout;
21
+ case 'error_permission':
22
+ case 'error_insufficient_permissions':
23
+ return l10n.stt_error_permission;
24
+ case 'error_busy':
25
+ case 'error_recognizer_busy':
26
+ case 'error_too_many_requests':
27
+ return l10n.stt_error_busy;
28
+ case 'error_network':
29
+ case 'error_network_timeout':
30
+ case 'error_server':
31
+ case 'error_server_disconnected':
32
+ return l10n.stt_error_network;
33
+ case 'error_audio':
34
+ case 'error_audio_error':
35
+ return l10n.stt_error_audio;
36
+ case 'error_client':
37
+ return l10n.stt_error_client;
38
+ case 'error_language_not_supported':
39
+ case 'error_language_unavailable':
40
+ return l10n.stt_error_language;
41
+ default:
42
+ if (error.startsWith('error_')) {
43
+ final cleanName = error.replaceFirst('error_', '').replaceAll('_', ' ');
44
+ return l10n.stt_error_generic(cleanName);
45
+ }
46
+ return error;
47
+ }
48
+}
lib/features/voice_mode/providers/voice_mode_provider.dart
+9
-30
@@ -7,6 +7,7 @@ import '../../../core/providers/chat_background_service_provider.dart';
7
import '../../../services/voice_feedback_service.dart';
8
import '../../chat/providers/chat_providers.dart';
9
import '../../stt/providers/stt_providers.dart';
10
+import '../../stt/utils/stt_error_messages.dart';
11
import '../../tts/providers/tts_providers.dart';
12
13
/// The phase of the voice-to-voice conversation loop.
@@ -121,13 +122,11 @@ class VoiceModeNotifier extends Notifier<VoiceModeState> {
122
}
123
});
124
124
- // Listen to STT errors and show them directly on the voice screen.
125
+ // Listen to STT errors and show them directly on the voice screen. The
126
+ // raw code is kept in state and localized by the view.
127
ref.listen<String?>(sttProvider.select((s) => s.error), (previous, next) {
128
if (!_active || next == null) return;
127
- state = state.copyWith(
128
- phase: VoiceModePhase.error,
129
- error: _mapSttError(next),
130
- );
129
+ state = state.copyWith(phase: VoiceModePhase.error, error: next);
130
ref.read(voiceFeedbackProvider).playDisconnected();
131
});
132
@@ -171,9 +170,13 @@ class VoiceModeNotifier extends Notifier<VoiceModeState> {
170
final available = await stt.initSpeech();
171
if (!_isCurrentListenAttempt(attempt)) return;
172
if (!available) {
173
+ // A missing recognizer isn't a permission problem (#100).
174
+ final noRecognizer = ref.read(sttProvider).error == sttUnavailableCode;
175
state = state.copyWith(
176
phase: VoiceModePhase.error,
176
- error: 'Microphone permission is required for voice mode.',
177
+ error: noRecognizer
178
+ ? sttUnavailableCode
179
+ : 'Microphone permission is required for voice mode.',
180
micLevel: 0,
181
);
182
ref.read(voiceFeedbackProvider).playDisconnected();
@@ -454,27 +457,3 @@ class VoiceModeNotifier extends Notifier<VoiceModeState> {
457
return _active && ref.mounted && attempt == _listenAttempt;
458
}
459
}
457
-
458
-String _mapSttError(String error) {
459
- switch (error) {
460
- case 'error_no_match':
461
- return 'No speech recognized. Tap to try again.';
462
- case 'error_speech_timeout':
463
- return 'No speech detected. Tap to try again.';
464
- case 'error_permission':
465
- return 'Microphone permission denied.';
466
- case 'error_busy':
467
- return 'Speech recognition is busy. Please try again.';
468
- case 'error_network':
469
- case 'error_network_timeout':
470
- return 'Network error. Please check your connection.';
471
- case 'error_audio':
472
- return 'Audio recording error. Please check your microphone.';
473
- default:
474
- if (error.startsWith('error_')) {
475
- final cleanName = error.replaceFirst('error_', '').replaceAll('_', ' ');
476
- return 'Speech recognition error: $cleanName';
477
- }
478
- return error;
479
- }
480
-}
lib/features/voice_mode/views/components/voice_transcript.dart
+4
-4
@@ -1,6 +1,8 @@
1
import 'package:flutter/material.dart';
2
import 'package:flutter_riverpod/flutter_riverpod.dart';
3
4
+import '../../../../l10n/app_localizations.dart';
5
+import '../../../stt/utils/stt_error_messages.dart';
6
import '../../../tts/providers/tts_providers.dart';
7
import '../../providers/voice_mode_provider.dart';
8
import '../../voice_mode_palette.dart';
@@ -172,10 +174,8 @@ class _VoiceTranscriptState extends ConsumerState<VoiceTranscript> {
174
false,
175
);
176
case VoiceModePhase.error:
175
- final errorText = widget.error ?? '';
176
- final isSpeechError = errorText.toLowerCase().contains('speech');
177
return (
178
- isSpeechError ? 'NO SPEECH DETECTED' : 'ERROR',
178
+ isNoSpeechSttError(widget.error) ? 'NO SPEECH DETECTED' : 'ERROR',
179
VoiceModePalette.accentFor(VoiceModePhase.error, isDark: isDark),
180
false,
181
);
@@ -283,7 +283,7 @@ class _VoiceTranscriptState extends ConsumerState<VoiceTranscript> {
283
284
case VoiceModePhase.error:
285
final errorText = (widget.error != null && widget.error!.isNotEmpty)
286
- ? widget.error!
286
+ ? sttErrorMessage(AppLocalizations.of(context), widget.error!)
287
: 'No speech recognized. Tap to try again.';
288
return Text(
289
errorText,
lib/l10n/app_ar.arb
+11
-1
@@ -936,5 +936,15 @@
936
"model_reasoning_on": "تشغيل",
937
"model_reasoning_help": "يُطبّق على الرد التالي. يؤدي الإيقاف إلى تعطيل التفكير إذا كان قالب المحادثة الخاص بالنموذج يدعم ذلك.",
938
"model_reasoning_save_error": "تعذّر حفظ وضع التفكير. يُرجى المحاولة مرة أخرى.",
939
- "on_device_engine_failed_error": "توقف النموذج على الجهاز عن الاستجابة، غالبًا لأن المحادثة تجاوزت نافذة السياق. تتم إعادة تحميل النموذج. حاول مرة أخرى، أو ابدأ محادثة جديدة، أو زد طول السياق من الإعدادات."
939
+ "on_device_engine_failed_error": "توقف النموذج على الجهاز عن الاستجابة، غالبًا لأن المحادثة تجاوزت نافذة السياق. تتم إعادة تحميل النموذج. حاول مرة أخرى، أو ابدأ محادثة جديدة، أو زد طول السياق من الإعدادات.",
940
+ "stt_error_no_match": "لم يتم التعرف على أي كلام. اضغط للمحاولة مرة أخرى.",
941
+ "stt_error_speech_timeout": "لم يتم اكتشاف أي كلام. اضغط للمحاولة مرة أخرى.",
942
+ "stt_error_permission": "تم رفض إذن الميكروفون.",
943
+ "stt_error_busy": "التعرف على الكلام مشغول. يرجى المحاولة مرة أخرى.",
944
+ "stt_error_network": "خطأ في الشبكة. تحقق من اتصالك وحاول مرة أخرى.",
945
+ "stt_error_audio": "خطأ في تسجيل الصوت. يرجى التحقق من الميكروفون.",
946
+ "stt_error_client": "تعذر بدء خدمة التعرف على الكلام. تأكد من تثبيت تطبيق إدخال صوتي وتعيينه كأداة التعرف على الكلام الافتراضية، ثم حاول مرة أخرى.",
947
+ "stt_error_language": "أداة التعرف على الكلام على هذا الجهاز لا تدعم لغتك.",
948
+ "stt_error_unavailable": "لم يتم العثور على خدمة للتعرف على الكلام على هذا الجهاز. ثبّت تطبيق إدخال صوتي (مثل FUTO Voice Input) وعيّنه كأداة التعرف على الكلام الافتراضية.",
949
+ "stt_error_generic": "خطأ في التعرف على الكلام: {code}"
950
}
lib/l10n/app_bn.arb
+11
-1
@@ -932,5 +932,15 @@
932
"model_reasoning_on": "চালু",
933
"model_reasoning_help": "পরবর্তী উত্তরে প্রযোজ্য হবে। মডেলের চ্যাট টেমপ্লেট সমর্থন করলে বন্ধ করলে চিন্তন বন্ধ হবে।",
934
"model_reasoning_save_error": "চিন্তন মোড সংরক্ষণ করা যায়নি। আবার চেষ্টা করুন।",
935
- "on_device_engine_failed_error": "অন-ডিভাইস মডেলটি সাড়া দেওয়া বন্ধ করেছে, সাধারণত কথোপকথন কনটেক্সট উইন্ডোর চেয়ে বড় হয়ে যাওয়ায়। মডেলটি আবার লোড হচ্ছে। আবার চেষ্টা করুন, নতুন চ্যাট শুরু করুন, অথবা সেটিংসে কনটেক্সট দৈর্ঘ্য বাড়ান।"
935
+ "on_device_engine_failed_error": "অন-ডিভাইস মডেলটি সাড়া দেওয়া বন্ধ করেছে, সাধারণত কথোপকথন কনটেক্সট উইন্ডোর চেয়ে বড় হয়ে যাওয়ায়। মডেলটি আবার লোড হচ্ছে। আবার চেষ্টা করুন, নতুন চ্যাট শুরু করুন, অথবা সেটিংসে কনটেক্সট দৈর্ঘ্য বাড়ান।",
936
+ "stt_error_no_match": "কোনো কথা শনাক্ত হয়নি। আবার চেষ্টা করতে ট্যাপ করুন।",
937
+ "stt_error_speech_timeout": "কোনো কথা পাওয়া যায়নি। আবার চেষ্টা করতে ট্যাপ করুন।",
938
+ "stt_error_permission": "মাইক্রোফোনের অনুমতি প্রত্যাখ্যাত হয়েছে।",
939
+ "stt_error_busy": "স্পিচ রিকগনিশন ব্যস্ত। আবার চেষ্টা করুন।",
940
+ "stt_error_network": "নেটওয়ার্ক ত্রুটি। সংযোগ পরীক্ষা করে আবার চেষ্টা করুন।",
941
+ "stt_error_audio": "অডিও রেকর্ডিং ত্রুটি। মাইক্রোফোন পরীক্ষা করুন।",
942
+ "stt_error_client": "স্পিচ রিকগনিশন সার্ভিস চালু হয়নি। একটি ভয়েস ইনপুট অ্যাপ ইনস্টল করে ডিফল্ট স্পিচ রিকগনাইজার হিসেবে সেট করুন, তারপর আবার চেষ্টা করুন।",
943
+ "stt_error_language": "এই ডিভাইসের স্পিচ রিকগনাইজার আপনার ভাষা সমর্থন করে না।",
944
+ "stt_error_unavailable": "এই ডিভাইসে কোনো স্পিচ রিকগনিশন সার্ভিস পাওয়া যায়নি। একটি ভয়েস ইনপুট অ্যাপ (যেমন FUTO Voice Input) ইনস্টল করে ডিফল্ট স্পিচ রিকগনাইজার হিসেবে সেট করুন।",
945
+ "stt_error_generic": "স্পিচ রিকগনিশন ত্রুটি: {code}"
946
}
lib/l10n/app_de.arb
+11
-1
@@ -929,5 +929,15 @@
929
"model_reasoning_on": "Ein",
930
"model_reasoning_help": "Gilt für die nächste Antwort. Aus deaktiviert das Denken, sofern die Chatvorlage des Modells dies unterstützt.",
931
"model_reasoning_save_error": "Denkmodus konnte nicht gespeichert werden. Bitte erneut versuchen.",
932
- "on_device_engine_failed_error": "Das On-Device-Modell reagiert nicht mehr, meist weil die Unterhaltung das Kontextfenster überschritten hat. Das Modell wird neu geladen. Versuche es erneut, starte einen neuen Chat oder erhöhe die Kontextlänge in den Einstellungen."
932
+ "on_device_engine_failed_error": "Das On-Device-Modell reagiert nicht mehr, meist weil die Unterhaltung das Kontextfenster überschritten hat. Das Modell wird neu geladen. Versuche es erneut, starte einen neuen Chat oder erhöhe die Kontextlänge in den Einstellungen.",
933
+ "stt_error_no_match": "Keine Sprache erkannt. Tippe, um es erneut zu versuchen.",
934
+ "stt_error_speech_timeout": "Keine Sprache erkannt. Tippe, um es erneut zu versuchen.",
935
+ "stt_error_permission": "Mikrofonberechtigung verweigert.",
936
+ "stt_error_busy": "Die Spracherkennung ist beschäftigt. Bitte versuche es erneut.",
937
+ "stt_error_network": "Netzwerkfehler. Bitte prüfe deine Verbindung und versuche es erneut.",
938
+ "stt_error_audio": "Fehler bei der Audioaufnahme. Bitte prüfe dein Mikrofon.",
939
+ "stt_error_client": "Der Spracherkennungsdienst konnte nicht gestartet werden. Stelle sicher, dass eine Spracheingabe-App installiert und als Standard-Spracherkennung festgelegt ist, und versuche es erneut.",
940
+ "stt_error_language": "Die Spracherkennung auf diesem Gerät unterstützt deine Sprache nicht.",
941
+ "stt_error_unavailable": "Auf diesem Gerät wurde kein Spracherkennungsdienst gefunden. Installiere eine Spracheingabe-App (zum Beispiel FUTO Voice Input) und lege sie als Standard-Spracherkennung fest.",
942
+ "stt_error_generic": "Fehler bei der Spracherkennung: {code}"
943
}
lib/l10n/app_en.arb
+12
-1
@@ -3452,5 +3452,16 @@
3452
"model_reasoning_on": "On",
3453
"model_reasoning_help": "Applies to the next response. Off disables thinking when supported by the model’s chat template.",
3454
"model_reasoning_save_error": "Could not save thinking mode. Please try again.",
3455
- "on_device_engine_failed_error": "The on-device model stopped responding, usually because the conversation grew past its context window. The model is being reloaded. Try again, start a new chat, or increase the context length in settings."
3455
+ "on_device_engine_failed_error": "The on-device model stopped responding, usually because the conversation grew past its context window. The model is being reloaded. Try again, start a new chat, or increase the context length in settings.",
3456
+ "stt_error_no_match": "No speech recognized. Tap to try again.",
3457
+ "stt_error_speech_timeout": "No speech detected. Tap to try again.",
3458
+ "stt_error_permission": "Microphone permission denied.",
3459
+ "stt_error_busy": "Speech recognition is busy. Please try again.",
3460
+ "stt_error_network": "Network error. Please check your connection and try again.",
3461
+ "stt_error_audio": "Audio recording error. Please check your microphone.",
3462
+ "stt_error_client": "The speech recognition service failed to start. Make sure a voice input app is installed and set as the default speech recognizer, then try again.",
3463
+ "stt_error_language": "The speech recognizer on this device doesn't support your language.",
3464
+ "stt_error_unavailable": "No speech recognition service found on this device. Install a voice input app (for example FUTO Voice Input) and set it as the default speech recognizer.",
3465
+ "stt_error_generic": "Speech recognition error: {code}",
3466
+ "@stt_error_generic": {"description": "Fallback speech recognition error with the platform error name", "placeholders": {"code": {"type": "String"}}}
3467
}
lib/l10n/app_es.arb
+11
-1
@@ -932,5 +932,15 @@
932
"model_reasoning_on": "Activado",
933
"model_reasoning_help": "Se aplica a la siguiente respuesta. Desactivado impide el razonamiento si la plantilla de chat del modelo lo permite.",
934
"model_reasoning_save_error": "No se pudo guardar el modo de razonamiento. Inténtalo de nuevo.",
935
- "on_device_engine_failed_error": "El modelo en el dispositivo dejó de responder, normalmente porque la conversación superó su ventana de contexto. El modelo se está recargando. Inténtalo de nuevo, inicia un chat nuevo o aumenta la longitud de contexto en los ajustes."
935
+ "on_device_engine_failed_error": "El modelo en el dispositivo dejó de responder, normalmente porque la conversación superó su ventana de contexto. El modelo se está recargando. Inténtalo de nuevo, inicia un chat nuevo o aumenta la longitud de contexto en los ajustes.",
936
+ "stt_error_no_match": "No se reconoció ninguna voz. Toca para intentarlo de nuevo.",
937
+ "stt_error_speech_timeout": "No se detectó voz. Toca para intentarlo de nuevo.",
938
+ "stt_error_permission": "Permiso de micrófono denegado.",
939
+ "stt_error_busy": "El reconocimiento de voz está ocupado. Inténtalo de nuevo.",
940
+ "stt_error_network": "Error de red. Comprueba tu conexión e inténtalo de nuevo.",
941
+ "stt_error_audio": "Error de grabación de audio. Revisa tu micrófono.",
942
+ "stt_error_client": "No se pudo iniciar el servicio de reconocimiento de voz. Asegúrate de tener instalada una app de entrada de voz configurada como reconocedor predeterminado e inténtalo de nuevo.",
943
+ "stt_error_language": "El reconocedor de voz de este dispositivo no admite tu idioma.",
944
+ "stt_error_unavailable": "No se encontró ningún servicio de reconocimiento de voz en este dispositivo. Instala una app de entrada de voz (por ejemplo FUTO Voice Input) y configúrala como reconocedor predeterminado.",
945
+ "stt_error_generic": "Error de reconocimiento de voz: {code}"
946
}
lib/l10n/app_fr.arb
+11
-1
@@ -929,5 +929,15 @@
929
"model_reasoning_on": "Activé",
930
"model_reasoning_help": "S’applique à la prochaine réponse. Désactivé coupe le raisonnement si le modèle de conversation le permet.",
931
"model_reasoning_save_error": "Impossible d’enregistrer le mode de réflexion. Veuillez réessayer.",
932
- "on_device_engine_failed_error": "Le modèle sur l'appareil ne répond plus, généralement parce que la conversation a dépassé sa fenêtre de contexte. Le modèle est en cours de rechargement. Réessayez, démarrez une nouvelle discussion ou augmentez la longueur du contexte dans les paramètres."
932
+ "on_device_engine_failed_error": "Le modèle sur l'appareil ne répond plus, généralement parce que la conversation a dépassé sa fenêtre de contexte. Le modèle est en cours de rechargement. Réessayez, démarrez une nouvelle discussion ou augmentez la longueur du contexte dans les paramètres.",
933
+ "stt_error_no_match": "Aucune parole reconnue. Touchez pour réessayer.",
934
+ "stt_error_speech_timeout": "Aucune parole détectée. Touchez pour réessayer.",
935
+ "stt_error_permission": "Autorisation du micro refusée.",
936
+ "stt_error_busy": "La reconnaissance vocale est occupée. Veuillez réessayer.",
937
+ "stt_error_network": "Erreur réseau. Vérifiez votre connexion et réessayez.",
938
+ "stt_error_audio": "Erreur d'enregistrement audio. Vérifiez votre micro.",
939
+ "stt_error_client": "Le service de reconnaissance vocale n'a pas pu démarrer. Vérifiez qu'une application de saisie vocale est installée et définie comme reconnaissance vocale par défaut, puis réessayez.",
940
+ "stt_error_language": "La reconnaissance vocale de cet appareil ne prend pas en charge votre langue.",
941
+ "stt_error_unavailable": "Aucun service de reconnaissance vocale trouvé sur cet appareil. Installez une application de saisie vocale (par exemple FUTO Voice Input) et définissez-la comme reconnaissance vocale par défaut.",
942
+ "stt_error_generic": "Erreur de reconnaissance vocale : {code}"
943
}
lib/l10n/app_hi.arb
+11
-1
@@ -932,5 +932,15 @@
932
"model_reasoning_on": "चालू",
933
"model_reasoning_help": "अगले उत्तर पर लागू होगा। बंद करने से चिंतन अक्षम होगा, यदि मॉडल का चैट टेम्पलेट इसका समर्थन करता है।",
934
"model_reasoning_save_error": "चिंतन मोड सहेजा नहीं जा सका। फिर से कोशिश करें।",
935
- "on_device_engine_failed_error": "ऑन-डिवाइस मॉडल ने जवाब देना बंद कर दिया, आमतौर पर इसलिए कि बातचीत उसकी कॉन्टेक्स्ट विंडो से बड़ी हो गई। मॉडल फिर से लोड हो रहा है। फिर से कोशिश करें, नई चैट शुरू करें, या सेटिंग्स में कॉन्टेक्स्ट लंबाई बढ़ाएँ।"
935
+ "on_device_engine_failed_error": "ऑन-डिवाइस मॉडल ने जवाब देना बंद कर दिया, आमतौर पर इसलिए कि बातचीत उसकी कॉन्टेक्स्ट विंडो से बड़ी हो गई। मॉडल फिर से लोड हो रहा है। फिर से कोशिश करें, नई चैट शुरू करें, या सेटिंग्स में कॉन्टेक्स्ट लंबाई बढ़ाएँ।",
936
+ "stt_error_no_match": "कोई आवाज़ पहचानी नहीं गई। फिर से कोशिश करने के लिए टैप करें।",
937
+ "stt_error_speech_timeout": "कोई आवाज़ नहीं मिली। फिर से कोशिश करने के लिए टैप करें।",
938
+ "stt_error_permission": "माइक्रोफ़ोन की अनुमति अस्वीकार की गई।",
939
+ "stt_error_busy": "वॉइस पहचान व्यस्त है। कृपया फिर से कोशिश करें।",
940
+ "stt_error_network": "नेटवर्क त्रुटि। कृपया अपना कनेक्शन जाँचें और फिर से कोशिश करें।",
941
+ "stt_error_audio": "ऑडियो रिकॉर्डिंग त्रुटि। कृपया अपना माइक्रोफ़ोन जाँचें।",
942
+ "stt_error_client": "वॉइस पहचान सेवा शुरू नहीं हो सकी। सुनिश्चित करें कि कोई वॉइस इनपुट ऐप इंस्टॉल है और डिफ़ॉल्ट स्पीच रिकग्नाइज़र के रूप में सेट है, फिर कोशिश करें।",
943
+ "stt_error_language": "इस डिवाइस का स्पीच रिकग्नाइज़र आपकी भाषा का समर्थन नहीं करता।",
944
+ "stt_error_unavailable": "इस डिवाइस पर कोई वॉइस पहचान सेवा नहीं मिली। कोई वॉइस इनपुट ऐप (जैसे FUTO Voice Input) इंस्टॉल करें और उसे डिफ़ॉल्ट स्पीच रिकग्नाइज़र के रूप में सेट करें।",
945
+ "stt_error_generic": "वॉइस पहचान त्रुटि: {code}"
946
}
lib/l10n/app_it.arb
+11
-1
@@ -932,5 +932,15 @@
932
"model_reasoning_on": "Attivo",
933
"model_reasoning_help": "Si applica alla prossima risposta. Disattivato impedisce il ragionamento se il template di chat del modello lo supporta.",
934
"model_reasoning_save_error": "Impossibile salvare la modalità di ragionamento. Riprova.",
935
- "on_device_engine_failed_error": "Il modello sul dispositivo ha smesso di rispondere, di solito perché la conversazione ha superato la finestra di contesto. Il modello viene ricaricato. Riprova, avvia una nuova chat o aumenta la lunghezza del contesto nelle impostazioni."
935
+ "on_device_engine_failed_error": "Il modello sul dispositivo ha smesso di rispondere, di solito perché la conversazione ha superato la finestra di contesto. Il modello viene ricaricato. Riprova, avvia una nuova chat o aumenta la lunghezza del contesto nelle impostazioni.",
936
+ "stt_error_no_match": "Nessun parlato riconosciuto. Tocca per riprovare.",
937
+ "stt_error_speech_timeout": "Nessun parlato rilevato. Tocca per riprovare.",
938
+ "stt_error_permission": "Autorizzazione al microfono negata.",
939
+ "stt_error_busy": "Il riconoscimento vocale è occupato. Riprova.",
940
+ "stt_error_network": "Errore di rete. Controlla la connessione e riprova.",
941
+ "stt_error_audio": "Errore di registrazione audio. Controlla il microfono.",
942
+ "stt_error_client": "Impossibile avviare il servizio di riconoscimento vocale. Assicurati che un'app di input vocale sia installata e impostata come riconoscimento vocale predefinito, poi riprova.",
943
+ "stt_error_language": "Il riconoscimento vocale di questo dispositivo non supporta la tua lingua.",
944
+ "stt_error_unavailable": "Nessun servizio di riconoscimento vocale trovato su questo dispositivo. Installa un'app di input vocale (ad esempio FUTO Voice Input) e impostala come riconoscimento vocale predefinito.",
945
+ "stt_error_generic": "Errore di riconoscimento vocale: {code}"
946
}
lib/l10n/app_ja.arb
+11
-1
@@ -932,5 +932,15 @@
932
"model_reasoning_on": "オン",
933
"model_reasoning_help": "次の応答に適用されます。モデルのチャットテンプレートが対応している場合、オフにすると思考を無効にします。",
934
"model_reasoning_save_error": "思考モードを保存できませんでした。もう一度お試しください。",
935
- "on_device_engine_failed_error": "オンデバイスモデルが応答しなくなりました。通常、会話がコンテキストウィンドウを超えたことが原因です。モデルを再読み込みしています。もう一度試すか、新しいチャットを開始するか、設定でコンテキスト長を増やしてください。"
935
+ "on_device_engine_failed_error": "オンデバイスモデルが応答しなくなりました。通常、会話がコンテキストウィンドウを超えたことが原因です。モデルを再読み込みしています。もう一度試すか、新しいチャットを開始するか、設定でコンテキスト長を増やしてください。",
936
+ "stt_error_no_match": "音声を認識できませんでした。タップしてもう一度お試しください。",
937
+ "stt_error_speech_timeout": "音声が検出されませんでした。タップしてもう一度お試しください。",
938
+ "stt_error_permission": "マイクへのアクセスが拒否されました。",
939
+ "stt_error_busy": "音声認識が使用中です。もう一度お試しください。",
940
+ "stt_error_network": "ネットワークエラーです。接続を確認してもう一度お試しください。",
941
+ "stt_error_audio": "録音エラーです。マイクを確認してください。",
942
+ "stt_error_client": "音声認識サービスを開始できませんでした。音声入力アプリがインストールされ、既定の音声認識に設定されていることを確認して、もう一度お試しください。",
943
+ "stt_error_language": "このデバイスの音声認識はお使いの言語に対応していません。",
944
+ "stt_error_unavailable": "このデバイスに音声認識サービスが見つかりません。音声入力アプリ(例: FUTO Voice Input)をインストールし、既定の音声認識に設定してください。",
945
+ "stt_error_generic": "音声認識エラー: {code}"
946
}
lib/l10n/app_ko.arb
+11
-1
@@ -943,5 +943,15 @@
943
"model_reasoning_on": "켜짐",
944
"model_reasoning_help": "다음 응답에 적용됩니다. 모델의 채팅 템플릿이 지원하는 경우 끄면 사고가 비활성화됩니다.",
945
"model_reasoning_save_error": "사고 모드를 저장하지 못했습니다. 다시 시도해 주세요.",
946
- "on_device_engine_failed_error": "온디바이스 모델이 응답을 멈췄습니다. 대개 대화가 컨텍스트 창을 초과했기 때문입니다. 모델을 다시 불러오는 중입니다. 다시 시도하거나 새 채팅을 시작하거나 설정에서 컨텍스트 길이를 늘리세요."
946
+ "on_device_engine_failed_error": "온디바이스 모델이 응답을 멈췄습니다. 대개 대화가 컨텍스트 창을 초과했기 때문입니다. 모델을 다시 불러오는 중입니다. 다시 시도하거나 새 채팅을 시작하거나 설정에서 컨텍스트 길이를 늘리세요.",
947
+ "stt_error_no_match": "음성을 인식하지 못했습니다. 다시 시도하려면 탭하세요.",
948
+ "stt_error_speech_timeout": "음성이 감지되지 않았습니다. 다시 시도하려면 탭하세요.",
949
+ "stt_error_permission": "마이크 권한이 거부되었습니다.",
950
+ "stt_error_busy": "음성 인식이 사용 중입니다. 다시 시도하세요.",
951
+ "stt_error_network": "네트워크 오류입니다. 연결을 확인하고 다시 시도하세요.",
952
+ "stt_error_audio": "오디오 녹음 오류입니다. 마이크를 확인하세요.",
953
+ "stt_error_client": "음성 인식 서비스를 시작하지 못했습니다. 음성 입력 앱이 설치되어 있고 기본 음성 인식기로 설정되어 있는지 확인한 후 다시 시도하세요.",
954
+ "stt_error_language": "이 기기의 음성 인식기가 사용자의 언어를 지원하지 않습니다.",
955
+ "stt_error_unavailable": "이 기기에서 음성 인식 서비스를 찾을 수 없습니다. 음성 입력 앱(예: FUTO Voice Input)을 설치하고 기본 음성 인식기로 설정하세요.",
956
+ "stt_error_generic": "음성 인식 오류: {code}"
957
}
lib/l10n/app_localizations.dart
+60
@@ -5852,6 +5852,66 @@ abstract class AppLocalizations {
5852
/// In en, this message translates to:
5853
/// **'The on-device model stopped responding, usually because the conversation grew past its context window. The model is being reloaded. Try again, start a new chat, or increase the context length in settings.'**
5854
String get on_device_engine_failed_error;
5855
+
5856
+ /// No description provided for @stt_error_no_match.
5857
+ ///
5858
+ /// In en, this message translates to:
5859
+ /// **'No speech recognized. Tap to try again.'**
5860
+ String get stt_error_no_match;
5861
+
5862
+ /// No description provided for @stt_error_speech_timeout.
5863
+ ///
5864
+ /// In en, this message translates to:
5865
+ /// **'No speech detected. Tap to try again.'**
5866
+ String get stt_error_speech_timeout;
5867
+
5868
+ /// No description provided for @stt_error_permission.
5869
+ ///
5870
+ /// In en, this message translates to:
5871
+ /// **'Microphone permission denied.'**
5872
+ String get stt_error_permission;
5873
+
5874
+ /// No description provided for @stt_error_busy.
5875
+ ///
5876
+ /// In en, this message translates to:
5877
+ /// **'Speech recognition is busy. Please try again.'**
5878
+ String get stt_error_busy;
5879
+
5880
+ /// No description provided for @stt_error_network.
5881
+ ///
5882
+ /// In en, this message translates to:
5883
+ /// **'Network error. Please check your connection and try again.'**
5884
+ String get stt_error_network;
5885
+
5886
+ /// No description provided for @stt_error_audio.
5887
+ ///
5888
+ /// In en, this message translates to:
5889
+ /// **'Audio recording error. Please check your microphone.'**
5890
+ String get stt_error_audio;
5891
+
5892
+ /// No description provided for @stt_error_client.
5893
+ ///
5894
+ /// In en, this message translates to:
5895
+ /// **'The speech recognition service failed to start. Make sure a voice input app is installed and set as the default speech recognizer, then try again.'**
5896
+ String get stt_error_client;
5897
+
5898
+ /// No description provided for @stt_error_language.
5899
+ ///
5900
+ /// In en, this message translates to:
5901
+ /// **'The speech recognizer on this device doesn\'t support your language.'**
5902
+ String get stt_error_language;
5903
+
5904
+ /// No description provided for @stt_error_unavailable.
5905
+ ///
5906
+ /// In en, this message translates to:
5907
+ /// **'No speech recognition service found on this device. Install a voice input app (for example FUTO Voice Input) and set it as the default speech recognizer.'**
5908
+ String get stt_error_unavailable;
5909
+
5910
+ /// Fallback speech recognition error with the platform error name
5911
+ ///
5912
+ /// In en, this message translates to:
5913
+ /// **'Speech recognition error: {code}'**
5914
+ String stt_error_generic(String code);
5915
}
5916
5917
class _AppLocalizationsDelegate
lib/l10n/app_localizations_ar.dart
+40
@@ -3138,4 +3138,44 @@ class AppLocalizationsAr extends AppLocalizations {
3138
@override
3139
String get on_device_engine_failed_error =>
3140
'توقف النموذج على الجهاز عن الاستجابة، غالبًا لأن المحادثة تجاوزت نافذة السياق. تتم إعادة تحميل النموذج. حاول مرة أخرى، أو ابدأ محادثة جديدة، أو زد طول السياق من الإعدادات.';
3141
+
3142
+ @override
3143
+ String get stt_error_no_match =>
3144
+ 'لم يتم التعرف على أي كلام. اضغط للمحاولة مرة أخرى.';
3145
+
3146
+ @override
3147
+ String get stt_error_speech_timeout =>
3148
+ 'لم يتم اكتشاف أي كلام. اضغط للمحاولة مرة أخرى.';
3149
+
3150
+ @override
3151
+ String get stt_error_permission => 'تم رفض إذن الميكروفون.';
3152
+
3153
+ @override
3154
+ String get stt_error_busy =>
3155
+ 'التعرف على الكلام مشغول. يرجى المحاولة مرة أخرى.';
3156
+
3157
+ @override
3158
+ String get stt_error_network =>
3159
+ 'خطأ في الشبكة. تحقق من اتصالك وحاول مرة أخرى.';
3160
+
3161
+ @override
3162
+ String get stt_error_audio =>
3163
+ 'خطأ في تسجيل الصوت. يرجى التحقق من الميكروفون.';
3164
+
3165
+ @override
3166
+ String get stt_error_client =>
3167
+ 'تعذر بدء خدمة التعرف على الكلام. تأكد من تثبيت تطبيق إدخال صوتي وتعيينه كأداة التعرف على الكلام الافتراضية، ثم حاول مرة أخرى.';
3168
+
3169
+ @override
3170
+ String get stt_error_language =>
3171
+ 'أداة التعرف على الكلام على هذا الجهاز لا تدعم لغتك.';
3172
+
3173
+ @override
3174
+ String get stt_error_unavailable =>
3175
+ 'لم يتم العثور على خدمة للتعرف على الكلام على هذا الجهاز. ثبّت تطبيق إدخال صوتي (مثل FUTO Voice Input) وعيّنه كأداة التعرف على الكلام الافتراضية.';
3176
+
3177
+ @override
3178
+ String stt_error_generic(String code) {
3179
+ return 'خطأ في التعرف على الكلام: $code';
3180
+ }
3181
}
lib/l10n/app_localizations_bn.dart
+39
@@ -3164,4 +3164,43 @@ class AppLocalizationsBn extends AppLocalizations {
3164
@override
3165
String get on_device_engine_failed_error =>
3166
'অন-ডিভাইস মডেলটি সাড়া দেওয়া বন্ধ করেছে, সাধারণত কথোপকথন কনটেক্সট উইন্ডোর চেয়ে বড় হয়ে যাওয়ায়। মডেলটি আবার লোড হচ্ছে। আবার চেষ্টা করুন, নতুন চ্যাট শুরু করুন, অথবা সেটিংসে কনটেক্সট দৈর্ঘ্য বাড়ান।';
3167
+
3168
+ @override
3169
+ String get stt_error_no_match =>
3170
+ 'কোনো কথা শনাক্ত হয়নি। আবার চেষ্টা করতে ট্যাপ করুন।';
3171
+
3172
+ @override
3173
+ String get stt_error_speech_timeout =>
3174
+ 'কোনো কথা পাওয়া যায়নি। আবার চেষ্টা করতে ট্যাপ করুন।';
3175
+
3176
+ @override
3177
+ String get stt_error_permission => 'মাইক্রোফোনের অনুমতি প্রত্যাখ্যাত হয়েছে।';
3178
+
3179
+ @override
3180
+ String get stt_error_busy => 'স্পিচ রিকগনিশন ব্যস্ত। আবার চেষ্টা করুন।';
3181
+
3182
+ @override
3183
+ String get stt_error_network =>
3184
+ 'নেটওয়ার্ক ত্রুটি। সংযোগ পরীক্ষা করে আবার চেষ্টা করুন।';
3185
+
3186
+ @override
3187
+ String get stt_error_audio =>
3188
+ 'অডিও রেকর্ডিং ত্রুটি। মাইক্রোফোন পরীক্ষা করুন।';
3189
+
3190
+ @override
3191
+ String get stt_error_client =>
3192
+ 'স্পিচ রিকগনিশন সার্ভিস চালু হয়নি। একটি ভয়েস ইনপুট অ্যাপ ইনস্টল করে ডিফল্ট স্পিচ রিকগনাইজার হিসেবে সেট করুন, তারপর আবার চেষ্টা করুন।';
3193
+
3194
+ @override
3195
+ String get stt_error_language =>
3196
+ 'এই ডিভাইসের স্পিচ রিকগনাইজার আপনার ভাষা সমর্থন করে না।';
3197
+
3198
+ @override
3199
+ String get stt_error_unavailable =>
3200
+ 'এই ডিভাইসে কোনো স্পিচ রিকগনিশন সার্ভিস পাওয়া যায়নি। একটি ভয়েস ইনপুট অ্যাপ (যেমন FUTO Voice Input) ইনস্টল করে ডিফল্ট স্পিচ রিকগনাইজার হিসেবে সেট করুন।';
3201
+
3202
+ @override
3203
+ String stt_error_generic(String code) {
3204
+ return 'স্পিচ রিকগনিশন ত্রুটি: $code';
3205
+ }
3206
}
lib/l10n/app_localizations_de.dart
+40
@@ -3153,4 +3153,44 @@ class AppLocalizationsDe extends AppLocalizations {
3153
@override
3154
String get on_device_engine_failed_error =>
3155
'Das On-Device-Modell reagiert nicht mehr, meist weil die Unterhaltung das Kontextfenster überschritten hat. Das Modell wird neu geladen. Versuche es erneut, starte einen neuen Chat oder erhöhe die Kontextlänge in den Einstellungen.';
3156
+
3157
+ @override
3158
+ String get stt_error_no_match =>
3159
+ 'Keine Sprache erkannt. Tippe, um es erneut zu versuchen.';
3160
+
3161
+ @override
3162
+ String get stt_error_speech_timeout =>
3163
+ 'Keine Sprache erkannt. Tippe, um es erneut zu versuchen.';
3164
+
3165
+ @override
3166
+ String get stt_error_permission => 'Mikrofonberechtigung verweigert.';
3167
+
3168
+ @override
3169
+ String get stt_error_busy =>
3170
+ 'Die Spracherkennung ist beschäftigt. Bitte versuche es erneut.';
3171
+
3172
+ @override
3173
+ String get stt_error_network =>
3174
+ 'Netzwerkfehler. Bitte prüfe deine Verbindung und versuche es erneut.';
3175
+
3176
+ @override
3177
+ String get stt_error_audio =>
3178
+ 'Fehler bei der Audioaufnahme. Bitte prüfe dein Mikrofon.';
3179
+
3180
+ @override
3181
+ String get stt_error_client =>
3182
+ 'Der Spracherkennungsdienst konnte nicht gestartet werden. Stelle sicher, dass eine Spracheingabe-App installiert und als Standard-Spracherkennung festgelegt ist, und versuche es erneut.';
3183
+
3184
+ @override
3185
+ String get stt_error_language =>
3186
+ 'Die Spracherkennung auf diesem Gerät unterstützt deine Sprache nicht.';
3187
+
3188
+ @override
3189
+ String get stt_error_unavailable =>
3190
+ 'Auf diesem Gerät wurde kein Spracherkennungsdienst gefunden. Installiere eine Spracheingabe-App (zum Beispiel FUTO Voice Input) und lege sie als Standard-Spracherkennung fest.';
3191
+
3192
+ @override
3193
+ String stt_error_generic(String code) {
3194
+ return 'Fehler bei der Spracherkennung: $code';
3195
+ }
3196
}
lib/l10n/app_localizations_en.dart
+38
@@ -3143,4 +3143,42 @@ class AppLocalizationsEn extends AppLocalizations {
3143
@override
3144
String get on_device_engine_failed_error =>
3145
'The on-device model stopped responding, usually because the conversation grew past its context window. The model is being reloaded. Try again, start a new chat, or increase the context length in settings.';
3146
+
3147
+ @override
3148
+ String get stt_error_no_match => 'No speech recognized. Tap to try again.';
3149
+
3150
+ @override
3151
+ String get stt_error_speech_timeout =>
3152
+ 'No speech detected. Tap to try again.';
3153
+
3154
+ @override
3155
+ String get stt_error_permission => 'Microphone permission denied.';
3156
+
3157
+ @override
3158
+ String get stt_error_busy => 'Speech recognition is busy. Please try again.';
3159
+
3160
+ @override
3161
+ String get stt_error_network =>
3162
+ 'Network error. Please check your connection and try again.';
3163
+
3164
+ @override
3165
+ String get stt_error_audio =>
3166
+ 'Audio recording error. Please check your microphone.';
3167
+
3168
+ @override
3169
+ String get stt_error_client =>
3170
+ 'The speech recognition service failed to start. Make sure a voice input app is installed and set as the default speech recognizer, then try again.';
3171
+
3172
+ @override
3173
+ String get stt_error_language =>
3174
+ 'The speech recognizer on this device doesn\'t support your language.';
3175
+
3176
+ @override
3177
+ String get stt_error_unavailable =>
3178
+ 'No speech recognition service found on this device. Install a voice input app (for example FUTO Voice Input) and set it as the default speech recognizer.';
3179
+
3180
+ @override
3181
+ String stt_error_generic(String code) {
3182
+ return 'Speech recognition error: $code';
3183
+ }
3184
}
lib/l10n/app_localizations_es.dart
+40
@@ -3167,4 +3167,44 @@ class AppLocalizationsEs extends AppLocalizations {
3167
@override
3168
String get on_device_engine_failed_error =>
3169
'El modelo en el dispositivo dejó de responder, normalmente porque la conversación superó su ventana de contexto. El modelo se está recargando. Inténtalo de nuevo, inicia un chat nuevo o aumenta la longitud de contexto en los ajustes.';
3170
+
3171
+ @override
3172
+ String get stt_error_no_match =>
3173
+ 'No se reconoció ninguna voz. Toca para intentarlo de nuevo.';
3174
+
3175
+ @override
3176
+ String get stt_error_speech_timeout =>
3177
+ 'No se detectó voz. Toca para intentarlo de nuevo.';
3178
+
3179
+ @override
3180
+ String get stt_error_permission => 'Permiso de micrófono denegado.';
3181
+
3182
+ @override
3183
+ String get stt_error_busy =>
3184
+ 'El reconocimiento de voz está ocupado. Inténtalo de nuevo.';
3185
+
3186
+ @override
3187
+ String get stt_error_network =>
3188
+ 'Error de red. Comprueba tu conexión e inténtalo de nuevo.';
3189
+
3190
+ @override
3191
+ String get stt_error_audio =>
3192
+ 'Error de grabación de audio. Revisa tu micrófono.';
3193
+
3194
+ @override
3195
+ String get stt_error_client =>
3196
+ 'No se pudo iniciar el servicio de reconocimiento de voz. Asegúrate de tener instalada una app de entrada de voz configurada como reconocedor predeterminado e inténtalo de nuevo.';
3197
+
3198
+ @override
3199
+ String get stt_error_language =>
3200
+ 'El reconocedor de voz de este dispositivo no admite tu idioma.';
3201
+
3202
+ @override
3203
+ String get stt_error_unavailable =>
3204
+ 'No se encontró ningún servicio de reconocimiento de voz en este dispositivo. Instala una app de entrada de voz (por ejemplo FUTO Voice Input) y configúrala como reconocedor predeterminado.';
3205
+
3206
+ @override
3207
+ String stt_error_generic(String code) {
3208
+ return 'Error de reconocimiento de voz: $code';
3209
+ }
3210
}
lib/l10n/app_localizations_fr.dart
+40
@@ -3156,4 +3156,44 @@ class AppLocalizationsFr extends AppLocalizations {
3156
@override
3157
String get on_device_engine_failed_error =>
3158
'Le modèle sur l\'appareil ne répond plus, généralement parce que la conversation a dépassé sa fenêtre de contexte. Le modèle est en cours de rechargement. Réessayez, démarrez une nouvelle discussion ou augmentez la longueur du contexte dans les paramètres.';
3159
+
3160
+ @override
3161
+ String get stt_error_no_match =>
3162
+ 'Aucune parole reconnue. Touchez pour réessayer.';
3163
+
3164
+ @override
3165
+ String get stt_error_speech_timeout =>
3166
+ 'Aucune parole détectée. Touchez pour réessayer.';
3167
+
3168
+ @override
3169
+ String get stt_error_permission => 'Autorisation du micro refusée.';
3170
+
3171
+ @override
3172
+ String get stt_error_busy =>
3173
+ 'La reconnaissance vocale est occupée. Veuillez réessayer.';
3174
+
3175
+ @override
3176
+ String get stt_error_network =>
3177
+ 'Erreur réseau. Vérifiez votre connexion et réessayez.';
3178
+
3179
+ @override
3180
+ String get stt_error_audio =>
3181
+ 'Erreur d\'enregistrement audio. Vérifiez votre micro.';
3182
+
3183
+ @override
3184
+ String get stt_error_client =>
3185
+ 'Le service de reconnaissance vocale n\'a pas pu démarrer. Vérifiez qu\'une application de saisie vocale est installée et définie comme reconnaissance vocale par défaut, puis réessayez.';
3186
+
3187
+ @override
3188
+ String get stt_error_language =>
3189
+ 'La reconnaissance vocale de cet appareil ne prend pas en charge votre langue.';
3190
+
3191
+ @override
3192
+ String get stt_error_unavailable =>
3193
+ 'Aucun service de reconnaissance vocale trouvé sur cet appareil. Installez une application de saisie vocale (par exemple FUTO Voice Input) et définissez-la comme reconnaissance vocale par défaut.';
3194
+
3195
+ @override
3196
+ String stt_error_generic(String code) {
3197
+ return 'Erreur de reconnaissance vocale : $code';
3198
+ }
3199
}
lib/l10n/app_localizations_hi.dart
+39
@@ -3154,4 +3154,43 @@ class AppLocalizationsHi extends AppLocalizations {
3154
@override
3155
String get on_device_engine_failed_error =>
3156
'ऑन-डिवाइस मॉडल ने जवाब देना बंद कर दिया, आमतौर पर इसलिए कि बातचीत उसकी कॉन्टेक्स्ट विंडो से बड़ी हो गई। मॉडल फिर से लोड हो रहा है। फिर से कोशिश करें, नई चैट शुरू करें, या सेटिंग्स में कॉन्टेक्स्ट लंबाई बढ़ाएँ।';
3157
+
3158
+ @override
3159
+ String get stt_error_no_match =>
3160
+ 'कोई आवाज़ पहचानी नहीं गई। फिर से कोशिश करने के लिए टैप करें।';
3161
+
3162
+ @override
3163
+ String get stt_error_speech_timeout =>
3164
+ 'कोई आवाज़ नहीं मिली। फिर से कोशिश करने के लिए टैप करें।';
3165
+
3166
+ @override
3167
+ String get stt_error_permission => 'माइक्रोफ़ोन की अनुमति अस्वीकार की गई।';
3168
+
3169
+ @override
3170
+ String get stt_error_busy => 'वॉइस पहचान व्यस्त है। कृपया फिर से कोशिश करें।';
3171
+
3172
+ @override
3173
+ String get stt_error_network =>
3174
+ 'नेटवर्क त्रुटि। कृपया अपना कनेक्शन जाँचें और फिर से कोशिश करें।';
3175
+
3176
+ @override
3177
+ String get stt_error_audio =>
3178
+ 'ऑडियो रिकॉर्डिंग त्रुटि। कृपया अपना माइक्रोफ़ोन जाँचें।';
3179
+
3180
+ @override
3181
+ String get stt_error_client =>
3182
+ 'वॉइस पहचान सेवा शुरू नहीं हो सकी। सुनिश्चित करें कि कोई वॉइस इनपुट ऐप इंस्टॉल है और डिफ़ॉल्ट स्पीच रिकग्नाइज़र के रूप में सेट है, फिर कोशिश करें।';
3183
+
3184
+ @override
3185
+ String get stt_error_language =>
3186
+ 'इस डिवाइस का स्पीच रिकग्नाइज़र आपकी भाषा का समर्थन नहीं करता।';
3187
+
3188
+ @override
3189
+ String get stt_error_unavailable =>
3190
+ 'इस डिवाइस पर कोई वॉइस पहचान सेवा नहीं मिली। कोई वॉइस इनपुट ऐप (जैसे FUTO Voice Input) इंस्टॉल करें और उसे डिफ़ॉल्ट स्पीच रिकग्नाइज़र के रूप में सेट करें।';
3191
+
3192
+ @override
3193
+ String stt_error_generic(String code) {
3194
+ return 'वॉइस पहचान त्रुटि: $code';
3195
+ }
3196
}
lib/l10n/app_localizations_it.dart
+39
@@ -3170,4 +3170,43 @@ class AppLocalizationsIt extends AppLocalizations {
3170
@override
3171
String get on_device_engine_failed_error =>
3172
'Il modello sul dispositivo ha smesso di rispondere, di solito perché la conversazione ha superato la finestra di contesto. Il modello viene ricaricato. Riprova, avvia una nuova chat o aumenta la lunghezza del contesto nelle impostazioni.';
3173
+
3174
+ @override
3175
+ String get stt_error_no_match =>
3176
+ 'Nessun parlato riconosciuto. Tocca per riprovare.';
3177
+
3178
+ @override
3179
+ String get stt_error_speech_timeout =>
3180
+ 'Nessun parlato rilevato. Tocca per riprovare.';
3181
+
3182
+ @override
3183
+ String get stt_error_permission => 'Autorizzazione al microfono negata.';
3184
+
3185
+ @override
3186
+ String get stt_error_busy => 'Il riconoscimento vocale è occupato. Riprova.';
3187
+
3188
+ @override
3189
+ String get stt_error_network =>
3190
+ 'Errore di rete. Controlla la connessione e riprova.';
3191
+
3192
+ @override
3193
+ String get stt_error_audio =>
3194
+ 'Errore di registrazione audio. Controlla il microfono.';
3195
+
3196
+ @override
3197
+ String get stt_error_client =>
3198
+ 'Impossibile avviare il servizio di riconoscimento vocale. Assicurati che un\'app di input vocale sia installata e impostata come riconoscimento vocale predefinito, poi riprova.';
3199
+
3200
+ @override
3201
+ String get stt_error_language =>
3202
+ 'Il riconoscimento vocale di questo dispositivo non supporta la tua lingua.';
3203
+
3204
+ @override
3205
+ String get stt_error_unavailable =>
3206
+ 'Nessun servizio di riconoscimento vocale trovato su questo dispositivo. Installa un\'app di input vocale (ad esempio FUTO Voice Input) e impostala come riconoscimento vocale predefinito.';
3207
+
3208
+ @override
3209
+ String stt_error_generic(String code) {
3210
+ return 'Errore di riconoscimento vocale: $code';
3211
+ }
3212
}
lib/l10n/app_localizations_ja.dart
+34
@@ -3092,4 +3092,38 @@ class AppLocalizationsJa extends AppLocalizations {
3092
@override
3093
String get on_device_engine_failed_error =>
3094
'オンデバイスモデルが応答しなくなりました。通常、会話がコンテキストウィンドウを超えたことが原因です。モデルを再読み込みしています。もう一度試すか、新しいチャットを開始するか、設定でコンテキスト長を増やしてください。';
3095
+
3096
+ @override
3097
+ String get stt_error_no_match => '音声を認識できませんでした。タップしてもう一度お試しください。';
3098
+
3099
+ @override
3100
+ String get stt_error_speech_timeout => '音声が検出されませんでした。タップしてもう一度お試しください。';
3101
+
3102
+ @override
3103
+ String get stt_error_permission => 'マイクへのアクセスが拒否されました。';
3104
+
3105
+ @override
3106
+ String get stt_error_busy => '音声認識が使用中です。もう一度お試しください。';
3107
+
3108
+ @override
3109
+ String get stt_error_network => 'ネットワークエラーです。接続を確認してもう一度お試しください。';
3110
+
3111
+ @override
3112
+ String get stt_error_audio => '録音エラーです。マイクを確認してください。';
3113
+
3114
+ @override
3115
+ String get stt_error_client =>
3116
+ '音声認識サービスを開始できませんでした。音声入力アプリがインストールされ、既定の音声認識に設定されていることを確認して、もう一度お試しください。';
3117
+
3118
+ @override
3119
+ String get stt_error_language => 'このデバイスの音声認識はお使いの言語に対応していません。';
3120
+
3121
+ @override
3122
+ String get stt_error_unavailable =>
3123
+ 'このデバイスに音声認識サービスが見つかりません。音声入力アプリ(例: FUTO Voice Input)をインストールし、既定の音声認識に設定してください。';
3124
+
3125
+ @override
3126
+ String stt_error_generic(String code) {
3127
+ return '音声認識エラー: $code';
3128
+ }
3129
}
lib/l10n/app_localizations_ko.dart
+34
@@ -3075,4 +3075,38 @@ class AppLocalizationsKo extends AppLocalizations {
3075
@override
3076
String get on_device_engine_failed_error =>
3077
'온디바이스 모델이 응답을 멈췄습니다. 대개 대화가 컨텍스트 창을 초과했기 때문입니다. 모델을 다시 불러오는 중입니다. 다시 시도하거나 새 채팅을 시작하거나 설정에서 컨텍스트 길이를 늘리세요.';
3078
+
3079
+ @override
3080
+ String get stt_error_no_match => '음성을 인식하지 못했습니다. 다시 시도하려면 탭하세요.';
3081
+
3082
+ @override
3083
+ String get stt_error_speech_timeout => '음성이 감지되지 않았습니다. 다시 시도하려면 탭하세요.';
3084
+
3085
+ @override
3086
+ String get stt_error_permission => '마이크 권한이 거부되었습니다.';
3087
+
3088
+ @override
3089
+ String get stt_error_busy => '음성 인식이 사용 중입니다. 다시 시도하세요.';
3090
+
3091
+ @override
3092
+ String get stt_error_network => '네트워크 오류입니다. 연결을 확인하고 다시 시도하세요.';
3093
+
3094
+ @override
3095
+ String get stt_error_audio => '오디오 녹음 오류입니다. 마이크를 확인하세요.';
3096
+
3097
+ @override
3098
+ String get stt_error_client =>
3099
+ '음성 인식 서비스를 시작하지 못했습니다. 음성 입력 앱이 설치되어 있고 기본 음성 인식기로 설정되어 있는지 확인한 후 다시 시도하세요.';
3100
+
3101
+ @override
3102
+ String get stt_error_language => '이 기기의 음성 인식기가 사용자의 언어를 지원하지 않습니다.';
3103
+
3104
+ @override
3105
+ String get stt_error_unavailable =>
3106
+ '이 기기에서 음성 인식 서비스를 찾을 수 없습니다. 음성 입력 앱(예: FUTO Voice Input)을 설치하고 기본 음성 인식기로 설정하세요.';
3107
+
3108
+ @override
3109
+ String stt_error_generic(String code) {
3110
+ return '음성 인식 오류: $code';
3111
+ }
3112
}
lib/l10n/app_localizations_pt.dart
+40
@@ -3184,4 +3184,44 @@ class AppLocalizationsPt extends AppLocalizations {
3184
@override
3185
String get on_device_engine_failed_error =>
3186
'O modelo no dispositivo parou de responder, geralmente porque a conversa ultrapassou a janela de contexto. O modelo está sendo recarregado. Tente novamente, inicie um novo chat ou aumente o comprimento do contexto nas configurações.';
3187
+
3188
+ @override
3189
+ String get stt_error_no_match =>
3190
+ 'Nenhuma fala reconhecida. Toque para tentar novamente.';
3191
+
3192
+ @override
3193
+ String get stt_error_speech_timeout =>
3194
+ 'Nenhuma fala detectada. Toque para tentar novamente.';
3195
+
3196
+ @override
3197
+ String get stt_error_permission => 'Permissão do microfone negada.';
3198
+
3199
+ @override
3200
+ String get stt_error_busy =>
3201
+ 'O reconhecimento de voz está ocupado. Tente novamente.';
3202
+
3203
+ @override
3204
+ String get stt_error_network =>
3205
+ 'Erro de rede. Verifique sua conexão e tente novamente.';
3206
+
3207
+ @override
3208
+ String get stt_error_audio =>
3209
+ 'Erro na gravação de áudio. Verifique seu microfone.';
3210
+
3211
+ @override
3212
+ String get stt_error_client =>
3213
+ 'Não foi possível iniciar o serviço de reconhecimento de voz. Verifique se um app de entrada por voz está instalado e definido como reconhecedor de fala padrão e tente novamente.';
3214
+
3215
+ @override
3216
+ String get stt_error_language =>
3217
+ 'O reconhecedor de fala deste dispositivo não suporta seu idioma.';
3218
+
3219
+ @override
3220
+ String get stt_error_unavailable =>
3221
+ 'Nenhum serviço de reconhecimento de voz encontrado neste dispositivo. Instale um app de entrada por voz (por exemplo FUTO Voice Input) e defina-o como reconhecedor de fala padrão.';
3222
+
3223
+ @override
3224
+ String stt_error_generic(String code) {
3225
+ return 'Erro de reconhecimento de voz: $code';
3226
+ }
3227
}
lib/l10n/app_localizations_ru.dart
+38
@@ -3168,4 +3168,42 @@ class AppLocalizationsRu extends AppLocalizations {
3168
@override
3169
String get on_device_engine_failed_error =>
3170
'Локальная модель перестала отвечать — обычно потому, что диалог превысил окно контекста. Модель перезагружается. Попробуйте снова, начните новый чат или увеличьте длину контекста в настройках.';
3171
+
3172
+ @override
3173
+ String get stt_error_no_match =>
3174
+ 'Речь не распознана. Нажмите, чтобы попробовать снова.';
3175
+
3176
+ @override
3177
+ String get stt_error_speech_timeout =>
3178
+ 'Речь не обнаружена. Нажмите, чтобы попробовать снова.';
3179
+
3180
+ @override
3181
+ String get stt_error_permission => 'Доступ к микрофону запрещён.';
3182
+
3183
+ @override
3184
+ String get stt_error_busy => 'Распознавание речи занято. Попробуйте снова.';
3185
+
3186
+ @override
3187
+ String get stt_error_network =>
3188
+ 'Ошибка сети. Проверьте подключение и попробуйте снова.';
3189
+
3190
+ @override
3191
+ String get stt_error_audio => 'Ошибка записи звука. Проверьте микрофон.';
3192
+
3193
+ @override
3194
+ String get stt_error_client =>
3195
+ 'Не удалось запустить службу распознавания речи. Убедитесь, что установлено приложение голосового ввода и оно выбрано распознавателем речи по умолчанию, затем попробуйте снова.';
3196
+
3197
+ @override
3198
+ String get stt_error_language =>
3199
+ 'Распознаватель речи на этом устройстве не поддерживает ваш язык.';
3200
+
3201
+ @override
3202
+ String get stt_error_unavailable =>
3203
+ 'На устройстве не найдена служба распознавания речи. Установите приложение голосового ввода (например, FUTO Voice Input) и выберите его распознавателем речи по умолчанию.';
3204
+
3205
+ @override
3206
+ String stt_error_generic(String code) {
3207
+ return 'Ошибка распознавания речи: $code';
3208
+ }
3209
}
lib/l10n/app_localizations_tr.dart
+39
@@ -3174,4 +3174,43 @@ class AppLocalizationsTr extends AppLocalizations {
3174
@override
3175
String get on_device_engine_failed_error =>
3176
'Cihaz üzerindeki model yanıt vermeyi durdurdu; genellikle sohbet bağlam penceresini aştığı için. Model yeniden yükleniyor. Tekrar deneyin, yeni bir sohbet başlatın veya ayarlardan bağlam uzunluğunu artırın.';
3177
+
3178
+ @override
3179
+ String get stt_error_no_match =>
3180
+ 'Konuşma tanınmadı. Tekrar denemek için dokunun.';
3181
+
3182
+ @override
3183
+ String get stt_error_speech_timeout =>
3184
+ 'Konuşma algılanmadı. Tekrar denemek için dokunun.';
3185
+
3186
+ @override
3187
+ String get stt_error_permission => 'Mikrofon izni reddedildi.';
3188
+
3189
+ @override
3190
+ String get stt_error_busy => 'Konuşma tanıma meşgul. Lütfen tekrar deneyin.';
3191
+
3192
+ @override
3193
+ String get stt_error_network =>
3194
+ 'Ağ hatası. Bağlantınızı kontrol edip tekrar deneyin.';
3195
+
3196
+ @override
3197
+ String get stt_error_audio =>
3198
+ 'Ses kaydı hatası. Lütfen mikrofonunuzu kontrol edin.';
3199
+
3200
+ @override
3201
+ String get stt_error_client =>
3202
+ 'Konuşma tanıma hizmeti başlatılamadı. Bir sesli giriş uygulamasının yüklü ve varsayılan konuşma tanıyıcı olarak ayarlı olduğundan emin olup tekrar deneyin.';
3203
+
3204
+ @override
3205
+ String get stt_error_language =>
3206
+ 'Bu cihazdaki konuşma tanıyıcı dilinizi desteklemiyor.';
3207
+
3208
+ @override
3209
+ String get stt_error_unavailable =>
3210
+ 'Bu cihazda konuşma tanıma hizmeti bulunamadı. Bir sesli giriş uygulaması (örneğin FUTO Voice Input) yükleyip varsayılan konuşma tanıyıcı olarak ayarlayın.';
3211
+
3212
+ @override
3213
+ String stt_error_generic(String code) {
3214
+ return 'Konuşma tanıma hatası: $code';
3215
+ }
3216
}
lib/l10n/app_localizations_zh.dart
+66
@@ -3067,6 +3067,39 @@ class AppLocalizationsZh extends AppLocalizations {
3067
@override
3068
String get on_device_engine_failed_error =>
3069
'设备端模型已停止响应,通常是因为对话超出了上下文窗口。正在重新加载模型。请重试、开始新对话,或在设置中增加上下文长度。';
3070
+
3071
+ @override
3072
+ String get stt_error_no_match => '未识别到语音。点按重试。';
3073
+
3074
+ @override
3075
+ String get stt_error_speech_timeout => '未检测到语音。点按重试。';
3076
+
3077
+ @override
3078
+ String get stt_error_permission => '麦克风权限被拒绝。';
3079
+
3080
+ @override
3081
+ String get stt_error_busy => '语音识别正忙,请重试。';
3082
+
3083
+ @override
3084
+ String get stt_error_network => '网络错误。请检查网络连接后重试。';
3085
+
3086
+ @override
3087
+ String get stt_error_audio => '录音出错,请检查麦克风。';
3088
+
3089
+ @override
3090
+ String get stt_error_client => '语音识别服务无法启动。请确认已安装语音输入应用并将其设为默认语音识别器,然后重试。';
3091
+
3092
+ @override
3093
+ String get stt_error_language => '此设备上的语音识别器不支持你的语言。';
3094
+
3095
+ @override
3096
+ String get stt_error_unavailable =>
3097
+ '此设备上未找到语音识别服务。请安装语音输入应用(例如 FUTO Voice Input)并将其设为默认语音识别器。';
3098
+
3099
+ @override
3100
+ String stt_error_generic(String code) {
3101
+ return '语音识别错误:$code';
3102
+ }
3103
}
3104
3105
/// The translations for Chinese, as used in Taiwan (`zh_TW`).
@@ -6038,4 +6071,37 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
6071
@override
6072
String get on_device_engine_failed_error =>
6073
'裝置端模型已停止回應,通常是因為對話超出了上下文視窗。正在重新載入模型。請重試、開始新對話,或在設定中增加上下文長度。';
6074
+
6075
+ @override
6076
+ String get stt_error_no_match => '未辨識到語音。點按重試。';
6077
+
6078
+ @override
6079
+ String get stt_error_speech_timeout => '未偵測到語音。點按重試。';
6080
+
6081
+ @override
6082
+ String get stt_error_permission => '麥克風權限遭拒。';
6083
+
6084
+ @override
6085
+ String get stt_error_busy => '語音辨識忙碌中,請重試。';
6086
+
6087
+ @override
6088
+ String get stt_error_network => '網路錯誤。請檢查連線後重試。';
6089
+
6090
+ @override
6091
+ String get stt_error_audio => '錄音發生錯誤,請檢查麥克風。';
6092
+
6093
+ @override
6094
+ String get stt_error_client => '語音辨識服務無法啟動。請確認已安裝語音輸入 App 並設為預設語音辨識器,然後重試。';
6095
+
6096
+ @override
6097
+ String get stt_error_language => '此裝置上的語音辨識器不支援你的語言。';
6098
+
6099
+ @override
6100
+ String get stt_error_unavailable =>
6101
+ '此裝置上找不到語音辨識服務。請安裝語音輸入 App(例如 FUTO Voice Input)並設為預設語音辨識器。';
6102
+
6103
+ @override
6104
+ String stt_error_generic(String code) {
6105
+ return '語音辨識錯誤:$code';
6106
+ }
6107
}
lib/l10n/app_pt.arb
+11
-1
@@ -943,5 +943,15 @@
943
"model_reasoning_on": "Ativado",
944
"model_reasoning_help": "Aplica-se à próxima resposta. Desativado impede o raciocínio se o modelo de chat permitir.",
945
"model_reasoning_save_error": "Não foi possível salvar o modo de raciocínio. Tente novamente.",
946
- "on_device_engine_failed_error": "O modelo no dispositivo parou de responder, geralmente porque a conversa ultrapassou a janela de contexto. O modelo está sendo recarregado. Tente novamente, inicie um novo chat ou aumente o comprimento do contexto nas configurações."
946
+ "on_device_engine_failed_error": "O modelo no dispositivo parou de responder, geralmente porque a conversa ultrapassou a janela de contexto. O modelo está sendo recarregado. Tente novamente, inicie um novo chat ou aumente o comprimento do contexto nas configurações.",
947
+ "stt_error_no_match": "Nenhuma fala reconhecida. Toque para tentar novamente.",
948
+ "stt_error_speech_timeout": "Nenhuma fala detectada. Toque para tentar novamente.",
949
+ "stt_error_permission": "Permissão do microfone negada.",
950
+ "stt_error_busy": "O reconhecimento de voz está ocupado. Tente novamente.",
951
+ "stt_error_network": "Erro de rede. Verifique sua conexão e tente novamente.",
952
+ "stt_error_audio": "Erro na gravação de áudio. Verifique seu microfone.",
953
+ "stt_error_client": "Não foi possível iniciar o serviço de reconhecimento de voz. Verifique se um app de entrada por voz está instalado e definido como reconhecedor de fala padrão e tente novamente.",
954
+ "stt_error_language": "O reconhecedor de fala deste dispositivo não suporta seu idioma.",
955
+ "stt_error_unavailable": "Nenhum serviço de reconhecimento de voz encontrado neste dispositivo. Instale um app de entrada por voz (por exemplo FUTO Voice Input) e defina-o como reconhecedor de fala padrão.",
956
+ "stt_error_generic": "Erro de reconhecimento de voz: {code}"
957
}
lib/l10n/app_ru.arb
+11
-1
@@ -929,5 +929,15 @@
929
"model_reasoning_on": "Вкл.",
930
"model_reasoning_help": "Применяется к следующему ответу. Выключение отключает рассуждения, если это поддерживается шаблоном чата модели.",
931
"model_reasoning_save_error": "Не удалось сохранить режим рассуждений. Попробуйте ещё раз.",
932
- "on_device_engine_failed_error": "Локальная модель перестала отвечать — обычно потому, что диалог превысил окно контекста. Модель перезагружается. Попробуйте снова, начните новый чат или увеличьте длину контекста в настройках."
932
+ "on_device_engine_failed_error": "Локальная модель перестала отвечать — обычно потому, что диалог превысил окно контекста. Модель перезагружается. Попробуйте снова, начните новый чат или увеличьте длину контекста в настройках.",
933
+ "stt_error_no_match": "Речь не распознана. Нажмите, чтобы попробовать снова.",
934
+ "stt_error_speech_timeout": "Речь не обнаружена. Нажмите, чтобы попробовать снова.",
935
+ "stt_error_permission": "Доступ к микрофону запрещён.",
936
+ "stt_error_busy": "Распознавание речи занято. Попробуйте снова.",
937
+ "stt_error_network": "Ошибка сети. Проверьте подключение и попробуйте снова.",
938
+ "stt_error_audio": "Ошибка записи звука. Проверьте микрофон.",
939
+ "stt_error_client": "Не удалось запустить службу распознавания речи. Убедитесь, что установлено приложение голосового ввода и оно выбрано распознавателем речи по умолчанию, затем попробуйте снова.",
940
+ "stt_error_language": "Распознаватель речи на этом устройстве не поддерживает ваш язык.",
941
+ "stt_error_unavailable": "На устройстве не найдена служба распознавания речи. Установите приложение голосового ввода (например, FUTO Voice Input) и выберите его распознавателем речи по умолчанию.",
942
+ "stt_error_generic": "Ошибка распознавания речи: {code}"
943
}
lib/l10n/app_tr.arb
+11
-1
@@ -929,5 +929,15 @@
929
"model_reasoning_on": "Açık",
930
"model_reasoning_help": "Sonraki yanıta uygulanır. Modelin sohbet şablonu destekliyorsa Kapalı seçeneği düşünmeyi devre dışı bırakır.",
931
"model_reasoning_save_error": "Düşünme modu kaydedilemedi. Lütfen tekrar deneyin.",
932
- "on_device_engine_failed_error": "Cihaz üzerindeki model yanıt vermeyi durdurdu; genellikle sohbet bağlam penceresini aştığı için. Model yeniden yükleniyor. Tekrar deneyin, yeni bir sohbet başlatın veya ayarlardan bağlam uzunluğunu artırın."
932
+ "on_device_engine_failed_error": "Cihaz üzerindeki model yanıt vermeyi durdurdu; genellikle sohbet bağlam penceresini aştığı için. Model yeniden yükleniyor. Tekrar deneyin, yeni bir sohbet başlatın veya ayarlardan bağlam uzunluğunu artırın.",
933
+ "stt_error_no_match": "Konuşma tanınmadı. Tekrar denemek için dokunun.",
934
+ "stt_error_speech_timeout": "Konuşma algılanmadı. Tekrar denemek için dokunun.",
935
+ "stt_error_permission": "Mikrofon izni reddedildi.",
936
+ "stt_error_busy": "Konuşma tanıma meşgul. Lütfen tekrar deneyin.",
937
+ "stt_error_network": "Ağ hatası. Bağlantınızı kontrol edip tekrar deneyin.",
938
+ "stt_error_audio": "Ses kaydı hatası. Lütfen mikrofonunuzu kontrol edin.",
939
+ "stt_error_client": "Konuşma tanıma hizmeti başlatılamadı. Bir sesli giriş uygulamasının yüklü ve varsayılan konuşma tanıyıcı olarak ayarlı olduğundan emin olup tekrar deneyin.",
940
+ "stt_error_language": "Bu cihazdaki konuşma tanıyıcı dilinizi desteklemiyor.",
941
+ "stt_error_unavailable": "Bu cihazda konuşma tanıma hizmeti bulunamadı. Bir sesli giriş uygulaması (örneğin FUTO Voice Input) yükleyip varsayılan konuşma tanıyıcı olarak ayarlayın.",
942
+ "stt_error_generic": "Konuşma tanıma hatası: {code}"
943
}
lib/l10n/app_zh.arb
+11
-1
@@ -932,5 +932,15 @@
932
"model_reasoning_on": "开启",
933
"model_reasoning_help": "应用于下一条回复。如果模型的聊天模板支持,关闭后将禁用思考。",
934
"model_reasoning_save_error": "无法保存思考模式。请重试。",
935
- "on_device_engine_failed_error": "设备端模型已停止响应,通常是因为对话超出了上下文窗口。正在重新加载模型。请重试、开始新对话,或在设置中增加上下文长度。"
935
+ "on_device_engine_failed_error": "设备端模型已停止响应,通常是因为对话超出了上下文窗口。正在重新加载模型。请重试、开始新对话,或在设置中增加上下文长度。",
936
+ "stt_error_no_match": "未识别到语音。点按重试。",
937
+ "stt_error_speech_timeout": "未检测到语音。点按重试。",
938
+ "stt_error_permission": "麦克风权限被拒绝。",
939
+ "stt_error_busy": "语音识别正忙,请重试。",
940
+ "stt_error_network": "网络错误。请检查网络连接后重试。",
941
+ "stt_error_audio": "录音出错,请检查麦克风。",
942
+ "stt_error_client": "语音识别服务无法启动。请确认已安装语音输入应用并将其设为默认语音识别器,然后重试。",
943
+ "stt_error_language": "此设备上的语音识别器不支持你的语言。",
944
+ "stt_error_unavailable": "此设备上未找到语音识别服务。请安装语音输入应用(例如 FUTO Voice Input)并将其设为默认语音识别器。",
945
+ "stt_error_generic": "语音识别错误:{code}"
946
}
lib/l10n/app_zh_TW.arb
+11
-1
@@ -932,5 +932,15 @@
932
"model_reasoning_on": "開啟",
933
"model_reasoning_help": "套用至下一則回覆。如果模型的聊天範本支援,關閉後將停用思考。",
934
"model_reasoning_save_error": "無法儲存思考模式。請再試一次。",
935
- "on_device_engine_failed_error": "裝置端模型已停止回應,通常是因為對話超出了上下文視窗。正在重新載入模型。請重試、開始新對話,或在設定中增加上下文長度。"
935
+ "on_device_engine_failed_error": "裝置端模型已停止回應,通常是因為對話超出了上下文視窗。正在重新載入模型。請重試、開始新對話,或在設定中增加上下文長度。",
936
+ "stt_error_no_match": "未辨識到語音。點按重試。",
937
+ "stt_error_speech_timeout": "未偵測到語音。點按重試。",
938
+ "stt_error_permission": "麥克風權限遭拒。",
939
+ "stt_error_busy": "語音辨識忙碌中,請重試。",
940
+ "stt_error_network": "網路錯誤。請檢查連線後重試。",
941
+ "stt_error_audio": "錄音發生錯誤,請檢查麥克風。",
942
+ "stt_error_client": "語音辨識服務無法啟動。請確認已安裝語音輸入 App 並設為預設語音辨識器,然後重試。",
943
+ "stt_error_language": "此裝置上的語音辨識器不支援你的語言。",
944
+ "stt_error_unavailable": "此裝置上找不到語音辨識服務。請安裝語音輸入 App(例如 FUTO Voice Input)並設為預設語音辨識器。",
945
+ "stt_error_generic": "語音辨識錯誤:{code}"
946
}
pubspec.lock
+1
-1
@@ -1970,7 +1970,7 @@ packages:
1970
source: hosted
1971
version: "7.4.0"
1972
speech_to_text_platform_interface:
1973
- dependency: transitive
1973
+ dependency: "direct dev"
1974
description:
1975
name: speech_to_text_platform_interface
1976
sha256: a7e16e02853853ed7534ac2bde9a1c4f39c8879970a7974ac6ff832d4bdaa4b0
pubspec.yaml
+1
@@ -102,6 +102,7 @@ dev_dependencies:
102
sdk: flutter
103
plugin_platform_interface: ^2.1.8
104
url_launcher_platform_interface: ^2.3.2
105
+ speech_to_text_platform_interface: ^2.4.0
106
107
# The "flutter_lints" package below contains a set of recommended lints to
108
# encourage good coding practices. The lint set provided by the package is
test/features/stt/stt_error_messages_test.dart
new
+38
@@ -0,0 +1,38 @@
1
+import 'package:flutter/widgets.dart';
2
+import 'package:flutter_test/flutter_test.dart';
3
+import 'package:localmind/features/stt/utils/stt_error_messages.dart';
4
+import 'package:localmind/l10n/app_localizations.dart';
5
+
6
+void main() {
7
+ final l10n = lookupAppLocalizations(const Locale('en'));
8
+
9
+ test('maps error_client to a recognizer hint instead of "client" (#100)', () {
10
+ final message = sttErrorMessage(l10n, 'error_client');
11
+ expect(message, l10n.stt_error_client);
12
+ expect(message, isNot(contains('error: client')));
13
+ });
14
+
15
+ test('maps a missing recognizer to the install hint', () {
16
+ expect(
17
+ sttErrorMessage(l10n, sttUnavailableCode),
18
+ l10n.stt_error_unavailable,
19
+ );
20
+ });
21
+
22
+ test('falls back to a readable name for unknown codes', () {
23
+ expect(
24
+ sttErrorMessage(l10n, 'error_something_new'),
25
+ l10n.stt_error_generic('something new'),
26
+ );
27
+ });
28
+
29
+ test('passes through non-code messages', () {
30
+ expect(sttErrorMessage(l10n, 'No server connected'), 'No server connected');
31
+ });
32
+
33
+ test('only no-match and timeout count as "no speech"', () {
34
+ expect(isNoSpeechSttError('error_no_match'), isTrue);
35
+ expect(isNoSpeechSttError('error_speech_timeout'), isTrue);
36
+ expect(isNoSpeechSttError('error_client'), isFalse);
37
+ });
38
+}
test/features/stt/stt_notifier_retry_test.dart
new
+133
@@ -0,0 +1,133 @@
1
+import 'dart:convert';
2
+
3
+import 'package:flutter/foundation.dart';
4
+import 'package:flutter/services.dart';
5
+import 'package:flutter_riverpod/flutter_riverpod.dart';
6
+import 'package:flutter_test/flutter_test.dart';
7
+import 'package:localmind/features/stt/providers/stt_providers.dart';
8
+import 'package:localmind/features/stt/utils/stt_error_messages.dart';
9
+import 'package:speech_to_text/speech_to_text.dart';
10
+import 'package:speech_to_text_platform_interface/speech_to_text_platform_interface.dart';
11
+
12
+void main() {
13
+ TestWidgetsFlutterBinding.ensureInitialized();
14
+
15
+ late _FakeSpeechPlatform platform;
16
+ late SpeechToTextPlatform original;
17
+ late ProviderContainer container;
18
+
19
+ setUp(() {
20
+ original = SpeechToTextPlatform.instance;
21
+ platform = _FakeSpeechPlatform();
22
+ SpeechToTextPlatform.instance = platform;
23
+ container = ProviderContainer(
24
+ overrides: [
25
+ sttProvider.overrideWith(
26
+ () => SttNotifier(speechFactory: SpeechToText.withMethodChannel),
27
+ ),
28
+ ],
29
+ );
30
+ });
31
+
32
+ tearDown(() {
33
+ container.dispose();
34
+ SpeechToTextPlatform.instance = original;
35
+ debugDefaultTargetPlatformOverride = null;
36
+ });
37
+
38
+ Future<void> startListening() =>
39
+ container.read(sttProvider.notifier).startListening(onResult: (_) {});
40
+
41
+ Future<void> waitForRetry() => Future<void>.delayed(
42
+ SttNotifier.clientErrorRetryDelay + const Duration(milliseconds: 50),
43
+ );
44
+
45
+ test('retries once on error_client with the on-device recognizer', () async {
46
+ debugDefaultTargetPlatformOverride = TargetPlatform.android;
47
+ await startListening();
48
+ expect(platform.onDeviceFlags, [false]);
49
+
50
+ platform.emitError('error_client');
51
+ await waitForRetry();
52
+
53
+ expect(platform.onDeviceFlags, [false, true]);
54
+ expect(container.read(sttProvider).error, isNull);
55
+ });
56
+
57
+ test('surfaces error_client when the retry fails too', () async {
58
+ debugDefaultTargetPlatformOverride = TargetPlatform.android;
59
+ await startListening();
60
+ platform.emitError('error_client');
61
+ await waitForRetry();
62
+ platform.emitError('error_client');
63
+ await Future<void>.delayed(Duration.zero);
64
+
65
+ expect(platform.onDeviceFlags, [false, true]);
66
+ expect(container.read(sttProvider).error, 'error_client');
67
+
68
+ // Neither recognizer worked, so the next attempt uses the default one.
69
+ await startListening();
70
+ expect(platform.onDeviceFlags.last, isFalse);
71
+ });
72
+
73
+ test('does not retry after the caller stopped listening', () async {
74
+ await startListening();
75
+ platform.emitError('error_client');
76
+ await container.read(sttProvider.notifier).cancelListening();
77
+ await waitForRetry();
78
+
79
+ expect(platform.onDeviceFlags, hasLength(1));
80
+ });
81
+
82
+ test('reports a missing recognizer as stt_unavailable', () async {
83
+ platform.initError = PlatformException(code: 'recognizerNotAvailable');
84
+ final available = await container.read(sttProvider.notifier).initSpeech();
85
+
86
+ expect(available, isFalse);
87
+ expect(container.read(sttProvider).error, sttUnavailableCode);
88
+ });
89
+}
90
+
91
+class _FakeSpeechPlatform extends SpeechToTextPlatform {
92
+ final List<bool> onDeviceFlags = [];
93
+ PlatformException? initError;
94
+
95
+ void emitError(String code) {
96
+ onError?.call(jsonEncode({'errorMsg': code, 'permanent': true}));
97
+ }
98
+
99
+ @override
100
+ Future<bool> hasPermission() async => true;
101
+
102
+ @override
103
+ Future<bool> initialize({
104
+ debugLogging = false,
105
+ List<SpeechConfigOption>? options,
106
+ }) async {
107
+ final error = initError;
108
+ if (error != null) throw error;
109
+ return true;
110
+ }
111
+
112
+ @override
113
+ Future<bool> listen({
114
+ String? localeId,
115
+ partialResults = true,
116
+ onDevice = false,
117
+ int listenMode = 0,
118
+ sampleRate = 0,
119
+ SpeechListenOptions? options,
120
+ }) async {
121
+ onDeviceFlags.add(options?.onDevice ?? onDevice as bool);
122
+ return true;
123
+ }
124
+
125
+ @override
126
+ Future<void> stop() async {}
127
+
128
+ @override
129
+ Future<void> cancel() async {}
130
+
131
+ @override
132
+ Future<List<dynamic>> locales() async => [];
133
+}
test/features/voice_mode/voice_mode_model_guard_test.dart
+29
-2
@@ -9,6 +9,7 @@ import 'package:localmind/features/on_device/providers/on_device_providers.dart'
9
import 'package:localmind/features/servers/data/models/server.dart';
10
import 'package:localmind/features/servers/providers/server_providers.dart';
11
import 'package:localmind/features/stt/providers/stt_providers.dart';
12
+import 'package:localmind/features/stt/utils/stt_error_messages.dart';
13
import 'package:localmind/features/tts/providers/tts_providers.dart';
14
import 'package:localmind/features/voice_mode/providers/voice_mode_provider.dart';
15
import 'package:localmind/services/voice_feedback_service.dart';
@@ -79,6 +80,27 @@ void main() {
80
},
81
);
82
83
+ test(
84
+ 'voice mode reports a missing recognizer instead of permission (#100)',
85
+ () async {
86
+ final events = <String>[];
87
+ final stt = _RecordingSttNotifier(
88
+ events: events,
89
+ initAvailable: false,
90
+ initError: sttUnavailableCode,
91
+ );
92
+ final background = _RecordingChatBackgroundService(events: events);
93
+ final container = _readyVoiceContainer(stt, background);
94
+ addTearDown(container.dispose);
95
+
96
+ container.read(voiceModeProvider.notifier).startSession();
97
+ await _flushAsyncWork();
98
+
99
+ expect(events, ['initSpeech']);
100
+ expect(container.read(voiceModeProvider).error, sttUnavailableCode);
101
+ },
102
+ );
103
+
104
test(
105
'voice mode cancels STT before stopping the microphone service',
106
() async {
@@ -174,14 +196,19 @@ class _EmptyEngineNotifier extends OnDeviceEngineNotifier {
196
}
197
198
class _RecordingSttNotifier extends SttNotifier {
177
- _RecordingSttNotifier({this.events = const [], this.initAvailable = true});
199
+ _RecordingSttNotifier({
200
+ this.events = const [],
201
+ this.initAvailable = true,
202
+ this.initError,
203
+ });
204
205
final List<String> events;
206
final bool initAvailable;
207
+ final String? initError;
208
int startCount = 0;
209
210
@override
184
- SttState build() => SttState(isAvailable: initAvailable);
211
+ SttState build() => SttState(isAvailable: initAvailable, error: initError);
212
213
@override
214
Future<bool> initSpeech() async {