/** * 中文语言包 — 集中管理用户可见文本。 * 后续如需多语言支持,可基于此结构扩展其他语言文件并接入 vue-i18n。 */ export const siteConfig = { pageTitle: '站点配置', pageDescription: '管理站点全局属性、视觉识别、点歌逻辑及系统安全策略', reset: '重置', saving: '保存中...', saved: '已保存', saveConfig: '保存配置', loading: '加载配置中...', // 基础信息 basicInfo: '基础信息', siteTitle: '站点标题', siteTitlePlaceholder: '请输入站点标题', icpNumber: '备案号 (ICP)', icpPlaceholder: '请输入备案号', gonganNumber: '公安联网备案号', gonganPlaceholder: '请输入公安备案号 (如:陕公网安备 61011302001964 号)', showBeianIcon: '显示备案图标', showBeianIconDesc: '在公安联网备案号前显示备案图标', siteDescription: '站点描述', siteDescriptionPlaceholder: '请输入站点描述', statisticsCode: '站点统计代码', statisticsCodeEnabled: '启用站点统计代码', statisticsCodeEnabledDesc: '开启后才会将下方统计代码注入到页面', statisticsCodePlaceholder: '粘贴统计代码片段(如百度统计、51.la、Clarity、Google Analytics 等)', statisticsCodeHint: '将注入到所有页面的 中,支持任意 HTML/JS 统计代码。保存后约 1 分钟内生效。', // 视觉识别 themeSettings: '主题设置', themeSettingsDesc: '为每个主题单独设置启用状态,并使用星标指定默认主题。', setDefaultTheme: '设为默认主题', enableTheme: '启用主题', disableTheme: '禁用主题', systemThemeHint: '需要经典深色和经典浅色同时启用', systemThemeAutoEnabled: '跟随系统需要经典深色和经典浅色,已自动启用', defaultTheme: '默认主题', defaultThemeDesc: '用户未自行选择主题时使用;用户自己的设置优先。', enabledThemes: '启用的主题', enabledThemesDesc: '关闭后,用户不能选择该主题;至少保留一个主题。', defaultThemeMustBeEnabled: '默认主题必须处于启用状态', systemThemeRequiresBothClassic: '启用跟随系统时,经典深色和经典浅色必须同时启用', visualIdentity: '视觉识别', siteLogoUrl: '站点 Logo URL', siteLogoPlaceholder: '请输入Logo图片URL', schoolLogoHome: '首页学校 Logo URL(深色模式)', schoolLogoHomePlaceholder: '请先输入深色模式学校 Logo URL', schoolLogoHomeLight: '首页学校 Logo URL(浅色模式)', schoolLogoHomeLightPlaceholder: '请输入浅色模式学校 Logo URL', schoolLogoPrint: '打印排期 Logo URL (小尺寸)', schoolLogoPrintPlaceholder: '请输入打印页学校Logo URL', // 投稿逻辑 submissionLogic: '投稿逻辑设置', enableCollaborative: '启用联合投稿', enableCollaborativeDesc: '允许用户添加联合投稿人并发起协作投稿', enableRemarks: '启用投稿备注留言', enableRemarksDesc: '允许用户在投稿时附加公开或仅管理员可见的备注', submissionNoteRequiresApproval: '投稿公开留言需审核', submissionNoteRequiresApprovalDesc: '开启后,用户投稿时勾选的公开留言需管理员在歌曲管理中通过后才能展示给其他用户', enableCardCodeRequests: '启用点歌券点歌', enableCardCodeLimitBypass: '允许点歌券突破投稿限额', enableCardCodeLimitBypassDesc: '开启后,有效点歌券投稿不占普通额度,并可在日、周或月额度用完后继续投稿', enableCardCodeRequestsDesc: '允许用户使用点歌券在投稿时抵扣或提交点歌', requireCardCodeForRequests: '强制使用点歌券投稿', requireCardCodeForRequestsDesc: '开启后,所有用户提交点歌时必须填写有效点歌券', enableReplay: '启用重播申请', enableReplayDesc: '允许用户对本学期已播放过的歌曲再次申请', enableLimit: '启用投稿限额', enableLimitDesc: '限制单个用户的点歌频率', dailyLimit: '每日限额', weeklyLimit: '每周限额', monthlyLimit: '每月限额', limitUnit: '首 / 人', dailyLimitLabel: '单日', weeklyLimitLabel: '单周', monthlyLimitLabel: '单月', limitLabelPrefix: '', limitLabelSuffix: '投稿上限', // 排期可见范围 scheduleVisibility: '排期可见范围', scheduleVisibilityDesc: '仅控制普通用户在前端可见的播出排期时间范围。管理员不受此限制。', daysBeforeEnabled: '启用可见前限制', daysBeforeEnabledDesc: '启用后,普通用户仅可查看最近设置天数内的排期。', daysAfterEnabled: '启用可见后限制', daysAfterEnabledDesc: '启用后,普通用户仅可查看未来设置天数内的排期。', daysBefore: '可见前', daysAfter: '可见后', daysUnit: '天', // 安全与隐私 securityPrivacy: '安全与隐私设置', captchaEnabled: '启用登录人机验证', captchaEnabledDesc: '开启后,可以有效防范暴力破解和机器人注册。', captchaType: '验证类型', captchaGraphic: '图形验证码', captchaTurnstile: 'Cloudflare Turnstile', captchaMaxFailures: '触发阈值(失败次数)', captchaMaxFailuresPlaceholder: '例如: 3', captchaMaxFailuresDesc: '连续密码错误达到此次数后,后续登录必须输入验证码。建议设置为 3-5 次。', turnstileSiteKey: 'Site Key (Sitekey)', turnstileSiteKeyPlaceholder: '在此输入 Turnstile 的 Site Key', turnstileSecretKey: 'Secret Key (Secret)', turnstileSecretKeyPlaceholder: '在此输入 Turnstile 的 Secret Key (留空表示不修改)', turnstileSecretKeyDesc: '开启 Turnstile 后,所有用户在每次登录时都需要进行安全验证。', allowRegister: '允许用户注册', allowRegisterDesc: '开启后,登录页将显示注册入口,用户可通过用户名和密码自助注册账号。', registerRequiresApproval: '注册需要管理员审核', registerRequiresApprovalDesc: '开启后,新注册的用户需管理员在用户管理中审核通过后才能登录。', oauthRegisterRequiresApproval: '第三方注册需管理员审核', oauthRegisterRequiresApprovalDesc: '开启后,通过第三方(GitHub/聚合登录等)新创建的用户同样需审核后才能登录。', registerEmailRequired: '注册时必须填写邮箱', registerEmailRequiredDesc: '开启后注册表单要求填写邮箱并通过验证码验证归属;需先配置SMTP邮件服务,未配置时不可开启。', registerEmailSmtpRequired: '请先在邮件推送设置中配置 SMTP 服务后再开启该功能', registerRequiresGradeClass: '注册时必须选择年级班级', registerRequiresGradeClassDesc: '开启后,注册表单(含第三方创建账户)必须选择系统内已有的年级和班级;选项需在年级班级管理中预先维护。', showBlacklistKeywords: '显示黑名单具体关键词', showBlacklistKeywordsDesc: '开启后,在投稿命中黑名单时将明确提示冲突关键词;关闭则仅提示"包含关键词"。', forcePasswordChangeOnFirstLogin: '首次登录强制修改密码', forcePasswordChangeOnFirstLoginDesc: '开启后,尚未设置过密码的新用户首次登录时必须设置新密码,完成前不能访问其他功能。', hideStudentInfo: '隐藏学生详细信息', hideStudentInfoDesc: '开启后,非管理员用户在前端点歌列表、排期预览中将无法查看投稿学生的完整学号与真实姓名。', telemetryEnabled: '启用错误追踪与遥测', telemetryEnabledDesc: '默认开启。开启后,系统会向 Sentry 发送前后端错误事件和实例在线事件(仅包含技术错误信息、实例 ID、请求路径和运行时环境),用于统计实例数量并定位部署问题。', telemetryPrivacy: '不会收集任何个人身份信息、用户数据或业务内容。', configWarning: '站点基础配置在保存后将立即对所有终端生效。请在修改关键业务逻辑(如投稿限额)前确保已知晓对现有用户的影响。', // 投稿须知 submissionGuidelines: '投稿须知', guidelinesPlaceholder: '请输入投稿须知内容(支持 Markdown 格式)', guidelinesEdit: '编辑', guidelinesPreview: '预览', defaultSiteTitle: '校园广播站点歌系统', defaultSubmissionGuidelines: `1. 投稿时无需加入书名号 2. 除DJ外,其他类型歌曲均接收(包括小语种) 3. 禁止投递含有违规内容的歌曲 4. 点播的歌曲将由管理员进行审核 5. 审核通过后将安排在播放时段播出 6. 提交即表明我已阅读投稿须知并已知该歌曲有概率无法播出 7. 本系统仅提供音乐搜索和播放管理功能,不存储任何音乐文件。所有音乐内容均来自第三方音乐平台,版权归原平台及版权方所有。用户点歌时请确保遵守相关音乐平台的服务条款,尊重音乐作品版权。我们鼓励用户支持正版音乐,在官方平台购买和收听喜爱的音乐作品。 8. 最终解释权归广播站所有`, // 提示消息 loadFailed: '加载配置失败', saveFailed: '保存配置失败', saveFailedRetry: '保存配置失败,请重试', saveSuccess: '配置保存成功!', fetchFailed: '获取配置失败', logs: { loadFailed: '加载配置失败:', apiErrorResponse: 'API错误响应:', parseApiErrorFailed: '无法解析API错误响应:', saveFailed: '保存配置失败:' }, // 平台名称 platformNetease: '网易云音乐', platformTencent: 'QQ音乐', platformBilibili: '哔哩哔哩', platformMigu: '咪咕音乐', platformEnabled: '已启用', platformDisabled: '已禁用', serverMessages: { oauthRedirectCallbackInvalid: 'oauthRedirectUri 必须是回调地址,例如 https://yourdomain.com/api/auth/[provider]/callback', oauthRedirectUrlInvalid: 'oauthRedirectUri 不是合法 URL,示例:https://yourdomain.com/api/auth/[provider]/callback', raw: { oauthRedirectCallbackInvalid: 'oauthRedirectUri 必须是回调地址,例如 https://yourdomain.com/api/auth/[provider]/callback', oauthRedirectUrlInvalid: 'oauthRedirectUri 不是合法URL,示例:https://yourdomain.com/api/auth/[provider]/callback', unauthorized: '未授权访问', adminOnly: '只有管理员才能更新系统设置', captchaProviderInvalid: 'captchaProvider 必须是 graphic 或 turnstile', turnstileRequired: '启用 Turnstile 验证前,请先配置 Site Key 和 Secret Key', smtpPortInvalid: 'smtpPort 必须是1-65535之间的整数', oauthBaseRequired: '启用 OAuth 登录方式前,请先在管理员后台配置 OAuth 重定向 URI 和 OAuth State 密钥', githubClientIdRequired: '启用 GitHub 登录时必须提供 Client ID', githubClientSecretRequired: '启用 GitHub 登录时必须提供 Client Secret', casdoorServerUrlRequired: '启用 Casdoor 登录时必须提供服务器 URL', casdoorClientIdRequired: '启用 Casdoor 登录时必须提供 Client ID', casdoorClientSecretRequired: '启用 Casdoor 登录时必须提供 Client Secret', casdoorOrganizationRequired: '启用 Casdoor 登录时必须提供组织名称', googleClientIdRequired: '启用 Google 登录时必须提供 Client ID', googleClientSecretRequired: '启用 Google 登录时必须提供 Client Secret', onlyOneLimit: '每日限额、每周限额和每月限额只能选择其中一种,其他必须设置为空', updateFailed: '更新系统设置失败', booleanSuffix: ' 必须是布尔值', positiveIntegerSuffix: ' 必须是正整数', nonNegativeIntegerOrNullSuffix: ' 必须是非负整数或null', customOAuthRequiredPrefix: '启用自定义 OAuth2 登录时必须提供 ', invalidUrlSuffix: ' 不是合法URL', customOAuthAuthorizeUrlLabel: '授权端点 URL', customOAuthTokenUrlLabel: 'Token 端点 URL', customOAuthUserInfoUrlLabel: '用户信息端点 URL', customOAuthClientIdLabel: 'Client ID', customOAuthClientSecretLabel: 'Client Secret', customOAuthUserIdFieldLabel: '用户 ID 字段名' }, unauthorized: '未授权访问', adminOnly: '只有管理员才能更新系统设置', mustBeBoolean: (field: string) => `${field} 必须是布尔值`, mustBePositiveInteger: (field: string) => `${field} 必须是正整数`, mustBeNonNegativeIntegerOrNull: (field: string) => `${field} 必须是非负整数或null`, captchaProviderInvalid: 'captchaProvider 必须是 graphic 或 turnstile', turnstileRequired: '启用 Turnstile 验证前,请先配置 Site Key 和 Secret Key', smtpPortInvalid: 'smtpPort 必须是1-65535之间的整数', oauthBaseRequired: '启用 OAuth 登录方式前,请先在管理员后台配置 OAuth 重定向 URI 和 OAuth State 密钥', githubClientIdRequired: '启用 GitHub 登录时必须提供 Client ID', githubClientSecretRequired: '启用 GitHub 登录时必须提供 Client Secret', casdoorServerUrlRequired: '启用 Casdoor 登录时必须提供服务器 URL', casdoorClientIdRequired: '启用 Casdoor 登录时必须提供 Client ID', casdoorClientSecretRequired: '启用 Casdoor 登录时必须提供 Client Secret', casdoorOrganizationRequired: '启用 Casdoor 登录时必须提供组织名称', googleClientIdRequired: '启用 Google 登录时必须提供 Client ID', googleClientSecretRequired: '启用 Google 登录时必须提供 Client Secret', customOAuthFieldRequired: (field: string) => `启用自定义 OAuth2 登录时必须提供 ${field}`, invalidUrl: (field: string) => `${field} 不是合法URL`, onlyOneLimit: '每日限额、每周限额和每月限额只能选择其中一种,其他必须设置为空', updateFailed: '更新系统设置失败', fields: { customOAuthAuthorizeUrl: '授权端点 URL', customOAuthTokenUrl: 'Token 端点 URL', customOAuthUserInfoUrl: '用户信息端点 URL', customOAuthClientId: 'Client ID', customOAuthClientSecret: 'Client Secret', customOAuthUserIdField: '用户 ID 字段名' } } } as const export const changePassword = { welcomeTitle: '欢迎使用VoiceHub', welcomeDesc: '为了保障您的账号安全,请设置一个新的密码', securityTitle: '账号安全', securityDesc: '定期更新密码有助于保护您的账号安全', tipsTitle: '密码安全建议', tipMinLength: '至少6个字符', tipCase: '包含大小写字母', tipSpecial: '包含数字和特殊字符', setNewPassword: '设置新密码', changePasswordTitle: '修改密码', setNewPasswordDesc: '请设置一个安全的密码', updatePasswordDesc: '更新您的登录密码', backToHome: '返回主页', logout: '退出登录' } as const export const common = { language: '语言', followSystem: '跟随系统', workerIn: '响应耗时', cancel: '取消', confirm: '确定', close: '关闭', retry: '重试', edit: '编辑', delete: '删除', actions: '操作', refreshData: '刷新数据', selectedItems: (count: number) => `已选择 ${count} 项`, noData: '暂无数据内容', loadingData: '正在加载数据...', searchPlaceholder: '搜索...', selectPlaceholder: '请选择', to: '至', clearFilters: '清除筛选', selectedCount: (count: number) => `已选 ${count} 项`, processing: '处理中...', confirmOperation: '确认操作', passwordStrengthLevels: { weak: '弱', medium: '中等', strong: '强', veryStrong: '极强' }, searchUsers: '搜索用户', searchUsersPlaceholder: '搜索用户名或姓名...', noMatchingUsers: '未找到匹配的用户', selectedUsers: (count: number) => `已选择 ${count} 人`, time: { justNow: '刚刚', minutesAgo: (count: number) => `${count}分钟前`, hoursAgo: (count: number) => `${count}小时前`, daysAgo: (count: number) => `${count}天前` }, scheduleForm: { title: (title: string) => `为歌曲 "${title}" 创建排期`, playDate: '播放日期', playTime: '播出时段', unspecified: '未指定', preferredPlayTime: '用户期望的播出时段:', creating: '创建中...', create: '创建排期', startAt: (time: string) => `${time} 开始`, endAt: (time: string) => `${time} 结束`, unlimited: '不限时间', dateRequired: '请选择播放日期' }, votersModal: { title: '投票人员列表', votes: (count: number) => `${count} 票`, loading: '正在加载投票人员...', voters: (count: number) => `投票人员 (${count})`, empty: '暂无投票', fetchFailed: '获取投票人员失败' }, userSongsModal: { title: '用户歌曲信息', loading: '加载数据中...', allSemesters: '全部学期', semesterFilter: '学期过滤', empty: '没有找到相关记录', votes: (count: number) => `${count} 票`, requests: (count: number) => `${count} 人申请`, requester: '投稿人:', tabs: { submitted: '投稿歌曲', voted: '投票歌曲', replay: '重播申请' }, fetchFailed: '获取用户歌曲信息失败', voted: '投票', requested: '申请', statuses: { played: '已播放', scheduled: '已排期', pending: '待排期' } } } as const export const pages = { authError: { title: '身份验证失败', errorCode: '错误代码', retryLogin: '重新尝试登录', backHome: '返回首页', contactAdmin: '如果您认为这是一个错误,请联系系统管理员', defaultMessage: '在尝试使用第三方账号登录时发生未知错误,请重试', aggregateUnavailableTitle: '当前登录方式暂不可用', aggregateUnavailableAction: '选择其他登录方式' }, resetPassword: { title: '重置密码', subtitle: '请设置您的新密码', goLogin: '去登录', invalidTokenFull: '重置链接无效或缺少Token,请重新获取邮件', invalidToken: '重置链接无效', newPassword: '新密码', passwordPlaceholder: '至少6个字符', passwordStrength: '密码强度', confirmPassword: '确认新密码', confirmPasswordPlaceholder: '请再次输入新密码', resetting: '重置中...', submit: '确认重置', backLogin: '返回登录', passwordMismatch: '两次输入的密码不一致', passwordTooShort: '密码长度不能少于6个字符', success: '密码重置成功', failed: '重置失败,请重试' }, forgotPassword: { title: '找回密码', subtitle: '请输入您的账号名和绑定的邮箱地址', backLogin: '返回登录', username: '账号名', usernamePlaceholder: '请输入您的账号名', verifyEmail: '验证邮箱', detectedEmailPrefix: '系统检测到该账号绑定了邮箱:', emailPlaceholder: '请补全完整的邮箱地址', verifying: '验证中...', sending: '发送中...', nextStep: '下一步', sendResetEmail: '发送重置邮件', previousStep: '上一步', usernameRequired: '请输入账号名', emailRequired: '请补全邮箱地址', mailSent: '重置邮件已发送', requestFailed: '请求失败,请稍后重试', serverMessages: { raw: { rateLimitedPattern: '操作过于频繁,请等待\\s*(\\d+)\\s*分钟后再试', usernameMissing: '请提供账号名', userNotFound: '找不到该账号名,请检查是否拼写错误', emailNotBound: '该账号未绑定安全邮箱,无法通过此方式找回密码。请联系管理员。', emailRequiredFull: '请输入完整的邮箱地址以验证身份', mailSentFull: '如果账号名和邮箱匹配,重置密码链接已发送至您的邮箱。请查收并按照邮件中的说明重置密码。', systemError: '系统错误,请稍后重试' }, rateLimited: (minutes: string | number) => `操作过于频繁,请等待 ${minutes} 分钟后再试`, usernameMissing: '请提供账号名', userNotFound: '找不到该账号名,请检查是否拼写错误', emailNotBound: '该账号未绑定安全邮箱,无法通过此方式找回密码。请联系管理员。', emailRequiredFull: '请输入完整的邮箱地址以验证身份', mailSentFull: '如果账号名和邮箱匹配,重置密码链接已发送至您的邮箱。请查收并按照邮件中的说明重置密码。', systemError: '系统错误,请稍后重试' } }, account: { title: '账号管理', subtitle: 'Account Management', oauthBinding: '第三方账号绑定', oauthBindingDesc: '绑定社交账号以便更快捷地登录系统', changePassword: '修改密码', changePasswordDesc: '为了您的账号安全,建议定期更换高强度密码', sessions: { title: '登录会话', desc: '查看并退出当前正在使用你账号的设备。', refresh: '刷新', loading: '正在加载登录会话...', empty: '暂无活跃的登录会话', current: '当前', ip: 'IP', loginMethod: '登录方式', lastActive: '最后活跃', expiresAt: '到期时间', logout: '登出', logoutOthers: '退出其他会话', logoutSuccess: '已退出该登录会话', logoutOthersSuccess: '已退出其他登录会话', logoutFailed: '退出登录会话失败', loadFailed: '加载登录会话失败', methods: { password: '密码', twoFactor: '双重认证', oauth: '第三方登录', webauthn: '通行密钥', legacy: '历史会话' } }, social: { title: '社交账号绑定', desc: '绑定您的社交账号以接收实时推送通知', loading: '加载绑定状态中...', emailNotifyTitle: '邮箱消息通知', currentEmail: '当前绑定邮箱', verified: '已验证', pendingVerify: '待验证', emailUnboundDesc: '绑定邮箱后,您可以接收到实时的邮件通知提醒。', emailPlaceholder: '请输入邮箱地址', pleaseWait: '请稍候...', bindNow: '立即绑定', emailCodeSentTip: '验证码已发送至您的邮箱,请在 5 分钟内完成验证。若未收到邮件,请检查垃圾箱。', emailCodePlaceholder: '输入 6 位数字验证码', verifying: '验证中...', confirmVerify: '确认验证', sending: '发送中...', resend: '重新发送', changeEmailAddress: '更换邮箱地址', changeEmail: '更换邮箱', unbinding: '正在解绑...', unbindEmail: '解绑邮箱', meowPushTitle: 'MeoW App 推送', currentBoundId: '当前绑定 ID', connected: '已连接', meowDesc: '通过 MeoW 客户端接收更及时的系统通知和歌曲状态变更提醒。', meowIdPlaceholder: '请输入 MeoW 用户 ID', sendCode: '发送验证码', meowCodeSentPrefix: '验证码已发送至 MeoW ID:', meowCodeSentSuffix: ',请在客户端查收。', codePlaceholder: '输入 6 位验证码', confirmBind: '确认绑定', cancel: '取消', unbindMeow: '解除 MeoW 账号绑定', loadFailedLog: '加载设置失败:', loadFailed: '加载设置失败,请刷新页面重试', meowIdRequired: '请输入 MeoW 用户 ID', meowCodeSent: '验证码已发送到您的 MeoW 账号', sendCodeFailed: '发送验证码失败', codeRequired: '请输入6位验证码', meowBindSuccess: 'MeoW 账号绑定成功!', verifyFailed: '验证失败', unbindMeowTitle: '解绑 MeoW 账号', unbindMeowMessage: '确定要解绑 MeoW 账号吗?解绑后将无法接收推送通知。', meowUnbound: 'MeoW 账号已解绑', unbindFailed: '解绑失败', emailRequired: '请输入邮箱地址', emailInvalid: '请输入有效的邮箱地址', emailCodeSent: '验证码已发送,请查收邮箱', bindFailed: '绑定失败', emailVerifySuccess: '邮箱验证成功', changeEmailTitle: '更换邮箱', changeEmailMessage: '更换邮箱将清除当前绑定的邮箱信息,需要重新验证新邮箱。确定要继续吗?', emailCleared: '已清除邮箱信息', emailCodeResent: '验证码已重新发送', sendFailed: '发送失败', unbindEmailTitle: '确认解绑邮箱', unbindEmailMessage: '解绑后将无法接收邮件通知,确定要继续吗?', emailUnbound: '邮箱已解绑' }, personalApiKey: { title: '个人 API Key', desc: '用于个人集成和投稿', create: '创建 API Key', loading: '正在加载 API Key...', emptyTitle: '还没有个人 API Key', emptyDesc: '创建后可用于个人侧的集成与投稿。', noDescription: '暂无描述', delete: '删除', cancel: '取消', keyPrefix: 'Key 前缀', createdAt: '创建时间', lastUsedAt: '最后使用', neverUsed: '从未使用', usageCount: '调用次数', expiresAt: '过期时间', neverExpires: '永不过期', deleteTitle: '删除个人 API Key', deleteMessageDefault: '确定要删除这个个人 API Key 吗?删除后相关集成将无法继续使用。', deleteMessage: (name: string) => `确定要删除个人 API Key “${name}”吗?删除后相关集成将无法继续使用。`, createdTitle: 'API Key 创建成功', createdDesc: '完整 Key 只会显示这一次', copyWarning: '请现在复制并保存。关闭窗口后,VoiceHub 不会再次显示完整 Key。', fullKey: '完整 Key', closeSaved: '我已保存,关闭', logsTitle: '调用记录', logsSubtitle: (name: string, total: number) => `${name} · 共 ${total} 条`, defaultName: '个人 API Key', defaultDescription: '用于个人集成和投稿', loadingLogs: '正在加载调用记录...', noLogs: '暂无调用记录', noLogsDesc: '这个令牌还没有产生过 API 调用。', logColumns: { time: '时间', method: '方法', endpoint: '接口', status: '状态', duration: '耗时', error: '错误' }, none: '无', pageInfo: (page: number, totalPages: number) => `第 ${page} / ${totalPages} 页`, previousPage: '上一页', nextPage: '下一页', status: { active: '可用', inactive: '停用', expired: '已过期' }, loadFailed: '加载个人 API Key 失败', createSuccess: '个人 API Key 创建成功', createFailed: '创建个人 API Key 失败', deleteSuccess: '个人 API Key 已删除', deleteFailed: '删除个人 API Key 失败', copied: '已复制到剪贴板', copyFailed: '复制失败,请手动选择 Key 复制', logsFailed: '加载调用记录失败' }, musicSource: { title: '音源设置', desc: '配置个人音源 API Key,解锁更高音质的播放链接', keyLabel: 'ChKSz API Key', keyPlaceholder: '粘贴你的 ChKSz API Key', showKey: '显示 Key', hideKey: '隐藏 Key', save: '保存', clear: '清除', test: '测试', saveSuccess: '音源 API Key 已保存(仅保存在当前浏览器)', clearSuccess: '音源 API Key 已清除', testSuccess: '测试通过:Key 有效,音源可用', testInvalid: '测试失败:Key 无效或已被限制', testTimeout: '测试超时,请稍后重试', testNetwork: '网络异常,无法连接音源服务', testEmpty: '请先填写 API Key', hint: 'Key 仅保存在当前浏览器,不会上传到服务器;可前往获取:' }, roles: { ADMIN: '管理员', SUPER_ADMIN: '超级管理员', SONG_ADMIN: '审歌员', USER: '普通用户' } }, dashboard: { backToTop: '返回顶部', fallbackTitle: '管理后台', defaultSiteTitle: '校园广播站点歌系统', tabs: { overview: '数据概览', songs: '歌曲管理', schedule: '排期管理', print: '打印排期', users: '用户管理', notifications: '通知管理', 'smtp-config': '邮件配置', playtimes: '播出时段', 'request-times': '投稿管理', semesters: '学期管理', blacklist: '黑名单管理', 'site-config': '站点配置', 'music-source': '音源控制', database: '数据库操作', 'api-keys': 'API密钥管理', 'card-codes': '点歌券管理' }, roles: { USER: '普通用户', SONG_ADMIN: '歌曲管理员', ADMIN: '超级管理员', SUPER_ADMIN: '超级管理员' } }, notificationSettings: { title: '消息设置', subtitle: 'Notification Settings', saving: '保存中...', saveSettings: '保存设置', loading: '加载设置中...', loadingShort: '加载中...', retry: '重试', inAppTitle: '站内消息设置', inAppDesc: '配置您希望在系统内接收的消息类型', songSelectedTitle: '歌曲被选中消息', songSelectedDesc: '当您投稿的歌曲被选中播放时通知您', songPlayedTitle: '歌曲已播放消息', songPlayedDesc: '当您投稿的歌曲播放完成时通知您', songVotedTitle: '歌曲获得投票消息', songVotedDesc: '当您投稿的歌曲获得投票时通知您', systemTitle: '系统通知', systemDesc: '接收系统重要通知和公告', voteThresholdTitle: '投票通知阈值', voteThresholdDesc: '当投票数达到此阈值时才发送通知', voteThresholdText: (count: number) => `每获得 ${count} 票通知一次`, voteUnit: '票', refreshTitle: '通知刷新间隔', refreshDesc: '设置系统自动检查新通知的时间间隔', seconds: (seconds: number) => `${seconds}秒`, minutes: (minutes: number) => `${minutes}分钟`, minutesSeconds: (minutes: number, seconds: number) => `${minutes}分${seconds}秒`, loadFailedLog: '加载设置失败:', loadFailed: '加载设置失败,请刷新页面重试', saveSuccess: '设置保存成功', saveFailed: '保存失败' }, home: { schoolLogoAlt: '学校Logo', userFallback: '用户', account: '账号管理', dashboard: '管理后台', logout: '退出登录', login: '登录', subtitle: 'VoiceHub 校园广播系统', tabs: { schedule: '播出排期', songs: '歌曲列表', request: '投稿歌曲', notification: '消息' }, loginRequired: '需要登录', loginRequiredDesc: '您需要登录才能查看通知', loginNow: '立即登录', notificationCenter: '通知中心', unreadOverview: '未读概览', unreadCountSummary: (count: number) => `${count} 条未读通知`, viewUnreadNotifications: '查看未读', notificationFilterLabel: '通知筛选', allNotifications: '所有', searchNotifications: '搜索通知', searchNotificationsPlaceholder: '搜索通知标题或正文...', clearNotificationSearch: '清空通知搜索', loading: '加载中...', noNotifications: '暂无通知', noUnreadNotifications: '暂无未读通知', noMatchingNotifications: '没有找到包含该关键字的通知', read: '已读', unread: '未读', sender: '发送人', systemSender: '系统', notificationTypes: { SONG_SELECTED: '歌曲已选中', SONG_PLAYED: '歌曲已播放', SONG_VOTED: '收到新投票', SONG_REJECTED: '歌曲被驳回', COLLABORATION_INVITE: '联合投稿邀请', COLLABORATION_RESPONSE: '联合投稿回复', SYSTEM_NOTICE: '系统通知', SYSTEM: '系统通知' }, inviteStatus: { accepted: '- 已接受', invalid: '- 已失效', rejected: '- 已拒绝' }, processing: '处理中...', acceptInvite: '接受邀请', reject: '拒绝', delete: '删除', paginationInfo: (total: number, current: number, pages: number) => `共 ${total} 条通知,第 ${current} / ${pages} 页`, pageSize: '每页显示:', previousPage: '上一页', nextPage: '下一页', markAllRead: '全部标记为已读', markAllReadSuccess: '已将全部通知标记为已读', clearAllMessages: '清空所有消息', clearAllSuccess: '已清空所有消息', rulesTitle: '点歌规则', rulesDesc: '投稿前请仔细阅读以下规则', submissionGuidelines: '投稿须知', defaultRules: [ '投稿时无需加入书名号', '除DJ外,其他类型歌曲均接收(包括小语种)', '禁止投递含有违规内容的歌曲' ], playbackTime: '播放时间', playbackTimeDesc: '每天夜自修静班前', gotIt: '我知道了', roles: { ADMIN: '管理员', SUPER_ADMIN: '超级管理员', SONG_ADMIN: '审歌员', USER: '普通用户' }, defaultRole: '管理员', classFallback: '同学', bootMessages: { START: '正在准备音乐播放环境', CONFIG: '正在加载站点配置', AUTH: '正在校验登录状态', SLOW_NETWORK: '网络有点慢,仍在同步数据', CONTENT: '正在同步排期与歌曲列表', FALLBACK: '正在使用可用数据继续打开首页', FINALIZING: '正在整理播放数据', COMPLETE: '加载完成,正在打开首页' }, pageSizeOptions: { five: '5条', ten: '10条', twenty: '20条', fifty: '50条' }, confirm: { ok: '确定', cancel: '取消', deleteTitle: '删除消息', deleteMessage: '确定要删除此消息吗?', clearTitle: '清空所有消息', clearMessage: '确定要清空所有消息吗?此操作不可撤销。', clearConfirm: '清空' }, time: { justNow: '刚刚', minutesAgo: (minutes: number) => `${minutes}分钟前`, hoursAgo: (hours: number) => `${hours}小时前`, daysAgo: (days: number) => `${days}天前`, weekdays: ['日', '一', '二', '三', '四', '五', '六'], dateFormat: (year: number, month: number, date: number, weekday: string) => `${year}年${month}月${date}日 周${weekday}`, seconds: (seconds: number) => `${seconds}秒`, minutes: (minutes: number) => `${minutes}分钟`, minutesSeconds: (minutes: number, seconds: number) => `${minutes}分${seconds}秒` }, messages: { requestLogin: '需要登录才能投稿歌曲', requestSuccess: (title: string, artist: string) => `《${title} - ${artist}》投稿成功!`, requestFailed: '点歌失败', voteLogin: '请先登录后再投票', cancelReplayLogin: '请先登录才能取消重播申请', requestReplayLogin: '请先登录才能申请重播', withdrawLogin: '请先登录才能撤回投稿', inviteAccepted: '已接受联合投稿邀请', inviteRejected: '已拒绝联合投稿邀请', operationFailed: '操作失败', notificationLogin: '需要登录才能查看通知', changePasswordTip: '为了您的账户安全,建议您修改密码。您可以点击右上角的"修改密码"按钮进行修改。' }, titleHome: '首页', titleLoading: '加载中' }, yearReview: { pageTitle: '我的年度回顾 - VoiceHub', loading: '正在生成您的年度回忆...', errorTitle: '获取数据失败', errorDesc: '可能是网络出了点小差错', retry: '重试', emptyTitle: '今年还没有点歌记录哦', emptyDesc: '快去点一首喜欢的歌吧', goRequest: '去点歌', scrollHint: '上滑开启', reportTitle: '年度点歌报告', firstSongBadge: '初次相遇', firstSongIntro: '这一年,你点的第一首歌是', date: (month: number, day: number) => `${month}月${day}日`, favoriteArtist: '特别偏爱', topArtistIntro: '你的年度歌手是', artistDesc: 'Ta 的声音似乎特别吸引你,陪伴了你无数个日夜。', future: '未来可期', futureDesc: '愿音乐继续陪伴你的每一天', backHome: '返回首页', commonPlatform: '常用平台', mostActive: '最活跃', activeMonth: (month: number) => `${month}月`, votesCast: '投出票数', musicJourney: '音乐足迹', totalRequestsIntro: '这一年,你一共发起了', requestCount: '次点歌', playedSummary: (count: number) => `其中有 ${count} 首`, playedDesc: '在广播站被播出,传递给了更多人', pendingPlayedDesc: '期待你的歌曲早日被播出', requests: '点歌次数', played: '已播放', votes: '投票数', footerSlogan: '用音乐记录每一刻', platforms: { netease: '网易云音乐', bilibili: '哔哩哔哩', qq: 'QQ音乐', kugou: '酷狗音乐', kuwo: '酷我音乐', migu: '咪咕音乐', tencent: 'QQ音乐' } }, login: { title: '登录', schoolLogoAlt: '学校Logo' }, auth: { loginForm: { bindExisting: '绑定现有账户', createAccount: '创建新账户', bindProvider: (providerName: string, providerUsername: string) => `即将绑定 ${providerName} 账号: ${providerUsername}`, createWithProvider: (providerName: string) => `通过 ${providerName} 创建新账户`, loginSubtitle: '登录您的VoiceHub账户', setUsername: '设置用户名', accountName: '账号名', usernamePlaceholder: '请输入账号名', usernamePattern: '3-30个字符,可使用英文、数字、下划线、连字符', usernameHint: '用户名不能重复,注册后无法修改', realName: '真实姓名', realNamePlaceholder: '请输入您的真实姓名', gradeLabel: '年级', classLabel: '班级', optional: '不填写', selectGrade: '请选择年级', selectClass: '请选择班级', selectGradeFirst: '先选择年级', classHint: '可选,只能选择系统内已有用户的年级和班级', noClassHint: '暂无可选年级班级,可直接跳过', classHintRequired: '必填,只能选择系统内已有的年级和班级', noClassHintRequired: '暂无可选年级班级,请联系管理员配置后再注册', setPassword: '设置密码', password: '密码', forgotPassword: '忘记密码?', passwordPlaceholder: '请输入密码', createPasswordPlaceholder: '至少6个字符', passwordStrength: '密码强度', confirmPassword: '确认密码', confirmPasswordPlaceholder: '请再次输入密码', welcomeBack: '欢迎回来', bindAccount: '绑定账号', createNewAccount: '创建新账户', registerTitle: '注册新账户', registerSubtitle: '注册您的VoiceHub账户', toRegister: '没有账号?立即注册', toLogin: '已有账号?去登录', register: '注册', registering: '注册中...', remarkLabel: '备注', remarkPlaceholder: '选填,如:我是高三X班成员', emailLabel: '邮箱', emailPlaceholder: '用于接收验证码与注册通知', emailCodeLabel: '邮箱验证码', emailCodePlaceholder: '6 位验证码', sendCode: '发送验证码', codeSent: '验证码已发送,请查收邮件', codeSendFailed: '验证码发送失败,请稍后重试', codeCountdown: (seconds: number) => `${seconds}s 后重新发送`, emailCodeRequired: '请先获取并填写邮箱验证码', emailInvalid: '请输入有效的邮箱地址', emailRequired: '请填写邮箱地址', registerSuccessPending: '注册成功,等待管理员审核', binding: '绑定中...', loggingIn: '登录中...', bindAndLogin: '绑定并登录', login: '登录', or: '或', webauthn: '使用 Windows Hello / Passkey 登录', platformNote: '不同VoiceHub平台的账号不互通', fullLoginInfo: '请填写完整的登录信息', fullRegisterInfo: '请填写完整的注册信息', gradeClassRequired: '年级和班级需要同时选择,或全部留空', gradeClassRequiredByConfig: '注册时必须选择年级和班级', bindFailed: '绑定失败,请检查账号密码', loginFailed: '登录失败,请检查账号密码', registerFailed: '注册失败,请稍后重试', passkeyFailed: 'Passkey 登录失败', passkeyLoginUnsupported: '当前浏览器不支持 Passkey 登录', passkeyAuthenticationIncomplete: 'Passkey 认证未完成', passkeySecurityInvalid: 'Passkey 的域名或安全上下文配置无效', passkeyOperationUnavailable: 'Passkey 操作已取消、已超时或没有可用凭据', passkeyCleanupNotified: '该 Passkey 已失效,系统已收到清理通知,请重新添加', passkeyCleanupRequired: '该 Passkey 已从 VoiceHub 删除,请先在设备密码保险箱中删除后重新添加', usernameLengthInvalid: '用户名长度需要在3-30个字符之间', usernamePatternInvalid: '用户名仅可包含英文、数字、下划线和连字符', registerPasswordTooShort: '密码长度至少为6个字符', registerPasswordMismatch: '两次输入的密码不一致', confirmBind: '确认绑定', confirmBindTitle: '确认绑定', confirmBindMessage: (providerName: string, providerUsername: string, username: string) => `确认将 ${providerName} 账号「${providerUsername}」与账户「${username}」绑定?绑定后即可使用 ${providerName} 直接登录。` }, oauthButtons: { divider: '或使用第三方账号登录', loginWith: (providerName: string) => `使用 ${providerName} 登录`, customOAuthProvider: '第三方 OAuth', aggregateOAuthProvider: '聚合登录', aggregateProviderName: (providerName: string) => `${providerName} 登录`, quickLoginWx: '使用微信登录', quickLoginQq: '使用QQ登录', aggregateLoginTypes: { qq: 'QQ', wx: '微信', alipay: '支付宝', sina: '微博', baidu: '百度', douyin: '抖音', huawei: '华为', xiaomi: '小米', gitee: 'Gitee', gitea: 'Gitea', bilibili: '哔哩哔哩', kuaishou: '快手' } }, bindReminder: { title: (providerName: string) => `绑定${providerName},下次一键登录`, description: (providerName: string) => `检测到你正在${providerName}内访问 VoiceHub。当前账号尚未绑定${providerName},绑定后下次可直接使用${providerName}快捷登录,无需再输入账号密码。`, bindNow: '立即绑定', ignore: '忽略', neverRemind: '不再提示' }, changePasswordForm: { currentPassword: '当前密码', currentPasswordPlaceholder: '请输入当前密码', newPassword: '新密码', newPasswordPlaceholder: '请输入新密码', passwordStrength: '密码强度', confirmPassword: '确认新密码', confirmPasswordPlaceholder: '请再次输入新密码', mismatch: '密码不匹配', matched: '密码匹配', processing: '处理中...', setInitial: '设置初始密码', submitChange: '确认修改密码', weak: '弱', medium: '中等', strong: '强', veryStrong: '极强', passwordTooShort: '密码长度至少为6位', newPasswordMismatch: '新密码和确认密码不匹配', newPasswordTooShort: '新密码长度至少为6位', initialSuccess: '密码设置成功!正在跳转...', changeSuccess: '密码修改成功!请重新登录', failed: '操作失败,请重试', showCurrentPassword: '显示当前密码', hideCurrentPassword: '隐藏当前密码', showNewPassword: '显示新密码', hideNewPassword: '隐藏新密码', showConfirmPassword: '显示确认密码', hideConfirmPassword: '隐藏确认密码' }, captchaInput: { label: '验证码', refreshTitle: '点击刷新验证码', alt: '验证码', placeholder: '请输入验证码', refresh: '换一张', loadFailed: '获取验证码失败' }, oauthBindingCard: { loading: '加载绑定状态...', unbound: '未绑定', processing: '处理中...', redirecting: '跳转中...', unbind: '解绑', bindNow: '立即绑定', avatarTitle: '头像', currentAvatar: '当前头像', setAsAvatar: '设为头像', avatarSetSuccess: '头像设置成功', avatarSetFailed: '头像设置失败', boundDevices: '已绑定', devices: '个设备', addDevice: '添加设备', httpsRequired: '需要 HTTPS 环境', rename: '重命名', addedAt: '添加于', save: '保存', cancel: '取消', remove: '移除', unbindTitle: '解除绑定', unbindMessage: (providerName: string) => `确定要解除 ${providerName} 账号的绑定吗?解除后您将无法使用该账号登录。`, removePasskeyTitle: '移除 Passkey', removePasskeyMessage: (deviceName: string) => `确定要移除设备 "${deviceName}" 吗?VoiceHub 会尝试通知当前设备同步删除;若系统不支持,仍需在密码保险箱中手动删除。`, unbindSuccess: '解除绑定成功', unbindFailed: '解绑失败', passkeyCleanupRequired: '已从 VoiceHub 移除,请同时在设备密码保险箱中删除对应 Passkey', browserNotSupported: '您的浏览器不支持 Windows Hello / Passkey', userCancelled: '用户取消了操作', passkeyOperationUnavailable: 'Passkey 操作已取消、已超时或没有可用凭据', passkeyAlreadyRegistered: '该 Passkey 已在当前账号中注册', passkeyAlgorithmUnsupported: '当前设备不支持服务器提供的 Passkey 加密算法', passkeySecurityInvalid: 'Passkey 的域名或安全上下文配置无效', passkeyRegistrationUnsupported: '当前浏览器不支持创建 Passkey', passkeyCreationIncomplete: 'Passkey 创建未完成', addDeviceSuccess: '设备添加成功', addDeviceFailed: '添加设备失败', nameRequired: '设备名称不能为空', nameTooLong: '设备名称过长 (最大50个字符)', renameSuccess: '设备名称修改成功', renameFailed: '修改失败' }, twoFactorVerify: { title: '双重认证', totpDesc: '请输入您的认证器应用生成的6位验证码', emailDesc: '请输入发送到您邮箱的验证码', emailLabel: '请补全您的邮箱以接收验证码', maskedEmailTip: '提示:', emailPlaceholder: '请输入完整邮箱地址', resendCountdown: (seconds: number) => `${seconds}秒后重新发送`, resendCode: '重新发送验证码', sendCode: '发送验证码', verifyLogin: '验证登录', switchToEmail: '无法使用验证器?切换到邮箱验证', switchToTotp: '使用验证器应用验证', backLogin: '返回登录', emailRequired: '请输入您的邮箱地址', codeSent: '验证码已发送', sendFailed: '发送失败', verifyFailed: '验证失败' }, twoFactorSetup: { title: '双重认证 (2FA)', enabledDesc: '您的账户已开启双重认证保护', disabledDesc: '未开启,建议开启以提升账户安全性', enable: '开启', disable: '关闭', setupTitle: '设置双重认证', setupDesc: '请使用 Google Authenticator 或其他验证器应用扫描下方二维码', manualKey: '手动输入密钥', copyKey: '复制密钥', code: '验证码', codePlaceholder: '请输入6位验证码', verifyAndEnable: '验证并开启', disableTitle: '关闭双重认证', disableContent: '关闭后,您的账户将不再受到双重认证保护。为确保安全,请输入您的登录密码以确认。', verifyAndDisable: '验证并关闭', passwordPlaceholder: '请输入当前登录密码', fetchFailed: '获取验证码失败', copied: '密钥已复制', copyFailed: '复制失败', enabled: '双重认证已开启', verifyFailed: '验证失败', passwordRequired: '请输入密码', disabled: '双重认证已关闭', disableFailed: '关闭失败' }, appLoadingScreen: { ariaLabel: 'VoiceHub 正在加载', message: '正在同步排期、歌曲和用户状态' } }, ui: { errorBoundary: { retrying: '正在重试', retry: '重新尝试', hideDetails: '隐藏详细信息', showDetails: '查看详细信息', debugInfo: '系统调试信息', defaultTitle: '加载失败', defaultMessage: '数据加载时发生错误,请稍后重试', retryFailed: '重试失败:' }, loadingState: { progress: '加载进度', cancel: '取消加载', defaultMessage: '正在加载...' }, pagination: { info: (current: number, total: number) => `第 ${current} 页 · 共 ${total} 页`, totalItems: (total: number, itemName: string) => `共 ${total} ${itemName}`, first: '首页', prev: '上一页', next: '下一页', last: '尾页', pagePlaceholder: '页', jump: '跳转', defaultItemName: '项' }, lyrics: { loading: '歌词加载中...', empty: '暂无歌词' }, playerControls: { previous: '上一首', noPrevious: '没有上一首', next: '下一首', noNext: '没有下一首' }, playerInfo: { openLyrics: '点击打开歌词', coverAlt: '封面', lyrics: '歌词', textCoverFallback: '音' }, lyricsModal: { unknownSong: '未知歌曲', unknownArtist: '未知艺术家', lyrics: '歌词', comments: '评论', settings: '歌词设置', amStyleLyrics: 'AM 风格歌词', fontSize: '字体大小', lyricOffset: '歌词偏移 (ms)', showTranslation: '显示翻译', showRoma: '显示罗马音', showYrc: '逐字歌词 (YRC)', amllNormalizeSpaces: '规范空格', amllResetLineTimestamps: '对齐行时间戳', amllConvertBgLines: '合并背景和声行', amllSyncBgLines: '同步背景行时间', amllCleanOverlaps: '清理时间戳重叠', amllTryAdvanceStart: '提前行入场', quality: '音质', lyricSource: '歌词来源', lyricSourceAuto: '自动', playMode: { loopOne: '单曲循环', order: '列表循环', off: '单曲播放' }, notifications: { loopOne: '已切换为单曲循环', off: '已切换为单曲播放', order: '已切换为列表循环' } }, audioQuality: { unknown: '未知音质', options: { standard: { label: '标准', description: '适合流量有限的情况' }, neteaseHq: { label: 'HQ极高', description: '高品质音乐体验' }, neteaseSq: { label: 'SQ无损', description: '无损音质,文件较大' }, neteaseHiRes: { label: 'Hi-Res', description: '高解析度无损' }, neteaseMaster: { label: '超清母带', description: '最高音质' }, tencentHq: { label: 'HQ高音质', description: '高品质音乐体验' }, tencentSq: { label: 'SQ无损', description: '无损音质,文件较大' }, tencentHiRes: { label: 'Hi-Res', description: '高解析度音质' }, tencentMaster: { label: '臻品母带2.0', description: '最高音质' }, bilibiliDefault: { label: '默认', description: '默认音质' }, miguHq: { label: 'HQ高音质', description: '高品质音乐体验' }, miguSq: { label: 'SQ无损', description: '无损音质,文件较大' }, miguZq24: { label: 'ZQ24无损', description: '高解析度音质,文件更大,需要更多流量' } } }, bilibiliIframe: { openInNewTab: '在新标签页打开', openInBilibili: '在哔哩哔哩打开', close: '关闭', loadFailed: '无法加载视频' }, songComments: { eyebrow: '网易云评论', qqEyebrow: 'QQ音乐评论', title: '听友评论', latest: '最新评论', hotSort: '热门评论', refresh: '刷新评论', noSource: '当前歌曲暂无网易云评论来源', qqNoSource: '当前歌曲暂无 QQ 音乐评论来源', loading: '正在加载评论', retry: '重试', commentsCount: (count: string) => `${count} 条评论`, empty: '这首歌还没有可展示的评论', userAvatar: '用户头像', neteaseUser: '网易云用户', qqUser: 'QQ 音乐用户', locationLabel: '来自', commentImage: '评论图片', openImagePreview: '查看大图', closeImagePreview: '关闭大图', originalComment: '原评论', showMoreReplies: '展开更多回复', hideReplies: '收起回复', unlike: '取消点赞', like: '点赞评论', loadingMore: '加载中...', loadMore: '加载更多评论', tenThousand: '万', justNow: '刚刚', minutesAgo: (minutes: number) => `${minutes} 分钟前`, hoursAgo: (hours: number) => `${hours} 小时前`, loginRequiredToLike: '请先登录网易云账号后再点赞评论', likeFailed: '评论点赞失败', loadFailed: '评论加载失败', dateLocale: 'zh-CN' } }, composableErrors: { adminOnly: (action: string) => `只有管理员才能${action}`, loginRequired: (action: string) => `需要登录才能${action}`, failed: (action: string) => `${action}失败`, actions: { createSchedule: '创建排期', removeSchedule: '移除排期', updateScheduleSequence: '更新排期顺序', markPlayed: '标记歌曲已播放', sendNotification: '发送系统通知', getSystemSettings: '获取系统设置', updateSystemSettings: '更新系统设置', getPlayTimes: '获取播放时段', createPlayTime: '创建播放时段', updatePlayTime: '更新播放时段', deletePlayTime: '删除播放时段', deleteSong: '删除歌曲', updateSong: '更新歌曲', addSong: '添加歌曲', updateNotificationSettings: '更新通知设置', markNotification: '标记通知', markAllNotifications: '标记所有通知', deleteNotification: '删除通知', clearNotifications: '清空通知', getSemesters: '获取学期列表', getCurrentSemester: '获取当前学期', createSemester: '创建学期', setActiveSemester: '设置活跃学期', updateSemester: '更新学期', deleteSemester: '删除学期', getSemesterOptions: '获取学期选项' }, lyrics: { missingParams: '缺少必要参数', notFound: '未获取到歌词', unavailable: '暂无歌词', fetchFailed: '获取歌词失败' } }, audioPlayer: { autoplayBlocked: '浏览器限制了自动播放,请点击播放器中的播放按钮继续播放', noPrevious: '没有上一首歌曲', previousFailed: '播放上一首歌曲失败', noNext: '没有下一首歌曲', nextFailed: '播放下一首歌曲失败', playFailed: (message: string) => `播放失败:${message}`, popupBlocked: '浏览器拦截了新标签页,请允许弹窗后重试', originalLinkOpened: '已为你打开原始链接', fallbackSource: '当前播放链接无效,已切换备用音源', consecutiveFailures: '连续多首歌曲播放失败,已停止自动播放', bilibiliSkipped: '哔哩哔哩视频播放失败,自动跳过', loopOneEnabled: '已切换为单曲循环', singleEnabled: '已切换为单曲播放', listLoopEnabled: '已切换为列表循环' }, songs: { actions: { loginRequest: '需要登录才能点歌', loginVote: '需要登录才能投票', alreadyVoted: '您已经为这首歌投过票了', voteCancelled: (title: string) => `已取消对歌曲《${title}》的投票`, voteSucceeded: (title: string) => `为歌曲《${title}》投票成功!`, loginWithdraw: '需要登录才能撤回歌曲', loginDelete: '需要登录才能删除歌曲', deleteSucceeded: '歌曲已成功删除!', loginMarkPlayed: '需要登录才能标记歌曲', markPlayedSucceeded: '歌曲已成功标记为已播放!', loginUnmarkPlayed: '需要登录才能撤回歌曲已播放状态', unmarkPlayedSucceeded: '歌曲已成功撤回已播放状态!', loginRequestReplay: '需要登录才能申请重播', replaySucceeded: '申请重播成功', replayAlreadyRequested: '您已经申请过重播这首歌了', loginCancelReplay: '需要登录才能取消重播申请', replayCancelled: '已取消重播申请', leaveCollaborationSucceeded: (title: string) => `已成功退出歌曲《${title}》的联合投稿`, withdrawSucceeded: (title: string) => `已成功撤回《${title}》的投稿`, withdrawSucceededQuota: (title: string) => `已成功撤回《${title}》的投稿,投稿配额已返还`, fallbackSongTitle: '歌曲' }, duplicateSongModal: { title: '歌曲已存在', desc: '这首歌曲已经在列表中了,不能重复投稿', tip: '您可以为它点赞支持,或者尝试搜索其他歌曲!', votes: (count: number) => `${count} 票`, played: '已播放', pending: '待播放', requester: '投稿者:', back: '返回重选', liked: '已点赞', likeNow: '立即点赞' }, bilibiliEpisodesModal: { uploader: 'UP主:', empty: '暂无剧集', pause: '暂停', preview: '预听', played: '已播放', scheduled: '已排期', submitted: '已投稿', liked: '已点赞', like: '点赞', submitting: '提交中...', select: '选择', submit: '投稿' }, musicLoginModal: { neteaseTitle: '网易云扫码登录', neteaseDesc: '扫描二维码以安全登录您的账号', qqTitle: 'QQ音乐扫码登录', qqDesc: '扫描二维码以获取账号播放能力', loadingQr: '正在获取二维码...', qrExpired: '二维码已失效', clickRefresh: '点击刷新', expiredRefresh: '二维码已过期,请点击刷新', neteaseWaiting: '请使用网易云音乐APP扫码登录', qqWaiting: '请使用 QQ 扫码登录', scanSuccess: '扫描成功,请在手机上确认', neteaseSuccess: '登录成功,正在跳转...', qqSuccess: '登录成功,正在关闭...', neteaseTip: '说明:登录状态将保存到您的浏览器中,用于搜索播客等功能。', qqTip: '登录状态仅保存到当前浏览器,用于 QQ 音乐播放和歌词解析。', channelQq: 'QQ 扫码', channelWx: '微信扫码', wxWaiting: '请使用微信扫一扫二维码', wxScanned: '已扫描,请在手机上确认', wxTip: '使用手机微信扫码登录,登录状态同样仅保存在当前浏览器。', retry: '重试', qqAccount: 'QQ音乐账号', qqQrIncomplete: 'QQ 登录二维码返回不完整', qqQrFailed: '获取 QQ 登录二维码失败', qqMissingCookie: 'QQ 登录成功但未返回 Cookie', qqCheckFailed: '检查 QQ 登录状态失败' }, mediaModals: { recentTitle: '最近播放 - 歌曲', recentDesc: '查看并快速投稿您最近在网易云播放的歌曲', loadingRecent: '正在获取播放记录...', retryLoad: '重试加载', noRecent: '暂无最近播放记录', checking: '检查中', played: '已播放', scheduled: '已排期', inList: '已在列表中', processing: '处理中...', continueSubmit: '继续投稿', liked: '已点赞', like: '点赞', submitting: '正在提交...', submitLoading: '提交中...', selectSubmit: '选择投稿', close: '关闭窗口', programListTitle: (radioName: string) => `${radioName} - 节目列表`, loadingPrograms: '加载节目中...', retry: '重试', noPrograms: '暂无节目', existing: '已存在', loadingMore: '加载中...', loadMore: '加载更多', fetchProgramsFailed: '获取节目失败', networkFailed: '网络请求失败', unknownDj: '未知主播', playedCannotLike: '已播放的歌曲不能点赞', scheduledCannotLike: '已排期的歌曲不能点赞', fetchRecentFailed: '获取最近播放失败', justNow: '刚刚', minutesAgo: (minutes: number) => `${minutes}分钟前`, hoursAgo: (hours: number) => `${hours}小时前`, monthDay: (month: number, day: number) => `${month}月${day}日`, tenThousand: '万' }, scheduleList: { addToPlaylist: '添加到歌单', chooseDate: '选择日期', noScheduleDates: '暂无排期日期', loading: '加载中...', emptyAll: '暂无排期信息', emptyAllDesc: '点歌后等待管理员安排播出时间', emptyDate: '当前日期暂无排期', emptyDateDesc: '请选择其他日期查看', unspecifiedPlayTime: '未指定时段', play: '播放', pause: '暂停', replaySong: '重播歌曲', viewSubmissionNote: '查看备注留言', replayApplicants: '重播申请人:', applicant: '申请人:', requester: '投稿人:', mainRequesterTitle: '主投稿人: ', requesterTitle: '投稿人: ', collaboratorsTitle: '联合投稿: ', unknown: '未知', replay: '重播', heat: '热度', cardCodeUsed: '点歌券', loginRequiredForPlaylist: '需要登录网易云音乐账号才能管理歌单', loginNow: '立即登录', currentAccount: '当前账号', neteaseUser: '网易云用户', targetPlaylist: '选择目标歌单', playlistPlaceholder: '请选择歌单', refreshPlaylist: '刷新歌单列表', deletePlaylist: '删除当前歌单', or: '或', createPlaylist: '创建新歌单', newPlaylistPlaceholder: '输入新歌单名称', create: '新建', privatePlaylist: '设为隐私歌单', selectSongs: '选择歌曲', selectAll: '全选', clear: '清空', noNeteaseSongs: '当前日期没有来自网易云的歌曲', playlistLoadFailed: '获取歌单列表失败', playlistLoadFailedWithMessage: (message: string) => `获取歌单列表失败:${message}`, playlistCreateSuccess: '歌单创建成功', playlistCreateFailed: '歌单创建失败', playlistCreateFailedWithMessage: (message: string) => `歌单创建失败:${message}`, deletePlaylistTitle: '删除歌单', deletePlaylistMessage: '确定要删除当前歌单吗?此操作无法撤销。', playlistDeleteSuccess: '歌单删除成功', playlistDeleteFailed: '歌单删除失败', playlistDeleteFailedWithMessage: (message: string) => `歌单删除失败:${message}`, playlistAddSuccess: (count: number) => `成功添加 ${count} 首歌曲到歌单`, playlistAddFailed: '添加到歌单失败', playlistAddFailedWithMessage: (message: string) => `添加到歌单失败:${message}`, musicUrlUnavailable: '无法获取音乐播放链接,请稍后再试', musicUrlFailed: '获取音乐播放链接失败', invalidDateFormat: '无效的日期格式', invalidDate: '无效的日期', missingMusicInfo: '歌曲缺少音乐平台或音乐ID信息,无法获取播放链接', mobileDate: (month: number, day: number, weekday: string) => `${month}月${day}日 ${weekday}`, fullDate: (year: number, month: number, day: number) => `${year}年${month}月${day}日`, playTimeStart: (time: string) => `${time} 开始`, playTimeEnd: (time: string) => `${time} 结束`, cancel: '取消', adding: '正在添加...', confirmAdd: '确认添加', submissionNote: '投稿备注留言', publicNote: '公开备注', privateNote: '仅管理员可见', songsCount: (count: number) => `${count}首` }, songList: { mobileSearchPlaceholder: '搜索点播记录...', searchPlaceholder: '输入想要搜索的歌曲', tabs: { all: '全部投稿', mine: '我的投稿', replays: '我的重播' }, currentSemester: '当前学期: ', refreshing: '正在刷新...', refresh: '刷新歌曲列表', loading: '加载中...', emptyMine: '您还没有投稿歌曲,马上去点歌吧!', emptyReplays: '您还没有申请重播的歌曲,去看看已经播放过的歌吧!', emptyAll: '暂无歌曲,马上去点歌吧!', play: '播放', pause: '暂停', playDate: (date: string) => `播放日期:${date}`, scheduleDate: (date: string) => `排期日期:${date}`, played: '已播放', scheduled: '已排期', replay: '重播', replaySong: '重播歌曲', viewSubmissionNote: '查看备注留言', mainRequesterTitle: '主投稿人: ', requesterTitle: '投稿人: ', collaboratorsTitle: '联合投稿: ', replayRequest: (count: number) => `重播申请 (${count}):`, requester: '投稿人:', heat: '热度', cardCodeUsed: '点歌券', likeAlt: '点赞', requestedAt: '投稿时间:', withdrawSubmission: '撤回投稿', leaveCollaboration: '退出联合投稿', withdraw: '撤销', cancelReplayTitle: '撤回重播申请', cancelReplay: '撤回申请', itemName: '首歌曲', submissionNote: '投稿备注留言', publicNote: '公开备注', privateNote: '仅管理员可见', unknownSong: '未知歌曲', unknownArtist: '未知歌手', unknownTime: '未知时间', unknownUser: '未知用户', textCoverFallback: '音', like: '点赞', inactiveSemester: '非活跃学期', notCurrentSemester: '非本学期', playedCannotLike: '已播放的歌曲不能点赞', scheduledCannotLike: '已排期的歌曲不能点赞', selfLikeDisabled: '不允许自己给自己点赞', unlike: '点击取消点赞', loginBeforeLike: '请先登录后再点赞', withdrawTitle: '撤回投稿', withdrawMessage: (title: string) => `确认撤回歌曲《${title}》的投稿吗?这将同时取消所有联合投稿关联。`, leaveTitle: '退出联合投稿', leaveMessage: (title: string) => `确认退出歌曲《${title}》的联合投稿吗?`, cancelReplayConfirmTitle: '取消重播申请', cancelReplayMessage: (title: string) => `确认取消歌曲《${title}》的重播申请吗?`, requestReplayTitle: '申请重播', requestReplayMessage: (title: string) => `确认申请重播歌曲《${title}》吗?`, processing: '处理中...', requestReplay: '申请重播', replayRequesting: '申请中...', replayRejectedCooldown: (hours: number) => `已拒绝(${hours}小时后可重新申请)`, replayed: '已重播', onlyCurrentSemesterReplay: '只能申请重播当前学期的歌曲', replayRejectedTooltip: (hours: number) => `申请被拒绝,需要等待 ${hours} 小时后才能重新申请`, alreadyReplayed: '该歌曲已重播', alreadyRequestedReplay: '该歌曲已申请过重播', musicUrlFailed: '获取音乐播放链接失败', semesterLoadFailed: '获取学期信息失败,请刷新页面重试', platformAutoSwitched: (name: string) => `当前平台已不可用,已自动切换至${name}` }, requestForm: { guidelinesTitle: '投稿须知', defaultGuidelines: [ '投稿时无需加入书名号', '除DJ外,其他类型歌曲均接收(包括小语种)', '禁止投递含有违规内容的歌曲', '点播的歌曲将由管理员进行审核', '审核通过后将安排在播放时段播出', '提交即表明我已阅读投稿须知并已知该歌曲有概率无法播出', '本系统仅提供音乐搜索和播放管理功能,不存储任何音乐文件。所有音乐内容均来自第三方音乐平台,版权归原平台及版权方所有。用户点歌时请确保遵守相关音乐平台的服务条款,尊重音乐作品版权。我们鼓励用户支持正版音乐,在官方平台购买和收听喜爱的音乐作品。', '最终解释权归广播站所有' ], mobileDefaultGuidelines: [ '投稿时无需加入书名号', '除DJ外,其他类型歌曲均接收(包括小语种)', '禁止投递含有违规内容的歌曲', '点播的歌曲将由管理员进行审核', '审核通过后将安排在播放时段播出', '提交即表明我已阅读投稿须知并已知该歌曲有概率无法播出', '本系统仅提供音乐搜索和播放管理功能,不存储任何音乐文件。所有音乐内容均来自第三方音乐平台,版权归原平台及版权方所有。', '最终解释权归广播站所有' ], searchLabel: '歌曲搜索', searchPlaceholder: '请输入歌曲名称', processing: '处理中...', search: '搜索', audioMatch: '听歌识曲', audioMatchShort: '识曲', importFromPast: '从往期导入', collaborators: '联合投稿', add: '添加', adminUnlimited: '您是管理员,不受投稿限制', outsideRequestTime: '当前不在投稿开放时段', submissionClosed: '投稿功能已关闭', currentPeriod: '当前时段:', accepted: '已接纳', todayRequests: '今日投稿:', weeklyRequests: '本周投稿:', monthlyRequests: '本月投稿:', remaining: '剩余', platforms: { netease: '网易云音乐', tencent: 'QQ音乐', bilibili: '哔哩哔哩', migu: '咪咕音乐' }, refreshing: '刷新中', neteaseLoginTitle: '登录网易云获取完整体验', qqLoginTitle: '登录 QQ 音乐提升播放稳定性', loginNow: '立即登录', importData: '导入数据', loggedIn: '已登录', qqLoggedIn: 'QQ音乐已登录', single: '单曲', podcast: '播客', recent: '最近', playlist: '歌单', exportCookie: '导出Cookie数据', logout: '退出登录', logoutQQ: '退出 QQ 音乐登录', qqLoginExpired: 'QQ 音乐登录已失效,请重新登录', preferredPlayTime: '期望播出时段', choosePlayTime: '选择时段', submissionNote: '投稿备注留言', cardCode: '点歌券', required: '必填', optional: '可选', editCardCode: '修改', addCardCode: '添加', clearCardCode: '清除点歌券', cardCodeLabel: '券码', clear: '清除', save: '保存', validatingCardCode: '正在验证点歌券...', validatingShort: '验证中', cardCodeRequiredHelper: '开启强制点歌券后,提交点歌时必须填写有效点歌券。', cardCodeOptionalHelper: '填写点歌券可用于抵扣或提交点歌。', cardCodeRequiredBypassHelper: '提交点歌时必须填写有效点歌券;点歌券投稿不占普通额度。', cardCodeOptionalBypassHelper: '使用有效点歌券可突破个人投稿限额,且不占普通额度。', cardCodeAvailableBypass: '点歌券可用,不占普通额度', cardCodePlaceholder: '请输入点歌券', cardCodeWillValidate: '已填写点歌券,提交前会验证', cardCodeRequiredStatus: '提交前需要添加有效点歌券', cardCodeOptionalStatus: '可选添加点歌券', cardCodeInvalid: '点歌券无效', cardCodeAvailable: '点歌券可用', cardCodeFilled: '已填点歌券', cardCodeRequiredShort: '点歌券必填', cardCodeOptionalShort: '点歌券可选', cardCodeSaveHint: '保存时会先验证点歌券是否可用。', cardCodeValidateFailed: '点歌券验证失败,请稍后重试', cardCodeRequiredWarning: '请先填写点歌券', cardCodeAuthRequired: '请先登录后再验证点歌券', cardCodeDisabled: '点歌券投稿功能未启用', cardCodeInvalidOrUsed: '点歌券无效或已被使用', cardCodeLockedOrUnavailable: '点歌券已被锁定或不可用', cardCodeRequiredForSite: '本站点已启用仅点歌券投稿,请提供有效点歌券', cardCodeTooLong: '点歌券不能超过100个字符', notifications: { restrictionSameSong: '该歌曲处于投稿限制冷却期,请稍后再试', restrictionSameArtist: '该歌手处于投稿限制冷却期,请稍后再试', restrictionGeneric: '该歌曲或歌手处于投稿限制冷却期,请稍后再试', exportSuccess: '导出成功', validatingCookie: '正在验证Cookie有效性...', importSuccess: '导入成功', cookieInvalid: '导入的Cookie无效或已过期', fileFormatError: '文件格式错误', importFailed: (message: string) => `导入失败: ${message}`, missingSongId: '无法投票:缺少歌曲ID', likeFailed: '点赞失败', songNameRequired: '歌曲名称不能为空', musicUrlFailedRetry: '获取音乐URL失败,请稍后重试', songUnavailable: '该歌曲无法播放,可能是付费内容', playFailed: '播放失败,请稍后重试', songSelectedMaybeLimited: '已选择歌曲,但可能无法播放完整版本', duplicateSong: '这首歌曲已经在列表中了,不能重复投稿。您可以为它点赞支持!', blacklistedSong: (reasons: string) => `该歌曲无法点歌: ${reasons}`, submitFailed: '投稿失败,请稍后重试', likeSuccess: '点赞成功!', likeFailedRetry: '点赞失败,请稍后重试', completeSongInfoRequired: '请输入完整的歌曲信息', fixCoverUrl: '请修正封面URL错误后再提交', fixPlayUrl: '请修正播放地址URL错误后再提交', replayAlreadyRequested: '该歌曲已申请过重播', replayRequestSuccess: '申请重播成功', replayRequestFailed: (message: string) => `申请重播失败: ${message}`, replayOriginalNotFound: '未找到可申请重播的原歌曲', periodQuotaFull: (accepted: number, expected: number) => `当前时段投稿名额已满 (${accepted}/${expected})`, dailyLimitReached: (used: number, limit: number) => `今日投稿已达上限 (${used}/${limit})`, weeklyLimitReached: (used: number, limit: number) => `本周投稿已达上限 (${used}/${limit})`, monthlyLimitReached: (used: number, limit: number) => `本月投稿已达上限 (${used}/${limit})` }, publicToUsers: '公开给已登录用户', submissionNoteApprovalHint: '公开留言需管理员审核通过后展示', coverAlt: '封面', albumDetailsTitle: '点击查看专辑详情', album: '专辑:', uploadToNeteaseCloud: '上传到网易云音乐云盘', allEpisodesSubmitted: '所有剧集已存在', partialEpisodesSubmitted: '部分剧集已存在', chooseEpisodes: '选择剧集', songPlayed: '歌曲已播放', songScheduled: '歌曲已排期', songExists: '歌曲已存在', continueSubmit: '继续投稿', playedCannotLike: '已播放的歌曲不能点赞', scheduledCannotLike: '已排期的歌曲不能点赞', liked: '已点赞', like: '点赞', played: '已播放', scheduled: '已排期', chooseProgram: '选择节目', chooseSubmit: '选择投稿', requestReplay: '申请重播', manualSubmitLong: '以上没有我想要的歌曲,手动输入提交', loginRequiredToSubmit: '请先登录后提交', loginRequiredNotice: '注意,您尚未登录,不能投稿', cardCodeBypassesLimit: '不占普通额度', noResults: '未找到相关歌曲', noResultsHint: '试试其他关键词或切换平台', noMatchingSongs: '没有找到匹配的歌曲', searchRequestFailed: '搜索请求失败,请稍后重试', manualSubmit: '手动输入提交', searchSongsAlt: '搜索歌曲', addCollaboratorTitle: '添加联合投稿人', albumModal: { albumFallback: '专辑', unknownArtist: '未知艺术家', songCount: (count: number) => `${count} 首`, publishTime: (date: string) => `发行时间:${date}`, company: (company: string) => `唱片公司:${company}`, viewFullIntro: '点击查看完整介绍', searchPlaceholder: '搜索专辑内歌曲...', loading: '加载中...', noMatches: '未找到匹配的歌曲', noSongs: '暂无歌曲', pause: '暂停', preview: '预听', submitted: '已投稿', submit: '投稿', albumIntro: '专辑简介', loadFailed: '加载失败,请稍后重试', fetchFailed: '获取专辑详情失败', unsupportedPlatform: '不支持的平台', tencentUnsupported: 'QQ音乐专辑详情功能暂未实现' }, importSongsModal: { resultTitle: '导入结果', resultDesc: '歌曲导入操作已完成', successCount: '成功导入', failedCount: '失败/跳过', details: '详细处理记录', allSuccess: '全部歌曲导入成功!', done: '完成并返回', title: '从历史学期导入', desc: '选择以往学期的歌曲并导入到当前学期', selectSemester: '选择学期', semesterPlaceholder: '请选择目标学期', loadingSongs: '正在加载歌曲...', retry: '重试加载', selectSemesterFirst: '请先选择一个学期', noSongs: '没有找到符合条件的歌曲', collected: '已收录', notCollected: '未收录', unplayed: '未被收录', played: '被收录', all: '全部', selectAll: '选择当前全部', cancelSelectAll: '取消全选', selectedSongs: (count: number) => `已选择 ${count} 首歌曲`, importFailed: '导入失败', loadSemestersFailed: '加载学期列表失败', loadSongsFailed: '加载歌曲列表失败', importing: '正在导入...', confirmImport: '确认导入' }, neteaseUpload: { title: '上传到网易云音乐', loginRequired: '请先登录网易云音乐账号', loginNow: '立即登录', quality: '选择音质', songInfo: '歌曲信息', coverAlt: '封面', cancel: '取消', uploading: '上传中...', startUpload: '开始上传', unknownSong: '未知歌曲', unknownArtist: '未知歌手', unknownAlbum: '未知专辑', statusGetDownloadUrl: '获取下载链接', statusDownloading: '正在下载音频', statusHashing: '正在计算文件指纹', statusToken: '正在获取上传凭证', statusUploading: '正在上传到网易云音乐', statusExists: '文件已存在,秒传成功', statusSaving: '正在保存云盘信息', statusPreparing: '准备中', statusDone: '上传完成', statusFailed: '上传失败', fetchingQQUrl: '正在从QQ音乐获取音频链接...', downloadingAudio: '正在下载音频文件...', uploadingCloud: '正在上传到网易云音乐云盘...', uploadSuccess: '歌曲已成功上传到您的网易云音乐云盘', missingSongId: '缺少歌曲ID (strMediaMid)', invalidPlayUrl: '无法获取有效的播放链接', emptyResponse: '响应体为空', missingResolvedId: '无法获取歌曲ID,请重试', missingMusicUrl: '无法获取音乐播放链接', unknownError: '未知错误', uploadFailed: (message: string) => `上传失败: ${message}`, requestFailed: (status: number | string) => `请求失败: ${status}`, downloadFailed: (status: number | string) => `下载失败: ${status}`, tokenFailed: (message: string | number) => `获取凭证失败: ${message}`, nosFailed: (status: number | string) => `NOS上传失败: ${status}`, nosNetworkError: 'NOS网络错误', saveMaybeFailed: (code: string | number) => `云盘信息保存可能失败 (错误码: ${code}),请检查云盘内是否成功上传歌曲。`, publishFailed: (message: string | number) => `发布失败: ${message}` }, playlistModal: { selectPlaylist: '选择歌单', playlistDetails: '歌单详情', processing: '处理中...', retry: '重试', emptyPlaylists: '暂无歌单', favSongs: '我喜欢', songCount: (count: number) => `${count}首`, emptyPlaylist: '歌单为空', exists: '已存在', loadMore: '加载更多', loadingMore: '加载中...', fetchPlaylistsFailed: '获取歌单列表失败', fetchSongsFailed: '获取歌单歌曲失败', networkFailed: '网络请求失败' }, audioMatchHint: '靠近音源播放,录制 3 秒识别歌曲', audioMatchScriptLoadFailed: (src: string) => `加载识曲资源失败: ${src}`, audioMatchEngineFailed: '识曲引擎初始化失败', unknownSong: '未知歌曲', unknownArtist: '未知歌手', audioMatchGenerating: '正在生成指纹并识别...', audioMatchNoMatch: '未识别到匹配歌曲,请换一段更清晰的副歌重试', audioMatchDone: (count: number) => `识别完成,找到 ${count} 个候选结果`, audioMatchFailed: '听歌识曲失败,请稍后重试', microphoneRequesting: '正在请求麦克风权限...', microphoneUnsupported: '当前环境不支持麦克风访问,请确保使用 HTTPS 访问或 localhost 调试', audioMatchRecordingProgress: (current: string, total: number) => `录音中 ${current}s / ${total}s`, microphoneTimeout: '麦克风授权超时,请在系统设置中确认已允许麦克风权限', microphoneReady: '麦克风已连接,点击开始识曲', audioMatchInitFailed: '无法初始化听歌识曲,请检查麦克风权限', microphoneAccessFailed: '无法访问麦克风,请稍后重试', preparing: '准备中...', recognizing: '识别中...', startAudioMatch: '开始识曲', recording: '录制中...', cancel: '取消', audioMatchResults: '识别结果', manualTitle: '手动输入歌曲信息', songName: '歌曲名称', artistName: '歌手名称', artistPlaceholder: '请输入歌手名称', coverUrl: '歌曲封面地址(选填)', coverPlaceholder: '请输入歌曲封面图片URL', playUrl: '播放地址(选填)', playUrlPlaceholder: '请输入歌曲播放URL', validUrl: 'URL有效', submitting: '提交中...', confirmSubmit: '确认提交' } } } as const export const auth = pages.auth export const ui = pages.ui export const songs = pages.songs export const yearReview = pages.yearReview export const composableErrors = pages.composableErrors export const audioPlayer = pages.audioPlayer export const importantNotification = { label: '重要通知', unread: '未读', read: '已读', sender: '发送人', systemSender: '系统', close: '已读', closing: '正在标记已读...', justNow: '刚刚', minutesAgo: (minutes: number) => `${minutes}分钟前`, hoursAgo: (hours: number) => `${hours}小时前`, daysAgo: (days: number) => `${days}天前`, loadFailed: '加载重要通知失败,请稍后重试', closeFailed: '标记已读失败,请重试', retry: '重试' } export const admin = { sidebar: { console: '管理控制台', logout: '退出登录', adminFallback: '管理员', avatarFallback: '管', sections: { overview: '概览', content: '内容管理', users: '用户管理', api: 'API管理', system: '系统管理', account: '账户管理' }, menu: { overview: '数据概览', schedule: '排期管理', print: '打印排期', songs: '歌曲管理', dataAnalysis: '数据分析', users: '用户管理', gradeClass: '年级班级', apiKeys: 'API密钥管理', notifications: '通知管理', smtpConfig: '邮件配置', playtimes: '播出时段', requestTimes: '投稿管理', semesters: '学期管理', blacklist: '黑名单管理', cardCodes: '点歌券管理', musicSource: '音源控制', siteConfig: '站点配置', database: '数据库操作', password: '修改密码' }, roles: { USER: '普通用户', SONG_ADMIN: '歌曲管理员', ADMIN: '管理员', SUPER_ADMIN: '超级管理员' } }, overview: { recentActivities: '最近活动', loading: '加载中...', noActivities: '暂无活动记录', systemStatus: '系统状态', online: '在线', offline: '离线', instanceId: '实例 ID', noInstanceId: '暂无实例 ID', quickActions: '快速操作', statCards: { totalSongs: '总歌曲数', registeredUsers: '注册用户', todaySchedules: '今日排期', weeklyRequests: '本周投稿' }, statusItems: { database: '数据库', api: 'API 服务', version: '系统版本', semester: '当前学期', blacklist: '黑名单项目' }, actions: { schedule: '管理排期', notifications: '发送通知', users: '用户管理', blacklist: '黑名单管理' }, copied: '实例 ID 已复制', copyFailed: '复制失败', loadFailed: '加载数据失败', normal: '正常', abnormal: '异常', unset: '未设置', itemUnit: (count: number) => `${count} 项`, justNow: '刚刚', minutesAgo: (minutes: number) => `${minutes}分钟前`, hoursAgo: (hours: number) => `${hours}小时前`, daysAgo: (days: number) => `${days}天前`, activityTypes: { song: '歌曲投稿', schedule: '排期更新', user: '用户操作', system: '系统事件' } }, blacklist: { title: '歌曲黑名单管理', desc: '禁止特定歌曲或包含关键词的歌曲被点播,维护广播内容的健康与合规', addTitle: '添加黑名单项', type: '封禁类型', song: '具体歌曲', keyword: '关键词', language: '语种', genre: '曲风', allTypes: '全部类型', songLabel: '歌曲名称 - 艺术家', keywordLabel: '关键词内容', languageLabel: '语种值', genreLabel: '曲风值', languageHint: '仅对网易云/QQ音源生效:「其他」指已判定但不属于上述语种的歌曲;无法判定或手动投稿不拦截', genreHint: '对网易云/QQ音源生效:QQ流派按官网英文分类映射,不属于上述候选的流派归入「其他」;无法判定不拦截', songPlaceholder: '例如: 歌曲名 - 艺术家', keywordPlaceholder: '例如: 敏感词、特定风格', reason: '封禁原因 (可选)', reasonPlaceholder: '简述加入黑名单的原因', processing: '处理中...', addButton: '添加到黑名单', searchPlaceholder: '在黑名单中搜索...', typeFilter: '类型筛选', listTitle: (total: number) => `黑名单列表 (${total} 项)`, reasonPrefix: '原因:', noReason: '未填写原因', createdAt: '创建时间:', disable: '禁用', enable: '启用', loading: '加载中...', emptyTitle: '未找到匹配的黑名单项', emptyDesc: '请尝试调整筛选条件或添加新项目', pagination: (page: number, pages: number) => `第 ${page} 页 / 共 ${pages} 页`, removeTitle: '确认从黑名单移除', removeMessage: (value: string) => `确定要移除 "${value}" 吗?移除后,该项目将恢复为正常状态。`, cancel: '取消', deleting: '删除中...', confirmRemove: '确认移除', fetchFailed: '获取黑名单失败', addSuccess: '黑名单项添加成功', addFailed: '添加黑名单项失败', addFailedPrefix: '添加失败: ', statusSuccess: (enabled: boolean) => `黑名单项已${enabled ? '启用' : '禁用'}`, updateFailed: '更新状态失败', deleteSuccess: '黑名单项删除成功', deleteFailed: '删除失败' }, gradeClass: { title: '年级班级管理', desc: '维护注册、批量修改与通知筛选时可选用的年级班级;未配置时将自动回退到从现有用户提取', gradeLabel: '年级', classLabel: '班级', gradePlaceholder: '如:高一', classPlaceholder: '如:一班', addButton: '添加', deleteButton: '删除', batchTitle: '批量生成', batchGradePlaceholder: '多个年级用逗号分隔,如:高一,高二,高三', batchClassPlaceholder: '多个班级用逗号分隔,支持数字区间,如:一班,二班 或 1-10', batchButton: '批量生成', batchResult: (added: number, skipped: number) => `已添加 ${added} 项${skipped > 0 ? `,跳过 ${skipped} 项已存在` : ''}`, batchInvalid: '请填写至少一个年级和一个班级', batchLimit: '单次批量最多 500 项,请缩小年级或班级范围', initTitle: '从现有用户初始化', initDesc: '自动提取当前所有活跃用户的年级班级组合并添加到配置,已存在的组合自动跳过', initButton: '从用户提取', initResult: (added: number, skipped: number) => `已提取 ${added} 项${skipped > 0 ? `,跳过 ${skipped} 项已存在` : ''}`, initFailed: '初始化失败', batchFailed: '批量生成失败', guideTitle: '使用说明', guideSingle: '单条添加:在左侧输入一个年级和一个班级,点击「添加」', guideBatchLine1: '批量生成:年级用逗号分隔多个值,如「高一,高二,高三」', guideBatchLine2: '班级支持逗号分隔与数字区间,如「1-10」会自动生成 1班~10班', guideDedup: '重复的组合会自动跳过;删除班级配置不影响已有用户的数据', classCount: (count: number) => `${count} 个班`, personCount: (count: number) => `${count} 人`, deleteGradeButton: '删除年级', deleteGradeTitle: '删除整个年级', deleteGradeMessage: (grade: string, count: number) => `确认删除「${grade}」下的 ${count} 个班级配置?仅影响选项列表,不影响已有用户数据`, deleteGradeSuccess: '年级配置已删除', addSuccess: '配置项已添加', addFailed: '添加失败', duplicate: '该年级班级组合已存在', deleteConfirm: '确认删除该配置项?仅影响选项列表,不影响已有用户数据', deleteSuccess: '配置项已删除', deleteFailed: '删除失败', loading: '加载中...', empty: '暂未配置年级班级', fallbackHint: '当前没有配置,注册等场景的选项将自动来自现有用户数据', loadFailed: '获取配置失败' }, songManagement: { title: '歌曲管理', stats: { total: '总计', played: '已播放', pending: '待播放' }, actions: { download: '下载', delete: '删除', addManual: '手动添加', refresh: '刷新', viewRemark: '查看备注留言', edit: '编辑歌曲', markPlayed: '标记为已播放', markUnplayed: '标记为未播放', reject: '驳回歌曲', deleteSong: '删除歌曲' }, filters: { semester: '学期', selectSemester: '选择学期', playTime: '播出时段', selectPlayTime: '选择时段', status: '状态', selectStatus: '选择状态', sort: '排序', selectSort: '选择排序' }, options: { allStatus: '全部状态', pending: '待排期', scheduled: '已排期', played: '已播放', hasNote: '有备注', newest: '最新投稿', oldest: '最早投稿', hotDesc: '热度最高', hotAsc: '热度最低', titleAsc: '标题 A-Z', titleDesc: '标题 Z-A' }, table: { songInfo: '歌曲信息', requester: '投稿人', stats: '统计', status: '状态', actions: '操作', selectPage: '全选本页' }, empty: { search: '没有找到匹配的歌曲', default: '暂无歌曲数据' }, dialog: { cancel: '取消', confirmDelete: '确认删除', deleteSongTitle: '删除歌曲', deleteSongMessage: (title: string) => `确定要删除歌曲 "${title}" 吗?此操作不可撤销。`, batchDeleteTitle: '批量删除歌曲', batchDeleteMessage: (count: number) => `确定要删除选中的 ${count} 首歌曲吗?此操作不可撤销。` }, rejectDialog: { title: '驳回歌曲', requester: (name: string) => `投稿人: ${name}`, reason: '驳回原因', reasonPlaceholder: '请输入驳回原因,将通过系统通知发送给投稿人...', addToBlacklist: '同时将此歌曲加入黑名单', blacklistHint: '加入黑名单后,该歌曲将无法再次被投稿', processing: '处理中...', confirm: '确认驳回' }, editModal: { editTitle: '编辑歌曲', addTitle: '手动添加歌曲', titleLabel: '歌曲名称', titlePlaceholder: '输入歌曲标题', artistLabel: '歌手', artistPlaceholder: '输入歌手姓名', requester: '投稿人', userSearchPlaceholder: '搜索用户姓名或用户名', selectedUser: (name: string) => `已选择: ${name}`, collaborators: '联合投稿人', collaboratorSearchPlaceholder: '搜索并添加联合投稿人', collaboratorHint: '支持添加多个联合投稿人,保存后立即生效', preferredPlayTime: '期望时段 (可选)', selectPreferredPlayTime: '选择期望播出时段', submissionNote: '歌曲备注', clearNote: '清空备注', cancelClearNote: '撤销清空', submissionNotePlaceholder: '填写歌曲备注', publicNote: '公开备注留言', publicNoteHint: '公开后其他用户可以看到此备注留言', clearNoteHint: '保存后将清空当前备注,可填写理由并发送通知', clearNoteReasonPlaceholder: '可选:请输入清空备注的理由,例如:备注内容违规', notifyAfterClear: '清空后发送通知', notifyAfterClearHint: '将通知主投稿人和当前联合投稿人', musicPlatform: '音乐平台 (可选)', selectPlatform: '选择平台', musicId: '音乐ID (可选)', musicIdPlaceholder: '输入平台唯一标识符', coverUrl: '封面URL (可选)', playUrl: '播放地址URL (可选)', duration: '时长 (秒)', durationPlaceholder: '例如: 240', durationHint: '取值范围 0~7200 秒(留空表示无时长信息),可通过后台校验自动验证', refreshDuration: '刷新', validUrl: 'URL有效', saving: '保存中...', saveChanges: '保存更改', adding: '添加中...', addSong: '添加歌曲' }, songDownloadDialog: { title: '下载歌曲', quality: '选择音质', advancedOptions: '高级选项', mergeIntoOne: '合并为一个文件', mergeDesc: '将选中歌曲按顺序合并为单个音频', normalizeAudio: '音频标准化', normalizeDesc: '统一峰值音量,可与导出格式独立使用', saveDbPresetTitle: '保存当前音量设置(包括开启状态)为默认', saved: '已保存!', savePreset: '保存预设', exportFormat: '导出格式', mergeNeedsFormat: '合并文件需要指定输出格式', transcodeSingle: '将单个音频转码为指定格式', format: '格式', customFilename: '自定义文件名', saveAsDefaultPreset: '保存为默认预设', filenamePlaceholder: '例如: 第XX期 - {songs}', insertAllSongs: '插入所有歌名', insertDate: '插入当前日期', placeholders: '可用占位符:', allSongs: '所有歌名', date: '日期', songList: '歌曲列表', estimatedDuration: (duration: string) => `预估总时长: ${duration}`, estimateSelectedTitle: '快速预估选中歌曲的总时长', estimatingDuration: '预估中...', estimateDuration: '预估时长', allSelectedHaveDuration: '所有选中歌曲已有时长信息', durationFromPlaybackUrlFailed: '无法从播放链接获取时长', previewDurationDetected: '疑似试听时长', estimateSuccess: (count: number) => `成功预估 ${count} 首歌曲的时长`, estimateFailedCount: (count: number) => `${count} 首歌曲预估失败`, estimateFailed: '预估时长失败', preloadSelectedTitle: '预下载选中歌曲到浏览器缓存', preloadSelected: '预下载选中', selectAll: '全选', deselectAll: '取消全选', deleteCache: '删除缓存', preloadSong: '预下载此歌曲', emptySongs: '暂无歌曲', processProgress: '处理进度', downloadProgress: '下载进度', downloadingSong: (song: string) => `正在下载: ${song}`, preparing: '准备中...', completeWithErrors: '下载完成,部分失败', complete: '下载完成', downloadFailedCount: (count: number) => `下载失败 (${count})`, selectedSongsCount: (count: number) => `已选择 ${count} 首歌曲`, cancel: '取消', close: '关闭', processing: '处理中...', downloading: '下载中...', startProcessing: '开始处理', startDownload: '开始下载', qualityDescriptions: { 2: '节省流量', 3: '高品质体验', 4: '极高音质', 5: '无损音质', 6: 'Hi-Res无损', 9: '超清母带', default: '标准音质' }, preloadFailed: (title: string) => `预下载失败: ${title}`, mergeTitle: '音频合并', mergeFailed: '合并失败', musicUrlMissing: '无法获取音乐播放链接', musicUrlFailed: (message: string) => `获取音乐播放链接失败: ${message}`, downloadingProgress: (title: string, percent: number) => `正在下载: ${title} (${percent}%)`, usingPreloadCache: (title: string) => `使用预下载缓存: ${title}`, downloadingTitle: (title: string) => `下载中: ${title}`, mergedFilename: (date: string, count: number, ext: string) => `排期合并_${date}_${count}首.${ext}`, preprocessingAudio: (value: number | string) => `正在预处理音频: ${value}%`, mergingAudio: (value: number | string) => `正在合并音频: ${value}%`, encodingAudio: (format: string, value: number | string) => `正在编码 ${format}: ${value}%`, encodingFailed: '编码失败', encoderWorkerFailed: '编码 Worker 运行失败', encoderWorkerTerminated: '编码 Worker 已终止', encodingCanceled: '编码任务已取消', decoding: (title: string) => `正在解码: ${title}`, normalizing: (title: string) => `正在标准化: ${title}`, converting: (title: string) => `正在转换格式: ${title}`, fastPreparing: (title: string) => `正在快速准备: ${title}`, noProcessedAudio: '没有成功处理的音频', fastMerging: '正在快速合并编码...', completedFile: (filename: string) => `处理完成: ${filename}`, preparingSong: (title: string) => `正在准备: ${title}`, decodeFailed: (message: string) => `解码失败: ${message}`, writingMergedFile: (title: string) => `正在写入合并文件: ${title}`, writeMergedFileFailed: (message: string) => `写入合并文件失败: ${message}`, finishingMergedFile: '正在完成合并文件...', compatibleMerge: '正在使用兼容模式合并...', fastMerge: '正在使用快速模式合并...', fastMergeMemoryFallback: '快速合并内存不足,已切换兼容模式重试', activeWorkers: (title: string, active: number, concurrency: number) => `${title} (${active}/${concurrency} 活动)`, remainingSongs: (count: number) => `剩余 ${count} 首`, processComplete: '处理完成', downloadSuccess: (count: number) => `成功下载 ${count} 首歌曲`, downloadCompleteWithCount: (success: number, failed: number) => `下载完成,成功 ${success} 首,失败 ${failed} 首` }, searchPlaceholder: '搜索歌曲标题、艺术家或投稿人...', loading: '正在加载...', unknown: '未知', unknownUser: '未知用户', unknownError: '未知错误', allSemesters: '全部学期', allPlayTimes: '全部时段', unspecifiedPlayTime: '未指定时段', scheduledWithDate: (date: string) => `待播放 (${date})`, platforms: { netease: '网易云音乐', tencent: 'QQ音乐', bilibili: '哔哩哔哩', migu: '咪咕音乐' }, timeAgo: { justNow: '刚刚', minutes: (minutes: number) => `${minutes}分钟前`, hours: (hours: number) => `${hours}小时前`, days: (days: number) => `${days}天前` }, selected: '已选择', selectedItems: (count: number) => `已选择 ${count} 项`, selectedSongs: (count: number) => `${count} 首歌曲`, preferredPlayTime: (name: string) => `期望: ${name}`, paginationItemName: '首歌曲', messages: { remarkVisibilityUpdated: '备注留言可见性已更新', remarkApproved: '备注留言已通过审核', remarkRejected: '备注留言已拒绝', deleteSuccess: '歌曲删除成功', batchDeleteSuccess: '批量删除成功', rejectSuccess: '歌曲驳回成功,已通知投稿人', validatingUrl: '正在验证URL,请稍候...', validatingCoverUrl: '正在验证封面URL,请稍候...', validatingPlayUrl: '正在验证播放地址URL,请稍候...', updateSuccess: '歌曲信息更新成功', addSuccess: '歌曲添加成功', durationRefreshed: '时长获取成功,已自动填入' }, errors: { remarkVisibilityUpdateFailed: '更新备注可见性失败', markFailed: (message: string) => `标记失败: ${message}`, deleteFailed: (message: string) => `删除失败: ${message}`, batchDeleteFailed: (message: string) => `批量删除失败: ${message}`, rejectReasonRequired: '请填写驳回原因', rejectFailed: (message: string) => `驳回失败: ${message}`, remarkUpdateFailed: '备注留言审核状态更新失败', songInfoRequired: '请填写歌曲名称和歌手', coverUrlInvalidOrPending: '请等待封面URL验证完成或修正无效的URL', playUrlInvalidOrPending: '请等待播放URL验证完成或修正无效的URL', updateFailed: '更新失败', requesterRequired: '请选择投稿人', semesterRequired: '请选择学期', coverUrlInvalid: '歌曲封面URL无效,请检查后重试', playUrlInvalid: '播放地址URL无效,请检查后重试', addFailed: '添加失败', durationRefreshFailed: (message: string) => `时长刷新失败: ${message || '未知错误'}`, durationInvalidRange: '时长需在 30–3600 秒之间', durationPlatformRequired: '请先填写音乐平台和音乐ID,才能刷新时长' } }, dataAnalysis: { title: '数据中心', desc: '洞察校园声音背后的互动趋势与影响力', loadingDesc: '正在获取最新的统计数据...', loadFailed: '数据加载失败', retryNow: '立即重试', retry: '重试', realtimeMode: '实时模式', selectSemester: '选择学期', allSemesters: '全部学期', stable: '稳定', currentActiveUsers: '当前活跃用户', onlineUnit: '人在线', todayRequests: '今日累计点播', songUnit: '首歌曲', trendTitle: '点歌趋势分析', trendDesc: '近 7 日投稿量波动情况', loadingTrends: '正在加载趋势数据...', noTrendData: '暂无趋势数据', topSongsTitle: '热门歌曲排行', likes: '点赞', replays: '重播', times: '次数', noData: '暂无数据', activeUsersTitle: '活跃用户排行榜', activity: '活跃度', noActiveUsers: '暂无活跃用户', semesterComparisonTitle: '学期对比分析', currentSemester: '当前学期', historyBaseline: '历史基准', totalSongs: '歌曲总量', totalSchedules: '排期总数', totalLikes: '获赞总数', noComparisonData: '暂无对比数据', activeUserDetails: '活跃用户详情', noOnlineUsers: '暂无在线用户', syncingRealtime: '实时数据同步中', countSongs: (count: number) => `${count}首`, userActivity: (contributions: number, likes: number) => `${contributions}首投稿 · ${likes}次点赞`, onlineCount: (count: number) => `${count} 在线`, andMoreUsers: (count: number) => `及其他 ${count} 位用户`, loadingSteps: ['获取学期信息', '加载统计数据', '获取图表数据', '加载实时数据'], kpi: { totalUsers: '注册用户总量', activeSongs: '活跃歌曲库', scheduleDays: '本学期排期天数', totalRequests: '累计点歌次数' }, messages: { updated: '数据已更新', refreshSuccess: '数据刷新成功' }, errors: { topSongs: '加载热门歌曲失败', loadData: '加载数据失败,请稍后重试', stats: '加载统计数据失败', trends: '加载趋势数据失败', activeUsers: '加载活跃用户失败', userEngagement: '加载用户参与度失败', semesterComparison: '加载学期对比失败', init: '初始化失败,请刷新页面重试', initNotify: '数据初始化失败', retry: '重试失败' } }, schedulePrinter: { title: '打印排期', desc: '自定义打印设置,预览并导出排期表', noPermissionTitle: '权限不足', noPermissionDesc: '您没有打印排期的权限,请联系管理员获取相应权限。', settingsTitle: '打印设置', paperSize: '纸张大小', selectPaperSize: '选择纸张大小', orientation: '页面方向', portrait: '纵向', landscape: '横向', layoutStyle: '排版样式', classicList: '经典列表', tableLayout: '表格排布', listColumns: '分栏显示', oneColumn: '一列', twoColumns: '两列', dateRange: '日期范围', displayContent: '显示内容', schoolLogo: '学校Logo', remark: '备注', remarkPlaceholder: '请输入备注信息(可选)', refreshPreview: '刷新预览', print: '打印', printing: '打印中...', exportPdf: '导出PDF', exportImage: '导出长图', exporting: '导出中...', previewArea: '预览区域', noData: '无数据', filtered: '被过滤', printTitle: '广播排期表', emptyTitle: '暂无排期数据', emptyNoSchedules: '请先在"排期管理"中添加排期,然后再来打印。', emptyFiltered: '当前日期范围内没有排期数据,请调整日期范围或检查排期设置。', footer: 'Generated by VoiceHub | 广播管理系统', songCount: (count: number) => `${count} 首歌曲`, countOnly: (count: number) => `${count}首`, generatedAt: (time: string) => `生成时间:${time}`, remarkPrefix: (remark: string) => `备注:${remark}`, dateRanges: { today: '今天', tomorrow: '明天', thisWeek: '本周', nextWeek: '下周' }, contentOptions: { cover: '歌曲封面', title: '歌曲名', artist: '歌手', requester: '投稿人', votes: '热度', sequence: '播放顺序', playTime: '播出时段' }, sequence: '序号', replay: '重播', crossSemester: '跨学期', requesterPrefix: '投稿人:', replayRequestsPrefix: '申请重播:', popularityPrefix: '热度:', replayCount: (count: number) => `${count}人`, replayCountShort: (count: number) => `重播:${count}`, popularityCountShort: (count: number) => `热度:${count}`, allSchedules: '全部排期', rangeStart: '开始', rangeEnd: '结束', rangeTo: (start: string, end: string) => `${start}\n至 ${end}`, unspecifiedPlayTime: '未指定时段', playTimeStarts: (name: string, time: string) => `${name} (${time}开始)`, playTimeEnds: (name: string, time: string) => `${name} (${time}结束)`, noSchedulesNotice: '当前没有排期数据,请先在排期管理中添加排期', loadFailed: (message: string) => `加载排期失败:${message}`, previewRefreshed: '预览已刷新', preparingPrint: '正在准备打印...', printFailed: (message: string) => `打印失败:${message}`, unknownError: '未知错误', previewNotFound: '预览内容未找到', preparingPdf: '正在准备PDF...', pdfExported: 'PDF导出成功', pdfExportFailed: (message: string) => `导出PDF失败:${message}`, imageExported: '图片导出成功', imageExportFailed: (message: string) => `导出长图失败:${message}`, segmentedExport: (count: number) => `已完成分段导出,共 ${count} 张图片`, autoSegmenting: '排期内容过长,将自动分段导出' }, scheduleManager: { jumpToday: '跳转到今天', selectSpecificDate: '选择特定日期', selectDate: '选择日期', cancel: '取消', confirm: '确认', playTime: '播出时段', loadingTitle: '正在加载排期数据', loadingMessage: '请稍候...', pendingSongs: '待排歌曲', poolList: '备选列表', poolItemName: '备选歌曲', addAllPending: '将全部待排歌曲移入备选池', addCurrentPage: '将本页歌曲移入备选池', moveAllToPool: '全部移入', addSingleToPool: '加入备选池', alreadyInPool: '已在备选池', removeFromPool: '从备选池移除', addToSchedule: '加入排期', poolEmptyHint: '备选池为空,从待排库中点击 + 添加', addAllPendingSuccess: (count) => `已移入 ${count} 首歌曲到备选池`, addAllPendingSkipped: (count) => `有 ${count} 首歌曲未成功移入`, addAllPendingFailed: '移入备选池失败,请重试', addAllPendingConfirmTitle: '全部移入备选池', addAllPendingConfirmMessage: (count) => `确定将 ${count} 首待排歌曲全部移入备选池?`, addCurrentPageConfirmTitle: '将本页移入备选池', addCurrentPageConfirmMessage: (count, page) => `确定将第 ${page} 页的 ${count} 首歌曲移入备选池?`, addCurrentPageSuccess: (count) => `本页已移入 ${count} 首歌曲到备选池`, addSingleToPoolSuccess: '已加入备选池', addSingleToPoolSkipped: '加入备选池失败', removeFromPoolSuccess: '已从备选池移除', removeFromPoolFailed: '移除失败', addedBy: '添加者', playSong: '播放歌曲', removeFromSchedule: '从排期移除', addToScheduleSuccess: '已加入排期', playlist: '播放列表', playOrder: '播放顺序', expectedTotalDuration: '预期总时长', searchAndFilter: '检索与筛选', searchPlaceholder: '搜索歌曲、艺术家...', currentSemester: '当前学期', preferredTime: '期望时段', grade: '年级', sort: '排序', playlistFilter: '歌单查重过滤', playlistFilterApplied: '已应用歌单过滤', viewRemark: '查看备注留言', cardPending: '点歌券待核销', cardCode: '点歌券', view: '查看', rejectRequest: '拒绝申请', saveDraft: '保存草稿', refreshDuration: '从平台重新获取歌曲时长', refreshAllDurations: '批量刷新时长', refreshPageDurations: '从平台重新获取本页歌曲时长', refreshCandidateDurations: '从平台重新获取候选歌曲时长', downloadSongs: '下载歌曲', markAllPlayed: '全部已播放', moveDate: '迁移日期', copyDate: '复制排期', copyDateSourceRange: '源日期范围', copyDateTargetRange: '目标日期范围', copyDateRangeStart: '起始日期', copyDateRangeEnd: '结束日期', copyDateModeLabel: '复制方式', singleDayCopy: '单天复制', cycleCopy: '周期复制', cycleCopySourceDate: '源日期', cycleCopyTargetStart: '起始目标日期', cycleCopyTargetEnd: '结束目标日期', cycleCopyTargetSingleDate: '目标日期', clearList: '清空列表', publishSchedule: '发布排期', publishOnly: '仅发布排期', saveAndPublish: '保存并发布', addSongsHint: '请从待排库中添加歌曲', autoSchedule: '自动排期', autoScheduleTitle: '自动排期', targetDuration: '目标时长', targetDurationPlaceholder: '输入预期总时长(分钟)', targetSongCount: '期望歌曲数量', targetSongCountPlaceholder: '可选,优先匹配歌曲数量', songCountUnit: '首', targetRequesterCount: '期望投稿人数', targetRequesterCountPlaceholder: '可选,优先覆盖不同投稿人', requesterCountUnit: '人', scheduleDirection: '时长方向', directionUnder: '不超过目标', directionMiddle: '相差最小', directionOver: '不低于目标', availableCount: (count) => `当前筛选下共 ${count} 首候选歌曲`, autoScheduleRun: '开始排期', resultTitle: '推荐结果', totalDuration: '合计', resultUnderTarget: (diff) => `低于目标 ${Math.floor(diff / 60)} 分 ${diff % 60} 秒`, resultOverTarget: (diff) => `超出目标 ${Math.floor(diff / 60)} 分 ${diff % 60} 秒`, tryAgain: '重新调整', confirmApply: '确认排期', previousPlan: '上一个方案', nextPlan: '下一个方案', planIndicator: (current, total) => `方案 ${current} / ${total}`, scheduleAlgorithm: '算法', algorithmAuto: '自动', algorithmGreedy: '贪心', algorithmExhaustive: '穷举', newPlan: '新增方案', fixExistingSelected: '固定已选歌曲', fixExistingCount: (n) => `已固定 ${n} 首`, fixExistingDuration: (sec) => `${Math.floor(sec / 60)}:${String(Math.floor(sec % 60)).padStart(2, '0')}`, fixExistingRemaining: (totalMin, fixedSec) => { const sec = Math.max(0, Math.floor(totalMin * 60 - fixedSec)) return `剩余 ${Math.floor(sec / 60)}分${String(Math.floor(sec % 60)).padStart(2, '0')}秒` }, fixExistingNone: '当前无已排期歌曲', replaySong: '重播歌曲', replay: '重播', draft: '草稿', replayApplicants: '重播申请人:', applicant: '申请人:', andMoreApplicants: (count: number) => ` 等${count}人`, publishThisDraft: '发布此草稿', moveDateTitle: '迁移排期日期', copyDateTitle: '复制排期日期', currentDate: (date: string) => `当前日期:${date}`, nextStep: '下一步', replayDetailTitle: (title: string) => `${title} - 重播申请详情`, noReplayDetails: '暂无详细申请记录', allGrades: '全部', allSemesters: '全部', monthLabel: (month: number) => `${month}月`, playlistName: (id: string | number) => `歌单 ${id}`, playTimeStart: (time: string) => `${time} 开始`, playTimeEnd: (time: string) => `${time} 结束`, allDay: '全天', positionShort: '序号', weekdays: ['日', '一', '二', '三', '四', '五', '六'], timeAgo: { justNow: '刚刚', minutes: (minutes: number) => `${minutes}分钟前`, hours: (hours: number) => `${hours}小时前`, days: (days: number) => `${days}天前` }, emptySearch: '未找到匹配的歌曲', emptySongs: '暂无歌曲记录', pendingSongItemName: '首待排歌曲', preferredPlayTime: (name: string) => `期望: ${name}`, tabs: { normal: '普通投稿', replay: '重播申请', all: '所有', pool: '备选池' }, allPlayTimes: '全部时段', unspecifiedPlayTime: '未指定时段', noPlayTimeAllDay: '未选择时段 (全天)', sortOptions: { newest: '最新投稿', oldest: '最早投稿', hotDesc: '热度最高', hotAsc: '热度最低' }, confirmations: { leaveUnsaved: '您有未保存的排期修改,确定要离开吗?', switchDateUnsaved: '您有未保存的排期修改,切换日期将丢失这些修改,确定要继续吗?', switchPlayTimeUnsaved: '您有未保存的排期修改,切换时段将丢失这些修改,确定要继续吗?', switchSemesterUnsaved: '您有未保存的排期修改,切换学期将丢失这些修改,确定要继续吗?', switchPageUnsaved: '您有未保存的排期修改,切换页面将丢失这些修改,确定要继续吗?', rejectReplayTitle: '拒绝重播申请', rejectReplayMessage: '确定要拒绝该重播申请吗?', markAllPlayedTitle: '标记全部已播', markAllPlayedMessage: '确定要将列表中的所有歌曲标记为已播放吗?', markAllPlayedConfirm: '确认标记', clearListTitle: '清空播放列表', clearListMessage: '确定要清空当前的播放顺序列表吗?未保存的修改将会丢失。', clearListConfirm: '确认清空', moveDateMessage: (sourceDate: string, count: number, targetDate: string) => `确定将 ${sourceDate} 的所有 ${count} 首歌曲迁移到 ${targetDate} 吗?歌曲顺序与内容将保持不变。`, moveDateConfirm: '确认迁移', copyDateMessage: (fromStart: string, fromEnd: string, sourceDays: number, toStart: string, toEnd: string, targetDays: number) => `确定将 ${fromStart} 至 ${fromEnd} 共 ${sourceDays} 天的排期复制到 ${toStart} 至 ${toEnd} 共 ${targetDays} 天吗?源排期将循环复用至填满目标区间。`, copyDateOverwriteMessage: (fromStart: string, fromEnd: string, sourceDays: number, toStart: string, toEnd: string, targetDays: number, draftDays: number) => `确定将 ${fromStart} 至 ${fromEnd} 共 ${sourceDays} 天的排期复制到 ${toStart} 至 ${toEnd} 共 ${targetDays} 天吗?目标区间内有 ${draftDays} 个日期的草稿将被覆盖。源排期将循环复用至填满目标区间。`, copyDateConfirm: '确认复制', copyDateSingleMessage: (sourceDate: string, targetDate: string) => `确定将 ${sourceDate} 的排期复制到 ${targetDate} 吗?`, copyDateSingleConfirm: '确认复制', copyDateOverwriteDraftConfirm: (draftCount: number) => `目标日期 ${draftCount} 首草稿将被覆盖,确定继续?`, deleteScheduleTitle: '删除排期', deleteScheduleMessage: '确定要删除当天的所有排期吗?此操作不可恢复。', deleteScheduleConfirm: '确认删除', publishScheduleTitle: '发布排期', publishScheduleMessage: '确定要发布当前排期吗?发布后将立即公示并发送通知。', publishDraftTitle: '发布草稿', publishDraftMessage: (title: string) => `确定要发布草稿《${title}》吗?发布后将立即公示并发送通知。` }, messages: { remarkVisibilityUpdated: '备注留言可见性已更新', replayRejected: '重播申请已拒绝', allMarkedPlayed: '所有歌曲已标记为播放', playlistCleared: '播放列表已清空,请记得保存修改', saveBeforeMove: '请先保存当前未发布修改后再执行迁移', saveBeforeCopy: '请先保存当前未发布修改后再执行复制', moveDateSuccess: (count: number, date: string) => `已迁移 ${count} 首歌曲到 ${date}`, copyDateSuccess: (count: number, toStart: string, toEnd: string) => `已逐日复制 ${count} 首歌曲至 ${toStart} ~ ${toEnd}`, draftSaved: '排期草稿保存成功!', allDraftsDeleted: '所有草稿已删除!', scheduleDeleted: '排期已删除!', schedulePublished: '排期发布成功,通知已发送!', draftPublished: (title: string) => `草稿《${title}》发布成功,通知已发送!`, durationUpdated: '时长已更新', durationFailed: '获取时长失败', durationNoPlatform: '歌曲缺少平台或音乐 ID 信息,无法获取时长', durationInvalid: '时长格式无效,请输入 分:秒 或 时:分:秒(最长 2 小时)', durationInputPlaceholder: '分:秒', editDuration: '点击编辑时长', allDurationsUpdated: (count: number) => `成功刷新 ${count} 首歌曲的时长`, allDurationsPartial: (ok: number, fail: number) => `刷新完成:成功 ${ok} 首,失败 ${fail} 首`, allDurationsFailed: '批量刷新时长失败', allDurationsSkipped: '当前无可刷新时长的歌曲', allDurationsCapped: '候选歌曲较多,本次仅刷新前 100 首', candidateDurationsUpdated: (count: number) => `成功刷新 ${count} 首候选歌曲的时长`, candidateDurationsPartial: (ok: number, fail: number) => `刷新完成:成功 ${ok} 首,失败 ${fail} 首`, candidateDurationsFailed: '刷新候选歌曲时长失败', candidateDurationsSkipped: '当前无候选歌曲可刷新时长', confirmAutoScheduleApplied: (count, duration) => `已自动排期 ${count} 首歌曲,合计 ${duration}`, allDurationsProgressTotal: '{0} 首歌', allDurationsProgressWithCount: '{0}/{1}(成功{2} 失败{3})', candidateDurationsProgressTotal: '{0} 首歌', allDurationsProgress: '{0} / {1}', autoScheduleNoResult: '未能找到满足条件的歌曲组合', autoScheduleNoMorePlans: '已无更多不同方案' }, playlistFilterModal: { title: '歌单重复过滤', defaultPlaylists: '预设榜单', customPlaylists: '自定义歌单 ID / 链接', refreshTitle: '重新获取所有自定义歌单信息', refresh: '刷新信息', playlistPlaceholder: '输入歌单 ID 或链接', addCustomPlaylist: '添加自定义歌单', clearFilter: '清除过滤', fetching: '获取中...', applyFilter: '应用过滤', defaultNames: { soaring: '飙升榜', newSongs: '新歌榜', original: '原创榜', hotSongs: '热歌榜' } }, remarkDialog: { title: '投稿备注留言', publicRemark: '公开备注', adminOnly: '仅管理员可见', updating: '更新中...', statusPending: '待审核', statusRejected: '已拒绝', approveButton: '通过', rejectButton: '拒绝' }, errors: { remarkVisibilityUpdateFailed: '更新备注可见性失败', rejectReplayFailed: (message: string) => `拒绝申请失败: ${message}`, operationFailed: '操作失败', invalidTargetDate: '目标日期无效,请使用 YYYY-MM-DD 格式并确保日期有效', sameTargetDate: '目标日期不能与当前日期相同', noMovableSongs: '当前日期没有可迁移的歌曲', moveDateFailed: (message: string) => `迁移失败: ${message}`, noCopyableSongs: '当前日期没有可复制的歌曲', invalidDateRange: '日期区间无效,起始日期不能晚于结束日期', targetDateConflicts: '目标区间中存在与源区间重合的日期', copyDateFailed: (message: string) => `复制失败: ${message}`, saveDraftFailed: (message: string) => `保存草稿失败: ${message}`, publishScheduleFailed: (message: string) => `发布排期失败: ${message}`, publishDraftFailed: (message: string) => `发布草稿失败: ${message}` } }, backupManager: { title: '数据库备份', desc: '导出和导入数据库备份', exportTitle: '导出备份', exportDesc: '创建数据库备份文件', exporting: '导出中...', startExport: '开始导出', importTitle: '导入备份', importDesc: '从备份文件恢复数据', importing: '导入中...', chooseFile: '选择文件', createTitle: '创建数据库备份', backupType: '备份类型', fullBackup: '完整备份(推荐)', fullBackupDesc: '备份所有数据表', userDataOnly: '仅用户数据', userDataOnlyDesc: '只备份用户相关数据', includeSystemSettings: '包含系统设置', includeSystemSettingsDesc: '包含系统配置和设置数据', cancel: '取消', creating: '创建中...', createBackup: '创建备份', importFileTitle: '导入备份文件', uploadTitle: '选择或拖拽备份文件', uploadDesc: '支持 .json 格式的备份文件,最大 100MB', restoreMode: '恢复模式', mergeMode: '合并模式(推荐)', mergeModeDesc: '更新现有记录,添加新记录', replaceMode: '替换模式', replaceModeDesc: '先清空数据,然后导入备份', confirmClear: '我确认要清空现有数据', confirmClearDesc: '此操作不可逆,请谨慎操作', overwriteSuperAdmin: '覆盖备份中的超级管理员账号数据', overwriteSuperAdminDesc: '关闭时将保留当前超级管理员及其第三方绑定、2FA相关数据', warningTitle: '注意', warningDesc: '导入备份将会影响现有数据,请确保您了解操作的后果。', startImport: '开始导入', downloaded: (filename: string, size: string) => `备份文件已下载: ${filename}${size}`, fileDownloadFailed: (message: string) => `文件下载失败: ${message}`, invalidResponse: '备份创建失败:无效的响应格式', serverResponseInvalid: '备份创建失败:服务器响应格式错误', createFailed: (message: string) => `创建备份失败: ${message}`, parseFailed: '无法解析备份文件,请检查文件格式是否正确。', restoreSuccess: (tables: number, records: number) => `备份恢复成功!处理了 ${tables} 个表,恢复了 ${records} 条记录`, restoreWarning: (count: number) => `恢复过程中发生了 ${count} 个错误`, restoreCompleteRedirect: '数据库恢复完成,3秒后将返回首页重新登录', importFailed: (message: string) => `备份导入失败: ${message}`, unknownError: '未知错误' }, oauthConfig: { title: 'OAuth 第三方登录配置', runtimeConfigNotice: 'OAuth 运行时配置已迁移到后台。环境变量仅用于兼容旧部署和一键导入,导入后以此页面保存的配置为准。', baseSettings: '基础设置', importEnv: '导入环境配置', allowRegistration: '允许第三方注册', allowRegistrationDesc: '开启后,允许用户通过 OAuth 创建新账号;关闭时,仅允许绑定已有账号', oauthRegisterRequiresApproval: '第三方注册需管理员审核', oauthRegisterRequiresApprovalDesc: '开启后,通过第三方新创建的用户需审核通过后才能登录。', allowed: '已允许', notAllowed: '未允许', redirectUri: 'OAuth 重定向 URI', redirectExample: '例:', stateSecret: 'OAuth State 密钥', stateSecretDesc: '用于加密/解密 OAuth 状态参数,建议使用强随机字符串', stateSecretPlaceholder: '输入强随机字符串', show: '显示', hide: '隐藏', enabled: '已启用', disabled: '未启用', casdoorServerUrl: 'Casdoor 服务器 URL', casdoorOrganizationName: 'Casdoor 组织名称', organizationPlaceholder: '输入组织名称', customOAuth: '第三方 OAuth2', displayName: '按钮显示名称', displayNamePlaceholder: '例如:校园统一认证', authorizeUrl: '授权地址 (Authorize URL)', tokenUrl: '令牌地址 (Token URL)', userInfoUrl: '用户信息地址 (UserInfo URL)', scope: '授权范围 (Scope)', clientId: '客户端 ID (Client ID)', clientSecret: '客户端密钥 (Client Secret)', githubTitle: 'GitHub OAuth', githubClientId: 'GitHub Client ID', githubClientSecret: 'GitHub Client Secret', casdoorTitle: 'Casdoor OAuth', casdoorClientId: 'Casdoor Client ID', casdoorClientSecret: 'Casdoor Client Secret', googleTitle: 'Google OAuth', googleClientId: 'Google Client ID', googleClientSecret: 'Google Client Secret', clientIdPlaceholder: '输入 Client ID', clientSecretPlaceholder: '输入 Client Secret', githubClientIdPlaceholder: '输入 GitHub Client ID', githubClientSecretPlaceholder: '输入 GitHub Client Secret', googleClientIdPlaceholder: '输入 Google Client ID(xxx.apps.googleusercontent.com)', googleClientSecretPlaceholder: '输入 Google Client Secret', aggregateTitle: '聚合登录', aggregateLoginTypeLabel: '登录方式', aggregateLoginTypePlaceholder: '请选择至少一种登录方式', aggregateLoginTypeDesc: '请选择当前聚合登录服务已接入并开通的登录方式;启用服务商尚未支持的平台会导致授权失败。每种登录方式会独立记录账号绑定关系。', aggregateEndpointLabel: '接口地址', aggregateEndpointDesc: '兼容彩虹聚合登录协议的服务端 connect.php 地址;公网应使用 HTTPS,可信内网可使用 HTTP。', aggregateClientIdPlaceholder: '输入聚合登录 AppID', aggregateClientSecretPlaceholder: '输入聚合登录 AppKey', aggregateDocLabel: '查看聚合登录开发文档', aggregateLoginTypes: { qq: 'QQ', wx: '微信', alipay: '支付宝', sina: '微博', baidu: '百度', douyin: '抖音', huawei: '华为', xiaomi: '小米', gitee: 'Gitee', gitea: 'Gitea', bilibili: '哔哩哔哩', kuaishou: '快手' }, clearBindingsTitle: '清除所有聚合登录绑定', clearBindingsDesc: '更换聚合登录提供商时使用,将清除系统中所有用户的聚合登录绑定关系并要求其重新绑定。', clearBindingsBtn: '清除绑定', clearBindingsConfirmTitle: '确认清除所有聚合登录绑定?', clearBindingsConfirmMessage: '此操作将永久清除系统中所有用户的聚合登录绑定关系。\n若更换了聚合登录提供商,旧数据已失效,清除后用户需重新绑定方可通过聚合登录访问账号。\n此操作不可撤销,是否继续?', clearBindingsSuccess: '已成功清除 {0} 条聚合登录绑定数据(影响 {1} 位用户)', clearBindingsFailed: '清除聚合登录绑定失败', userIdField: '用户 ID 字段', usernameField: '用户名字段', nameField: '昵称字段', emailField: '邮箱字段', avatarField: '头像字段', brokerHintPrefix: '在 Vercel 等平台进行多环境部署时,GitHub OAuth App 等提供商通常只能配置单一的回调地址。为了解决这个问题,项目可以使用', brokerHintSuffix: '中间件作为统一的回调入口。该中间件能根据 state 参数动态转发回调请求到正确的部署环境,从而实现单个 OAuth App 支持无限个预览/生产环境。详情请参考该项目文档。', importFailed: '导入环境配置失败', logs: { fetchEnvFailed: '获取环境变量失败:', importEnvFailed: '导入环境配置失败:' } }, musicSourceController: { title: '音源控制', description: '管理音乐平台的开关状态和搜索顺序,配置后立即生效', saveConfig: '保存配置', saving: '保存中...', saved: '已保存', reset: '重置', loading: '加载中...', fetchFailed: '获取配置失败', saveFailedRetry: '保存配置失败,请重试', saveSuccess: '音源配置已保存', switchTitle: '平台开关', switchDesc: '开启或关闭各音乐平台的搜索功能', orderTitle: '搜索顺序', orderDesc: '拖拽调整平台在搜索按钮区的显示顺序', resetOrder: '重置顺序', mustKeepOne: '至少保留一个平台启用' }, playTimeManager: { title: '播出时段管理', desc: '定义校园广播的常规播放窗口,用户仅可在这些时间段内进行点歌或查看排期', enableSelection: '启用播出时段选择', add: '添加播出时段', aboutTitle: '关于时段限制', aboutDesc: '启用全局时段选择后,系统将仅在定义的时段内开放点歌功能。如果未设置开始或结束时间,系统将视为该边界不设限。', loading: '加载中...', fetchFailed: '获取数据失败', emptyTitle: '暂无播出时段', emptyDesc: '点击“添加播出时段”按钮创建第一个播出时段', enabled: '已启用', disabled: '已禁用', enable: '启用', disable: '禁用', unlimited: '不限', noDescription: '暂无详细描述...', editTitle: '编辑播出时段', addTitle: '添加播出时段', name: '时段名称', namePlaceholder: '例如: 午间广播', startTimeOptional: '开始时间 (可选)', startTimeHint: '留空表示不限制开始时间', endTimeOptional: '结束时间 (可选)', endTimeHint: '留空表示不限制结束时间', descriptionOptional: '描述 (可选)', descriptionPlaceholder: '请输入时段描述信息...', enableThisPlayTime: '启用此播出时段', cancel: '取消', saving: '保存中...', saveSettings: '保存设置', deleting: '删除中...', confirmDelete: '确认删除', deleteConfirmTitle: (name: string) => `确定要删除播出时段 "${name}" 吗?`, deleteConfirmDesc: '此操作不可恢复,相关的歌曲点播和排期的时段设置将受影响或被清除。', messages: { systemSettingsUpdated: '系统设置已更新', playTimeEnabled: '播出时段已启用', playTimeDisabled: '播出时段已禁用', playTimeDeleted: '播出时段已删除', playTimeUpdated: '播出时段已更新', playTimeCreated: '播出时段已创建' }, errors: { adminOnly: '只有管理员才能管理播出时段', fetchPlayTimesFailed: '获取播出时段失败', updateSystemSettingsFailed: '更新系统设置失败', updatePlayTimeStatusFailed: '更新播出时段状态失败', deletePlayTimeFailed: '删除播出时段失败', startBeforeEnd: '开始时间必须早于结束时间', nameRequired: '时段名称不能为空', nameExists: '播出时段名称已存在,请使用其他名称', savePlayTimeFailed: '保存播出时段失败' } }, requestTimeManager: { title: '投稿开放管理', desc: '管理全校师生点歌投稿的开放时间、限制数量及全局状态控制', currentStatus: '当前状态', open: '已开放', closed: '已关闭', enableRequest: '启用投稿', enableTimeLimit: '启用时段限制', addTime: '添加投稿时段', addTimeDesc: '创建一个新的投稿开放周期', expired: '已过期', enabled: '已启用', disabled: '已禁用', none: '暂无', enable: '启用', disable: '禁用', unlimited: '不限', noDescription: '暂无详细描述...', progress: '投稿进度', editTitle: '编辑投稿开放时段', addTitle: '添加投稿开放时段', name: '时段名称', namePlaceholder: '例如: 2025冬季常规点歌', startDateTime: '开始日期时间', endDateTime: '结束日期时间', expectedCount: '计划投稿数', expectedCountShort: '计划数', songUnit: '首歌曲', expectedHint: '填 0 表示不限制投稿总数', enableThisRequestTime: '启用此投稿时段', enableThisRequestTimeHint: '只有启用的时段才会根据时间限制生效', descriptionOptional: '时段描述 (可选)', descriptionPlaceholder: '请输入针对此开放周期的特殊规则或介绍信息...', cancel: '取消', saving: '保存中...', saveSettings: '保存设置', keepTime: '保留时段', deleting: '删除中...', confirmDelete: '确认删除', deleteConfirmTitle: (name: string) => `确定要彻底移除 "${name}" 吗?`, deleteConfirmPrefix: '删除时段后,原本属于此周期的投稿关联记录可能失效。建议先尝试', deleteConfirmSuffix: '该时段。', priorityTitle: '逻辑优先级说明', globalSwitch: '全局开关', priorityGlobal: '具有最高优先级,关闭后所有投稿均不可用。', timeLimit: '时段限制', priorityTimeLimitPrefix: '开启', priorityTimeLimitMiddle: '后,系统会检查当前时间是否处于任一', priorityTimeLimitAnd: '且未达到', priorityTimeLimitSuffix: '的时段内。', priorityNoLimit: '若关闭时段限制,则全天候均可投稿(只要全局开关开启)。', noticeTitle: '注意事项', noticeOverlap: '时段重叠时,系统将合并开放范围。', noticeUnlimited: '计划投稿数设置为 0 时,系统将忽略数量上限检查。', noticeExpired: '过期的时段将自动显示为“已过期”,不可编辑或重新启用。', enableRestriction: '启用重复投稿限制', restrictionScope: '限制范围', restrictionScopeSelf: '用户自己', restrictionScopeAll: '所有人', restrictionScopeDesc: '选择对比哪些用户的排期记录', sameSongRestrictionHours: '同一首歌限制时间', sameSongRestrictionHoursDesc: '同一首歌进入排期后的禁止再次投稿时间窗口,留空表示不设冷却窗口,上限 30 天(720 小时)', sameArtistRestrictionHours: '同一歌手限制时间', sameArtistRestrictionHoursDesc: '同一歌手进入排期后的禁止再次投稿时间窗口,留空表示不设冷却窗口,上限 30 天(720 小时)', restrictionUnit: '小时', restrictionPanelTitle: '重复投稿限制', restrictionPanelDesc: '对进入排期的歌曲或歌手设置再次投稿冷却窗口', restrictionPanelHint: '关闭后不做任何重复投稿限制,普通用户可再次投稿已排期或已播放的歌曲;开启后限制范围同时作用于同一首歌和同一歌手两个检查,两项时长都留空时沿用本学期同一首歌不可重复投稿的规则', restrictionSaveSuccess: '限制设置已保存', restrictionSaveFailed: '保存限制设置失败', stats: { activeSlots: '活跃时段', totalAccepted: '累计已接收', totalCapacity: '计划总容量', remainingCapacity: '剩余总名额' }, errors: { adminOnly: '只有管理员才能管理投稿开放时段', fetchFailed: '获取投稿开放时段失败', fetchFailedWithStatus: (status: number) => `获取投稿开放时段失败: ${status}`, updateSystemSettingsFailed: '更新系统设置失败', updateSystemSettingsFailedWithStatus: (status: number) => `更新系统设置失败: ${status}`, updateStatusFailed: '更新投稿开放时段状态失败', updateStatusFailedWithStatus: (status: number) => `更新投稿开放时段状态失败: ${status}`, deleteFailed: '删除投稿开放时段失败', deleteFailedWithStatus: (status: number) => `删除投稿开放时段失败: ${status}`, startBeforeEnd: '开始时间必须早于结束时间', nameRequired: '时段名称不能为空', nameExists: '投稿开放时段名称已存在,请使用其他名称', saveFailed: '保存投稿开放时段失败', saveFailedWithStatus: (isUpdate: boolean, status: number) => `${isUpdate ? '更新' : '创建'}投稿开放时段失败: ${status}` } }, semesterManager: { title: '学期管理', desc: '定义系统的教学周期,点歌、排期及统计数据将基于当前活跃学期进行归档', add: '添加新学期', currentActive: '当前活跃学期', createdAt: (date: string) => `创建于 ${date}`, inProgress: '正在进行中', noCurrent: '未设置当前活跃学期', createNow: '立即创建', switchTitle: '学期切换说明', switchDesc: '切换学期后,前端点歌界面将清空旧排期。所有历史数据会自动归档至对应学期下,您仍可在数据中心进行查看。', historyTitle: '学期历史记录', historyCount: (count: number) => `共 ${count} 条`, loading: '加载中...', currentSemester: '当前学期', setCurrent: '设为当前', editSemester: '修改学期', deleteSemester: '删除学期', empty: '暂无学期数据', semesterName: '学期名称', namePlaceholder: '例如: 2025学年第一学期', setAsActive: '设为当前活跃学期', setAsActiveHint: '创建后将立即激活此学期,原学期将变为历史状态', namingTip: '提示:请按照统一的命名规范设置学期名称,这有助于数据归档后的检索与分析。', cancel: '取消', saving: '保存中...', creating: '创建中...', saveChanges: '保存修改', createSemester: '创建学期', confirmDelete: '确认删除', deleteDialogTitle: '确认删除学期', deleteMessage: (name: string) => `确定要彻底删除 "${name}" 吗?此操作将同步清除该学期下的所有点歌记录、排期数据和统计信息。数据一旦删除将无法找回。`, terms: { first: '第一学期', second: '第二学期' }, recommendedName: (academicYear: number, term: string) => `${academicYear}学年${term}`, messages: { activeSet: '活跃学期设置成功!', deleted: '学期删除成功!', nameUnchanged: '学期名称未发生变化', updated: '学期修改成功!', created: '学期创建成功!' }, errors: { setActiveFailedRetry: '设置活跃学期失败,请稍后重试', setFailed: '设置失败', deleteFailed: '删除学期失败', deleteFailedShort: '删除失败', updateFailed: '修改学期失败', createFailed: '创建学期失败' } }, smtpManager: { title: '邮件服务配置', desc: '配置 SMTP 服务以发送系统验证码、投稿通知及其他重要提醒', reload: '重载SMTP', reloading: '重载中...', save: '保存配置', saving: '保存中...', serviceConfig: '服务配置', smtpHost: 'SMTP 服务器', port: '端口', secure: '加密方式', username: '发件人账号', fromEmail: '发件人邮箱 (From Email)', fromEmailHint: '通常与发件人账号一致,部分服务商强制要求一致。', password: '授权码 / 密码', fromName: '发件人姓名', serviceTest: '服务测试', testEmail: '测试接收邮箱', testEmailPlaceholder: '输入测试邮箱地址', send: '发送', sending: '发送中', sent: '已发送', secureOptions: { ssl: 'SSL/TLS', none: '无' }, defaultFromName: '校园广播站', loadFailed: '加载配置失败', incompleteConfig: '请填写完整的SMTP配置信息', saveSuccess: 'SMTP配置保存成功', saveFailed: '保存配置失败', resetSuccess: '配置已重置', reloadSuccess: 'SMTP配置已重载', reloadFailed: '重载SMTP配置失败', serverRequired: '请先配置SMTP服务器信息', testConnectionFailed: '测试连接失败', testEmailRequired: '请输入测试邮箱地址', testEmailSuccess: '测试邮件发送成功', testEmailFailed: '发送测试邮件失败', serverMessages: { methodNotAllowed: { raw: '方法不被允许', text: '方法不被允许' }, unauthorized: { raw: '未授权访问', text: '未授权访问' }, adminReloadOnly: { raw: '只有管理员才能重载SMTP配置', text: '只有管理员才能重载 SMTP 配置' }, adminTestConnectionOnly: { raw: '只有管理员才能测试SMTP连接', text: '只有管理员才能测试 SMTP 连接' }, adminTestEmailOnly: { raw: '只有管理员才能发送测试邮件', text: '只有管理员才能发送测试邮件' }, smtpDisabled: { raw: 'SMTP服务未启用', text: 'SMTP 服务未启用' }, incompleteConfig: { raw: '请填写完整的SMTP配置信息', text: '请填写完整的 SMTP 配置信息' }, testEmailRequired: { raw: '请输入测试邮箱地址', text: '请输入测试邮箱地址' }, reloadSuccess: { raw: 'SMTP配置已重载', text: 'SMTP 配置已重载' }, reloadCleared: { raw: 'SMTP未启用或配置不完整,已清空当前SMTP实例', text: 'SMTP 未启用或配置不完整,已清空当前 SMTP 实例' }, reloadFailed: { raw: 'SMTP配置重载失败', text: 'SMTP 配置重载失败' }, invalidOrDisabled: { raw: 'SMTP配置无效或未启用', text: 'SMTP 配置无效或未启用' }, initializeFailed: { raw: '初始化SMTP配置失败', text: '初始化 SMTP 配置失败' }, connectionSuccess: { raw: 'SMTP连接测试成功', text: 'SMTP 连接测试成功' }, connectionFailed: { raw: 'SMTP连接测试失败', text: 'SMTP 连接测试失败' }, testConnectionFailed: { raw: '测试连接失败', text: '测试连接失败' }, testEmailSuccess: { raw: '测试邮件发送成功', text: '测试邮件发送成功' }, testEmailSendFailed: { raw: '测试邮件发送失败', text: '测试邮件发送失败' }, sendTestEmailFailed: { raw: '发送测试邮件失败', text: '发送测试邮件失败' } } }, emailTemplateManager: { title: '邮件模板管理', desc: '自定义系统邮件的主题与内容,支持变量替换', refreshPreview: '刷新预览', livePreview: '实时预览', saving: '保存中...', updateTemplate: '更新模板', searchPlaceholder: '搜索模板...', builtin: '内置', custom: '自定义', templateName: '模板名称', emailSubject: '邮件主题', supportsVariables: '支持变量', subjectPlaceholder: '请输入邮件主题...', availableVariables: '可用变量', htmlContent: 'HTML 内容', restoreDefault: '恢复默认配置', livePreviewLabel: '实时预览:', hidePreview: '隐藏预览', emptySelectTemplate: '请在左侧选择一个邮件模板', previewData: { name: '张三', title: '系统通知', message: '这是一条预览内容\n支持换行与链接' }, messages: { saved: '模板已保存', restored: '已恢复默认模板' }, errors: { saveFailed: '保存失败', restoreFailed: '恢复失败', previewFailed: '预览失败' } }, notificationSender: { title: '向用户发送通知', desc: '即时推送系统公告、活动信息或重要提醒至指定群体', notificationTitle: '通知标题', titlePlaceholder: '请输入通知标题', notificationContent: '通知内容', contentPlaceholder: '请输入通知详情内容...', markdownHint: '支持 Markdown 格式,将按右侧预览安全渲染。', importantToggleTitle: '重要通知弹窗提醒', importantToggleDescription: '用户登录后将立即弹窗展示,关闭后标记为已读', scope: '通知范围', allUsersHint: '将向系统中所有已注册的活跃用户发送此通知。', selectGrade: '选择年级', grade: '年级', className: '班级', selectGradePlaceholder: '请选择年级', selectClassPlaceholder: '请选择班级', add: '添加', noClassSelected: '未选择任何班级', userSearchPlaceholder: '搜索并选择用户 (姓名、用户名或ID)...', searchResults: (count: number) => `搜索结果 (${count})`, selected: '已选择', select: '选择', selectedUsers: (count: number) => `已选择用户 (${count})`, clearAll: '清空全部', noUsersSelected: '未选择任何用户', send: '发送通知', sending: '发送中...', previewTitle: '通知预览', previewSender: '管理员', senderLabel: '发送人', previewTitlePlaceholder: '通知标题', previewContentPlaceholder: '这里将显示通知的详细内容预览...', previewScope: (scope: string) => `发送范围: ${scope}`, previewHint: '预览图仅供参考布局,实际发送效果可能会根据用户设备显示语言和屏幕尺寸有所不同。', roles: { admin: '管理员', teacher: '教师', student: '学生' }, scopeDescriptions: { all: '全体用户', grade: (grade: string) => `${grade}年级`, class: (grade: string, className: string) => `${grade}年级${className}班`, multiClass: (count: number) => `${count}个班级`, specificUsers: (count: number) => `已选择${count}个用户`, selectGrade: '请选择年级', selectClass: '请选择班级', selectUsers: '请选择用户' }, messages: { sendSuccess: (count: number) => `成功发送通知给 ${count} 名用户` }, errors: { adminOnly: '只有管理员可以发送系统通知', incomplete: '请填写完整信息', sendFailed: '发送通知失败', sendError: '发送通知时发生错误' }, targets: { all: '全体用户', grade: '按年级选择', class: '按班级选择', multiClass: '多班级选择', specificUsers: '指定用户' }, history: { title: '发送历史', description: '每次发送归为一条记录,用户已读情况可在明细中查看', refresh: '刷新', refreshing: '刷新中...', searchPlaceholder: '搜索通知标题或正文', typeFilter: '通知类型', allTypes: '全部类型', senderFilter: '发送人', allSenders: '全部发送人', sentAtSort: '发送时间排序', newestFirst: '最新发送优先', oldestFirst: '最早发送优先', clearFilters: '清除筛选', statusFilter: '按已读状态筛选', all: '全部', read: '已读', unread: '未读', notification: '通知', sender: '发送人', systemSender: '系统', recipient: '接收用户', recipientCountLabel: '接收人数', recipientCount: (count: number) => `${count} 人`, type: '类型', status: '状态', sentAt: '发送时间', readAt: '已读时间', actions: '操作', viewDetails: '查看明细', view: '查看', edit: '编辑', delete: '删除', detailsEyebrow: '用户已读情况', close: '关闭', editEyebrow: '编辑发送记录', editNotification: '修改通知', editTitle: '通知标题', editTitlePlaceholder: '请输入通知标题', editContent: '通知正文', editContentPlaceholder: '请输入 Markdown 通知正文', editImportant: '重要通知弹窗提醒', editImportantDescription: '保存后将生成新的通知批次,所有接收用户(含已读和已删除该通知的用户)会重置为未读并重新收到弹窗提醒', preview: 'Markdown 预览', cancel: '取消', save: '保存修改', saving: '正在保存...', deleteNotification: '删除通知', deleteConfirmation: (title: string) => `确定删除“${title}”吗?该通知对所有接收用户的记录都会被删除,且无法恢复。`, confirmDelete: '确认删除', titleContentRequired: '通知标题和正文不能为空', titleTooLong: (max: number) => `通知标题不能超过 ${max} 个字符`, contentTooLong: (max: number) => `通知正文不能超过 ${max} 个字符`, updateSuccess: '通知已修改', updateFailed: '修改通知失败,请重试', deleteSuccess: '通知已删除', deleteFailed: '删除通知失败,请重试', important: '重要通知', normal: '普通通知', untitled: '无标题通知', notRead: '尚未阅读', loading: '正在加载发送历史...', detailsLoading: '正在加载用户明细...', empty: '暂无发送记录', emptyDescription: '发送系统通知后,每次发送会作为一条记录显示在这里。', filteredEmpty: '没有符合条件的发送记录', filteredEmptyDescription: '请调整关键词或筛选条件后重试。', noRecipients: '当前筛选条件下没有接收用户', loadFailed: '加载通知历史失败,请重试', detailsLoadFailed: '加载用户已读明细失败,请重试', retry: '重试', unknownTime: '时间未知', unknownUser: (id: number) => `用户 #${id}`, userId: (id: number) => `用户 ID:${id}`, itemName: '条发送记录', recipientItemName: '位接收用户' } }, cardCodesManager: { title: '点歌券管理', desc: '管理点歌券的创建、筛选、批量核销、导入导出和备注信息', refresh: '刷新', exporting: '导出中...', searchPlaceholder: '搜索点歌券、备注', status: '状态', allStatus: '全部状态', clearFilters: '清空筛选', selectedItems: (count: number) => `已选择 ${count} 项`, applyBulk: '执行批量操作', cancelSelection: '取消选择', loading: '加载点歌券中...', cardCode: '点歌券', note: '备注', time: '时间', actions: '操作', copy: '复制点歌券', lockedAt: (time: string) => `锁定:${time}`, redeemedAt: (time: string) => `核销:${time}`, saveNote: '保存备注', createdAt: (time: string) => `创建:${time}`, updatedAt: (time: string) => `更新:${time}`, available: '可用', locked: '锁定', redeemed: '核销', invalid: '作废', lockedStatus: '已锁定', redeemedStatus: '已核销', invalidStatus: '已作废', setAvailable: '设为可用', setLocked: '设为锁定', setRedeemed: '设为核销', setInvalid: '设为作废', unknown: '未知', empty: '没有找到符合条件的点歌券', itemName: '张点歌券', createTitle: '批量创建 / 导入', createDesc: '支持手动粘贴、分隔导入,也支持自动生成点歌券', manualImport: '手动导入', autoGenerate: '自动生成', manualPlaceholder: '输入单个点歌券,或使用逗号/换行/空格分隔多个点歌券', generateCount: '生成数量', prefix: '前缀', prefixPlaceholder: '例如 VH-', randomLength: '随机长度', charset: '字符集', bulkNotePlaceholder: '可选:批量备注', createCardCode: '创建点歌券', fillDemo: '填充示例', demoNote: '示例点歌券', lastGeneratedTitle: (count: number) => `本次生成 ${count} 张点歌券`, lastGeneratedDesc: '仅保留最近一次自动生成结果,方便发放前复制。', copyAll: '一键复制', quickTipsTitle: '快速说明', quickTips: [ '支持按状态和关键词筛选,搜索范围包含点歌券和备注。', '支持单条和批量状态切换,方便锁定、核销或作废。', '备注可直接就地编辑,适合记录发放对象、批次来源等信息。', '导出会按当前筛选条件生成完整 CSV;勾选点歌券后会优先导出勾选项。' ], redeemLogsTitle: '兑换日志', redeemLogsDesc: '记录点歌券被哪个账号兑换、兑换时间、来源与关联歌曲', refreshLogs: '刷新日志', keyword: '关键词', logSearchPlaceholder: '点歌券 / 账号 / 歌曲 / 来源', source: '来源', allSources: '全部来源', redeemer: '兑换账号', redeemerPlaceholder: '用户名 / 昵称', startDate: '起始日期', endDate: '结束日期', queryLogs: '查询日志', clearConditions: '清空条件', loadingLogs: '加载兑换日志中...', logId: '日志ID', redeemedTime: '兑换时间', relatedSong: '关联歌曲', unknownUser: '未知用户', noRedeemLogs: '暂无兑换日志', exportSelected: (count: number) => `导出已选 ${count} 项`, exportFiltered: '导出筛选结果', sources: { adminManual: '手动核销', admin: '管理员操作', scheduleAuto: '排期自动', scheduleRemove: '移除排期', schedule: '排期', withdraw: '撤回' }, messages: { fetchFailed: '获取点歌券失败', fetchLogsFailed: '获取点歌券兑换日志失败', copied: '点歌券已复制', copyFailed: '复制失败,请手动复制', exportFailed: '导出点歌券失败', exportSelectedSuccess: '已导出勾选点歌券', exportFilteredSuccess: '已导出筛选结果', statusUpdated: '状态已更新', updateStatusFailed: '更新点歌券状态失败', noteSaved: '备注已保存', saveNoteFailed: '保存备注失败', inputRequired: '请先输入点歌券', createSuccess: (count: number) => `创建成功,共 ${count} 条`, createDone: (inserted: number, skipped: number) => `创建完成,成功 ${inserted} 条,跳过 ${skipped} 条重复项`, createFailed: '创建点歌券失败', noGeneratedToCopy: '暂无可复制的本次生成点歌券', copiedGenerated: (count: number) => `已复制 ${count} 张点歌券` }, stats: { total: '总数', all: '全部', available: '可用', unused: '未使用', locked: '锁定', pendingRedeem: '待核销', redeemed: '核销', completed: '已完成' } }, databaseManager: { title: '数据库操作', desc: '执行系统底层维护任务,包括备份、恢复及全局数据重置', highRisk: '高风险操作', executing: '执行中...', maintenanceTitle: '数据库维护建议', maintenanceDesc: '建议每周进行一次全量备份。在执行“恢复备份”或“重置数据库”前,请务必先创建一份当前的数据备份,以免误操作造成不可挽回的损失。', backupTitle: '创建数据库备份', restoreTitle: '恢复数据库备份', selectContent: '选择包含的内容', backupHint: '备份文件将以 .json 格式生成并自动下载', cancel: '取消', exporting: '正在导出...', startExport: '开始导出', selectFile: '点击选择或拖拽备份文件', fileHint: '仅支持 VoiceHub 导出的 .json 格式', restoreMode: '恢复模式', restoreModes: { merge: { title: '增量模式', desc: '仅导入不重复的新记录' }, replace: { title: '覆盖模式', desc: '清空现有表后完整恢复' } }, overwriteSuperAdmin: '覆盖备份中的超级管理员账号数据', overwriteSuperAdminDesc: '关闭时将保留当前超级管理员账号及其第三方绑定、2FA等关联数据', replaceWarning: '注意:覆盖模式将永久清空当前数据库中对应的表内容。此操作将导致现有会话中断。', restoring: '正在恢复...', confirmRestore: '确认并开始恢复', resetSequenceTitle: '重置数据表序列', selectTargetTable: '选择目标表', sequenceHelpTitle: '什么是重置序列?', sequenceHelpDesc: '如果您的数据表 ID 出现了断档或在手动操作数据库后无法自增,重置序列可以将数据库底层的计数器更新为当前 ID 最大值 +1,从而解决 ID 冲突导致的写入失败问题。此操作不会修改任何现有数据。', resetting: '正在重置...', executeReset: '执行重置', dangerResetTitle: '危险操作:重置数据库', dangerResetHeading: '您正在执行极其危险的操作!', dangerResetPrefix: '重置操作将永久删除系统中的所有', dangerResetScope: '歌曲、投稿记录、排期文件、通知、日志及除您以外的用户账号', confirmCodeLabel: '请输入以下代码以确认操作', confirmCodePlaceholder: '在此输入上述代码...', confirmResetDatabase: '确认彻底重置', cards: { backup: { title: '创建备份', desc: '导出当前数据库的所有数据到文件,用于安全备份或迁移。', button: '创建备份文件' }, restore: { title: '恢复备份', desc: '从之前导出的备份文件中恢复系统数据。', button: '选择备份文件' }, resetSeq: { title: '重置序列', desc: '修复数据表的自增ID序列,确保新记录的ID从正确值开始。', button: '开始重置序列' }, resetDb: { title: '重置数据库', desc: '清空除管理员账号外的所有系统数据。此操作不可撤销。', button: '立即重置数据库' }, autoBackup: { title: '自动备份', desc: '配置多种备份方式,通过外部触发实现定时自动备份', button: '配置自动备份' } }, backupOptions: { songs: { label: '歌曲与排期数据', desc: '包含所有歌曲库、用户投稿记录及历史播音排期' }, system: { label: '系统配置信息', desc: '包含站点设置、黑名单、播出时段等全局参数' }, users: { label: '用户账户数据', desc: '包含所有注册用户的权限、偏好设置(不含管理员敏感信息)' } }, tableOptions: [ { label: '重置所有表 (All)', value: 'all' }, { label: '歌曲表 (Song)', value: 'Song' }, { label: '用户表 (User)', value: 'User' }, { label: '用户身份表 (UserIdentity)', value: 'UserIdentity' }, { label: '用户状态日志表 (UserStatusLog)', value: 'UserStatusLog' }, { label: '投票表 (Vote)', value: 'Vote' }, { label: '排期表 (Schedule)', value: 'Schedule' }, { label: '通知表 (Notification)', value: 'Notification' }, { label: '通知设置表 (NotificationSettings)', value: 'NotificationSettings' }, { label: '播放时段表 (PlayTime)', value: 'PlayTime' }, { label: '学期表 (Semester)', value: 'Semester' }, { label: '系统设置表 (SystemSettings)', value: 'SystemSettings' }, { label: '歌曲黑名单表 (SongBlacklist)', value: 'SongBlacklist' }, { label: '歌曲重播申请表 (SongReplayRequest)', value: 'SongReplayRequest' }, { label: '投稿时段表 (RequestTime)', value: 'RequestTime' }, { label: '邮件模板表 (EmailTemplate)', value: 'EmailTemplate' } ], progress: { readingFile: '正在读取文件...', clearingData: '正在清空现有数据...', restoringTable: (table: string, start: number, end: number, total: number, percent: number) => `正在恢复 ${table} (${start}-${end}/${total}) ${percent}%`, fixingSequence: '正在修复数据表序列...', reloadingSmtp: '正在重载SMTP配置...', finalizingAdmin: '正在完成管理员替换...' }, messages: { parseBackupFailed: '无法解析备份文件,请检查文件格式是否正确。', invalidJsonFile: '请选择有效的JSON备份文件', backupDownloaded: '备份文件已下载', selectBackupFile: '请选择备份文件', restoreSuccessRelogin: '数据库恢复成功,正在重新登录', restoreSuccess: '数据库恢复成功', sequenceResetSuccess: '序列重置成功', databaseResetSuccess: '数据库已成功重置' }, logs: { parseBackupFailed: '解析备份文件失败:', createBackupFailed: '创建备份失败:', restoreBackupFailed: '恢复备份失败:', resetSequenceFailed: '重置序列失败:', resetDatabaseFailed: '重置数据库失败:' }, errors: { noBackupContent: '请至少选择一项备份内容', downloadFailed: (status: number) => `下载失败: ${status}`, createBackupFailed: '备份创建失败', createBackupFailedWithMessage: (message: string) => `创建备份失败: ${message}`, invalidBackupFormat: '无法解析备份文件,文件格式不正确', missingBackupData: '备份文件缺少数据部分', clearDataFailed: '清空数据失败', restoreTableFailed: (table: string) => `恢复表 ${table} 失败`, fixSequenceFailed: '序列修复失败', smtpReloadFailed: 'SMTP配置重载失败', restoreBackupFailedWithMessage: (message: string) => `恢复备份失败: ${message}`, resetFailed: '重置失败', resetSequenceFailedWithMessage: (message: string) => `重置序列失败: ${message}`, resetDatabaseFailedWithMessage: (message: string) => `重置数据库失败: ${message}` }, autoBackup: { title: '自动备份设置', cancel: '取消', saveAll: '保存全部', masterSwitch: { label: '启用自动备份', desc: 'API 被触发时,总开关关闭则不执行任何备份;开启时仅执行已启用的备份方式', }, methods: { title: '备份方式', s3: { name: 'S3 兼容存储', desc: '支持 R2 / S3 / B2 / MinIO 等', endpoint: 'Endpoint', endpointPlaceholder: 'https://xxx.r2.cloudflarestorage.com', bucket: 'Bucket', bucketPlaceholder: 'my-backups', region: 'Region', regionPlaceholder: 'auto', pathPrefix: '路径前缀', pathPrefixPlaceholder: 'voicehub-backups/', accessKey: 'Access Key ID', accessKeyPlaceholder: '请输入 Access Key ID', secretKey: 'Secret Access Key', secretKeyPlaceholder: '请输入 Secret Access Key', testConnection: '测试连接', }, webdav: { name: 'WebDAV', desc: '支持 Nextcloud / 群晖 / ownCloud', url: '服务器地址', urlPlaceholder: 'https://example.com/remote.php/dav/files/user/', username: '用户名', usernamePlaceholder: '请输入用户名', password: '密码', passwordPlaceholder: '请输入密码', path: '上传路径', pathPlaceholder: 'voicehub-backups/', testConnection: '测试连接', }, telegram: { name: 'Telegram Bot', desc: '通过 Bot 将备份文件发送至聊天', botToken: 'Bot Token', botTokenPlaceholder: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', chatId: 'Chat ID', chatIdPlaceholder: '123456789', testSend: '测试发送', }, email: { name: '邮件附件', desc: '将备份文件发送至指定邮箱', recipient: '收件人邮箱', recipientPlaceholder: 'admin@example.com', testSend: '测试发送', smtpHint: '使用站点已配置的邮件服务发送,只需填写收件人邮箱即可', }, }, endpoint: { title: 'API 触发端点', hint: '请先在「API 密钥管理」页面创建一个密钥,勾选「自动备份」权限,然后从外部定时调用此端点即可触发备份。', url: '备份端点 URL', methods: '触发方式', curlTab: 'cURL', cronjobTab: 'cron-job.org', githubTab: 'GitHub Actions', cronTab: 'Linux Cron', curlHint: '将 YOUR_API_KEY 替换为你的 API 密钥,在终端中运行即可触发一次备份。', cronjobLink: '访问 cron-job.org 免费创建定时任务', githubHint: '在 GitHub 仓库 Settings → Secrets 中配置 BACKUP_URL 和 API_KEY,将上述内容保存为 .github/workflows/backup.yml。', cronHint: '将 YOUR_API_KEY 替换为实际的 API 密钥,在服务器上执行 crontab -e 并添加上述内容。', }, history: { title: '备份历史', empty: '暂无备份记录', emptyHint: '触发一次备份后,记录将显示在此处', clear: '清空历史', }, messages: { copied: '已复制到剪贴板', copyFailed: '复制失败', testConnection: '正在测试连接...', testSend: '正在测试发送...', allSaved: '全部配置已保存', } } }, userManager: { title: '用户管理', subtitle: (total: number) => `系统共有 ${total} 位成员 · 权限与账户管理`, add: '添加', import: '导入', update: '更新', searchPlaceholder: '通过姓名或学号搜索...', role: '角色', allRoles: '全部角色', status: '状态', allStatus: '全部状态', sort: '排序', sortPlaceholder: '排序方式', loading: '正在加载用户...', emptySearch: '没有找到匹配的用户', empty: '暂无用户数据', itemName: '个用户', archivedUsers: '已归档用户', archivedSubtitle: (total: number) => `已归档 ${total} 位毕业生/退学账号`, organization: { title: '组织结构', subtitle: (total: number) => `${total} 位成员 · 按年级和班级统计`, refresh: '刷新组织结构', currentScope: '当前范围', clear: '清除', loading: '正在加载结构...', empty: '暂无可统计的用户', count: (total: number) => `(共${total}人)`, unnamedUser: '未命名用户', unsetGrade: '未设置年级', unsetClass: '未设置班级', stages: { junior: '初中', senior: '高中', university: '大学', staff: '教职工', other: '其他', withdrawn: '离校用户', graduate: '毕业生' }, loadFailed: '组织结构加载失败' }, table: { userDetails: '用户详情', role: '角色权限', status: '账户状态', class: '所在班级', lastActivity: '最后交互', actions: '操作' }, roles: { user: '普通用户', songAdmin: '歌曲管理员', admin: '管理员', superAdmin: '超级管理员' }, statuses: { active: '正常', pending: '待审核', withdrawn: '退学', graduate: '毕业生', disabled: '禁用', activeAccess: '正常访问', withdrawnAccess: '限制访问 (退学)', graduateAccess: '限制访问 (毕业生)' }, actions: { edit: '编辑', editUser: '编辑用户', viewSongs: '查看歌曲', records: '记录', reset: '重置', resetPassword: '重置密码', deleteUser: '删除用户', approve: '审核', cancel: '取消', close: '关闭窗口' }, approval: { title: '注册审核', username: '用户名', name: '姓名', grade: '年级', class: '班级', gradeNotSet: '不设置', registeredAt: '注册时间', remark: '注册备注', emptyRemark: '未填写', editHint: '通过时可修改以下注册信息', approve: '通过', reject: '拒绝', rejectReason: '拒绝理由', rejectReasonPlaceholder: '选填,将记录在状态日志中', confirmReject: '确认拒绝该注册申请?拒绝后该账户将被删除', approveSuccess: '注册审核已通过', rejectSuccess: '注册申请已拒绝', approveFailed: '注册审核操作失败', rejectFailed: '注册审核操作失败' }, mobile: { accountStatus: '账户状态', roleLevel: '角色/等级', class: '所在班级', recentActivity: '最近活动', lastLoginIp: '最后登录IP' }, form: { editTitle: '编辑用户信息', createTitle: '创建新用户', desc: '请填写以下账户详细信息以继续', name: '姓名', namePlaceholder: '请输入真实姓名', username: '用户名/学号', usernamePlaceholder: '登录唯一标识', newPassword: '新密码 (留空则不修改)', initialPassword: '初始密码', passwordPlaceholder: '设置安全访问密码', role: '角色权限', rolePlaceholder: '请选择角色', status: '账户状态', statusPlaceholder: '请选择状态', grade: '年级', gradePlaceholder: '例如: 2024', class: '班级', classPlaceholder: '例如: 1班', cancel: '取消操作', saving: '正在保存...', update: '更新用户信息', create: '确认创建用户' }, resetPasswordModal: { title: '重置访问密码', descPrefix: '正在为', descSuffix: '修改登录凭据', newPassword: '新密码', newPasswordPlaceholder: '设置高强度新密码', confirmPassword: '确认新密码', confirmPasswordPlaceholder: '请再次输入以确认', cancel: '取消', resetting: '正在重置...', confirm: '确认重置密码' }, importModal: { title: '批量导入用户', desc: '支持 .xlsx 格式文件,请按模板要求上传', instructionsTitle: '导入说明', instructionsLine1: '请上传Excel格式文件 (.xlsx),系统会自动解析数据。', instructionsLine2: '注意:第一行可以是标题行(会自动跳过),角色字段必须匹配系统定义的角色。', sampleHeaders: { name: '姓名', username: '用户名', password: '密码', role: '角色', grade: '年级', class: '班级' }, sampleName: '张三', sampleGrade: '高一', sampleClass: '1班', templateSheetName: '用户导入模板', templateFileName: '用户批量导入模板.xlsx', supportedRoles: '支持的角色:', supportedRolesFull: 'USER(普通用户)、ADMIN(管理员)、SONG_ADMIN(歌曲管理员)、SUPER_ADMIN(超级管理员)', supportedRolesLimited: 'USER(普通用户)、SONG_ADMIN(歌曲管理员)', downloadTemplate: '下载模板', chooseFile: '选择数据文件', uploadTitle: '点击或拖拽上传 Excel 文件', uploadHint: '仅支持 .xlsx 格式', previewData: (count: number) => `预览数据 (${count}条记录)`, account: '账号', gradeClass: '年级/班级', moreRecords: (count: number) => `以及另外 ${count} 条记录...`, cancel: '取消', importing: '正在导入...', confirm: '确认开始导入' }, batchUpdateModal: { title: '批量更新学生信息', desc: '快速调整学生年级、班级或通过 Excel 批量修改', updateTypes: { gradeOnly: { title: '仅更新年级', desc: '批量更新选中学生的年级,保持班级不变' }, excelBatch: { title: 'Excel 批量更新', desc: '通过 Excel 文件精确匹配并批量修改学生信息' }, statusBatch: { title: '设置账户状态', desc: '批量设置选中学生的账户状态' }, songAdminBatch: { title: '歌曲管理员', desc: '批量更新歌曲管理员的年级、班级、账号状态' } }, fields: { username: '用户名', name: '姓名', realName: '真实姓名' }, studentFilter: { title: '学生范围筛选', currentGrade: '当前年级', currentClass: '当前班级', allGrades: '全部年级', allClasses: '全部班级', selectUsers: (selected: number, total: number) => `选择用户 (${selected}/${total})`, clearSelection: '取消全选', selectAll: '选择当前全部', noMatchedUsers: '没有匹配条件的用户' }, gradeSettings: { title: '目标设置', targetGrade: '目标年级', targetGradePlaceholder: '例如: 2025', keepClass: '保持原有班级不变' }, statusSettings: { sourceStatus: '前置账户状态', sourceStatusPlaceholder: '请选择前置状态', title: '目标状态设置', targetStatus: '选择账户状态', targetStatusPlaceholder: '请选择目标状态', reason: '变更原因说明', reasonPlaceholder: '例如: 2025届学生统一毕业' }, songAdminSettings: { title: '歌曲管理员信息更新', desc: '选中用户将应用以下变更(留空则保持原值)', scope: '歌曲管理员范围筛选', currentGrade: '当前年级', currentClass: '当前班级', allGrades: '全部年级', allClasses: '全部班级', selectUsers: (selected: number, total: number) => `选择管理员 (${selected}/${total})`, clearSelection: '取消全选', selectAll: '选择当前全部', noMatchedUsers: '没有匹配条件的歌曲管理员', targetSettings: '更新目标设置', targetGrade: '目标年级', targetGradePlaceholder: '例如: 2025(留空保持原值)', targetClass: '目标班级', targetClassPlaceholder: '例如: 1班(留空保持原值)', targetStatus: '目标账号状态', targetStatusPlaceholder: '请选择目标状态(留空保持原值)' }, statusOptions: { all: '不限当前状态', active: '正常访问', graduate: '限制访问 (毕业生)', withdrawn: '限制访问 (退学)' }, excelUpload: { dragTitle: '拖拽 Excel 文件到此处', or: '或', chooseFile: '点击选择文件', supportedFormats: '(支持 .xlsx / .xls)' }, matchType: { title: '匹配方式', byUsername: '按用户名匹配', byName: '按姓名匹配', usernamePrefix: '通过', usernameSuffix: '精确定位账户,适用于学号不变的常规更新', namePrefix: '通过', nameMiddle: '定位账户,', nameSuffix: '列将作为新学号,适用于人员流动后学号前移的场景' }, fileSpec: { title: '文件格式规范', headerLine: '第一行为表头:用户名、姓名、年级、班级、新用户名', usernameColumn: '列用于精确匹配现有账户', nameColumn: '列用于精确匹配现有账户', blankKeepsOriginal: '字段留空则保持原值不变,不进行覆盖更新', downloadTemplate: '获取模板文件' }, preview: { blockersTitle: (count: number) => `需要处理的用户 (${count})`, blockersDesc: '以下用户不在当前更新列表中,但占用了目标用户名。请先将其标记为退学或禁用后再更新。', dataPreview: (visible: number, total: number) => `数据预览 (${visible}/${total}条)`, pending: (count: number) => `待更新 (${count})`, noChangeCount: (count: number) => `无变更 (${count})`, errorCount: (count: number) => `错误 (${count})`, matchUser: '匹配用户', matchName: '匹配姓名', currentInfo: '当前信息', afterUpdate: '更新后', matchStatus: '匹配状态', noChange: '无变更', ready: '已就绪', moreQueued: (count: number) => `以及另外 ${count} 条记录已在队列中` }, actions: { cancel: '取消操作', submitting: '正在提交更新...', confirm: '确认并开始更新' }, template: { headers: { username: '用户名', name: '姓名', grade: '年级', class: '班级', newUsername: '新用户名' }, sampleName1: '张三', sampleName2: '李四', sampleClass1: '1班', sampleClass2: '2班', sheetName: '学生信息', fileName: '学生信息批量更新模板.xlsx' }, progress: { processing: (current: number, total: number) => `正在更新:正在处理第 ${current} / ${total} 批数据...`, completed: (success: number, failed: number) => `更新完成:成功 ${success} 个,失败 ${failed} 个` }, messages: { partialGradeSuccess: (failed: number) => `部分更新成功,${failed} 个用户因权限或状态等原因跳过`, gradeSuccess: (count: number) => `成功更新 ${count} 个用户的年级`, partialExcelSuccess: (success: number, failed: number) => `部分更新成功:成功 ${success} 个,失败 ${failed} 个,请检查后重试`, excelFailed: (failed: number) => `批量更新失败:${failed} 个用户未能更新,请检查后重试`, partialStatusSuccess: (failed: number) => `部分更新成功,${failed} 个用户因权限或状态等原因跳过`, statusSuccess: '批量更新状态成功', songAdminSuccess: (count: number) => `成功更新 ${count} 位歌曲管理员信息`, partialSongAdminSuccess: (failed: number) => `部分更新成功,${failed} 位管理员因权限或状态等原因跳过`, songAdminNoChanges: '所选歌曲管理员的信息没有需要更新的变更' }, errors: { invalidExcelFormat: 'Excel文件格式错误,请检查文件格式', readFileFailed: '读取文件失败,请重试', unknownExcelError: '未知错误,请检查文件格式或网络连接', processExcelFailed: (message: string) => `处理Excel文件失败: ${message}`, fieldRequired: (field: string) => `${field}不能为空`, duplicateNames: '存在多个同名用户,请切换至按用户名匹配', userNotFound: '用户不存在', duplicateTarget: (username: string) => `重复的更新目标:多行数据尝试更新为同一个用户名 ${username}`, usernameOccupied: (username: string, name: string) => `用户名 ${username} 被占用,请先处理 ${name} 的账户`, loadXlsxFailed: '无法加载Excel处理库,请检查网络连接', loadXlsxRetry: 'Excel处理库加载失败,请刷新页面后重试', batchUpdateFailed: (message: string) => `批量更新失败: ${message}`, unknownError: '未知错误', batchUpdateGeneric: '批量更新失败', updateFailedWithEtc: (message: string) => `更新失败: ${message} 等`, noValidUpdates: '没有有效的更新数据', batchRequestFailed: '批量更新请求失败', invalidBatchResponse: '批量更新接口返回格式异常', statusUpdateFailed: '批量更新状态失败', songAdminUpdateFailed: '批量更新歌曲管理员失败' } }, deleteDialog: { title: '确认删除用户', message: (name: string) => `确定要删除用户 "${name}" 吗?此操作将永久移除该账户,不可撤销。`, confirm: '确认删除' }, detail: { title: '用户详细信息', desc: '查看完整的账户资料与操作记录', basicInfo: '基本信息', userId: '用户 ID', name: '姓名', username: '用户名', role: '角色权限', grade: '年级', class: '班级', unset: '未设置', status: '账户状态', passwordStatus: '密码状态', passwordChanged: '密码已修改', requirePasswordChange: '需要修改密码', meowBinding: 'MeoW 账号绑定', emailBinding: '邮箱绑定', oauthBinding: 'OAuth 账号绑定', bound: (value: string) => `已绑定: ${value}`, unbound: '未绑定', oauthBindingsTitle: 'OAuth 绑定详情', oauthBindingsDesc: '查看该用户绑定的第三方账号信息', oauthBindingsEmpty: '暂无绑定信息', oauthProvider: '绑定平台', oauthUsername: '平台用户名', oauthUserId: '平台用户 ID', oauthBoundAt: '绑定时间', oauthNoUsername: '未提供用户名', oauthNoId: '未提供 ID', oauthUnknownDevice: '未知设备', oauthTotpLabel: '双重认证', oauthIdHidden: '已隐藏', oauthUnknownTime: '未知时间', verified: '已验证', unverified: '未验证', loginInfo: '登录信息', lastLogin: '最后登录', loginIp: '登录 IP', unknown: '未知', timeRecords: '时间记录', createdAt: '创建时间', updatedAt: '最近更新', statusLogs: '状态变更日志', loadingLogs: '正在加载记录...', noLogs: '暂无状态变更记录', initial: '初始', reason: '原因:', operator: '操作者:', system: '系统' }, sortOptions: { default: '默认排序 (ID)', nameAsc: '名称 (A-Z)', nameDesc: '名称 (Z-A)', lastLoginDesc: '最近登录', lastLoginAsc: '最早登录', createdAtDesc: '最近注册', createdAtAsc: '最早注册' }, time: { never: '从未登录', justNow: '刚刚', minutesAgo: (minutes: number) => `${minutes}分钟前`, hoursAgo: (hours: number) => `${hours}小时前`, daysAgo: (days: number) => `${days}天前`, unknown: '未知时间' }, notifications: { selfEditForbidden: '禁止在用户管理中修改自己的账户', selfResetForbidden: '禁止在用户管理中重置自己的密码', selfDeleteForbidden: '不能删除自己的账户', deleteSuccess: '用户删除成功', deleteFailed: (message: string) => `删除用户失败: ${message}`, updateSuccess: '用户更新成功', createSuccess: '用户创建成功', resetSuccess: '密码重置成功', detailLoadFailed: (message: string) => `加载用户详情失败:${message}`, loadFailed: (message: string) => `加载用户失败: ${message}`, excelLoadFailed: 'Excel处理库加载失败,请刷新页面后重试' }, errors: { requiredInfo: '请填写必要信息', passwordRequired: '请输入密码', saveFailed: '保存失败', newPasswordRequired: '请输入新密码', passwordMismatch: '两次输入的密码不一致', resetFailed: '重置失败', xlsxLoadFailed: '无法加载Excel处理库,请刷新页面重试', noValidData: '未找到有效数据', parseExcelFailed: (message: string) => `解析Excel文件失败: ${message}`, readFileFailed: '读取文件失败', processExcelFailed: (message: string) => `处理Excel文件失败: ${message}`, partialImportFailed: (errors: string) => `部分导入失败原因:\n${errors}`, importFailedWithReasons: (errors: string) => `导入失败,请检查数据格式后重试。\n失败原因:\n${errors}`, importRuntimeFailed: (count: number, message: string) => `导入过程中发生错误 (已成功导入 ${count} 个): ${message}`, statusLogsFailed: '加载状态日志失败' }, importProgress: { processingBatch: (current: number, total: number) => `正在导入:正在处理第 ${current} / ${total} 批数据...`, complete: (created: number, failed: number) => `导入完成:成功导入 ${created} 个,失败 ${failed} 个`, batchFailed: (batch: number, message: string) => `第 ${batch} 批请求失败: ${message}`, rowError: (row: string | number, name: string, reason: string) => `第${row}行${name}: ${reason}` } }, apiKeys: { title: 'API密钥管理', desc: '管理开放API的访问密钥,控制第三方应用的访问权限', create: '创建API密钥', searchPlaceholder: '搜索API密钥名称或描述...', status: '状态', allStatus: '全部状态', active: '活跃', inactive: '非活跃', expired: '已过期', creatorPlaceholder: '创建者用户名', loading: '加载中...', emptyTitle: '暂无API密钥', emptyDesc: '您还没有创建任何访问密钥。创建密钥后,您可以安全地将 VoiceHub 集成到第三方应用程序中。', createFirst: '创建您的第一个密钥', noDescription: '暂无描述', unknown: '未知', creator: '创建者', createdAt: '创建时间', permissions: '权限列表', itemName: '个API密钥', edit: '编辑API密钥', name: '名称 *', namePlaceholder: '输入API密钥名称', description: '描述', descriptionPlaceholder: '输入API密钥描述 (可选)', expiresAt: '过期时间', expiresOptions: { never: '永不过期', keep: '保持不变', threeDays: '3天后过期', sevenDays: '7天后过期', thirtyDays: '30天后过期', sixtyDays: '60天后过期', ninetyDays: '90天后过期' }, permissionSettings: '权限设置 *', enabled: '启用此API密钥', cancel: '取消', saving: '保存中...', createKey: '创建密钥', saveChanges: '保存更改', createSuccessTitle: 'API密钥创建成功', createSuccessHeading: 'API密钥创建成功!', createSuccessDesc: '请妥善保管以下API密钥,它只会显示这一次。', fullKey: '完整API密钥', copyWarning: '请立即复制并保存此API密钥,关闭此窗口后将无法再次查看完整密钥', closeSaved: '我已保存,关闭窗口', details: 'API密钥详情', basicInfo: '基本信息', nameField: '名称:', statusField: '状态:', descField: '描述:', creatorField: '创建者:', createdAtField: '创建时间:', expiresAtField: '过期时间:', usageStats: '使用统计', totalCalls: '总调用次数', lastUsedAt: '最后使用时间', neverChecked: '从未核对', recentLogs: '最近调用日志', loadingLogs: '正在加载日志...', noLogs: '暂无调用记录', confirmDeleteTitle: '确认删除', delete: '删除', deleteMessage: (name: string) => `确定要删除API密钥 "${name}" 吗?此操作不可撤销。`, permissionOptions: { scheduleRead: { label: '排期查询', description: '查看排期列表和详情' }, songsRead: { label: '歌曲查询', description: '查看歌曲列表和详情' }, songsRequest: { label: '歌曲投稿', description: '代表令牌所属用户提交点歌' }, songsWrite: { label: '歌曲管理', description: '更新歌曲状态' }, cardCodesRead: { label: '点歌券查询', description: '查看点歌券列表和统计' }, cardCodesWrite: { label: '点歌券管理', description: '创建和更新点歌券' }, cardCodesDelete: { label: '点歌券删除', description: '删除点歌券' }, backupExecute: { label: '自动备份', description: '触发自动备份任务' } }, loadFailed: '加载API密钥失败', nameRequired: '请输入密钥名称', permissionRequired: '请至少选择一个权限', updateSuccess: 'API密钥更新成功', updateFailed: '更新API密钥失败', createFailed: '创建API密钥失败', deleteSuccess: 'API密钥删除成功', deleteFailed: '删除API密钥失败', detailFailed: '获取API密钥详情失败', logsFailed: '获取API使用日志失败', copied: '已复制到剪贴板', copyFailed: '复制失败', expiresAtText: (date: string) => `到期: ${date}` } } as const // ==================== 主题 ==================== export const theme = { select: '选择主题', System: '跟随系统', ClassicDark: '经典深色', ClassicLight: '经典浅色', ModernLight: '现代浅色' } as const // 服务端业务错误码本地化文案(按 server/config/constants.ts 的 SERVER_ERROR_CODES 键入)。 // 客户端通过 useServerErrors().localize(err) 按 err.data.code 命中此表,未命中回退服务端英文 message。 export const serverErrors = { CARD_CODE_AUTH_REQUIRED: '请先登录后再验证点歌券', CARD_CODE_REQUIRED: '请先填写点歌券', CARD_CODE_DISABLED: '点歌券投稿功能未启用', CARD_CODE_INVALID_OR_USED: '点歌券无效或已被使用', CARD_CODE_LOCKED_OR_UNAVAILABLE: '点歌券已被锁定或不可用', CARD_CODE_REQUIRED_FOR_SITE: '本站点已启用仅点歌券投稿,请提供有效点歌券', CARD_CODE_TOO_LONG: '点歌券不能超过100个字符', AUTH_CSRF_COOKIE_MISSING: 'CSRF验证失败:Cookie丢失,请从登录页面重新开始', AUTH_CHALLENGE_EXPIRED: 'Challenge 已失效', AUTH_CHALLENGE_INVALID: 'Challenge 已失效或不匹配', AUTH_STATE_INVALID: 'state 无效或已过期', AUTH_MISSING_CODE_OR_STATE: '缺少 code 或 state', AUTH_MISSING_PROVIDER: '缺少 provider 参数', AUTH_OAUTH_PROVIDER_DISABLED: 'OAuth 提供商已被禁用', AUTH_OAUTH_PROVIDER_STATE_MISMATCH: 'OAuth provider 与 state 不匹配', AUTH_OAUTH_REDIRECT_ORIGIN_MISMATCH: 'OAuth 回调地址与当前请求源站不一致,请在管理员后台将 OAuth 重定向 URI 配置为当前站点域名', AUTH_OAUTH_REDIRECT_INVALID: 'OAuth 重定向 URI 配置无效,请在管理员后台检查配置', AUTH_WEBAUTHN_RP_ID_INVALID: 'WebAuthn RP ID 配置无效', AUTH_UNSUPPORTED_VERIFICATION_TYPE: '不支持的验证类型', AUTH_CAPTCHA_FAILED_OR_EXPIRED: '人机验证失败或已过期,请重试', AUTH_CAPTCHA_SERVICE_UNAVAILABLE: '人机验证服务暂时不可用', AUTH_SESSION_EXPIRED: '会话已失效,请重新登录', AUTH_CREDENTIAL_CORRUPTED: '凭证数据损坏', AUTH_CREDENTIAL_MISSING: '凭证数据缺失', AUTH_CREDENTIAL_MISSING_PUBLICKEY: '凭证数据缺失 publicKey', AUTH_TOTP_CODE_INVALID: '动态验证码错误', AUTH_TOTP_TOO_MANY_ATTEMPTS: '动态验证码错误次数过多,请在 5 分钟后重试', AUTH_INCOMPLETE_PARAMS: '参数不完整', COMMON_INVALID_PARAMS: '参数错误', THEME_INVALID_LIST: '启用的主题列表无效', THEME_INVALID_DEFAULT: '默认主题必须有效且处于启用状态', THEME_SYSTEM_REQUIRES_CLASSIC: '跟随系统时必须同时启用经典深色和经典浅色', SETTINGS_GRADE_CLASS_OPTIONS_MISSING: '请先在年级班级管理中配置年级班级,再启用该选项', BILIBILI_PLAYURL_FAILED: '获取 Bilibili 音频链接失败', AUTH_NAME_USERNAME_PASSWORD_REQUIRED: '姓名、用户名、密码不能为空', AUTH_USERNAME_LENGTH_INVALID: '用户名长度需要在3-30个字符之间', AUTH_USERNAME_PATTERN_INVALID: '用户名仅可包含英文、数字、下划线和连字符', AUTH_PASSWORD_TOO_SHORT: '密码长度不能少于6个字符', AUTH_PASSWORD_TOO_LONG: '密码长度不能超过128位', AUTH_PASSWORD_TOO_MANY_BYTES: '密码有效长度不能超过72字节', AUTH_PASSWORD_TOO_COMMON: '该密码过于常见,请更换更安全的密码', AUTH_PASSWORD_COMPLEXITY_REQUIRED: '密码至少需要包含大写字母、小写字母、数字、特殊字符中的三类', AUTH_INITIAL_PASSWORD_COMPLEXITY_REQUIRED: '密码至少需要包含大写字母、小写字母、数字、特殊字符中的两类', AUTH_PASSWORD_NOT_SET: '当前账号尚未设置密码,请使用初始密码设置功能', AUTH_INITIAL_PASSWORD_NOT_REQUIRED: '当前账号不需要设置初始密码,请使用修改密码功能', AUTH_PASSWORD_CHANGE_REQUIRED: '请先完成密码修改后再继续', AUTH_PASSWORD_STATE_CHANGED: '密码状态已变化,请重新验证后再试', AUTH_GRADE_CLASS_TOGETHER: '年级和班级需要同时选择,或全部留空', AUTH_GRADE_CLASS_REQUIRED: '注册时必须选择年级和班级', AUTH_UNSUPPORTED_OAUTH_PROVIDER: '当前仅支持 GitHub / Casdoor / Google / 聚合登陆 / 第三方 OAuth2', AUTH_CURRENT_PASSWORD_INCORRECT: '当前密码不正确', AUTH_CURRENT_AND_NEW_PASSWORD_REQUIRED: '当前密码和新密码都是必需的', AUTH_PASSWORD_ALREADY_SET: '您已经设置过密码,请使用修改密码功能', AUTH_IP_BLOCKED_RETRY_MINUTES: '您的IP地址已被限制访问,请在 {0} 分钟后重试', AUTH_ACCOUNT_NAME_NOT_FOUND: '找不到该账号名,请检查是否拼写错误', AUTH_RATE_LIMITED_MINUTES: '操作过于频繁,请等待 {0} 分钟后再试', AUTH_RATE_LIMITED_SECONDS: '操作过于频繁,请等待 {0} 秒后再试', AUTH_EMAIL_CODE_INVALID: '邮箱验证码无效或已过期,请重新获取', AUTH_EMAIL_CODE_COOLDOWN: '验证码发送过于频繁,请 1 分钟后再试', AUTH_EMAIL_CODE_DAILY_LIMIT: '今日验证码发送次数已达上限,请明天再试', AUTH_EMAIL_SERVICE_UNAVAILABLE: '邮件服务未配置或不可用,请联系管理员', AUTH_DATABASE_UNAVAILABLE: '数据库服务暂时不可用', AUTH_NEW_PASSWORD_SAME_AS_CURRENT: '新密码不能与当前密码相同', AUTH_NEW_PASSWORD_REQUIRED: '新密码不能为空', AUTH_REGISTER_PASSWORD_MISMATCH: '两次输入的密码不一致', AUTH_INVALID_REGISTER_TOKEN: '无效的注册令牌', AUTH_INVALID_BINDING_TOKEN: '无效的绑定令牌', AUTH_INVALID_RESET_LINK: '无效的重置链接', AUTH_UPDATE_FAILED: '更新失败', AUTH_SERVER_CONFIG_ERROR: '服务器配置错误', AUTH_AGGREGATED_LOGIN_UNSUPPORTED: '未启用或不支持的聚合登录方式', AUTH_TOTP_NOT_ENABLED: '未开启TOTP验证', AUTH_PASSKEY_ACCOUNT_NOT_FOUND: '未找到该 Passkey 关联的账号', AUTH_DEVICE_NOT_FOUND: '未找到该设备', AUTH_UNAUTHORIZED: '未授权', AUTH_UNAUTHORIZED_ACCESS: '未授权访问', AUTH_TOKEN_MISSING: '未提供认证令牌', AUTH_MULTI_IP_PROTECTION: '检测到同一账号短期多IP登录,当前IP限制 {0} 分钟,账户保护 {1} 分钟', AUTH_REGISTER_SESSION_EXPIRED: '注册会话已过期,请重新通过第三方登录发起', USER_NOT_FOUND: '用户不存在', AUTH_USER_NOT_FOUND_OR_NO_EMAIL: '用户不存在或未绑定邮箱', AUTH_USERNAME_PASSWORD_REQUIRED: '用户名和密码不能为空', AUTH_USERNAME_TAKEN: '用户名已存在,请使用其他用户名', AUTH_INVALID_CREDENTIALS: '用户名或密码错误', AUTH_LOGIN_UNKNOWN_ERROR: '登录过程中发生未知错误', AUTH_OAUTH_REGISTER_DISABLED: '系统已关闭第三方账号注册功能', AUTH_OAUTH_REGISTER_DISABLED_BIND: '系统已关闭第三方账号注册功能,请登录现有账号进行绑定', AUTH_REGISTER_DISABLED: '系统未开放注册', AUTH_USER_PENDING_APPROVAL: '账号待管理员审核,请耐心等待', AUTH_SYSTEM_ERROR: '系统错误,请稍后重试', AUTH_BINDING_SESSION_INVALID: '绑定会话已失效,请重新发起绑定', AUTH_BINDING_SESSION_EXPIRED: '绑定会话已过期,请重新通过第三方登录发起', AUTH_MISSING_CREDENTIAL_ID: '缺少 Credential ID', AUTH_MISSING_REQUIRED_PARAMS: '缺少必要参数', AUTH_MISSING_PROVIDER_PARAM: '缺少提供商参数', AUTH_MISSING_PRE_TOKEN: '缺少预认证令牌', AUTH_MISSING_PRE_TOKEN_RELOGIN: '缺少预认证令牌,请重新登录', AUTH_AGGREGATED_CALLBACK_STATE_MISMATCH: '聚合登录回调类型与 state 不匹配', AUTH_AGGREGATED_METHOD_CHANGED: '聚合登录方式未启用或已变更', AUTH_AGGREGATED_STATE_INVALID: '聚合登录状态无效或已过期', AUTH_DEVICE_NAME_TOO_LONG: '设备名称过长', AUTH_OAUTH_BOUND_OTHER_USER: '该第三方账号已被其他用户绑定', AUTH_OAUTH_ALREADY_BOUND: '该第三方账号已被绑定,请直接登录或绑定到现有账户', AUTH_ACCOUNT_UNAVAILABLE_OR_RESTRICTED: '该账号不可用或已限制访问', AUTH_ACCOUNT_GRADUATED: '该账号已毕业,限制访问', AUTH_ACCOUNT_BANNED: '该账号已被封禁', AUTH_ACCOUNT_WITHDRAWN: '该账号已退学,限制访问', AUTH_ACCOUNT_CURRENTLY_UNAVAILABLE: '该账号当前不可用', AUTH_NO_SECURITY_EMAIL: '该账号未绑定安全邮箱,无法通过此方式找回密码。请联系管理员。', AUTH_RESET_LINK_INVALIDATED: '该重置链接已失效(密码已被修改)', AUTH_CAPTCHA_REQUIRED: '请完成人机验证', AUTH_IMAGE_CAPTCHA_REQUIRED: '请完成图形验证码', AUTH_ACCOUNT_NAME_REQUIRED: '请提供账号名', AUTH_GRADE_CLASS_MUST_EXIST: '请选择系统内已存在的年级和班级', AUTH_ACCOUNT_DISABLED_OR_RESTRICTED: '账号已被禁用或限制访问', AUTH_ACCOUNT_RISK_CONTROL: '账户处于风险控制期,请在 {0} 分钟后重试', AUTH_ACCOUNT_LOCKED_MINUTES: '账户已被锁定,请在 {0} 分钟后重试', AUTH_ACCOUNT_LOCKED: '账户已被锁定,请稍后重试', AUTH_EMAIL_MISMATCH: '邮箱地址不匹配', AUTH_RESET_PASSWORD_TOO_MANY: '重置密码尝试次数过多,请等待 {0} 分钟后再试', AUTH_RESET_LINK_EXPIRED: '重置链接已过期,请重新申请', AUTH_USER_ID_MISMATCH: '非法操作:用户ID不匹配', AUTH_VERIFICATION_FAILED: '验证失败', AUTH_TOO_MANY_VERIFY_ATTEMPTS: '验证尝试次数过多,请重新获取', AUTH_CODE_SEND_FAILED: '验证码发送失败', AUTH_CODE_ALREADY_USED: '验证码已使用,请重新获取', AUTH_CODE_EXPIRED: '验证码已过期', AUTH_CODE_EXPIRED_OR_MISSING: '验证码已过期或不存在', AUTH_CODE_SERVICE_CONFIG_ERROR: '验证码服务配置错误,请联系管理员', AUTH_CODE_INVALID_OR_EXPIRED: '验证码错误或已过期,请重新输入', AUTH_CODE_WRONG_ATTEMPTS_LEFT: '验证码错误,剩余尝试次数:{0}', SONG_INVALID_ID: '无效的歌曲 ID', HTTP_METHOD_NOT_ALLOWED: '方法不被允许', SONG_ALREADY_EXISTS: '歌曲已存在', SONG_TITLE_ARTIST_REQUIRED: '歌曲名和艺术家不能为空', SONG_CANNOT_SELF_VOTE: '不允许自己给自己投票', SONG_VOTE_NOT_FOUND: '你尚未为这首歌投票,无法取消', SONG_ALREADY_VOTED: '你已经为这首歌投过票了', SONG_REPLAY_CANCEL_FAILED: '取消重播申请失败,请稍后再试', SONG_VOTERS_ADMIN_ONLY: '只有管理员才能查看投票人员列表', SONG_WITHDRAW_OWN_ONLY: '只能撤回自己的投稿或退出联合投稿', SONG_REPLAY_CURRENT_SEMESTER_ONLY: '只能申请重播当前学期的歌曲', SONG_INVITATION_FAILED: '处理邀请失败', SONG_SCHEDULED_CANNOT_WITHDRAW: '已排期的歌曲不能撤回', SONG_PLAYED_CANNOT_WITHDRAW: '已播放的歌曲不能撤回', SONG_NO_ACTIVE_SEMESTER_REPLAY: '当前没有活跃学期,无法申请重播', SONG_RESTRICTION_SAME_SONG: '《{1}》排期后 {0} 小时内不能重复投稿', SONG_RESTRICTION_SAME_ARTIST: '歌手“{1}”的歌曲排期后 {0} 小时内不能重复投稿', SONG_REPLAY_ALREADY_REQUESTED: '您已经申请过重播该歌曲', SONG_REPLAY_COOLDOWN: '重播申请冷却中,还需等待 {0} 小时', SONG_REPLAY_INVALID_REQUEST: '重播申请无效或已被处理', SONG_REPLAY_PLAY_TIME_DISABLED: '播出时段选择功能未启用', SONG_REPLAY_PLAY_TIME_INVALID: '选择的播出时段不存在或未启用', SONG_REQUESTER_NOT_FOUND: '投稿人用户不存在', SONG_OPERATION_FAILED: '操作失败,请稍后重试', SONG_INVITATION_NOT_FOUND: '未找到待处理的邀请', AUTH_LOGIN_REQUIRED: '请先登录', SONG_NO_ACTIVE_SEMESTER_VOTE: '未设置活跃学期,无法进行投票操作', COMMON_INSUFFICIENT_PERMISSION: '权限不足', COMMON_TARGET_NOT_FOUND: '目标不存在', USER_NOT_PENDING: '仅待审核用户可执行审核操作', GRADE_CLASS_DUPLICATE: '该年级班级组合已存在', SONG_ID_REQUIRED: '歌曲ID不能为空', SONG_NOT_FOUND: '歌曲不存在', SONG_DURATION_PLATFORM_REQUIRED: '歌曲缺少平台或音乐 ID 信息,无法获取时长', SONG_CARD_RELEASE_FAILED: '点歌券释放失败,撤回已终止', SONG_NO_ACTIVE_SEMESTER_IMPORT: '系统未设置当前活跃学期,无法导入歌曲。请联系管理员先设置活跃学期。', SONG_FETCH_VOTERS_FAILED: '获取投票人员列表失败', SONG_FETCH_STATUS_FAILED: '获取投稿状态失败', SONG_FETCH_COUNT_FAILED: '获取歌曲数量失败', SONG_TEMP_PROTECTED_SECONDS: '该歌曲处于临时保护期,剩余 {0} 秒', SONG_NOT_PLAYED_NO_REPLAY: '该歌曲尚未播放,无法申请重播', SONG_SCHEDULED_NO_VOTE: '该歌曲已排期,无法进行投票操作', SONG_PLAYED_NO_VOTE: '该歌曲已播放,无法进行投票操作', SONG_SELECT_TO_IMPORT: '请选择要导入的歌曲', SONG_REPLAY_NOT_FOUND_OR_FORBIDDEN: '重播申请不存在或无权取消', SONG_REPLAY_DISABLED: '重播申请功能未开启', SONG_LOGIN_REQUIRED_CANCEL_REPLAY: '需要登录才能取消重播申请', SONG_LOGIN_REQUIRED_VOTE: '需要登录才能投票', SONG_LOGIN_REQUIRED_WITHDRAW: '需要登录才能撤回歌曲', SONG_LOGIN_REQUIRED_VIEW_VOTERS: '需要登录才能查看投票人员', SONG_LOGIN_REQUIRED_VIEW_STATUS: '需要登录才能查看投稿状态', SONG_LOGIN_REQUIRED_REQUEST: '需要登录才能点歌', SONG_LOGIN_REQUIRED_REPLAY: '需要登录才能申请重播', SONG_INACTIVE_SEMESTER_VOTE: '非活跃学期,无法进行投票操作', USER_API_KEY_NOT_FOUND: '个人集成令牌不存在', USER_API_KEY_ID_REQUIRED: '令牌 ID 不能为空', USER_API_KEY_ID_INVALID: '无效的令牌 ID', USER_API_KEY_CREATE_FAILED: '创建个人 API Key 失败', USER_API_KEY_CREATE_FAILED_DETAIL: '创建个人 API Key 失败:{0}', USER_API_KEY_DELETE_FAILED_DETAIL: '删除个人集成令牌失败:{0}', USER_CODE_SEND_FAILED: '发送验证码失败,请稍后重试', USER_PASSWORD_INCORRECT: '密码错误', USER_2FA_ALREADY_ENABLED: '已开启双重认证', USER_API_KEY_LIMIT_REACHED: '每个用户最多只能创建 5 个个人集成令牌', USER_EMAIL_BIND_FAILED: '绑定邮箱失败', USER_MISSING_CODE_OR_SECRET: '缺少验证码或密钥', USER_API_KEY_FETCH_FAILED_DETAIL: '获取个人集成令牌失败:{0}', USER_API_KEY_LOGS_FETCH_FAILED_DETAIL: '获取个人集成令牌日志失败:{0}', USER_YEAR_REVIEW_FETCH_FAILED: '获取年度总结失败', USER_EMAIL_UNBIND_FAILED: '解绑邮箱失败', USER_EMAIL_TAKEN: '该邮箱已被其他用户绑定', USER_SEND_CODE_FIRST: '请先发送验证码', USER_BIND_EMAIL_FIRST: '请先绑定邮箱', USER_REQUEST_VALIDATION_FAILED: '请求参数验证失败:{0}', USER_PASSWORD_REQUIRED: '请输入密码', USER_INVALID_EMAIL: '请输入有效的邮箱地址', USER_EMAIL_AND_CODE_REQUIRED: '邮箱与验证码不能为空', USER_EMAIL_CHANGED_RESEND: '邮箱已发生变化,请重新发送验证码', USER_EMAIL_ALREADY_VERIFIED: '邮箱已验证,无需重新发送', USER_RESEND_EMAIL_FAILED: '重新发送验证邮件失败', USER_CODE_ALREADY_USED: '验证码已使用,请重新发送', USER_CODE_EXPIRED_RESEND: '验证码已过期,请重新发送', USER_CODE_INVALID: '验证码错误', USER_CODE_TOO_MANY_ATTEMPTS: '验证码错误次数过多,请重新发送', BACKUP_DISABLED: '自动备份未启用', MUSIC_SOURCE_PLATFORM_DISABLED: '平台“{0}”已关闭,可用平台:{1}', QQ_COMMENT_FETCH_FAILED: 'QQ 音乐评论获取失败,请稍后重试', BACKUP_NOT_CONFIGURED: '自动备份未配置', NO_BACKUP_METHOD_ENABLED: '没有启用任何备份方式', BACKUP_FAILED: '备份执行失败', SMTP_NOT_CONFIGURED: '邮件服务未配置', NOTIFICATION_AUTH_REQUIRED: '请先登录后再操作通知', NOTIFICATION_ADMIN_REQUIRED: '只有管理员可以发送系统通知', NOTIFICATION_IMPORTANT_INVALID: '重要通知标记必须是布尔值', NOTIFICATION_TITLE_CONTENT_REQUIRED: '通知标题和内容不能为空', NOTIFICATION_TITLE_TOO_LONG: '通知标题不能超过 {0} 个字符', NOTIFICATION_CONTENT_TOO_LONG: '通知正文不能超过 {0} 个字符', NOTIFICATION_USER_ID_INVALID: '用户 ID 无效', NOTIFICATION_SCOPE_INVALID: '通知范围无效', NOTIFICATION_GRADE_REQUIRED: '年级不能为空', NOTIFICATION_GRADE_CLASS_REQUIRED: '年级和班级不能为空', NOTIFICATION_CLASSES_REQUIRED: '请选择有效的班级', NOTIFICATION_USERS_REQUIRED: '请选择至少一名用户', NOTIFICATION_SEND_FAILED: '发送通知失败', NOTIFICATION_FETCH_FAILED: '获取重要通知失败', NOTIFICATION_ID_INVALID: '通知 ID 无效', NOTIFICATION_NOT_FOUND: '通知不存在', NOTIFICATION_FORBIDDEN: '无权操作此通知', NOTIFICATION_MARK_READ_FAILED: '标记通知为已读失败', NOTIFICATION_DELETE_FAILED: '删除通知失败', NOTIFICATION_CLEAR_FAILED: '清空通知失败', NOTIFICATION_HISTORY_STATUS_INVALID: '通知历史状态筛选值无效', NOTIFICATION_HISTORY_FILTER_INVALID: '通知历史筛选条件无效', NOTIFICATION_HISTORY_FETCH_FAILED: '获取通知历史失败', NOTIFICATION_HISTORY_UPDATE_FAILED: '修改通知失败', NOTIFICATION_HISTORY_DELETE_FAILED: '删除通知失败', } as const