fix(i18n): 完善国际化并迁移 WLOC 脚本

This commit is contained in:
xweiba
2026-09-11 02:39:00 +08:00
parent 908ac8f734
commit 05949703af
42 changed files with 2006 additions and 160 deletions
+32 -18
View File
@@ -95,9 +95,10 @@ struct BugReportView: View {
do {
let response = try await thirdPartyProxy.query()
let active = response.success && response.latitude != nil && response.longitude != nil
testLog = "第三方代理测试模式:模块连接成功;已保存坐标=\(active ? "是" : "否")"
let savedCoordinate = active ? String(localized: "是") : String(localized: "否")
testLog = String(localized: "第三方代理测试模式:模块连接成功;已保存坐标=\(savedCoordinate)")
} catch {
testLog = "第三方代理测试模式:模块连接失败;\(error.localizedDescription)"
testLog = String(localized: "第三方代理测试模式:模块连接失败;\(error.localizedDescription)")
}
} else {
_ = await setup.runVerificationTest()
@@ -113,22 +114,11 @@ struct BugReportView: View {
let systemVersion = UIDevice.current.systemVersion
// 拼接报告
let report = """
### 环境信息
App 版本: \(appVersion)
系统版本: iOS \(systemVersion)
运行模式: \(runtimeMode.mode.displayName)
第三方客户端: \(runtimeMode.mode == .thirdParty ? thirdPartyClient.selectedClient.name : "不适用")
可复现环境: \(isReproducible ? "是" : "否")
### 问题描述
\(description.trimmingCharacters(in: .whitespacesAndNewlines))
### 诊断日志
```
\(testLog.isEmpty ? "(无诊断数据)" : testLog)
```
"""
let report = bugReport(
appVersion: appVersion,
systemVersion: systemVersion,
testLog: testLog
)
// 复制到剪切板
UIPasteboard.general.string = report
@@ -138,4 +128,28 @@ struct BugReportView: View {
showCopiedAlert = true
}
}
private func bugReport(appVersion: String, systemVersion: String, testLog: String) -> String {
let client = runtimeMode.mode == .thirdParty
? thirdPartyClient.selectedClient.name
: String(localized: "不适用")
let reproducible = isReproducible ? String(localized: "是") : String(localized: "否")
let diagnostics = testLog.isEmpty ? String(localized: "(无诊断数据)") : testLog
return """
### \(String(localized: "环境信息"))
\(String(localized: "App 版本")): \(appVersion)
\(String(localized: "系统版本")): iOS \(systemVersion)
\(String(localized: "运行模式")): \(runtimeMode.mode.displayName)
\(String(localized: "第三方客户端")): \(client)
\(String(localized: "可复现环境")): \(reproducible)
### \(String(localized: "问题描述"))
\(description.trimmingCharacters(in: .whitespacesAndNewlines))
### \(String(localized: "诊断日志"))
```
\(diagnostics)
```
"""
}
}
+24 -17
View File
@@ -23,7 +23,10 @@ struct RuntimeLogsView: View {
private var filteredEntries: [RuntimeLogEntry] {
let q = logFilter.trimmingCharacters(in: .whitespacesAndNewlines)
guard !q.isEmpty else { return entries }
return entries.filter { $0.message.localizedCaseInsensitiveContains(q) }
return entries.filter {
$0.localizedMessage.localizedCaseInsensitiveContains(q)
|| $0.localizedCategory.localizedCaseInsensitiveContains(q)
}
}
var body: some View {
@@ -201,7 +204,7 @@ struct RuntimeLogsView: View {
.foregroundStyle(entry.level == .error ? .red : entry.level == .warning ? .orange : .blue).frame(width: 18)
VStack(alignment: .leading, spacing: 4) {
HStack {
Text("\(entry.source) \(entry.category)").font(.caption.weight(.semibold))
Text("\(entry.source) \(entry.localizedCategory)").font(.caption.weight(.semibold))
Spacer()
Button {
UIPasteboard.general.string = entry.renderedText
@@ -225,9 +228,9 @@ struct RuntimeLogsView: View {
}
.buttonStyle(.plain)
}
Text(entry.message).font(.caption.monospaced()).textSelection(.enabled)
Text(entry.localizedMessage).font(.caption.monospaced()).textSelection(.enabled)
if !entry.details.isEmpty {
Text(entry.details.sorted(by: { $0.key < $1.key }).map { "\($0.key): \($0.value)" }.joined(separator: "\n"))
Text(entry.localizedDetailsText)
.font(.caption2.monospaced()).foregroundStyle(.secondary).textSelection(.enabled)
}
}
@@ -246,22 +249,26 @@ struct RuntimeLogsView: View {
let active = response.success && response.latitude != nil && response.longitude != nil
testSucceeded = true
testResult = active ? String(localized: "第三方模块连接通过,已有坐标") : String(localized: "第三方模块连接通过,暂无坐标")
testMessage = """
======== 第三方代理连接检测 ========
模式: 测试模式
请求: wloc-settings/save?action=query
拦截响应: 有效 JSON
已保存坐标: \(active ? "是" : "否")
"""
testMessage = thirdPartyTestLog(active: active)
} catch {
testSucceeded = false
testResult = String(localized: "第三方模块连接失败")
testMessage = """
======== 第三方代理连接检测 ========
模式: 测试模式
请求: wloc-settings/save?action=query
结果: \(error.localizedDescription)
"""
testMessage = thirdPartyTestLog(error: error)
}
}
private func thirdPartyTestLog(active: Bool? = nil, error: Error? = nil) -> String {
var lines = [
String(localized: "======== 第三方代理连接检测 ========"),
String(localized: "模式: 测试模式"),
String(localized: "请求: wloc-settings/save?action=query")
]
if let active {
lines.append(String(localized: "拦截响应: 有效 JSON"))
lines.append(String(localized: "已保存坐标: \(active ? String(localized: "是") : String(localized: "否"))"))
} else if let error {
lines.append(String(localized: "结果: \(error.localizedDescription)"))
}
return lines.joined(separator: "\n")
}
}
+34 -32
View File
@@ -220,15 +220,15 @@ struct FirstSetupView: View {
return thirdPartyTestFailure.message
}
guard !setup.message.isEmpty else { return nil }
return """
======== 第三方代理运行检测 ========
当前客户端:\(thirdPartyClient.selectedClient.name)
触发来源:地图或设置中的第三方代理操作
请求动作:WLOC 配置接口
检测结果:失败
错误详情:\(setup.message)
处理建议:确认模块已启用,并检查 MITM、证书和代理/VPN 连接。
"""
return [
String(localized: "======== 第三方代理运行检测 ========"),
String(localized: "当前客户端:\(thirdPartyClient.selectedClient.name)"),
String(localized: "触发来源:地图或设置中的第三方代理操作"),
String(localized: "请求动作:WLOC 配置接口"),
String(localized: "检测结果:失败"),
String(localized: "错误详情:\(setup.message)"),
String(localized: "处理建议:确认模块已启用,并检查 MITM、证书和代理/VPN 连接。")
].joined(separator: "\n")
}
private var modeStep: some View {
@@ -468,10 +468,10 @@ struct FirstSetupView: View {
Text("返回格式")
.font(.subheadline.bold())
Text("""
Text(String(localized: """
成功:{"success":true,"longitude":113.0,"latitude":22.0,"accuracy":25}
失败:{"success":false,"error":"错误说明"}
""")
"""))
.font(.caption.monospaced())
.textSelection(.enabled)
@@ -641,7 +641,7 @@ struct FirstSetupView: View {
private func setupScreenshot(
assetName: String,
title: String,
caption: LocalizedStringKey
caption: String
) -> some View {
if let image = UIImage(named: assetName) {
Button {
@@ -657,7 +657,7 @@ struct FirstSetupView: View {
.clipShape(RoundedRectangle(cornerRadius: 6))
HStack(spacing: 6) {
Image(systemName: "arrow.up.left.and.arrow.down.right")
Text(caption)
Text(LocalizedStringKey(caption))
}
.font(.caption2)
.foregroundStyle(.secondary)
@@ -672,7 +672,11 @@ struct FirstSetupView: View {
)
}
.buttonStyle(.plain)
.accessibilityLabel(LocalizedStringKey(title))
.accessibilityLabel(
Text(LocalizedStringKey(title))
+ Text(": ")
+ Text(LocalizedStringKey(caption))
)
.accessibilityHint("轻点查看大图")
}
}
@@ -872,21 +876,19 @@ struct FirstSetupView: View {
"处理建议": ThirdPartyProxyError.recoverySuggestion(for: error)
]
)
thirdPartyTestFailure = ThirdPartyConnectionTestFailure(
message: """
======== 第三方代理连接检测 ========
当前客户端:\(client.name)
配置接口:/wloc-settings/save
请求动作:WLOC query
检查范围:模块拦截、MITM、证书、代理/VPN 连接
连接状态:\(connectionState)
检测结果:失败
耗时:\(elapsedMilliseconds) ms
错误类型:\(errorType)
错误详情:\(error.localizedDescription)
处理建议:\(ThirdPartyProxyError.recoverySuggestion(for: error))。
"""
)
thirdPartyTestFailure = ThirdPartyConnectionTestFailure(message: [
String(localized: "======== 第三方代理连接检测 ========"),
String(localized: "当前客户端:\(client.name)"),
String(localized: "配置接口:/wloc-settings/save"),
String(localized: "请求动作:WLOC query"),
String(localized: "检查范围:模块拦截、MITM、证书、代理/VPN 连接"),
String(localized: "连接状态:\(connectionState)"),
String(localized: "检测结果:失败"),
String(localized: "耗时:\(elapsedMilliseconds) ms"),
String(localized: "错误类型:\(errorType)"),
String(localized: "错误详情:\(error.localizedDescription)"),
String(localized: "处理建议:\(ThirdPartyProxyError.recoverySuggestion(for: error))。")
].joined(separator: "\n"))
showsThirdPartyFailureLog = true
}
}
@@ -895,11 +897,11 @@ struct FirstSetupView: View {
private var thirdPartyConnectionStateDescription: String {
switch thirdPartyProxy.connectionState {
case .unknown:
return "未检测"
return String(localized: "未检测")
case .connected(let active):
return active ? "已连接,有保存坐标" : "已连接,无保存坐标"
return active ? String(localized: "已连接,有保存坐标") : String(localized: "已连接,无保存坐标")
case .failed(let message):
return "连接失败(\(message))"
return String(localized: "连接失败(\(message))")
}
}
+5 -2
View File
@@ -766,7 +766,8 @@ struct MapHomeView: View {
private func presentSuccessfulOperationTip(_ kind: VirtualLocationTipKind) {
let count = tipPreferences.recordSuccessfulOperation(kind)
let operationName = kind == .activation ? "开启" : "关闭"
RuntimeLogger.info("APP", "提醒", "累计\(operationName)虚拟定位次数", details: [
RuntimeLogger.info("APP", "提醒", "累计虚拟定位操作次数", details: [
"操作": operationName,
"次数": String(count),
"运行模式": runtimeMode.mode.displayName,
"可显示不再提醒": String(tipPreferences.canSuppress(kind))
@@ -1335,7 +1336,9 @@ struct MapHomeView: View {
context.showFailureAlert,
!Task.isCancelled,
mapState.selection.revision == context.intent.selectionRevision else { return }
RuntimeLogger.info("APP", "地图", "定位失败 status=\(realtime.authorizationStatus.rawValue)")
RuntimeLogger.info("APP", "地图", "定位失败", details: [
"授权状态rawValue": String(realtime.authorizationStatus.rawValue)
])
showLocationAlert = true
return
}
+1 -1
View File
@@ -182,5 +182,5 @@ struct ProxyCoordinateSnapshot: Equatable {
enum ProxyError: LocalizedError {
case startFailed
var errorDescription: String? { "Go proxy 启动失败" }
var errorDescription: String? { String(localized: "Go proxy 启动失败") }
}
+2 -2
View File
@@ -222,11 +222,11 @@ struct SettingsView: View {
Section("致谢") {
Button {
if let url = URL(string: "https://github.com/Yu9191/wloc") {
if let url = URL(string: "https://github.com/xweiba/location-spoofer/blob/main/docs/THIRD_PARTY_MODULES.md") {
UIApplication.shared.open(url)
}
} label: {
Label("核心定位改写逻辑移植自 Yu9191/wloc", systemImage: "heart.fill")
Label("定位改写脚本源自 Yu9191/wloc,现由本项目维护", systemImage: "heart.fill")
.foregroundStyle(.pink)
}
}
+20 -20
View File
@@ -108,36 +108,36 @@ final class SetupCoordinator: ObservableObject {
testLog = ""
let log = { (msg: String) in self.testLog += msg + "\n" }
log("======== 代理验证测试 ========")
log("App 版本: \(appVersion)")
log("系统版本: iOS \(UIDevice.current.systemVersion)")
log(String(localized: "======== 代理验证测试 ========"))
log(String(localized: "App 版本: \(appVersion)"))
log(String(localized: "系统版本: iOS \(UIDevice.current.systemVersion)"))
log("")
// Step A: Proxy running
log("[步骤 A] 检查代理是否运行…")
log(" 端口: 127.0.0.1:8888")
log(String(localized: "[步骤 A] 检查代理是否运行…"))
log(String(localized: " 端口: 127.0.0.1:8888"))
let stepAStart = Date()
if !proxy.isRunning {
log(" ⚠ 代理未运行,尝试启动…")
log(String(localized: " ⚠ 代理未运行,尝试启动…"))
do { try await proxy.start() } catch {
log(" ✗ 启动失败: \(error.localizedDescription)")
log(String(localized: " ✗ 启动失败: \(error.localizedDescription)"))
return .proxyNotRunning
}
log(" ✓ 代理启动成功")
log(String(localized: " ✓ 代理启动成功"))
} else {
log(" ✓ 代理已在运行中")
log(String(localized: " ✓ 代理已在运行中"))
}
collectProxyLogs(since: stepAStart, to: log)
// Step B: Combined CA + WiFi proxy check (single request)
log("")
log("[步骤 B] 检测证书与 WiFi 代理…")
log(" 方式: 请求 baidu.com/paopao-verify-<token>")
log(" 结果判定: TLS 错误=证书问题 / 响应不匹配=代理未配置 / 匹配=通过")
log(String(localized: "[步骤 B] 检测证书与 WiFi 代理…"))
log(String(localized: " 方式: 请求 baidu.com/paopao-verify-<token>"))
log(String(localized: " 结果判定: TLS 错误=证书问题 / 响应不匹配=代理未配置 / 匹配=通过"))
let stepBStart = Date()
let verifyToken = CoreBridge.refreshVerifyToken()
guard !verifyToken.isEmpty else {
log(" ✗ 无法生成验证 token")
log(String(localized: " ✗ 无法生成验证 token"))
return .certNotTrusted
}
do {
@@ -150,17 +150,17 @@ final class SetupCoordinator: ObservableObject {
let statusCode = (resp as? HTTPURLResponse)?.statusCode ?? 0
let body = String(data: data, encoding: .utf8) ?? ""
if body == verifyToken {
log(" ✓ 证书已信任,WiFi 代理已配置")
log(String(localized: " ✓ 证书已信任,WiFi 代理已配置"))
} else {
log(" ✗ 响应不匹配: HTTP \(statusCode), \(data.count) bytes,WiFi 代理未配置")
log(String(localized: " ✗ 响应不匹配: HTTP \(statusCode), \(data.count) bytes,WiFi 代理未配置"))
return .wifiProxyNotConfigured
}
} catch {
let ns = error as NSError
let msg = error.localizedDescription
log(" ✗ 请求失败 [\(ns.domain) code=\(ns.code)]: \(msg)")
log(String(localized: " ✗ 请求失败 [\(ns.domain) code=\(ns.code)]: \(msg)"))
if isCertificateTrustError(nsError: ns, message: msg) {
log(" TLS/证书校验失败,CA 证书未信任")
log(String(localized: " TLS/证书校验失败,CA 证书未信任"))
return .certNotTrusted
}
return .wifiProxyNotConfigured
@@ -168,7 +168,7 @@ final class SetupCoordinator: ObservableObject {
collectProxyLogs(since: stepBStart, to: log)
log("")
log("======== 环境检测通过 ✓ ========")
log(String(localized: "======== 环境检测通过 ✓ ========"))
return .success
}
@@ -202,9 +202,9 @@ final class SetupCoordinator: ObservableObject {
$0.source == "CORE" && $0.category == "Proxy" && $0.timestamp >= date
}
guard !proxyEntries.isEmpty else { return }
log(" --- 代理日志 ---")
log(String(localized: " --- 代理日志 ---"))
for e in proxyEntries {
log(" " + e.message)
log(" " + e.localizedMessage)
}
}
}