Files
photo-live/apps/mobile/lib/l10n/app_en.arb
T
浅念 7e5c550fb3 feat(app): block selecting already-uploaded photos at picker tap (double-tap to force)
方案 A(选图点选拦截):multiImagePickerProvider 经 wechat_assets_picker
10.1.3 官方钩子 AssetPickerConfig.selectPredicate 挂 PickerDuplicateGate——
点选「已上传到目标相册」的照片当场拦下(SnackBar 提示),再次点击同一张
强制选择(escape hatch)。

- MultiImagePicker typedef 增参 accountId/albumId(拦截判定范围=当前
  目标相册;相册详情/连拍页两处调用点传入);
- 判定口径同 checkDuplicatesUnified:本机 TaskStore(同账号+相册+
  completed,filename+bytes)∪ 服务器单项预检(bytes;本机命中短路
  服务器,点选延迟考量);任一半场异常按该半场无命中,fileSize 失败等
  整体异常直接放行——enqueue 弹窗 + init 409 兜底不变;
- per-asset 判定缓存(二次点击瞬回)+ 二次点击放行集;取消选择恒放行
  且不预热放行集;
- AssetEntity 事实适配(PickerAssetFact 测试接缝):fileSize 为
  photo_manager 3.12 的 Future<int> 平台通道 getter(entity.dart:778),
  惰性求值;title 为 String?(Android 恒有值;iOS 需 needTitle——null
  时本机半场跳过,服务器按 bytes 仍可判);
- l10n pickerDuplicateBlocked(zh/en);测试替身签名同步
  (album_detail/capture_page 页测 + integration_test app_boot),
  页测补 (accountId, albumId) 接线断言;gate 五态用例入 enqueue_test。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 10:10:49 +08:00

441 lines
17 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"@@locale": "en",
"appName": "Photo Live",
"login": "Sign in",
"logout": "Sign out",
"username": "Account",
"password": "Password",
"albums": "Albums",
"albumDetail": "Album details",
"queue": "Uploads",
"settings": "Settings",
"language": "Language",
"settingsSectionAccount": "Account",
"settingsSectionLanguage": "Language",
"settingsSectionSecurity": "Security",
"settingsSectionUploadHelp": "Upload help",
"settingsSectionAbout": "About",
"settingsSignedInAccount": "Currently signed-in account",
"settingsVersion": "Version",
"settingsUploadHelpTitle": "How background uploads work",
"settingsUploadHelpBody": "While the app stays in the background, the system keeps uploads running within its battery limits. If you force quit the app or the system stops it, unfinished tasks pause and resume the next time you open the app. Tasks waiting for the network start automatically once a connection is available — no manual retry needed.",
"logoutConfirmTitle": "Sign out?",
"logoutConfirmBody": "Local upload tasks are preserved on this device and will resume when you sign back in.",
"localeFollowSystem": "Follow system",
"localeChinese": "中文",
"localeEnglish": "English",
"retry": "Retry",
"cancel": "Cancel",
"errorGeneric": "Something went wrong, please retry",
"ok": "OK",
"navAlbums": "Albums",
"navUploads": "Uploads",
"navSettings": "Settings",
"badgeUploading": "{count} tasks",
"@badgeUploading": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"albumUploadsOn": "Uploads on",
"albumUploadsOff": "Uploads off",
"albumPublicOff": "Not public",
"loginHint": "Sign in with your staff account",
"loginTitle": "Your event. In focus.",
"loginSubtitle": "Sign in to manage albums and photos",
"loginAskAdmin": "Ask admin for account",
"loginShowPassword": "Show password",
"loginHidePassword": "Hide password",
"languageDone": "Done",
"passwordSecurityHint": "Choose a new password with at least 8 characters.",
"passwordSave": "Save password",
"settingsSectionGeneral": "General",
"logoutConfirmBodyIdle": "You will be signed out on this device.",
"fieldRequired": "This field is required",
"passwordChangeTitle": "Change password",
"currentPassword": "Current password",
"newPassword": "New password",
"confirmNewPassword": "Confirm new password",
"passwordMinLength": "New password must be at least 8 characters",
"passwordMismatch": "New passwords do not match",
"passwordChangeSuccess": "Password changed",
"errorAuthInvalidCredentials": "Incorrect account or password",
"errorOldPasswordIncorrect": "Current password is incorrect",
"errorAuthRateLimited": "Too many attempts. Please try again later",
"errorAuthTokenExpired": "Session expired. Please sign in again",
"errorValidation": "Invalid input. Please check and retry",
"errorNetwork": "Network error. Check your connection and retry",
"errorNetworkTimeout": "Network timed out. Please retry",
"errorInternal": "Service temporarily unavailable. Please retry later",
"albumsEmpty": "No albums yet. Tap \"Create album\" to get started",
"loadMoreFailed": "Failed to load more. Tap to retry",
"albumCreate": "Create album",
"albumTitle": "Title",
"albumDescription": "Description",
"albumVenue": "Venue",
"albumAddress": "Address",
"albumStartAt": "Start time",
"albumEndAtOptional": "End time (optional)",
"clearEndAt": "Clear end time",
"albumTimezone": "Timezone",
"albumTimezoneInvalid": "Invalid IANA timezone name",
"formStartAtRequired": "Pick a start time",
"formDefaultLocaleMissing": "Default locale must have a title",
"formTitleRequiredWithFields": "Title is required when description, venue or address is filled",
"formEndAtNotAfterStartAt": "End time must be after start time",
"formEventDetails": "Event details",
"coverPicker": "Album cover",
"coverPickerHint": "Tap to select a cover image (optional)",
"coverSelected": "Cover selected, will upload on save",
"coverUploadFailed": "Cover upload failed, you can retry from album detail later",
"formDescriptionLanguages": "Description & languages",
"formDefaultLanguage": "Default language",
"formDetailsTab": "Details",
"formAccessTab": "Access",
"formAllowUploads": "Allow uploads",
"formAllowUploadsDesc": "Allow staff to upload photos to this album",
"formPublicAccess": "Public access",
"formPublicAccessDesc": "Anyone with the link can view photos",
"formAllowDownloads": "Allow downloads",
"formAllowDownloadsDesc": "Viewers can download browse-quality photos",
"formOriginalDownloads": "Original downloads",
"formOriginalDownloadsDesc": "Viewers can download original photos",
"createAlbumTitle": "Create album",
"createAlbumSubmit": "Create album",
"editAlbumTitle": "Edit album",
"saveChanges": "Save changes",
"unsavedChangesTitle": "Discard changes?",
"unsavedChangesBody": "Your edits are not saved yet. Leaving now will discard them.",
"discardChanges": "Discard",
"keepEditing": "Keep editing",
"create": "Create",
"save": "Save",
"albumStatusActive": "Active",
"albumStatusOffline": "Offline",
"tagUpload": "Upload",
"tagPublic": "Public",
"tagDownload": "Download",
"tagOriginal": "Original",
"notSet": "Not set",
"actionEdit": "Edit",
"membersTitle": "Members",
"membersTitleCount": "Members ({count})",
"@membersTitleCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"ownerGroup": "Owner",
"collaboratorsGroup": "Collaborators",
"noCollaborators": "No collaborators yet",
"inviteColleague": "Invite colleague",
"alreadyAdded": "Already added",
"add": "Add",
"categoriesTitle": "Categories",
"newCategory": "New category",
"editCategory": "Edit category",
"deleteCategoryConfirm": "Delete \"{name}\"? Its photos will become uncategorized.",
"@deleteCategoryConfirm": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"noCategories": "No categories yet",
"albumCategories": "Categories",
"shareQrTitle": "Share QR code",
"albumPhotos": "Photos",
"delete": "Delete",
"categoryNameZh": "Chinese name",
"categoryNameEn": "English name",
"categorySortOrder": "Sort order",
"categoryNameRequired": "At least one language name is required",
"categorySortOrderInvalid": "Sort order must be an integer",
"inviteSearchHint": "Search by account prefix to invite (at least 2 characters)",
"inviteNoResults": "No matching users",
"memberInvited": "Invited",
"removeMember": "Remove member",
"removeMemberConfirm": "Remove {name} from this album?",
"@removeMemberConfirm": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"roleOwner": "Owner",
"roleCollaborator": "Collaborator",
"selfMarker": " (you)",
"errorMemberConflict": "User is already a member",
"qrHint": "Scan the code or open the link to view",
"copyLink": "Copy link",
"copiedToClipboard": "Copied",
"openInBrowser": "Open in browser",
"photosTask9Placeholder": "Photo management is a placeholder; the full experience ships in Task 9",
"albumPhotosEmpty": "No photos yet",
"visibilityPublished": "Published",
"visibilityUnpublished": "Unpublished",
"visibilityHidden": "Hidden",
"visibilityDeleted": "Deleted",
"procPendingUpload": "Pending upload",
"procUploaded": "Uploaded",
"procProcessing": "Processing",
"procReady": "Ready",
"procProcessingFailed": "Processing failed",
"queueStubHint": "Local upload queue and continuous capture arrive in Task 9",
"serverHistoryEntry": "Server history",
"serverHistoryTitle": "Server history (cross-device)",
"serverHistoryBanner": "Upload records from all of your devices. The local queue is on the Uploads tab.",
"serverHistoryEmpty": "No upload sessions yet",
"uploadStatePending": "Pending",
"uploadStateConfirmed": "Confirmed",
"uploadStateCancelled": "Cancelled",
"uploadStateExpired": "Expired",
"thisDevice": "This device",
"queueAlbumFilterAll": "All albums",
"queueStateAll": "All",
"queueStateInProgress": "In progress",
"queueStateNeedsAttention": "Needs attention",
"queueStateCompleted": "Completed",
"queueSummaryCompleted": "completed",
"queueSummaryUploading": "uploading",
"queueSummaryWaiting": "waiting",
"queueSummaryNeedAttention": "need attention",
"queueRowUploadingPercent": "Uploading {percent}%",
"@queueRowUploadingPercent": {
"placeholders": {
"percent": {
"type": "int"
}
}
},
"queueRowConfirming": "Confirming upload",
"queueRowWaitingUpload": "Waiting to upload",
"queueRowPreparing": "Preparing photo",
"queueWaitingNetworkHint": "Resumes automatically when the network recovers",
"queueRowFileUnavailable": "File unavailable",
"queueActionSelectAgain": "Select again",
"queueActionRemoveRecord": "Remove record",
"queueRemoveRecordTitle": "Remove this record?",
"queueRemoveRecordBody": "This only removes the local task record. Photos already uploaded are not deleted from the cloud.",
"queueRemoveRecordConfirm": "Remove",
"queueRetryAllScope": "Only failed uploads on this device are retried. Tasks waiting for the network recover automatically.",
"queueTimeAll": "Any time",
"queueTimeToday": "Today",
"queueTimeLast7Days": "Last 7 days",
"queueTimeLast30Days": "Last 30 days",
"queueEmpty": "No upload tasks",
"queueRetryAllFailed": "Retry all failed",
"queueAttemptCount": "{count} attempt(s)",
"@queueAttemptCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"captureQueued": "{count} queued",
"@captureQueued": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"captureFlipCamera": "Switch camera",
"captureFlash": "Flash",
"uploadsHistory": "History",
"uploadsToday": "Today",
"uploadsThisDevice": "This device",
"uploadsCompleted": "completed",
"uploadsUploading": "uploading",
"uploadsWaiting": "waiting",
"uploadsNeedsAttention": "Needs attention",
"uploadsAll": "All",
"uploadsActive": "Active",
"uploadsConfirming": "Confirming…",
"uploadsWaitingUpload": "Waiting to upload",
"uploadsWaitingNetwork": "Waiting for network",
"uploadsFileUnavailable": "File unavailable",
"uploadsSelectAgain": "Select again",
"uploadsRemoveRecord": "Remove record",
"uploadsRemoveRecordConfirm": "Remove",
"uploadsRetryEligible": "Retry eligible",
"uploadsRetryEligibleScope": "Retries failed uploads that can recover on their own. Files marked unavailable need to be selected again.",
"uploadsNoNeedsAttention": "No tasks need attention",
"uploadsShowingNeedsAttention": "Showing tasks that need your attention",
"uploadsFilters": "Filters",
"serverRecords": "Server records",
"serverSubtitle": "All devices · Your account",
"serverConfirmed": "Confirmed",
"serverReady": "Ready",
"serverProcessing": "Processing",
"serverDeviceUnknown": "Unknown device",
"taskStatePreparing": "Preparing",
"taskStatePreparationFailed": "Preparation failed",
"taskStateQueued": "Queued",
"taskStateUploading": "Uploading",
"taskStateUploadedConfirming": "Confirming",
"taskStateCompleted": "Completed",
"taskStateWaitingNetwork": "Waiting for network",
"taskStateRetryableFailed": "Upload failed",
"taskStateCancelled": "Cancelled",
"errorPrepSourceUnreadable": "Could not read the selected photo. Please reselect",
"errorPrepUnsupportedType": "Only JPG, PNG and HEIC images are supported",
"errorPrepTooLarge": "Photo exceeds the 50MB limit",
"errorPrepCopyFailed": "Failed to copy the photo. Please retry",
"errorUploadSourceMissing": "Source file is missing. Please reselect",
"errorAlbumUploadDisabled": "Album uploads are disabled",
"errorUploadSessionConflict": "Upload session conflict. Please retry",
"errorUploadVerifyFailed": "Upload verification failed. Will retry",
"errorPhotoDuplicate": "Possible duplicate: an identical photo already exists in this album",
"captureTitle": "Continuous capture",
"captureCategoryDefault": "Default category",
"captureSwitchHint": "Switching only affects photos captured afterwards",
"capturePendingBadge": "Pending {count}",
"@capturePendingBadge": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"captureFailedBadge": "Failed {count}",
"@captureFailedBadge": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"capturePickFromGallery": "Pick from gallery",
"captureShutter": "Capture",
"captureQueuedBadge": "Queued {count}",
"@captureQueuedBadge": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"captureEnqueuedFeedback": "Added to queue",
"captureExitTitle": "Leave shooting?",
"captureExitBody": "{count} photo(s) are still uploading. Tasks will continue in the background after you leave.",
"@captureExitBody": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"captureKeepShooting": "Keep shooting",
"captureExitConfirm": "Leave",
"cameraPermissionDenied": "Camera unavailable. Allow camera access in system settings",
"cameraInitFailed": "Camera failed to initialize",
"uploadActionCapture": "Capture and upload",
"uploadActionPick": "Pick from gallery",
"uploadAction": "Upload",
"uploadEnqueuedCount": "Added {count} photo(s) to the upload queue",
"@uploadEnqueuedCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"uploadPickNone": "No photos selected",
"pickerDuplicateBlocked": "Already uploaded to this album — tap again to select anyway",
"albumManagePhotos": "Manage photos",
"albumTakeFirstPhoto": "Take the first photo",
"albumUploadDisabledHint": "Uploads are off for this album. New photos cannot be added right now",
"albumRecentPhotos": "Recent uploads",
"photoFilterAll": "All",
"photoFilterFailed": "Failed",
"photosScopeOwnHint": "Collaborator view: only photos you uploaded are shown",
"photosEmptyFiltered": "No photos match this filter",
"photoHide": "Hide",
"photoUnhide": "Unhide",
"photoDeleteConfirmTitle": "Delete this photo?",
"photoDeleteConfirmBody": "This will soft-delete the photo. It can be managed by admins. Cloud storage is not immediately purged.",
"photoHiddenToast": "Hidden",
"photoUnhiddenToast": "Unhidden",
"photoDeletedToast": "Deleted",
"photoReload": "Reload",
"photoPreviewUnavailable": "Image unavailable",
"albumsSubtitle": "Organize and manage event photos",
"actionPhotos": "Photos",
"actionMembers": "Members",
"actionCategories": "Categories",
"actionShare": "Share",
"recentPhotos": "Recent photos",
"seeAllPhotos": "See all",
"editAlbum": "Edit album",
"manageMembers": "Manage members",
"shareAlbum": "Share album",
"emptyAlbumTitle": "Ready for your first photo",
"emptyAlbumSubtitle": "Photos you take or pick will appear here",
"processingPhotos": "Processing...",
"readonlyMember": "You can browse photos shared by others",
"moreActions": "More actions",
"photosTitle": "{count} photos",
"@photosTitle": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"photoUploadedBy": "Uploaded by {name}",
"@photoUploadedBy": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"photoDimensions": "{width}×{height}",
"@photoDimensions": {
"placeholders": {
"width": {
"type": "int"
},
"height": {
"type": "int"
}
}
},
"photoStatus": "Status",
"photoHideAction": "Hide photo",
"photoPublishAction": "Publish again",
"shareScanHint": "Scan to view photos",
"shareNotPublic": "This link is not publicly accessible yet",
"hidePhotoTitle": "Hide this photo?",
"hidePhotoBody": "Viewers will no longer see this photo. Authorized album managers can publish it again.",
"deleteAlbum": "Delete album",
"deleteAlbumConfirmTitle": "Delete this album?",
"deleteAlbumConfirmBody": "The album becomes invisible immediately and cannot be restored. Data is retained; recovery requires operations.",
"albumDeleted": "Album deleted",
"bannerPicker": "Banner",
"bannerPickerHint": "Tap to pick a banner image (shown atop the viewer page)",
"bannerSelected": "Banner selected — will upload on save",
"bannerUploadFailed": "Banner upload failed",
"shareCardMode": "Share to...",
"sharePosterMode": "Generate QR poster",
"posterDownload": "Download poster image",
"posterSaved": "Poster saved to gallery",
"posterSaveFailed": "Failed to save poster",
"close": "Close",
"albumUploadDisabled": "Upload is disabled for this album",
"networkOfflineBanner": "No network. Photos will upload automatically when reconnected.",
"cropTitle": "Crop image",
"cropConfirm": "Done",
"cropCancel": "Cancel",
"cropProcessing": "Processing…",
"cropUnsupportedFormat": "This image format isn't supported yet — please pick JPG/PNG"
}