fix(panel): localize every user-reachable API error code (#60)
This commit is contained in:
3 files changed
+162
-2
No files matched your search
@@ -26,5 +26,42 @@
|
||||
"passkey_already_bound": "This Passkey is already bound to another account.",
|
||||
"passkey_unavailable": "Passkey subsystem is not available right now.",
|
||||
"passkey_not_allowed": "The operation was cancelled by the user or browser.",
|
||||
"passkey_aborted": "Passkey registration was aborted."
|
||||
"passkey_aborted": "Passkey registration was aborted.",
|
||||
"bad_name": "That server name is invalid — use 3–32 lowercase letters, digits or dashes, and avoid reserved names.",
|
||||
"bad_subdomain": "That subdomain is invalid — use 3–32 lowercase letters, digits or dashes, and avoid reserved names.",
|
||||
"at_capacity": "The cluster is at its running-server cap — try again once a server stops.",
|
||||
"storage_immutable": "Storage size can't be changed online.",
|
||||
"email_taken": "That email is already verified on another account — sign in with it or use another address.",
|
||||
"mail_undeliverable": "The verification email could not be delivered — try again later, or ask the operator to check the mail relay.",
|
||||
"bad_path": "That path is invalid — use a relative path inside the world directory.",
|
||||
"too_large": "That is larger than the size limit.",
|
||||
"files_timeout": "The file operation timed out — try again shortly.",
|
||||
"files_unavailable": "File editing isn't available right now.",
|
||||
"jobs_unavailable": "The background job service isn't available right now.",
|
||||
"already_terminal": "This build already finished — there is nothing to cancel.",
|
||||
"build_unavailable": "Image builds aren't available right now.",
|
||||
"build_logs_unavailable": "Build logs aren't available right now.",
|
||||
"already_reviewed": "This submission has already been reviewed.",
|
||||
"submissions_unavailable": "Submissions aren't available right now.",
|
||||
"uploads_unavailable": "Uploads aren't available right now.",
|
||||
"backup_unavailable": "Backups aren't available right now.",
|
||||
"account_retired": "This account has been retired — sign in with the account it was migrated to.",
|
||||
"no_migration": "There is no migration in progress.",
|
||||
"not_confirmed": "This migration hasn't been confirmed yet.",
|
||||
"already_confirmed": "This migration has already been confirmed.",
|
||||
"invalid_target": "The migration target must be a different account.",
|
||||
"target_not_found": "No account matches that migration target.",
|
||||
"target_unavailable": "That migration target isn't available.",
|
||||
"no_passkey": "This account has no Passkey bound yet.",
|
||||
"passkey_required": "Bind a Passkey before doing that.",
|
||||
"no_step_up_factor": "This account has no verified email or Passkey to confirm with yet.",
|
||||
"passkey_login_failed": "Passkey verification failed — try again.",
|
||||
"passkey_login_invalid": "That Passkey sign-in request is invalid or expired — start it again.",
|
||||
"too_many_challenges": "Too many verification attempts right now — try again shortly.",
|
||||
"op_login_invalid": "This operator sign-in couldn't be completed — restart the sign-in.",
|
||||
"op_login_not_found": "No pending operator sign-in with that id.",
|
||||
"too_many_streams": "Too many live streams are open — close some pages and try again.",
|
||||
"protected_admin": "That name belongs to a linked administrator and can't be reclaimed.",
|
||||
"auth_unavailable": "The sign-in service isn't available right now.",
|
||||
"setup_token_invalid": "That setup token is invalid or expired."
|
||||
}
|
||||
@@ -26,5 +26,42 @@
|
||||
"passkey_already_bound": "此 Passkey 已被其他账户绑定。",
|
||||
"passkey_unavailable": "Passkey 功能当前不可用。",
|
||||
"passkey_not_allowed": "操作已被用户或浏览器取消。",
|
||||
"passkey_aborted": "Passkey 注册已被取消。"
|
||||
"passkey_aborted": "Passkey 注册已被取消。",
|
||||
"bad_name": "服务器名称不合法:需为 3–32 位小写字母、数字或连字符,且不能使用保留名。",
|
||||
"bad_subdomain": "子域名不合法:需为 3–32 位小写字母、数字或连字符,且不能使用保留名。",
|
||||
"at_capacity": "集群的在线服务器已达上限——等一台服务器停止后再试。",
|
||||
"storage_immutable": "存储容量不支持在线调整。",
|
||||
"email_taken": "该邮箱已在其他账户上完成验证;请直接用该邮箱登录,或换一个地址。",
|
||||
"mail_undeliverable": "验证码邮件发送失败——请稍后重试,或联系管理员检查邮件服务。",
|
||||
"bad_path": "路径不合法——请使用世界目录内的相对路径。",
|
||||
"too_large": "内容超出大小限制,无法处理。",
|
||||
"files_timeout": "文件操作超时——请稍后重试。",
|
||||
"files_unavailable": "文件功能当前不可用。",
|
||||
"jobs_unavailable": "后台任务服务当前不可用。",
|
||||
"already_terminal": "该构建已经结束,无法重复取消。",
|
||||
"build_unavailable": "构建功能当前不可用。",
|
||||
"build_logs_unavailable": "构建日志暂时不可用。",
|
||||
"already_reviewed": "该提交已经审核过了。",
|
||||
"submissions_unavailable": "提交流程当前不可用。",
|
||||
"uploads_unavailable": "上传功能当前不可用。",
|
||||
"backup_unavailable": "备份功能当前不可用。",
|
||||
"account_retired": "该账户已退役——请使用迁移后的账户登录。",
|
||||
"no_migration": "当前没有进行中的迁移。",
|
||||
"not_confirmed": "该迁移尚未完成确认。",
|
||||
"already_confirmed": "该迁移已经确认过了。",
|
||||
"invalid_target": "迁移目标账户不能与来源账户相同。",
|
||||
"target_not_found": "找不到迁移目标账户。",
|
||||
"target_unavailable": "迁移目标账户当前不可用。",
|
||||
"no_passkey": "该账户尚未绑定 Passkey。",
|
||||
"passkey_required": "此操作需要先绑定 Passkey。",
|
||||
"no_step_up_factor": "该账户还没有已验证的邮箱或 Passkey,无法完成此操作。",
|
||||
"passkey_login_failed": "Passkey 验证失败——请重试。",
|
||||
"passkey_login_invalid": "Passkey 登录请求无效或已过期——请重新发起。",
|
||||
"too_many_challenges": "验证请求过于频繁——请稍后再试。",
|
||||
"op_login_invalid": "本次管理员登录未能完成——请重新发起登录。",
|
||||
"op_login_not_found": "找不到该管理员登录请求。",
|
||||
"too_many_streams": "同时打开的实时连接过多——请关闭一些页面后再试。",
|
||||
"protected_admin": "该名字属于已绑定的管理员账户,不能被认领。",
|
||||
"auth_unavailable": "登录服务当前不可用。",
|
||||
"setup_token_invalid": "初始化令牌无效或已过期。"
|
||||
}
|
||||
@@ -683,6 +683,92 @@ export function humanizeError(e: unknown): string {
|
||||
return t("no_world_volume");
|
||||
case "restore_unavailable":
|
||||
return t("restore_unavailable");
|
||||
// Server create/edit (spec §22): the portability regex + reservation list are
|
||||
// enforced server-side, and the create form's own checks are weaker, so these
|
||||
// refusals reach the dialog as-is.
|
||||
case "bad_name":
|
||||
return t("bad_name");
|
||||
case "bad_subdomain":
|
||||
return t("bad_subdomain");
|
||||
case "at_capacity":
|
||||
return t("at_capacity");
|
||||
case "storage_immutable":
|
||||
return t("storage_immutable");
|
||||
// Email identity: the verified-email uniqueness index (migration 0020) plus
|
||||
// VerifyEmailOTP's guard make a second verified holder impossible; the OTP
|
||||
// relay can also refuse to deliver at all.
|
||||
case "email_taken":
|
||||
return t("email_taken");
|
||||
case "mail_undeliverable":
|
||||
return t("mail_undeliverable");
|
||||
// File editor (spec §7): path/size refusals from the sandboxed job, plus the
|
||||
// subsystem being unwired.
|
||||
case "bad_path":
|
||||
return t("bad_path");
|
||||
case "too_large":
|
||||
return t("too_large");
|
||||
case "files_timeout":
|
||||
return t("files_timeout");
|
||||
case "files_unavailable":
|
||||
return t("files_unavailable");
|
||||
case "jobs_unavailable":
|
||||
return t("jobs_unavailable");
|
||||
// Builds, uploads and review: terminal-state conflicts and unwired subsystems.
|
||||
case "already_terminal":
|
||||
return t("already_terminal");
|
||||
case "build_unavailable":
|
||||
return t("build_unavailable");
|
||||
case "build_logs_unavailable":
|
||||
return t("build_logs_unavailable");
|
||||
case "already_reviewed":
|
||||
return t("already_reviewed");
|
||||
case "submissions_unavailable":
|
||||
return t("submissions_unavailable");
|
||||
case "uploads_unavailable":
|
||||
return t("uploads_unavailable");
|
||||
case "backup_unavailable":
|
||||
return t("backup_unavailable");
|
||||
// Account migration + the re-auth steps it depends on: every refusal below is
|
||||
// an expected outcome of the Account → migrate flow, not a fault.
|
||||
case "account_retired":
|
||||
return t("account_retired");
|
||||
case "no_migration":
|
||||
return t("no_migration");
|
||||
case "not_confirmed":
|
||||
return t("not_confirmed");
|
||||
case "already_confirmed":
|
||||
return t("already_confirmed");
|
||||
case "invalid_target":
|
||||
return t("invalid_target");
|
||||
case "target_not_found":
|
||||
return t("target_not_found");
|
||||
case "target_unavailable":
|
||||
return t("target_unavailable");
|
||||
case "no_passkey":
|
||||
return t("no_passkey");
|
||||
case "passkey_required":
|
||||
return t("passkey_required");
|
||||
case "no_step_up_factor":
|
||||
return t("no_step_up_factor");
|
||||
case "passkey_login_failed":
|
||||
return t("passkey_login_failed");
|
||||
case "passkey_login_invalid":
|
||||
return t("passkey_login_invalid");
|
||||
case "too_many_challenges":
|
||||
return t("too_many_challenges");
|
||||
// Operator-login approvals, live streams, and the remaining auth doors.
|
||||
case "op_login_invalid":
|
||||
return t("op_login_invalid");
|
||||
case "op_login_not_found":
|
||||
return t("op_login_not_found");
|
||||
case "too_many_streams":
|
||||
return t("too_many_streams");
|
||||
case "protected_admin":
|
||||
return t("protected_admin");
|
||||
case "auth_unavailable":
|
||||
return t("auth_unavailable");
|
||||
case "setup_token_invalid":
|
||||
return t("setup_token_invalid");
|
||||
default:
|
||||
if (err.status === 401) return t("session_expired");
|
||||
if (err.status === 403) return t("forbidden");
|
||||
|
||||
Reference in new issue
Block a user