欢迎页面支持多语言

This commit is contained in:
xintaofei
2026-03-07 12:17:57 +08:00
parent aeecc4769c
commit 6c48be023c
15 changed files with 685 additions and 72 deletions

View File

@@ -0,0 +1,146 @@
import { extractAppCommandError, toErrorMessage } from "@/lib/app-error"
export type WelcomeErrorKey =
| "errors.unknown"
| "errors.invalidInput"
| "errors.notFound"
| "errors.alreadyExists"
| "errors.dependencyMissing"
| "errors.databaseError"
| "errors.ioError"
| "errors.externalCommandFailed"
| "errors.windowOperationFailed"
| "errors.gitNotInstalled"
| "errors.targetDirectoryNotEmpty"
| "errors.repositoryNotFound"
| "errors.networkUnavailable"
| "errors.authenticationFailed"
| "errors.permissionDenied"
export interface WelcomeErrorResult {
key: WelcomeErrorKey
detail?: string
}
export function normalizeErrorMessage(error: unknown): string {
return toErrorMessage(error)
}
function stripClonePrefix(message: string): string {
return message.replace(/^clone failed:\s*/i, "").trim()
}
function mapCommonCodeToKey(code: string): WelcomeErrorKey {
switch (code) {
case "invalid_input":
return "errors.invalidInput"
case "not_found":
return "errors.notFound"
case "already_exists":
return "errors.alreadyExists"
case "permission_denied":
return "errors.permissionDenied"
case "dependency_missing":
return "errors.dependencyMissing"
case "network_error":
return "errors.networkUnavailable"
case "authentication_failed":
return "errors.authenticationFailed"
case "database_error":
return "errors.databaseError"
case "io_error":
return "errors.ioError"
case "external_command_failed":
return "errors.externalCommandFailed"
case "window_operation_failed":
return "errors.windowOperationFailed"
default:
return "errors.unknown"
}
}
export function resolveWelcomeError(error: unknown): WelcomeErrorResult {
const appError = extractAppCommandError(error)
if (appError) {
const key = mapCommonCodeToKey(appError.code)
const detail =
key === "errors.unknown" ? appError.detail || appError.message : undefined
return detail ? { key, detail } : { key }
}
return {
key: "errors.unknown",
detail: normalizeErrorMessage(error),
}
}
export function resolveCloneError(error: unknown): WelcomeErrorResult {
const appError = extractAppCommandError(error)
if (appError) {
switch (appError.code) {
case "dependency_missing":
return { key: "errors.gitNotInstalled" }
case "already_exists":
return { key: "errors.targetDirectoryNotEmpty" }
case "not_found":
return { key: "errors.repositoryNotFound" }
case "network_error":
return { key: "errors.networkUnavailable" }
case "authentication_failed":
return { key: "errors.authenticationFailed" }
case "permission_denied":
return { key: "errors.permissionDenied" }
default: {
const key = mapCommonCodeToKey(appError.code)
const detail =
key === "errors.unknown"
? appError.detail || appError.message
: undefined
return detail ? { key, detail } : { key }
}
}
}
const rawMessage = normalizeErrorMessage(error)
const message = stripClonePrefix(rawMessage)
const normalized = message.toLowerCase()
if (normalized.includes("git is not installed")) {
return { key: "errors.gitNotInstalled" }
}
if (normalized.includes("already exists and is not an empty directory")) {
return { key: "errors.targetDirectoryNotEmpty" }
}
if (normalized.includes("repository not found")) {
return { key: "errors.repositoryNotFound" }
}
if (
normalized.includes("could not resolve host") ||
normalized.includes("network is unreachable") ||
normalized.includes("connection timed out") ||
normalized.includes("failed to connect")
) {
return { key: "errors.networkUnavailable" }
}
if (
normalized.includes("authentication failed") ||
normalized.includes("could not read username") ||
normalized.includes("permission denied (publickey)")
) {
return { key: "errors.authenticationFailed" }
}
if (normalized.includes("permission denied")) {
return { key: "errors.permissionDenied" }
}
return {
key: "errors.unknown",
detail: message || rawMessage || undefined,
}
}