You've already forked immich
mirror of
https://github.com/immich-app/immich.git
synced 2025-08-08 23:07:06 +02:00
re-write localization service and add translation extension
This commit is contained in:
16
mobile/lib/extensions/translation_extensions.dart
Normal file
16
mobile/lib/extensions/translation_extensions.dart
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:immich_mobile/services/localization.service.dart';
|
||||||
|
|
||||||
|
final _translationService = EasyLocalizationService();
|
||||||
|
|
||||||
|
extension StringTranslation on String {
|
||||||
|
String t([Map<String, Object>? args]) {
|
||||||
|
return _translationService.translate(this, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BuildContextTranslation on BuildContext {
|
||||||
|
String t(String key, [Map<String, Object>? args]) {
|
||||||
|
return _translationService.translate(key, args);
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import 'package:flutter_displaymode/flutter_displaymode.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/locales.dart';
|
import 'package:immich_mobile/constants/locales.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translation_extensions.dart';
|
||||||
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
||||||
import 'package:immich_mobile/providers/app_life_cycle.provider.dart';
|
import 'package:immich_mobile/providers/app_life_cycle.provider.dart';
|
||||||
import 'package:immich_mobile/providers/asset_viewer/share_intent_upload.provider.dart';
|
import 'package:immich_mobile/providers/asset_viewer/share_intent_upload.provider.dart';
|
||||||
@ -22,6 +23,7 @@ import 'package:immich_mobile/routing/router.dart';
|
|||||||
import 'package:immich_mobile/routing/app_navigation_observer.dart';
|
import 'package:immich_mobile/routing/app_navigation_observer.dart';
|
||||||
import 'package:immich_mobile/services/background.service.dart';
|
import 'package:immich_mobile/services/background.service.dart';
|
||||||
import 'package:immich_mobile/services/local_notification.service.dart';
|
import 'package:immich_mobile/services/local_notification.service.dart';
|
||||||
|
import 'package:immich_mobile/services/localization.service.dart';
|
||||||
import 'package:immich_mobile/theme/dynamic_theme.dart';
|
import 'package:immich_mobile/theme/dynamic_theme.dart';
|
||||||
import 'package:immich_mobile/theme/theme_data.dart';
|
import 'package:immich_mobile/theme/theme_data.dart';
|
||||||
import 'package:immich_mobile/utils/bootstrap.dart';
|
import 'package:immich_mobile/utils/bootstrap.dart';
|
||||||
@ -158,12 +160,12 @@ class ImmichAppState extends ConsumerState<ImmichApp>
|
|||||||
void _configureFileDownloaderNotifications() {
|
void _configureFileDownloaderNotifications() {
|
||||||
FileDownloader().configureNotification(
|
FileDownloader().configureNotification(
|
||||||
running: TaskNotification(
|
running: TaskNotification(
|
||||||
'downloading_media'.tr(),
|
'downloading_media'.t(),
|
||||||
'${'file_name'.tr()}: {filename}',
|
'${'file_name'.t()}: {filename}',
|
||||||
),
|
),
|
||||||
complete: TaskNotification(
|
complete: TaskNotification(
|
||||||
'download_finished'.tr(),
|
'download_finished'.t(),
|
||||||
'${'file_name'.tr()}: {filename}',
|
'${'file_name'.t()}: {filename}',
|
||||||
),
|
),
|
||||||
progressBar: true,
|
progressBar: true,
|
||||||
);
|
);
|
||||||
@ -205,34 +207,34 @@ class ImmichAppState extends ConsumerState<ImmichApp>
|
|||||||
overrides: [
|
overrides: [
|
||||||
localeProvider.overrideWithValue(context.locale),
|
localeProvider.overrideWithValue(context.locale),
|
||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp.router(
|
||||||
|
title: 'Immich',
|
||||||
|
debugShowCheckedModeBanner: true,
|
||||||
localizationsDelegates: context.localizationDelegates,
|
localizationsDelegates: context.localizationDelegates,
|
||||||
supportedLocales: context.supportedLocales,
|
supportedLocales: context.supportedLocales,
|
||||||
locale: context.locale,
|
locale: context.locale,
|
||||||
debugShowCheckedModeBanner: true,
|
themeMode: ref.watch(immichThemeModeProvider),
|
||||||
home: MaterialApp.router(
|
darkTheme: getThemeData(
|
||||||
title: 'Immich',
|
colorScheme: immichTheme.dark,
|
||||||
debugShowCheckedModeBanner: false,
|
locale: context.locale,
|
||||||
themeMode: ref.watch(immichThemeModeProvider),
|
|
||||||
darkTheme: getThemeData(
|
|
||||||
colorScheme: immichTheme.dark,
|
|
||||||
locale: context.locale,
|
|
||||||
),
|
|
||||||
theme: getThemeData(
|
|
||||||
colorScheme: immichTheme.light,
|
|
||||||
locale: context.locale,
|
|
||||||
),
|
|
||||||
routeInformationParser: router.defaultRouteParser(),
|
|
||||||
routerDelegate: router.delegate(
|
|
||||||
navigatorObservers: () => [AppNavigationObserver(ref: ref)],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
theme: getThemeData(
|
||||||
|
colorScheme: immichTheme.light,
|
||||||
|
locale: context.locale,
|
||||||
|
),
|
||||||
|
routeInformationParser: router.defaultRouteParser(),
|
||||||
|
routerDelegate: router.delegate(
|
||||||
|
navigatorObservers: () => [AppNavigationObserver(ref: ref)],
|
||||||
|
),
|
||||||
|
builder: (context, child) {
|
||||||
|
EasyLocalizationService.setContext(context);
|
||||||
|
return child!;
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: prefer-single-widget-per-file
|
|
||||||
class MainWidget extends StatelessWidget {
|
class MainWidget extends StatelessWidget {
|
||||||
const MainWidget({super.key});
|
const MainWidget({super.key});
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import 'dart:ui' show DartPluginRegistrant, IsolateNameServer, PluginUtilities;
|
|||||||
|
|
||||||
import 'package:cancellation_token_http/http.dart';
|
import 'package:cancellation_token_http/http.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
@ -34,6 +33,7 @@ import 'package:immich_mobile/utils/bootstrap.dart';
|
|||||||
import 'package:immich_mobile/utils/diff.dart';
|
import 'package:immich_mobile/utils/diff.dart';
|
||||||
import 'package:immich_mobile/utils/http_ssl_options.dart';
|
import 'package:immich_mobile/utils/http_ssl_options.dart';
|
||||||
import 'package:path_provider_foundation/path_provider_foundation.dart';
|
import 'package:path_provider_foundation/path_provider_foundation.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translation_extensions.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart' show PMProgressHandler;
|
import 'package:photo_manager/photo_manager.dart' show PMProgressHandler;
|
||||||
|
|
||||||
final backgroundServiceProvider = Provider((ref) => BackgroundService());
|
final backgroundServiceProvider = Provider((ref) => BackgroundService());
|
||||||
@ -76,8 +76,7 @@ class BackgroundService {
|
|||||||
Future<bool> enableService({bool immediate = false}) async {
|
Future<bool> enableService({bool immediate = false}) async {
|
||||||
try {
|
try {
|
||||||
final callback = PluginUtilities.getCallbackHandle(_nativeEntry)!;
|
final callback = PluginUtilities.getCallbackHandle(_nativeEntry)!;
|
||||||
final String title =
|
final String title = 'backup_background_service_default_notification'.t();
|
||||||
"backup_background_service_default_notification".tr();
|
|
||||||
final bool ok = await _foregroundChannel
|
final bool ok = await _foregroundChannel
|
||||||
.invokeMethod('enable', [callback.toRawHandle(), title, immediate]);
|
.invokeMethod('enable', [callback.toRawHandle(), title, immediate]);
|
||||||
return ok;
|
return ok;
|
||||||
@ -325,7 +324,8 @@ class BackgroundService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final translationsOk = await loadTranslations();
|
final translationsOk =
|
||||||
|
await EasyLocalizationService().loadTranslations();
|
||||||
if (!translationsOk) {
|
if (!translationsOk) {
|
||||||
debugPrint("[_callHandler] could not load translations");
|
debugPrint("[_callHandler] could not load translations");
|
||||||
}
|
}
|
||||||
@ -452,8 +452,8 @@ class BackgroundService {
|
|||||||
toUpload = await backupService.removeAlreadyUploadedAssets(toUpload);
|
toUpload = await backupService.removeAlreadyUploadedAssets(toUpload);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_showErrorNotification(
|
_showErrorNotification(
|
||||||
title: "backup_background_service_error_title".tr(),
|
title: 'backup_background_service_error_title'.t(),
|
||||||
content: "backup_background_service_connection_failed_message".tr(),
|
content: 'backup_background_service_connection_failed_message'.t(),
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -468,7 +468,7 @@ class BackgroundService {
|
|||||||
_assetsToUploadCount = toUpload.length;
|
_assetsToUploadCount = toUpload.length;
|
||||||
_uploadedAssetsCount = 0;
|
_uploadedAssetsCount = 0;
|
||||||
_updateNotification(
|
_updateNotification(
|
||||||
title: "backup_background_service_in_progress_notification".tr(),
|
title: 'backup_background_service_in_progress_notification'.t(),
|
||||||
content: notifyTotalProgress
|
content: notifyTotalProgress
|
||||||
? formatAssetBackupProgress(
|
? formatAssetBackupProgress(
|
||||||
_uploadedAssetsCount,
|
_uploadedAssetsCount,
|
||||||
@ -502,8 +502,8 @@ class BackgroundService {
|
|||||||
|
|
||||||
if (!ok && !_cancellationToken!.isCancelled) {
|
if (!ok && !_cancellationToken!.isCancelled) {
|
||||||
_showErrorNotification(
|
_showErrorNotification(
|
||||||
title: "backup_background_service_error_title".tr(),
|
title: 'backup_background_service_error_title'.t(),
|
||||||
content: "backup_background_service_backup_failed_message".tr(),
|
content: 'backup_background_service_backup_failed_message'.t(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,8 +561,8 @@ class BackgroundService {
|
|||||||
|
|
||||||
void _onBackupError(ErrorUploadAsset errorAssetInfo) {
|
void _onBackupError(ErrorUploadAsset errorAssetInfo) {
|
||||||
_showErrorNotification(
|
_showErrorNotification(
|
||||||
title: "backup_background_service_upload_failure_notification"
|
title: 'backup_background_service_upload_failure_notification'
|
||||||
.tr(namedArgs: {'filename': errorAssetInfo.fileName}),
|
.t({'filename': errorAssetInfo.fileName}),
|
||||||
individualTag: errorAssetInfo.id,
|
individualTag: errorAssetInfo.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -576,8 +576,8 @@ class BackgroundService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_throttledDetailNotify.title =
|
_throttledDetailNotify.title =
|
||||||
"backup_background_service_current_upload_notification"
|
'backup_background_service_current_upload_notification'
|
||||||
.tr(namedArgs: {'filename': currentUploadAsset.fileName});
|
.t({'filename': currentUploadAsset.fileName});
|
||||||
_throttledDetailNotify.progress = 0;
|
_throttledDetailNotify.progress = 0;
|
||||||
_throttledDetailNotify.total = 0;
|
_throttledDetailNotify.total = 0;
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,128 @@
|
|||||||
// ignore_for_file: implementation_imports
|
// ignore_for_file: implementation_imports
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:easy_localization/src/easy_localization_controller.dart';
|
import 'package:easy_localization/src/easy_localization_controller.dart';
|
||||||
import 'package:easy_localization/src/localization.dart';
|
import 'package:easy_localization/src/localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
import 'package:intl/message_format.dart';
|
||||||
import 'package:immich_mobile/constants/locales.dart';
|
import 'package:immich_mobile/constants/locales.dart';
|
||||||
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
||||||
|
|
||||||
/// Workaround to manually load translations in another Isolate
|
abstract class ILocalizationService {
|
||||||
Future<bool> loadTranslations() async {
|
String translate(String key, [Map<String, Object>? args]);
|
||||||
await EasyLocalizationController.initEasyLocation();
|
|
||||||
|
|
||||||
final controller = EasyLocalizationController(
|
Locale get currentLocale;
|
||||||
supportedLocales: locales.values.toList(),
|
|
||||||
useFallbackTranslations: true,
|
|
||||||
saveLocale: true,
|
|
||||||
assetLoader: const CodegenLoader(),
|
|
||||||
path: translationsPath,
|
|
||||||
useOnlyLangCode: false,
|
|
||||||
onLoadError: (e) => debugPrint(e.toString()),
|
|
||||||
fallbackLocale: locales.values.first,
|
|
||||||
);
|
|
||||||
|
|
||||||
await controller.loadTranslations();
|
bool get isInitialized;
|
||||||
|
|
||||||
return Localization.load(
|
Future<bool> loadTranslations();
|
||||||
controller.locale,
|
|
||||||
translations: controller.translations,
|
Future<void> changeLocale(Locale localeCode);
|
||||||
fallbackTranslations: controller.fallbackTranslations,
|
}
|
||||||
);
|
|
||||||
|
class EasyLocalizationService implements ILocalizationService {
|
||||||
|
EasyLocalizationService._internal();
|
||||||
|
|
||||||
|
static EasyLocalizationService? _instance;
|
||||||
|
static EasyLocalizationService get instance {
|
||||||
|
_instance ??= EasyLocalizationService._internal();
|
||||||
|
return _instance!;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory EasyLocalizationService() => instance;
|
||||||
|
|
||||||
|
static BuildContext? _context;
|
||||||
|
static EasyLocalizationController? _controller;
|
||||||
|
static bool _isInitialized = false;
|
||||||
|
|
||||||
|
static void setContext(BuildContext context) {
|
||||||
|
if (_context != context) {
|
||||||
|
debugPrint('🔄 Updating EasyLocalization context');
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuildContext? get context => _context;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String translate(String key, [Map<String, Object>? args]) {
|
||||||
|
if (_context != null) {
|
||||||
|
try {
|
||||||
|
String message = _context!.tr(key);
|
||||||
|
if (args != null) {
|
||||||
|
return MessageFormat(message, locale: Intl.defaultLocale ?? 'en')
|
||||||
|
.format(args);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Translation error for key "$key": $e');
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Locale get currentLocale {
|
||||||
|
if (_controller != null) {
|
||||||
|
return _controller!.locale;
|
||||||
|
}
|
||||||
|
if (_context != null) {
|
||||||
|
return _context!.locale;
|
||||||
|
}
|
||||||
|
return Intl.defaultLocale != null
|
||||||
|
? Locale(Intl.defaultLocale!)
|
||||||
|
: locales.values.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isInitialized => _isInitialized;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> changeLocale(Locale localeCode) async {
|
||||||
|
try {
|
||||||
|
if (_context != null) {
|
||||||
|
await _context!.setLocale(localeCode);
|
||||||
|
}
|
||||||
|
if (_controller != null) {
|
||||||
|
await _controller!.setLocale(localeCode);
|
||||||
|
}
|
||||||
|
debugPrint('✅ Locale changed to: $localeCode');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Failed to change locale to $localeCode: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> loadTranslations() async {
|
||||||
|
if (_isInitialized) {
|
||||||
|
debugPrint('✅ Translations already loaded');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await EasyLocalizationController.initEasyLocation();
|
||||||
|
_controller = EasyLocalizationController(
|
||||||
|
supportedLocales: locales.values.toList(),
|
||||||
|
useFallbackTranslations: true,
|
||||||
|
saveLocale: true,
|
||||||
|
assetLoader: const CodegenLoader(),
|
||||||
|
path: translationsPath,
|
||||||
|
useOnlyLangCode: false,
|
||||||
|
onLoadError: (e) => debugPrint(e.toString()),
|
||||||
|
fallbackLocale: locales.values.first,
|
||||||
|
);
|
||||||
|
await _controller!.loadTranslations();
|
||||||
|
final bool result = Localization.load(
|
||||||
|
_controller!.locale,
|
||||||
|
translations: _controller!.translations,
|
||||||
|
fallbackTranslations: _controller!.fallbackTranslations,
|
||||||
|
);
|
||||||
|
_isInitialized = result;
|
||||||
|
debugPrint('✅ Translations loaded: $result');
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Error loading translations: $e');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ import 'dart:async';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:immich_mobile/constants/locales.dart';
|
import 'package:immich_mobile/constants/locales.dart';
|
||||||
import 'package:immich_mobile/services/localization.service.dart';
|
import 'package:immich_mobile/services/localization.service.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translation_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/widgets/common/search_field.dart';
|
import 'package:immich_mobile/widgets/common/search_field.dart';
|
||||||
|
|
||||||
@ -12,15 +12,14 @@ class LanguageSettings extends HookConsumerWidget {
|
|||||||
const LanguageSettings({super.key});
|
const LanguageSettings({super.key});
|
||||||
|
|
||||||
Future<void> _applyLanguageChange(
|
Future<void> _applyLanguageChange(
|
||||||
BuildContext context,
|
|
||||||
ValueNotifier<Locale> selectedLocale,
|
ValueNotifier<Locale> selectedLocale,
|
||||||
ValueNotifier<bool> isLoading,
|
ValueNotifier<bool> isLoading,
|
||||||
) async {
|
) async {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
try {
|
try {
|
||||||
await context.setLocale(selectedLocale.value);
|
await EasyLocalizationService().changeLocale(selectedLocale.value);
|
||||||
await loadTranslations();
|
await EasyLocalizationService().loadTranslations();
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
@ -29,7 +28,7 @@ class LanguageSettings extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final localeEntries = useMemoized(() => locales.entries.toList(), const []);
|
final localeEntries = useMemoized(() => locales.entries.toList(), const []);
|
||||||
final currentLocale = context.locale;
|
final currentLocale = EasyLocalizationService().currentLocale;
|
||||||
final filteredLocaleEntries =
|
final filteredLocaleEntries =
|
||||||
useState<List<MapEntry<String, Locale>>>(localeEntries);
|
useState<List<MapEntry<String, Locale>>>(localeEntries);
|
||||||
final selectedLocale = useState<Locale>(currentLocale);
|
final selectedLocale = useState<Locale>(currentLocale);
|
||||||
@ -115,7 +114,6 @@ class LanguageSettings extends HookConsumerWidget {
|
|||||||
isDisabled: isButtonDisabled,
|
isDisabled: isButtonDisabled,
|
||||||
isLoading: isLoading.value,
|
isLoading: isLoading.value,
|
||||||
onPressed: () => _applyLanguageChange(
|
onPressed: () => _applyLanguageChange(
|
||||||
context,
|
|
||||||
selectedLocale,
|
selectedLocale,
|
||||||
isLoading,
|
isLoading,
|
||||||
),
|
),
|
||||||
@ -162,7 +160,7 @@ class _LanguageSearchBar extends StatelessWidget {
|
|||||||
child: SearchField(
|
child: SearchField(
|
||||||
autofocus: false,
|
autofocus: false,
|
||||||
contentPadding: const EdgeInsets.all(12),
|
contentPadding: const EdgeInsets.all(12),
|
||||||
hintText: 'language_search_hint'.tr(),
|
hintText: 'language_search_hint'.t(),
|
||||||
prefixIcon: const Icon(Icons.search_rounded),
|
prefixIcon: const Icon(Icons.search_rounded),
|
||||||
suffixIcon: controller.text.isNotEmpty
|
suffixIcon: controller.text.isNotEmpty
|
||||||
? IconButton(
|
? IconButton(
|
||||||
@ -196,14 +194,14 @@ class _LanguageNotFound extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'language_no_results_title'.tr(),
|
'language_no_results_title'.t(),
|
||||||
style: context.textTheme.titleMedium?.copyWith(
|
style: context.textTheme.titleMedium?.copyWith(
|
||||||
color: context.colorScheme.onSurface,
|
color: context.colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
'language_no_results_subtitle'.tr(),
|
'language_no_results_subtitle'.t(),
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
color: context.colorScheme.onSurface.withValues(alpha: 0.8),
|
color: context.colorScheme.onSurface.withValues(alpha: 0.8),
|
||||||
),
|
),
|
||||||
@ -246,7 +244,7 @@ class _LanguageApplyButton extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Text(
|
: Text(
|
||||||
'setting_languages_apply'.tr(),
|
'setting_languages_apply'.t(),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 16.0,
|
fontSize: 16.0,
|
||||||
|
Reference in New Issue
Block a user