feat: localisation with en, de, fr and it

This commit is contained in:
cogwheel0
2025-08-23 20:09:43 +05:30
parent b898adbe40
commit a852ce7848
36 changed files with 3912 additions and 203 deletions

View File

@@ -6,6 +6,7 @@ import 'api_error_handler.dart';
import 'api_error_interceptor.dart';
import '../../shared/theme/app_theme.dart';
import '../../shared/theme/theme_extensions.dart';
import 'package:conduit/l10n/app_localizations.dart';
/// Enhanced error service with comprehensive error handling capabilities
/// Provides unified error management across the application
@@ -136,8 +137,8 @@ class EnhancedErrorService {
action: isRetryableError && onRetry != null
? SnackBarAction(
label: retryDelay != null && retryDelay.inSeconds > 5
? 'Retry (${retryDelay.inSeconds}s)'
: 'Retry',
? "${AppLocalizations.of(context)!.retry} (${retryDelay.inSeconds}s)"
: AppLocalizations.of(context)!.retry,
textColor: AppTheme.neutral50,
onPressed: onRetry,
)
@@ -208,14 +209,14 @@ class EnhancedErrorService {
Navigator.of(context).pop();
onRetry();
},
child: const Text('Retry'),
child: Text(AppLocalizations.of(context)!.retry),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
onDismiss?.call();
},
child: const Text('OK'),
child: Text(AppLocalizations.of(context)!.ok),
),
],
);
@@ -281,7 +282,7 @@ class EnhancedErrorService {
ElevatedButton.icon(
onPressed: onRetry,
icon: const Icon(Icons.refresh),
label: const Text('Try Again'),
label: const Text('Retry'),
),
],
],

View File

@@ -79,6 +79,36 @@ class ThemeModeNotifier extends StateNotifier<ThemeMode> {
}
}
// Locale provider
final localeProvider = StateNotifierProvider<LocaleNotifier, Locale?>(
(ref) {
final storage = ref.watch(optimizedStorageServiceProvider);
return LocaleNotifier(storage);
},
);
class LocaleNotifier extends StateNotifier<Locale?> {
final OptimizedStorageService _storage;
LocaleNotifier(this._storage) : super(null) {
_loadLocale();
}
void _loadLocale() {
final code = _storage.getLocaleCode();
if (code != null && code.isNotEmpty) {
state = Locale(code);
} else {
state = null; // system
}
}
Future<void> setLocale(Locale? locale) async {
state = locale;
await _storage.setLocaleCode(locale?.languageCode);
}
}
// Server connection providers - optimized with caching
final serverConfigsProvider = FutureProvider<List<ServerConfig>>((ref) async {
final storage = ref.watch(optimizedStorageServiceProvider);

View File

@@ -23,6 +23,7 @@ class OptimizedStorageService {
static const String _activeServerIdKey = 'active_server_id';
static const String _rememberCredentialsKey = 'remember_credentials';
static const String _themeModeKey = 'theme_mode';
static const String _localeCodeKey = 'locale_code_v1';
static const String _localConversationsKey = 'local_conversations';
static const String _onboardingSeenKey = 'onboarding_seen_v1';
static const String _reviewerModeKey = 'reviewer_mode_v1';
@@ -226,6 +227,20 @@ class OptimizedStorageService {
await _prefs.setString(_themeModeKey, mode);
}
/// Locale Management
String? getLocaleCode() {
// Returns a locale code like 'en', 'de', 'fr', 'it'. Null means system.
return _prefs.getString(_localeCodeKey);
}
Future<void> setLocaleCode(String? code) async {
if (code == null || code.isEmpty) {
await _prefs.remove(_localeCodeKey);
} else {
await _prefs.setString(_localeCodeKey, code);
}
}
/// Onboarding
Future<bool> getOnboardingSeen() async {
return _prefs.getBool(_onboardingSeenKey) ?? false;

View File

@@ -182,12 +182,12 @@ class UserFriendlyErrorHandler {
List<ErrorRecoveryAction> _getServerRecoveryActions() {
return [
ErrorRecoveryAction(
label: 'Try Again',
label: 'Retry',
action: ErrorActionType.retry,
description: 'Retry your request',
),
ErrorRecoveryAction(
label: 'Wait & Retry',
label: 'Retry',
action: ErrorActionType.retryLater,
description: 'Wait a moment then try again',
),
@@ -223,7 +223,7 @@ class UserFriendlyErrorHandler {
description: 'Sign in to your account',
),
ErrorRecoveryAction(
label: 'Try Again',
label: 'Retry',
action: ErrorActionType.retry,
description: 'Retry the request',
),
@@ -280,7 +280,7 @@ class UserFriendlyErrorHandler {
description: 'Select another file',
),
ErrorRecoveryAction(
label: 'Try Again',
label: 'Retry',
action: ErrorActionType.retry,
description: 'Retry the operation',
),
@@ -314,7 +314,7 @@ class UserFriendlyErrorHandler {
description: 'Open app settings to grant permissions',
),
ErrorRecoveryAction(
label: 'Try Again',
label: 'Retry',
action: ErrorActionType.retry,
description: 'Retry after granting permission',
),
@@ -324,7 +324,7 @@ class UserFriendlyErrorHandler {
List<ErrorRecoveryAction> _getGenericRecoveryActions() {
return [
ErrorRecoveryAction(
label: 'Try Again',
label: 'Retry',
action: ErrorActionType.retry,
description: 'Retry the operation',
),

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../shared/theme/theme_extensions.dart';
import '../error/enhanced_error_service.dart';
import 'package:conduit/l10n/app_localizations.dart';
/// Error boundary widget that catches and handles errors in child widgets
class ErrorBoundary extends ConsumerStatefulWidget {
@@ -122,7 +123,7 @@ class _ErrorBoundaryState extends ConsumerState<ErrorBoundary> {
),
const SizedBox(height: 16),
Text(
'Something went wrong',
AppLocalizations.of(context)!.errorMessage,
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
color: context.conduitTheme.textPrimary,
),
@@ -140,7 +141,7 @@ class _ErrorBoundaryState extends ConsumerState<ErrorBoundary> {
FilledButton.icon(
onPressed: _retry,
icon: const Icon(Icons.refresh),
label: const Text('Try Again'),
label: Text(AppLocalizations.of(context)!.retry),
),
],
],
@@ -239,7 +240,7 @@ class AsyncErrorBoundary extends ConsumerWidget {
(context as Element).markNeedsBuild();
},
icon: const Icon(Icons.refresh),
label: const Text('Retry'),
label: Text(AppLocalizations.of(context)!.retry),
),
],
],