feat: localisation with en, de, fr and it
This commit is contained in:
@@ -8,6 +8,7 @@ import '../../../shared/theme/theme_extensions.dart';
|
||||
import '../../../shared/widgets/markdown/streaming_markdown_widget.dart';
|
||||
import '../../../core/utils/reasoning_parser.dart';
|
||||
import 'enhanced_image_attachment.dart';
|
||||
import 'package:conduit/l10n/app_localizations.dart';
|
||||
|
||||
class AssistantMessageWidget extends ConsumerStatefulWidget {
|
||||
final dynamic message;
|
||||
@@ -559,7 +560,7 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
||||
icon: Platform.isIOS
|
||||
? CupertinoIcons.arrow_clockwise
|
||||
: Icons.refresh,
|
||||
label: 'Retry',
|
||||
label: AppLocalizations.of(context)!.retry,
|
||||
onTap: widget.onRegenerate,
|
||||
),
|
||||
] else ...[
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:dio/dio.dart' as dio;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import '../../../shared/theme/theme_extensions.dart';
|
||||
import 'package:conduit/l10n/app_localizations.dart';
|
||||
import '../../../core/providers/app_providers.dart';
|
||||
import '../../auth/providers/unified_auth_providers.dart';
|
||||
|
||||
@@ -74,6 +75,7 @@ class _EnhancedImageAttachmentState
|
||||
}
|
||||
|
||||
Future<void> _loadImage() async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
// Check global cache first
|
||||
if (_globalImageCache.containsKey(widget.attachmentId)) {
|
||||
if (mounted) {
|
||||
@@ -142,7 +144,7 @@ class _EnhancedImageAttachmentState
|
||||
return;
|
||||
} else {
|
||||
// If API service is not available, show error
|
||||
final error = 'Unable to load image: API service not available';
|
||||
final error = l10n.unableToLoadImage;
|
||||
_globalErrorStates[widget.attachmentId] = error;
|
||||
_globalLoadingStates[widget.attachmentId] = false;
|
||||
if (mounted) {
|
||||
@@ -157,7 +159,7 @@ class _EnhancedImageAttachmentState
|
||||
|
||||
final api = ref.read(apiServiceProvider);
|
||||
if (api == null) {
|
||||
final error = 'API service not available';
|
||||
final error = l10n.apiUnavailable;
|
||||
_globalErrorStates[widget.attachmentId] = error;
|
||||
_globalLoadingStates[widget.attachmentId] = false;
|
||||
if (mounted) {
|
||||
@@ -176,7 +178,7 @@ class _EnhancedImageAttachmentState
|
||||
final ext = fileName.toLowerCase().split('.').last;
|
||||
|
||||
if (!['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'].contains(ext)) {
|
||||
final error = 'Not an image file: $fileName';
|
||||
final error = l10n.notAnImageFile(fileName);
|
||||
_globalErrorStates[widget.attachmentId] = error;
|
||||
_globalLoadingStates[widget.attachmentId] = false;
|
||||
if (mounted) {
|
||||
@@ -214,7 +216,7 @@ class _EnhancedImageAttachmentState
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
final error = 'Failed to load image: ${e.toString()}';
|
||||
final error = l10n.failedToLoadImage(e.toString());
|
||||
_globalErrorStates[widget.attachmentId] = error;
|
||||
_globalLoadingStates[widget.attachmentId] = false;
|
||||
if (mounted) {
|
||||
@@ -443,7 +445,7 @@ class _EnhancedImageAttachmentState
|
||||
if (commaIndex != -1) {
|
||||
actualBase64 = _cachedImageData!.substring(commaIndex + 1);
|
||||
} else {
|
||||
throw Exception('Invalid data URL format');
|
||||
throw Exception(AppLocalizations.of(context)!.invalidDataUrl);
|
||||
}
|
||||
} else {
|
||||
actualBase64 = _cachedImageData!;
|
||||
@@ -456,14 +458,14 @@ class _EnhancedImageAttachmentState
|
||||
fit: BoxFit.cover,
|
||||
gaplessPlayback: true, // Prevents flashing during rebuilds
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
_errorMessage = 'Failed to decode image';
|
||||
_errorMessage = AppLocalizations.of(context)!.failedToDecodeImage;
|
||||
return _buildErrorState();
|
||||
},
|
||||
);
|
||||
|
||||
return _wrapImage(imageWidget);
|
||||
} catch (e) {
|
||||
_errorMessage = 'Invalid image format';
|
||||
_errorMessage = AppLocalizations.of(context)!.invalidImageFormat;
|
||||
return _buildErrorState();
|
||||
}
|
||||
}
|
||||
@@ -650,6 +652,7 @@ class FullScreenImageViewer extends ConsumerWidget {
|
||||
}
|
||||
|
||||
Future<void> _shareImage(BuildContext context, WidgetRef ref) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
try {
|
||||
Uint8List bytes;
|
||||
String? fileExtension;
|
||||
@@ -679,7 +682,7 @@ class FullScreenImageViewer extends ConsumerWidget {
|
||||
);
|
||||
final data = response.data;
|
||||
if (data == null || data.isEmpty) {
|
||||
throw Exception('Empty image data');
|
||||
throw Exception(l10n.emptyImageData);
|
||||
}
|
||||
bytes = Uint8List.fromList(data);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import '../../tools/widgets/unified_tools_modal.dart';
|
||||
import '../../tools/providers/tools_providers.dart';
|
||||
|
||||
import '../../../shared/utils/platform_utils.dart';
|
||||
import 'package:conduit/l10n/app_localizations.dart';
|
||||
|
||||
class ModernChatInput extends ConsumerStatefulWidget {
|
||||
final Function(String) onSendMessage;
|
||||
@@ -264,7 +265,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
onTap: widget.enabled
|
||||
? _showAttachmentOptions
|
||||
: null,
|
||||
tooltip: 'Add attachment',
|
||||
tooltip: AppLocalizations.of(context)!.addAttachment,
|
||||
),
|
||||
const SizedBox(width: Spacing.sm),
|
||||
],
|
||||
@@ -272,8 +273,8 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
Expanded(
|
||||
child: Semantics(
|
||||
textField: true,
|
||||
label: 'Message input',
|
||||
hint: 'Type your message',
|
||||
label: AppLocalizations.of(context)!.messageInputLabel,
|
||||
hint: AppLocalizations.of(context)!.messageInputHint,
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
focusNode: _focusNode,
|
||||
@@ -291,7 +292,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
color: context.conduitTheme.inputText,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Message...',
|
||||
hintText: AppLocalizations.of(context)!.messageHintText,
|
||||
hintStyle: TextStyle(
|
||||
color:
|
||||
context.conduitTheme.inputPlaceholder,
|
||||
@@ -363,7 +364,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
onTap: widget.enabled
|
||||
? _showAttachmentOptions
|
||||
: null,
|
||||
tooltip: 'Add attachment',
|
||||
tooltip: AppLocalizations.of(context)!.addAttachment,
|
||||
),
|
||||
const SizedBox(width: Spacing.sm),
|
||||
// Tools button
|
||||
@@ -374,7 +375,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
_showUnifiedToolsModal();
|
||||
}
|
||||
: null,
|
||||
tooltip: 'Tools',
|
||||
tooltip: AppLocalizations.of(context)!.tools,
|
||||
isActive:
|
||||
ref
|
||||
.watch(selectedToolIdsProvider)
|
||||
@@ -391,7 +392,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
onTap: widget.enabled
|
||||
? widget.onVoiceInput
|
||||
: null,
|
||||
tooltip: 'Voice input',
|
||||
tooltip: AppLocalizations.of(context)!.voiceInput,
|
||||
isActive: _isRecording,
|
||||
),
|
||||
const SizedBox(width: Spacing.sm),
|
||||
@@ -431,7 +432,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
// Generating -> STOP variant
|
||||
if (isGenerating) {
|
||||
return Tooltip(
|
||||
message: 'Stop generating',
|
||||
message: AppLocalizations.of(context)!.stopGenerating,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
@@ -482,7 +483,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
|
||||
// Default SEND variant
|
||||
return Tooltip(
|
||||
message: enabled ? 'Send message' : 'Send',
|
||||
message: enabled ? AppLocalizations.of(context)!.sendMessage : AppLocalizations.of(context)!.send,
|
||||
child: Opacity(
|
||||
opacity: enabled ? Alpha.primary : Alpha.disabled,
|
||||
child: IgnorePointer(
|
||||
@@ -626,7 +627,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
Expanded(
|
||||
child: _buildAttachmentOption(
|
||||
icon: Platform.isIOS ? CupertinoIcons.doc : Icons.attach_file,
|
||||
label: 'File',
|
||||
label: AppLocalizations.of(context)!.file,
|
||||
onTap: () {
|
||||
HapticFeedback.lightImpact();
|
||||
Navigator.pop(context); // Close modal
|
||||
@@ -637,7 +638,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
Expanded(
|
||||
child: _buildAttachmentOption(
|
||||
icon: Platform.isIOS ? CupertinoIcons.photo : Icons.image,
|
||||
label: 'Photo',
|
||||
label: AppLocalizations.of(context)!.photo,
|
||||
onTap: () {
|
||||
HapticFeedback.lightImpact();
|
||||
Navigator.pop(context); // Close modal
|
||||
@@ -650,7 +651,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
icon: Platform.isIOS
|
||||
? CupertinoIcons.camera
|
||||
: Icons.camera_alt,
|
||||
label: 'Camera',
|
||||
label: AppLocalizations.of(context)!.camera,
|
||||
onTap: () {
|
||||
HapticFeedback.lightImpact();
|
||||
Navigator.pop(context); // Close modal
|
||||
|
||||
Reference in New Issue
Block a user