Add English localization (device-language based)

Add English as an overlay localization following the device language,
keeping Simplified Chinese as the base/development language. Untranslated
strings fall back to Chinese automatically.

- project.yml: set developmentLanguage zh-Hans and knownRegions (zh-Hans/en/Base)
- Resources/en.lproj/{Localizable,InfoPlist}.strings: ~230 English strings
- Resources/zh-Hans.lproj/InfoPlist.strings: Chinese permission prompts
- Restructure ternary Text/Label and String-typed UI messages so they
  localize (String(localized:), LocalizedStringKey helper params); replace
  a .contains("通过") success check with a dedicated flag
- Localize user-facing model/coordinator/error messages across App and Shared

Internal RuntimeLogger logs and diagnostic/report bodies remain in Chinese.
This commit is contained in:
Syntax-Error-1337
2026-09-10 01:05:45 +08:00
parent eadeca636d
commit 908ac8f734
17 changed files with 493 additions and 121 deletions
+2 -2
View File
@@ -8,8 +8,8 @@ enum ProxyRuntimeMode: String, CaseIterable, Codable, Identifiable {
var displayName: String {
switch self {
case .localWiFi: return "APP模式"
case .thirdParty: return "第三方代理模式"
case .localWiFi: return String(localized: "APP模式")
case .thirdParty: return String(localized: "第三方代理模式")
}
}
}
+11 -11
View File
@@ -25,25 +25,25 @@ enum ThirdPartyProxyError: LocalizedError, Equatable {
var errorDescription: String? {
switch self {
case .invalidResponse:
return "第三方代理返回了无法识别的数据"
return String(localized: "第三方代理返回了无法识别的数据")
case .moduleNotIntercepted:
return "请求未被第三方代理模块拦截,请检查模块、MITM 和代理连接"
return String(localized: "请求未被第三方代理模块拦截,请检查模块、MITM 和代理连接")
case .rejected(let message):
return message
case .coordinateMismatch:
return "第三方代理保存的坐标与当前选点不一致"
return String(localized: "第三方代理保存的坐标与当前选点不一致")
case .network(let message):
return "第三方代理请求失败:\(message)"
return String(localized: "第三方代理请求失败:\(message)")
}
}
var recoverySuggestion: String {
return "检查模块、MITM、证书和代理/VPN连接"
return String(localized: "检查模块、MITM、证书和代理/VPN连接")
}
static func recoverySuggestion(for error: Error) -> String {
(error as? Self)?.recoverySuggestion
?? "检查模块、MITM、证书和代理/VPN连接"
?? String(localized: "检查模块、MITM、证书和代理/VPN连接")
}
}
@@ -106,7 +106,7 @@ final class ThirdPartyProxyManager: ObservableObject {
randomRadius: RandomRadiusStore.shared.isEnabled ? RandomRadiusStore.shared.radius : 0
))
guard response.success else {
throw ThirdPartyProxyError.rejected(response.error ?? "第三方代理拒绝保存坐标")
throw ThirdPartyProxyError.rejected(response.error ?? String(localized: "第三方代理拒绝保存坐标"))
}
guard let latitude = response.latitude,
let longitude = response.longitude,
@@ -127,7 +127,7 @@ final class ThirdPartyProxyManager: ObservableObject {
func clear() async throws {
let response = try await perform(action: .clear)
guard response.success else {
throw ThirdPartyProxyError.rejected(response.error ?? "第三方代理清除坐标失败")
throw ThirdPartyProxyError.rejected(response.error ?? String(localized: "第三方代理清除坐标失败"))
}
activeSettings = nil
connectionState = .connected(active: false)
@@ -143,7 +143,7 @@ final class ThirdPartyProxyManager: ObservableObject {
if response.error?.contains("无已保存") == true {
return false
}
throw ThirdPartyProxyError.rejected(response.error ?? "第三方代理查询失败")
throw ThirdPartyProxyError.rejected(response.error ?? String(localized: "第三方代理查询失败"))
}
private enum Action {
@@ -154,7 +154,7 @@ final class ThirdPartyProxyManager: ObservableObject {
private func perform(action: Action) async throws -> ThirdPartyProxySettingsResponse {
guard !isRequesting else {
throw ThirdPartyProxyError.rejected("已有第三方代理请求正在执行")
throw ThirdPartyProxyError.rejected(String(localized: "已有第三方代理请求正在执行"))
}
isRequesting = true
defer { isRequesting = false }
@@ -224,7 +224,7 @@ enum ThirdPartyProxyClient: String, CaseIterable, Identifiable {
}
var verificationText: String? {
self == .shadowrocket ? nil : "配置已提供,尚未验证"
self == .shadowrocket ? nil : String(localized: "配置已提供,尚未验证")
}
var moduleFileName: String {
+14
View File
@@ -26,4 +26,18 @@ enum VerificationResult: Equatable, Identifiable {
var isSuccess: Bool { self == .success }
/// Localized, user-facing title. `id` stays stable for routing/equality.
var localizedTitle: String {
switch self {
case .success: return String(localized: "成功")
case .proxyNotRunning: return String(localized: "代理未运行")
case .verificationInProgress: return String(localized: "已有验证正在进行")
case .verificationSuperseded: return String(localized: "验证已被新位置取代")
case .certNotTrusted: return String(localized: "证书未信任")
case .wifiProxyNotConfigured: return String(localized: "WiFi代理未配置")
case .coordinateWriteFailed: return String(localized: "坐标写入失败")
case .patchFailed: return String(localized: "改写验证失败")
}
}
}