mirror of
https://github.com/xweiba/location-spoofer.git
synced 2026-09-25 16:11:54 +08:00
fix(i18n): 完善国际化并迁移 WLOC 脚本
This commit is contained in:
+32
-18
@@ -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
@@ -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
@@ -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))")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -182,5 +182,5 @@ struct ProxyCoordinateSnapshot: Equatable {
|
||||
|
||||
enum ProxyError: LocalizedError {
|
||||
case startFailed
|
||||
var errorDescription: String? { "Go proxy 启动失败" }
|
||||
var errorDescription: String? { String(localized: "Go proxy 启动失败") }
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user