feat(mobile): UI-03 forms and collaboration pages (09-12)

- Page 09 create: grouped form (Event details / Description & languages),
  required default-language selector, zh-CN/en tabs with per-locale
  title/description/venue/address, explicit timezone field, bottom save
  button kept keyboard-reachable, create mode has no Access tab
- Page 10 edit: Details/Access tabs sharing one draft; Access has four
  switches with explanations; original downloads constrained by downloads
  (disabled + forced off in PATCH); unsaved-changes PopScope confirm;
  save commits all changes in one minimal PATCH
- Page 11 members: Owner group + Collaborators list with initial avatars
  and per-row remove; full-width Invite colleague opens account-search
  bottom sheet (debounced prefix search, race guard, already-added state);
  remove confirm names the member
- Page 12 categories: extracted to standalone page with per-row edit/
  delete menu and New category sheet (language tabs + name + sort order);
  delete confirm mentions photo impact; collaborator browse-only; old
  inline section removed from album detail
- l10n: new form/members/categories keys both locales; regenerated
- tests: form 14, members 6, categories 7, detail nav 1; full suite green

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-22 01:23:02 +08:00
parent 5715c608d8
commit 8bd09eefb9
13 changed files with 2322 additions and 1184 deletions
+38 -17
View File
@@ -66,28 +66,40 @@
"albumsEmpty": "No albums yet. Tap \"Create album\" to get started",
"loadMoreFailed": "Failed to load more. Tap to retry",
"albumCreate": "Create album",
"albumEdit": "Edit album",
"albumSectionEventInfo": "Event info",
"albumSectionContent": "Multilingual content",
"albumSectionAccess": "Access settings",
"albumTitle": "Title",
"albumDescription": "Description",
"albumVenue": "Venue",
"albumAddress": "Address",
"albumDefaultLocale": "Default locale",
"albumStartAt": "Start time",
"albumEndAtOptional": "End time (optional)",
"clearEndAt": "Clear end time",
"albumTimezone": "Timezone",
"albumTimezoneInvalid": "Invalid IANA timezone name",
"switchUpload": "Allow uploads",
"switchPublic": "Publicly visible",
"switchDownload": "Allow downloads",
"switchOriginalDownload": "Allow original downloads",
"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",
"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",
@@ -98,27 +110,36 @@
"tagOriginal": "Original",
"notSet": "Not set",
"actionEdit": "Edit",
"albumMembers": "Members",
"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",
"deleteConfirmCategory": "Delete this category? Its photos will become uncategorized.",
"categoryEmpty": "No categories yet. Tap + to add one",
"categoryAdd": "Add category",
"categoryEdit": "Edit category",
"categoryNameZh": "Chinese name",
"categoryNameEn": "English name",
"categorySortOrder": "Sort order",
"categoryNameRequired": "At least one language name is required",
"categorySortOrderInvalid": "Sort order must be an integer",
"albumMembersEmpty": "No members yet",
"inviteSearchHint": "Search by account prefix to invite (at least 2 characters)",
"inviteNoResults": "No matching users",
"invite": "Invite",
"memberInvited": "Invited",
"removeMember": "Remove member",
"removeMemberConfirm": "Remove this member?",
"removeMemberConfirm": "Remove {name} from this album?",
"@removeMemberConfirm": { "placeholders": { "name": { "type": "String" } } },
"roleOwner": "Owner",
"roleCollaborator": "Collaborator",
"selfMarker": " (you)",
+203 -95
View File
@@ -488,30 +488,6 @@ abstract class AppLocalizations {
/// **'新建相册'**
String get albumCreate;
/// No description provided for @albumEdit.
///
/// In zh, this message translates to:
/// **'编辑相册'**
String get albumEdit;
/// No description provided for @albumSectionEventInfo.
///
/// In zh, this message translates to:
/// **'活动信息'**
String get albumSectionEventInfo;
/// No description provided for @albumSectionContent.
///
/// In zh, this message translates to:
/// **'多语言内容'**
String get albumSectionContent;
/// No description provided for @albumSectionAccess.
///
/// In zh, this message translates to:
/// **'访问设置'**
String get albumSectionAccess;
/// No description provided for @albumTitle.
///
/// In zh, this message translates to:
@@ -536,12 +512,6 @@ abstract class AppLocalizations {
/// **'地址'**
String get albumAddress;
/// No description provided for @albumDefaultLocale.
///
/// In zh, this message translates to:
/// **'默认语言'**
String get albumDefaultLocale;
/// No description provided for @albumStartAt.
///
/// In zh, this message translates to:
@@ -572,30 +542,6 @@ abstract class AppLocalizations {
/// **'无效的 IANA 时区名称'**
String get albumTimezoneInvalid;
/// No description provided for @switchUpload.
///
/// In zh, this message translates to:
/// **'允许上传'**
String get switchUpload;
/// No description provided for @switchPublic.
///
/// In zh, this message translates to:
/// **'公开可见'**
String get switchPublic;
/// No description provided for @switchDownload.
///
/// In zh, this message translates to:
/// **'允许下载'**
String get switchDownload;
/// No description provided for @switchOriginalDownload.
///
/// In zh, this message translates to:
/// **'允许下载原图'**
String get switchOriginalDownload;
/// No description provided for @formStartAtRequired.
///
/// In zh, this message translates to:
@@ -620,6 +566,132 @@ abstract class AppLocalizations {
/// **'结束时间必须晚于开始时间'**
String get formEndAtNotAfterStartAt;
/// No description provided for @formEventDetails.
///
/// In zh, this message translates to:
/// **'活动信息'**
String get formEventDetails;
/// No description provided for @formDescriptionLanguages.
///
/// In zh, this message translates to:
/// **'描述与语言'**
String get formDescriptionLanguages;
/// No description provided for @formDefaultLanguage.
///
/// In zh, this message translates to:
/// **'默认语言'**
String get formDefaultLanguage;
/// No description provided for @formDetailsTab.
///
/// In zh, this message translates to:
/// **'详情'**
String get formDetailsTab;
/// No description provided for @formAccessTab.
///
/// In zh, this message translates to:
/// **'访问'**
String get formAccessTab;
/// No description provided for @formAllowUploads.
///
/// In zh, this message translates to:
/// **'允许上传'**
String get formAllowUploads;
/// No description provided for @formAllowUploadsDesc.
///
/// In zh, this message translates to:
/// **'允许工作人员向该相册上传照片'**
String get formAllowUploadsDesc;
/// No description provided for @formPublicAccess.
///
/// In zh, this message translates to:
/// **'公开访问'**
String get formPublicAccess;
/// No description provided for @formPublicAccessDesc.
///
/// In zh, this message translates to:
/// **'任何获得链接的人都可以查看照片'**
String get formPublicAccessDesc;
/// No description provided for @formAllowDownloads.
///
/// In zh, this message translates to:
/// **'允许下载'**
String get formAllowDownloads;
/// No description provided for @formAllowDownloadsDesc.
///
/// In zh, this message translates to:
/// **'观众可以下载浏览质量的照片'**
String get formAllowDownloadsDesc;
/// No description provided for @formOriginalDownloads.
///
/// In zh, this message translates to:
/// **'下载原图'**
String get formOriginalDownloads;
/// No description provided for @formOriginalDownloadsDesc.
///
/// In zh, this message translates to:
/// **'观众可以下载原图照片'**
String get formOriginalDownloadsDesc;
/// No description provided for @createAlbumTitle.
///
/// In zh, this message translates to:
/// **'新建相册'**
String get createAlbumTitle;
/// No description provided for @createAlbumSubmit.
///
/// In zh, this message translates to:
/// **'新建相册'**
String get createAlbumSubmit;
/// No description provided for @editAlbumTitle.
///
/// In zh, this message translates to:
/// **'编辑相册'**
String get editAlbumTitle;
/// No description provided for @saveChanges.
///
/// In zh, this message translates to:
/// **'保存修改'**
String get saveChanges;
/// No description provided for @unsavedChangesTitle.
///
/// In zh, this message translates to:
/// **'放弃修改?'**
String get unsavedChangesTitle;
/// No description provided for @unsavedChangesBody.
///
/// In zh, this message translates to:
/// **'修改尚未保存,离开将丢失这些修改。'**
String get unsavedChangesBody;
/// No description provided for @discardChanges.
///
/// In zh, this message translates to:
/// **'放弃'**
String get discardChanges;
/// No description provided for @keepEditing.
///
/// In zh, this message translates to:
/// **'继续编辑'**
String get keepEditing;
/// No description provided for @create.
///
/// In zh, this message translates to:
@@ -680,11 +752,83 @@ abstract class AppLocalizations {
/// **'编辑'**
String get actionEdit;
/// No description provided for @albumMembers.
/// No description provided for @membersTitle.
///
/// In zh, this message translates to:
/// **'成员管理'**
String get albumMembers;
/// **'成员'**
String get membersTitle;
/// No description provided for @membersTitleCount.
///
/// In zh, this message translates to:
/// **'成员({count})'**
String membersTitleCount(int count);
/// No description provided for @ownerGroup.
///
/// In zh, this message translates to:
/// **'创建者'**
String get ownerGroup;
/// No description provided for @collaboratorsGroup.
///
/// In zh, this message translates to:
/// **'协作者'**
String get collaboratorsGroup;
/// No description provided for @noCollaborators.
///
/// In zh, this message translates to:
/// **'还没有协作者'**
String get noCollaborators;
/// No description provided for @inviteColleague.
///
/// In zh, this message translates to:
/// **'邀请同事'**
String get inviteColleague;
/// No description provided for @alreadyAdded.
///
/// In zh, this message translates to:
/// **'已添加'**
String get alreadyAdded;
/// No description provided for @add.
///
/// In zh, this message translates to:
/// **'添加'**
String get add;
/// No description provided for @categoriesTitle.
///
/// In zh, this message translates to:
/// **'分类'**
String get categoriesTitle;
/// No description provided for @newCategory.
///
/// In zh, this message translates to:
/// **'新增分类'**
String get newCategory;
/// No description provided for @editCategory.
///
/// In zh, this message translates to:
/// **'编辑分类'**
String get editCategory;
/// No description provided for @deleteCategoryConfirm.
///
/// In zh, this message translates to:
/// **'删除「{name}」?该分类下的照片将变为未分类。'**
String deleteCategoryConfirm(String name);
/// No description provided for @noCategories.
///
/// In zh, this message translates to:
/// **'暂无分类'**
String get noCategories;
/// No description provided for @albumCategories.
///
@@ -710,30 +854,6 @@ abstract class AppLocalizations {
/// **'删除'**
String get delete;
/// No description provided for @deleteConfirmCategory.
///
/// In zh, this message translates to:
/// **'确定删除该分类?该分类下的照片将变为未分类。'**
String get deleteConfirmCategory;
/// No description provided for @categoryEmpty.
///
/// In zh, this message translates to:
/// **'暂无分类,点击右上角新增'**
String get categoryEmpty;
/// No description provided for @categoryAdd.
///
/// In zh, this message translates to:
/// **'新增分类'**
String get categoryAdd;
/// No description provided for @categoryEdit.
///
/// In zh, this message translates to:
/// **'编辑分类'**
String get categoryEdit;
/// No description provided for @categoryNameZh.
///
/// In zh, this message translates to:
@@ -764,12 +884,6 @@ abstract class AppLocalizations {
/// **'排序序号必须是整数'**
String get categorySortOrderInvalid;
/// No description provided for @albumMembersEmpty.
///
/// In zh, this message translates to:
/// **'暂无成员'**
String get albumMembersEmpty;
/// No description provided for @inviteSearchHint.
///
/// In zh, this message translates to:
@@ -782,12 +896,6 @@ abstract class AppLocalizations {
/// **'未找到匹配用户'**
String get inviteNoResults;
/// No description provided for @invite.
///
/// In zh, this message translates to:
/// **'邀请'**
String get invite;
/// No description provided for @memberInvited.
///
/// In zh, this message translates to:
@@ -803,8 +911,8 @@ abstract class AppLocalizations {
/// No description provided for @removeMemberConfirm.
///
/// In zh, this message translates to:
/// **'确定移除该成员?'**
String get removeMemberConfirm;
/// **'确定将 {name} 从该相册移除?'**
String removeMemberConfirm(String name);
/// No description provided for @roleOwner.
///
+111 -48
View File
@@ -211,18 +211,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get albumCreate => 'Create album';
@override
String get albumEdit => 'Edit album';
@override
String get albumSectionEventInfo => 'Event info';
@override
String get albumSectionContent => 'Multilingual content';
@override
String get albumSectionAccess => 'Access settings';
@override
String get albumTitle => 'Title';
@@ -235,9 +223,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get albumAddress => 'Address';
@override
String get albumDefaultLocale => 'Default locale';
@override
String get albumStartAt => 'Start time';
@@ -253,18 +238,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get albumTimezoneInvalid => 'Invalid IANA timezone name';
@override
String get switchUpload => 'Allow uploads';
@override
String get switchPublic => 'Publicly visible';
@override
String get switchDownload => 'Allow downloads';
@override
String get switchOriginalDownload => 'Allow original downloads';
@override
String get formStartAtRequired => 'Pick a start time';
@@ -278,6 +251,73 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get formEndAtNotAfterStartAt => 'End time must be after start time';
@override
String get formEventDetails => 'Event details';
@override
String get formDescriptionLanguages => 'Description & languages';
@override
String get formDefaultLanguage => 'Default language';
@override
String get formDetailsTab => 'Details';
@override
String get formAccessTab => 'Access';
@override
String get formAllowUploads => 'Allow uploads';
@override
String get formAllowUploadsDesc =>
'Allow staff to upload photos to this album';
@override
String get formPublicAccess => 'Public access';
@override
String get formPublicAccessDesc => 'Anyone with the link can view photos';
@override
String get formAllowDownloads => 'Allow downloads';
@override
String get formAllowDownloadsDesc =>
'Viewers can download browse-quality photos';
@override
String get formOriginalDownloads => 'Original downloads';
@override
String get formOriginalDownloadsDesc =>
'Viewers can download original photos';
@override
String get createAlbumTitle => 'Create album';
@override
String get createAlbumSubmit => 'Create album';
@override
String get editAlbumTitle => 'Edit album';
@override
String get saveChanges => 'Save changes';
@override
String get unsavedChangesTitle => 'Discard changes?';
@override
String get unsavedChangesBody =>
'Your edits are not saved yet. Leaving now will discard them.';
@override
String get discardChanges => 'Discard';
@override
String get keepEditing => 'Keep editing';
@override
String get create => 'Create';
@@ -309,7 +349,47 @@ class AppLocalizationsEn extends AppLocalizations {
String get actionEdit => 'Edit';
@override
String get albumMembers => 'Members';
String get membersTitle => 'Members';
@override
String membersTitleCount(int count) {
return 'Members ($count)';
}
@override
String get ownerGroup => 'Owner';
@override
String get collaboratorsGroup => 'Collaborators';
@override
String get noCollaborators => 'No collaborators yet';
@override
String get inviteColleague => 'Invite colleague';
@override
String get alreadyAdded => 'Already added';
@override
String get add => 'Add';
@override
String get categoriesTitle => 'Categories';
@override
String get newCategory => 'New category';
@override
String get editCategory => 'Edit category';
@override
String deleteCategoryConfirm(String name) {
return 'Delete \"$name\"? Its photos will become uncategorized.';
}
@override
String get noCategories => 'No categories yet';
@override
String get albumCategories => 'Categories';
@@ -323,19 +403,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get delete => 'Delete';
@override
String get deleteConfirmCategory =>
'Delete this category? Its photos will become uncategorized.';
@override
String get categoryEmpty => 'No categories yet. Tap + to add one';
@override
String get categoryAdd => 'Add category';
@override
String get categoryEdit => 'Edit category';
@override
String get categoryNameZh => 'Chinese name';
@@ -351,9 +418,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get categorySortOrderInvalid => 'Sort order must be an integer';
@override
String get albumMembersEmpty => 'No members yet';
@override
String get inviteSearchHint =>
'Search by account prefix to invite (at least 2 characters)';
@@ -361,9 +425,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get inviteNoResults => 'No matching users';
@override
String get invite => 'Invite';
@override
String get memberInvited => 'Invited';
@@ -371,7 +432,9 @@ class AppLocalizationsEn extends AppLocalizations {
String get removeMember => 'Remove member';
@override
String get removeMemberConfirm => 'Remove this member?';
String removeMemberConfirm(String name) {
return 'Remove $name from this album?';
}
@override
String get roleOwner => 'Owner';
+107 -47
View File
@@ -206,18 +206,6 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get albumCreate => '新建相册';
@override
String get albumEdit => '编辑相册';
@override
String get albumSectionEventInfo => '活动信息';
@override
String get albumSectionContent => '多语言内容';
@override
String get albumSectionAccess => '访问设置';
@override
String get albumTitle => '标题';
@@ -230,9 +218,6 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get albumAddress => '地址';
@override
String get albumDefaultLocale => '默认语言';
@override
String get albumStartAt => '开始时间';
@@ -248,18 +233,6 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get albumTimezoneInvalid => '无效的 IANA 时区名称';
@override
String get switchUpload => '允许上传';
@override
String get switchPublic => '公开可见';
@override
String get switchDownload => '允许下载';
@override
String get switchOriginalDownload => '允许下载原图';
@override
String get formStartAtRequired => '请选择开始时间';
@@ -272,6 +245,69 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get formEndAtNotAfterStartAt => '结束时间必须晚于开始时间';
@override
String get formEventDetails => '活动信息';
@override
String get formDescriptionLanguages => '描述与语言';
@override
String get formDefaultLanguage => '默认语言';
@override
String get formDetailsTab => '详情';
@override
String get formAccessTab => '访问';
@override
String get formAllowUploads => '允许上传';
@override
String get formAllowUploadsDesc => '允许工作人员向该相册上传照片';
@override
String get formPublicAccess => '公开访问';
@override
String get formPublicAccessDesc => '任何获得链接的人都可以查看照片';
@override
String get formAllowDownloads => '允许下载';
@override
String get formAllowDownloadsDesc => '观众可以下载浏览质量的照片';
@override
String get formOriginalDownloads => '下载原图';
@override
String get formOriginalDownloadsDesc => '观众可以下载原图照片';
@override
String get createAlbumTitle => '新建相册';
@override
String get createAlbumSubmit => '新建相册';
@override
String get editAlbumTitle => '编辑相册';
@override
String get saveChanges => '保存修改';
@override
String get unsavedChangesTitle => '放弃修改?';
@override
String get unsavedChangesBody => '修改尚未保存,离开将丢失这些修改。';
@override
String get discardChanges => '放弃';
@override
String get keepEditing => '继续编辑';
@override
String get create => '创建';
@@ -303,7 +339,47 @@ class AppLocalizationsZh extends AppLocalizations {
String get actionEdit => '编辑';
@override
String get albumMembers => '成员管理';
String get membersTitle => '成员';
@override
String membersTitleCount(int count) {
return '成员($count)';
}
@override
String get ownerGroup => '创建者';
@override
String get collaboratorsGroup => '协作者';
@override
String get noCollaborators => '还没有协作者';
@override
String get inviteColleague => '邀请同事';
@override
String get alreadyAdded => '已添加';
@override
String get add => '添加';
@override
String get categoriesTitle => '分类';
@override
String get newCategory => '新增分类';
@override
String get editCategory => '编辑分类';
@override
String deleteCategoryConfirm(String name) {
return '删除「$name」?该分类下的照片将变为未分类。';
}
@override
String get noCategories => '暂无分类';
@override
String get albumCategories => '分类管理';
@@ -317,18 +393,6 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get delete => '删除';
@override
String get deleteConfirmCategory => '确定删除该分类?该分类下的照片将变为未分类。';
@override
String get categoryEmpty => '暂无分类,点击右上角新增';
@override
String get categoryAdd => '新增分类';
@override
String get categoryEdit => '编辑分类';
@override
String get categoryNameZh => '中文名称';
@@ -344,18 +408,12 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get categorySortOrderInvalid => '排序序号必须是整数';
@override
String get albumMembersEmpty => '暂无成员';
@override
String get inviteSearchHint => '输入账号前缀搜索邀请(至少 2 个字符)';
@override
String get inviteNoResults => '未找到匹配用户';
@override
String get invite => '邀请';
@override
String get memberInvited => '已邀请';
@@ -363,7 +421,9 @@ class AppLocalizationsZh extends AppLocalizations {
String get removeMember => '移除成员';
@override
String get removeMemberConfirm => '确定移除该成员?';
String removeMemberConfirm(String name) {
return '确定将 $name 从该相册移除?';
}
@override
String get roleOwner => '创建者';
+38 -17
View File
@@ -66,28 +66,40 @@
"albumsEmpty": "暂无相册,点击「新建相册」开始",
"loadMoreFailed": "加载更多失败,点击重试",
"albumCreate": "新建相册",
"albumEdit": "编辑相册",
"albumSectionEventInfo": "活动信息",
"albumSectionContent": "多语言内容",
"albumSectionAccess": "访问设置",
"albumTitle": "标题",
"albumDescription": "描述",
"albumVenue": "场地",
"albumAddress": "地址",
"albumDefaultLocale": "默认语言",
"albumStartAt": "开始时间",
"albumEndAtOptional": "结束时间(可选)",
"clearEndAt": "清除结束时间",
"albumTimezone": "时区",
"albumTimezoneInvalid": "无效的 IANA 时区名称",
"switchUpload": "允许上传",
"switchPublic": "公开可见",
"switchDownload": "允许下载",
"switchOriginalDownload": "允许下载原图",
"formStartAtRequired": "请选择开始时间",
"formDefaultLocaleMissing": "默认语言必须填写标题",
"formTitleRequiredWithFields": "填写了描述/场地/地址时,标题不能为空",
"formEndAtNotAfterStartAt": "结束时间必须晚于开始时间",
"formEventDetails": "活动信息",
"formDescriptionLanguages": "描述与语言",
"formDefaultLanguage": "默认语言",
"formDetailsTab": "详情",
"formAccessTab": "访问",
"formAllowUploads": "允许上传",
"formAllowUploadsDesc": "允许工作人员向该相册上传照片",
"formPublicAccess": "公开访问",
"formPublicAccessDesc": "任何获得链接的人都可以查看照片",
"formAllowDownloads": "允许下载",
"formAllowDownloadsDesc": "观众可以下载浏览质量的照片",
"formOriginalDownloads": "下载原图",
"formOriginalDownloadsDesc": "观众可以下载原图照片",
"createAlbumTitle": "新建相册",
"createAlbumSubmit": "新建相册",
"editAlbumTitle": "编辑相册",
"saveChanges": "保存修改",
"unsavedChangesTitle": "放弃修改?",
"unsavedChangesBody": "修改尚未保存,离开将丢失这些修改。",
"discardChanges": "放弃",
"keepEditing": "继续编辑",
"create": "创建",
"save": "保存",
"albumStatusActive": "正常",
@@ -98,27 +110,36 @@
"tagOriginal": "原图",
"notSet": "未定",
"actionEdit": "编辑",
"albumMembers": "成员管理",
"membersTitle": "成员",
"membersTitleCount": "成员({count})",
"@membersTitleCount": { "placeholders": { "count": { "type": "int" } } },
"ownerGroup": "创建者",
"collaboratorsGroup": "协作者",
"noCollaborators": "还没有协作者",
"inviteColleague": "邀请同事",
"alreadyAdded": "已添加",
"add": "添加",
"categoriesTitle": "分类",
"newCategory": "新增分类",
"editCategory": "编辑分类",
"deleteCategoryConfirm": "删除「{name}」?该分类下的照片将变为未分类。",
"@deleteCategoryConfirm": { "placeholders": { "name": { "type": "String" } } },
"noCategories": "暂无分类",
"albumCategories": "分类管理",
"shareQrTitle": "分享二维码",
"albumPhotos": "照片管理",
"delete": "删除",
"deleteConfirmCategory": "确定删除该分类?该分类下的照片将变为未分类。",
"categoryEmpty": "暂无分类,点击右上角新增",
"categoryAdd": "新增分类",
"categoryEdit": "编辑分类",
"categoryNameZh": "中文名称",
"categoryNameEn": "英文名称",
"categorySortOrder": "排序序号",
"categoryNameRequired": "至少填写一个语言的名称",
"categorySortOrderInvalid": "排序序号必须是整数",
"albumMembersEmpty": "暂无成员",
"inviteSearchHint": "输入账号前缀搜索邀请(至少 2 个字符)",
"inviteNoResults": "未找到匹配用户",
"invite": "邀请",
"memberInvited": "已邀请",
"removeMember": "移除成员",
"removeMemberConfirm": "确定移除该成员?",
"removeMemberConfirm": "确定将 {name} 从该相册移除?",
"@removeMemberConfirm": { "placeholders": { "name": { "type": "String" } } },
"roleOwner": "创建者",
"roleCollaborator": "协作者",
"selfMarker": "(我)",