refactor(mobile): migrate trash review strings to typed translations

This commit is contained in:
Peter Ombodi 2026-08-10 18:26:22 +03:00
parent 8d1a4ec737
commit 57ac0ec86d
6 changed files with 44 additions and 48 deletions

View file

@ -502,7 +502,7 @@
"advanced_settings_readonly_mode_subtitle": "Enables the read-only mode where the photos can be only viewed, things like selecting multiple images, sharing, casting, delete are all disabled. Enable/Disable read-only via user avatar from the main screen",
"advanced_settings_readonly_mode_title": "Read-only mode",
"advanced_settings_review_remote_deletions_subtitle": "Manually review cloud trash changes.",
"advanced_settings_review_remote_deletions_subtitle_android": "Restorations are applied automatically when Media Management Access is allowed.",
"advanced_settings_review_remote_deletions_subtitle_android": "Manually review cloud trash changes. Restorations are applied automatically when Media Management Access is allowed.",
"advanced_settings_review_remote_deletions_title": "Review remote deletions",
"advanced_settings_sync_remote_deletions_off_subtitle": "Cloud trash changes are ignored",
"advanced_settings_sync_remote_deletions_selector_title": "Sync remote deletions [EXPERIMENTAL]",
@ -593,11 +593,6 @@
"asset_not_found_on_icloud": "Asset not found on iCloud. the asset may be inaccessible due to bad file stored on iCloud",
"asset_offline": "Asset Offline",
"asset_offline_description": "This external asset is no longer found on disk. Please contact your Immich administrator for help.",
"asset_out_of_sync_title": "Out-of-sync assets list",
"asset_out_of_sync_trash_confirmation_text": "Move {count, plural, one {asset} other {# assets}} to your device trash?",
"asset_out_of_sync_trash_confirmation_title": "Sync trash change",
"asset_out_of_sync_trash_subtitle": "Assets moved to the Immich cloud trash: choose to move them to local trash or keep them on this device.",
"asset_out_of_sync_trash_subtitle_result": "Nothing left to review — all decisions applied.",
"asset_skipped": "Skipped",
"asset_skipped_in_trash": "In trash",
"asset_troubleshoot": "Asset Troubleshoot",
@ -612,7 +607,7 @@
"assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} cannot be added to the album",
"assets_cannot_be_added_to_albums": "{count, plural, one {Asset} other {Assets}} cannot be added to any of the albums",
"assets_count": "{count, plural, one {# asset} other {# assets}}",
"assets_denied_to_moved_to_trash_count": "Keeping local copies of {count, plural, one {# asset} other {# assets}}",
"assets_kept_on_device_count": "Keeping local copies of {count, plural, one {# asset} other {# assets}}",
"assets_moved_to_trash_count": "Moved {count, plural, one {# asset} other {# assets}} to trash",
"assets_permanently_deleted_count": "Permanently deleted {count, plural, one {# asset} other {# assets}}",
"assets_removed_count": "Removed {count, plural, one {# asset} other {# assets}}",
@ -1804,7 +1799,6 @@
"resume_paused_jobs": "Resume {count, plural, one {# paused job} other {# paused jobs}}",
"review_duplicates": "Review duplicates",
"review_large_files": "Review large files",
"review_out_of_sync_changes": "Review out-of-sync changes",
"role": "Role",
"role_editor": "Editor",
"role_viewer": "Viewer",
@ -2148,6 +2142,12 @@
"trash_no_results_message": "Trashed photos and videos will show up here.",
"trash_page_delete_all": "Delete All",
"trash_page_info": "Trashed items will be permanently deleted after {days} days",
"trash_review_banner_title": "Review out-of-sync changes",
"trash_review_confirmation_text": "Move {count, plural, one {asset} other {# assets}} to your device trash?",
"trash_review_confirmation_title": "Sync trash change",
"trash_review_empty_subtitle": "Nothing left to review — all decisions applied.",
"trash_review_subtitle": "Assets moved to the Immich cloud trash: choose to move them to local trash or keep them on this device.",
"trash_review_title": "Out-of-sync assets list",
"trashed_items_will_be_permanently_deleted_after": "Trashed items will be permanently deleted after {days, plural, one {# day} other {# days}}.",
"trigger": "Trigger",
"trigger_asset_metadata_extraction": "Asset Metadata Extraction",

View file

@ -1,5 +1,4 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
@ -34,7 +33,7 @@ class DriftTrashReviewPage extends ConsumerWidget {
],
child: Timeline(
appBar: SliverAppBar(
title: Text('asset_out_of_sync_title'.tr()),
title: Text(context.t.trash_review_title),
floating: true,
snap: true,
pinned: true,
@ -52,10 +51,8 @@ class DriftTrashReviewPage extends ConsumerWidget {
builder: (context, ref, _) {
final outOfSyncCount = ref.watch(pendingTrashReviewCountProvider).value ?? 0;
return outOfSyncCount > 0
? const Text('asset_out_of_sync_trash_subtitle').tr()
: Center(
child: Text('asset_out_of_sync_trash_subtitle_result', style: context.textTheme.bodyLarge).tr(),
);
? Text(context.t.trash_review_subtitle)
: Center(child: Text(context.t.trash_review_empty_subtitle, style: context.textTheme.bodyLarge));
},
),
),
@ -82,8 +79,8 @@ class _TrashReviewKebabMenu extends ConsumerWidget {
await showDialog<bool>(
context: context,
builder: (_) => ConfirmDialog(
title: context.t.asset_out_of_sync_trash_confirmation_title,
content: context.t.asset_out_of_sync_trash_confirmation_text(count: count),
title: context.t.trash_review_confirmation_title,
content: context.t.trash_review_confirmation_text(count: count),
onOk: () async {
final result = await ref.read(actionProvider.notifier).resolveAllRemoteTrash(keep: false);
if (!context.mounted) {

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart';
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
@ -14,8 +14,8 @@ void showKeepResultToast(BuildContext context, ActionResult result) {
return;
}
final message = result.success
? 'assets_denied_to_moved_to_trash_count'.t(args: {'count': '${result.count}'})
: 'scaffold_body_error_occurred'.t();
? context.t.assets_kept_on_device_count(count: result.count)
: context.t.scaffold_body_error_occurred;
ImmichToast.show(
context: context,
msg: message,
@ -49,12 +49,12 @@ class KeepOnDeviceActionButton extends ConsumerWidget {
? BaseActionButton(
maxWidth: 110.0,
iconData: iconData,
label: 'keep'.t(),
label: context.t.keep,
onPressed: () => _onTap(context, ref),
)
: TextButton.icon(
icon: const Icon(iconData),
label: Text('keep_on_device'.t(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
label: Text(context.t.keep_on_device, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
onPressed: () => _onTap(context, ref),
);
}

View file

@ -1,10 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/extensions/platform_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart';
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
@ -17,8 +16,8 @@ void showTrashResultToast(BuildContext context, ActionResult result) {
return;
}
final message = result.success
? 'assets_moved_to_trash_count'.t(args: {'count': '${result.count}'})
: 'errors.something_went_wrong'.t();
? context.t.assets_moved_to_trash_count(count: result.count)
: context.t.errors.something_went_wrong;
ImmichToast.show(
context: context,
msg: message,
@ -56,14 +55,14 @@ class MoveToTrashActionButton extends ConsumerWidget {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('asset_out_of_sync_trash_confirmation_title'.tr()),
content: Text('asset_out_of_sync_trash_confirmation_text'.t(args: {'count': '$selectedCount'})),
title: Text(context.t.trash_review_confirmation_title),
content: Text(context.t.trash_review_confirmation_text(count: selectedCount)),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(false), child: Text('cancel'.tr())),
TextButton(onPressed: () => Navigator.of(context).pop(false), child: Text(context.t.cancel)),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
style: TextButton.styleFrom(foregroundColor: Theme.of(context).colorScheme.error),
child: Text('control_bottom_app_bar_trash_from_immich'.tr()),
child: Text(context.t.control_bottom_app_bar_trash_from_immich),
),
],
);
@ -91,13 +90,13 @@ class MoveToTrashActionButton extends ConsumerWidget {
? BaseActionButton(
maxWidth: 100.0,
iconData: iconData,
label: 'delete'.tr(),
label: context.t.delete,
onPressed: () => _onTap(context, ref),
)
: TextButton.icon(
icon: Icon(iconData, color: Colors.red[400]),
label: Text(
'control_bottom_app_bar_trash_from_immich'.tr(),
context.t.control_bottom_app_bar_trash_from_immich,
style: TextStyle(fontSize: 14, color: Colors.red[400], fontWeight: FontWeight.bold),
),
onPressed: () => _onTap(context, ref),

View file

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/models/server_info/server_disk_info.model.dart';
import 'package:immich_mobile/pages/common/settings.page.dart';
import 'package:immich_mobile/providers/auth.provider.dart';
@ -121,7 +121,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
contentPadding: const EdgeInsets.only(left: 18, right: 18),
minLeadingWidth: 40,
leading: Icon(Icons.warning_amber_rounded, color: textColor, size: 20),
title: Text('review_out_of_sync_changes'.t(), style: textStyle),
title: Text(context.t.trash_review_banner_title, style: textStyle),
onTap: () => context.pushRoute(const DriftTrashReviewRoute()),
trailing: Text('($outOfSyncCount)', style: textStyle),
),

View file

@ -8,6 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/services/log.service.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
@ -160,10 +161,9 @@ class _TrashSyncModeSelector extends HookConsumerWidget {
final manageMediaAndroidPermission = ref.watch(_manageMediaPermissionProvider);
final manageMediaAndroidPermissionValue = manageMediaAndroidPermission.valueOrNull;
final isTrashSyncEnabled = selectedTrashSyncMode != TrashSyncMode.off;
final reviewRemoteDeletionsSubtitle = [
"advanced_settings_review_remote_deletions_subtitle".tr(),
if (Platform.isAndroid) "advanced_settings_review_remote_deletions_subtitle_android".tr(),
].join(' ');
final reviewRemoteDeletionsSubtitle = Platform.isAndroid
? context.t.advanced_settings_review_remote_deletions_subtitle_android
: context.t.advanced_settings_review_remote_deletions_subtitle;
void showManageMediaRequiredSnackBar() {
if (!context.mounted) {
@ -172,7 +172,7 @@ class _TrashSyncModeSelector extends HookConsumerWidget {
context.scaffoldMessenger.showSnackBar(
SnackBar(
content: Text(
"manage_media_access_review_rationale".tr(),
context.t.manage_media_access_review_rationale,
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
),
),
@ -224,7 +224,7 @@ class _TrashSyncModeSelector extends HookConsumerWidget {
Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(
"advanced_settings_sync_remote_deletions_selector_title".tr(),
context.t.advanced_settings_sync_remote_deletions_selector_title,
style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500, height: 1.5),
),
),
@ -233,18 +233,18 @@ class _TrashSyncModeSelector extends HookConsumerWidget {
child: SettingsRadioListTile<TrashSyncMode>(
groups: [
SettingsRadioGroup(
title: 'off'.tr(),
subtitle: 'advanced_settings_sync_remote_deletions_off_subtitle'.tr(),
title: context.t.off,
subtitle: context.t.advanced_settings_sync_remote_deletions_off_subtitle,
value: TrashSyncMode.off,
),
if (!Platform.isIOS)
SettingsRadioGroup(
title: 'advanced_settings_sync_remote_deletions_title'.tr(),
subtitle: 'advanced_settings_sync_remote_deletions_subtitle'.tr(),
title: context.t.advanced_settings_sync_remote_deletions_title,
subtitle: context.t.advanced_settings_sync_remote_deletions_subtitle,
value: TrashSyncMode.autoSync,
),
SettingsRadioGroup(
title: 'advanced_settings_review_remote_deletions_title'.tr(),
title: context.t.advanced_settings_review_remote_deletions_title,
subtitle: reviewRemoteDeletionsSubtitle,
value: TrashSyncMode.review,
),
@ -255,13 +255,13 @@ class _TrashSyncModeSelector extends HookConsumerWidget {
),
if (Platform.isAndroid)
SettingsActionTile(
title: "manage_media_access_title".tr(),
title: context.t.manage_media_access_title,
statusText: manageMediaAndroidPermissionValue == null
? null
: manageMediaAndroidPermissionValue == true
? "allowed".tr()
: "not_allowed".tr(),
subtitle: "manage_media_access_rationale".tr(),
? context.t.allowed
: context.t.not_allowed,
subtitle: context.t.manage_media_access_rationale,
statusColor: manageMediaAndroidPermissionValue == false && isTrashSyncEnabled
? const Color.fromARGB(255, 243, 188, 106)
: null,