diff --git a/App/BugReportView.swift b/App/BugReportView.swift index 89e1fee..9862196 100644 --- a/App/BugReportView.swift +++ b/App/BugReportView.swift @@ -95,10 +95,10 @@ struct BugReportView: View { do { let response = try await thirdPartyProxy.query() let active = response.success && response.latitude != nil && response.longitude != nil - let savedCoordinate = active ? String(localized: "是") : String(localized: "否") - testLog = String(localized: "第三方代理测试模式:模块连接成功;已保存坐标=\(savedCoordinate)") + let savedCoordinate = active ? AppLocalization.string("是") : AppLocalization.string("否") + testLog = AppLocalization.string("第三方代理测试模式:模块连接成功;已保存坐标=\(savedCoordinate)") } catch { - testLog = String(localized: "第三方代理测试模式:模块连接失败;\(error.localizedDescription)") + testLog = AppLocalization.string("第三方代理测试模式:模块连接失败;\(error.localizedDescription)") } } else { _ = await setup.runVerificationTest() @@ -132,21 +132,21 @@ struct BugReportView: View { 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 + : AppLocalization.string("不适用") + let reproducible = isReproducible ? AppLocalization.string("是") : AppLocalization.string("否") + let diagnostics = testLog.isEmpty ? AppLocalization.string("(无诊断数据)") : testLog return """ - ### \(String(localized: "环境信息")) - \(String(localized: "App 版本")): \(appVersion) - \(String(localized: "系统版本")): iOS \(systemVersion) - \(String(localized: "运行模式")): \(runtimeMode.mode.displayName) - \(String(localized: "第三方客户端")): \(client) - \(String(localized: "可复现环境")): \(reproducible) + ### \(AppLocalization.string("环境信息")) + \(AppLocalization.string("App 版本")): \(appVersion) + \(AppLocalization.string("系统版本")): iOS \(systemVersion) + \(AppLocalization.string("运行模式")): \(runtimeMode.mode.displayName) + \(AppLocalization.string("第三方客户端")): \(client) + \(AppLocalization.string("可复现环境")): \(reproducible) - ### \(String(localized: "问题描述")) + ### \(AppLocalization.string("问题描述")) \(description.trimmingCharacters(in: .whitespacesAndNewlines)) - ### \(String(localized: "诊断日志")) + ### \(AppLocalization.string("诊断日志")) ``` \(diagnostics) ``` diff --git a/App/ContentView.swift b/App/ContentView.swift index 38dd42f..8c3f9af 100644 --- a/App/ContentView.swift +++ b/App/ContentView.swift @@ -177,7 +177,7 @@ struct ContentView: View { switch prompt.requirement { case .required: let details = prompt.releaseNotes - ?? String(localized: "更新说明暂时无法加载,请前往最新 Release 页面查看。") + ?? AppLocalization.string("更新说明暂时无法加载,请前往最新 Release 页面查看。") return Alert( title: Text("需要更新"), message: Text( @@ -189,7 +189,7 @@ struct ContentView: View { ) case .recommended: let details = prompt.releaseNotes - ?? String(localized: "更新说明暂时无法加载,请前往最新 Release 页面查看。") + ?? AppLocalization.string("更新说明暂时无法加载,请前往最新 Release 页面查看。") return Alert( title: Text("发现新版本"), message: Text( diff --git a/App/DiagnosticsView.swift b/App/DiagnosticsView.swift index 696bd06..86d7b88 100644 --- a/App/DiagnosticsView.swift +++ b/App/DiagnosticsView.swift @@ -109,9 +109,9 @@ struct RuntimeLogsView: View { let result = await setup.runVerificationTest() testSucceeded = result.isSuccess testResult = result.isSuccess - ? String(localized: "环境检测通过") - : String(localized: "环境检测失败: \(result.localizedTitle)") - if !result.isSuccess { testResult += String(localized: ",查看下方日志") } + ? AppLocalization.string("环境检测通过") + : AppLocalization.string("环境检测失败: \(result.localizedTitle)") + if !result.isSuccess { testResult += AppLocalization.string(",查看下方日志") } testMessage = setup.testLog } isTesting = false; refresh() @@ -248,26 +248,26 @@ struct RuntimeLogsView: View { let response = try await thirdPartyProxy.query() let active = response.success && response.latitude != nil && response.longitude != nil testSucceeded = true - testResult = active ? String(localized: "第三方模块连接通过,已有坐标") : String(localized: "第三方模块连接通过,暂无坐标") + testResult = active ? AppLocalization.string("第三方模块连接通过,已有坐标") : AppLocalization.string("第三方模块连接通过,暂无坐标") testMessage = thirdPartyTestLog(active: active) } catch { testSucceeded = false - testResult = String(localized: "第三方模块连接失败") + testResult = AppLocalization.string("第三方模块连接失败") 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") + AppLocalization.string("======== 第三方代理连接检测 ========"), + AppLocalization.string("模式: 测试模式"), + AppLocalization.string("请求: wloc-settings/save?action=query") ] if let active { - lines.append(String(localized: "拦截响应: 有效 JSON")) - lines.append(String(localized: "已保存坐标: \(active ? String(localized: "是") : String(localized: "否"))")) + lines.append(AppLocalization.string("拦截响应: 有效 JSON")) + lines.append(AppLocalization.string("已保存坐标: \(active ? AppLocalization.string("是") : AppLocalization.string("否"))")) } else if let error { - lines.append(String(localized: "结果: \(error.localizedDescription)")) + lines.append(AppLocalization.string("结果: \(error.localizedDescription)")) } return lines.joined(separator: "\n") } diff --git a/App/FirstSetupView.swift b/App/FirstSetupView.swift index 9980d50..c5242ee 100644 --- a/App/FirstSetupView.swift +++ b/App/FirstSetupView.swift @@ -221,13 +221,13 @@ struct FirstSetupView: View { } guard !setup.message.isEmpty else { return nil } return [ - String(localized: "======== 第三方代理运行检测 ========"), - String(localized: "当前客户端:\(thirdPartyClient.selectedClient.name)"), - String(localized: "触发来源:地图或设置中的第三方代理操作"), - String(localized: "请求动作:WLOC 配置接口"), - String(localized: "检测结果:失败"), - String(localized: "错误详情:\(setup.message)"), - String(localized: "处理建议:确认模块已启用,并检查 MITM、证书和代理/VPN 连接。") + AppLocalization.string("======== 第三方代理运行检测 ========"), + AppLocalization.string("当前客户端:\(thirdPartyClient.selectedClient.name)"), + AppLocalization.string("触发来源:地图或设置中的第三方代理操作"), + AppLocalization.string("请求动作:WLOC 配置接口"), + AppLocalization.string("检测结果:失败"), + AppLocalization.string("错误详情:\(setup.message)"), + AppLocalization.string("处理建议:确认模块已启用,并检查 MITM、证书和代理/VPN 连接。") ].joined(separator: "\n") } @@ -354,7 +354,7 @@ struct FirstSetupView: View { if let url = await setup.proxy.prepareCertificateDownloadURL() { certificateDownloadDestination = CertificateDownloadDestination(url: url) } else { - setupActionError = setup.proxy.error ?? String(localized: "无法准备证书下载页面,请查看诊断日志") + setupActionError = setup.proxy.error ?? AppLocalization.string("无法准备证书下载页面,请查看诊断日志") } } }, @@ -468,7 +468,7 @@ struct FirstSetupView: View { Text("返回格式") .font(.subheadline.bold()) - Text(String(localized: """ + Text(AppLocalization.string(""" 成功:{"success":true,"longitude":113.0,"latitude":22.0,"accuracy":25} 失败:{"success":false,"error":"错误说明"} """)) @@ -565,7 +565,7 @@ struct FirstSetupView: View { if let thirdPartyFailureLog { testResultView( success: false, - title: String(localized: "接口连接失败"), + title: AppLocalization.string("接口连接失败"), log: thirdPartyFailureLog ) .id("thirdPartyFailureLog") @@ -698,7 +698,7 @@ struct FirstSetupView: View { UIApplication.shared.open(url, options: [:]) { opened in guard !opened else { return } Task { @MainActor in - manualHint = String(localized: "无法打开 \(client.name),请确认客户端已安装后手动打开。") + manualHint = AppLocalization.string("无法打开 \(client.name),请确认客户端已安装后手动打开。") } } } @@ -760,7 +760,7 @@ struct FirstSetupView: View { let success = result.isSuccess testResultView( success: success, - title: success ? String(localized: "环境检测通过") : failureSummary(result), + title: success ? AppLocalization.string("环境检测通过") : failureSummary(result), log: setup.testLog ) } @@ -889,17 +889,17 @@ struct FirstSetupView: View { ] ) 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))。") + AppLocalization.string("======== 第三方代理连接检测 ========"), + AppLocalization.string("当前客户端:\(client.name)"), + AppLocalization.string("配置接口:/wloc-settings/save"), + AppLocalization.string("请求动作:WLOC query"), + AppLocalization.string("检查范围:模块拦截、MITM、证书、代理/VPN 连接"), + AppLocalization.string("连接状态:\(connectionState)"), + AppLocalization.string("检测结果:失败"), + AppLocalization.string("耗时:\(elapsedMilliseconds) ms"), + AppLocalization.string("错误类型:\(errorType)"), + AppLocalization.string("错误详情:\(error.localizedDescription)"), + AppLocalization.string("处理建议:\(ThirdPartyProxyError.recoverySuggestion(for: error))。") ].joined(separator: "\n")) showsThirdPartyFailureLog = true } @@ -909,11 +909,11 @@ struct FirstSetupView: View { private var thirdPartyConnectionStateDescription: String { switch thirdPartyProxy.connectionState { case .unknown: - return String(localized: "未检测") + return AppLocalization.string("未检测") case .connected(let active): - return active ? String(localized: "已连接,有保存坐标") : String(localized: "已连接,无保存坐标") + return active ? AppLocalization.string("已连接,有保存坐标") : AppLocalization.string("已连接,无保存坐标") case .failed(let message): - return String(localized: "连接失败(\(message))") + return AppLocalization.string("连接失败(\(message))") } } @@ -966,14 +966,14 @@ struct FirstSetupView: View { private func failureSummary(_ result: VerificationResult) -> String { switch result { - case .certNotTrusted: return String(localized: "证书尚未安装或信任") - case .wifiProxyNotConfigured: return String(localized: "Wi-Fi 代理未正确设置") - case .proxyNotRunning: return String(localized: "本地代理未能启动") - case .verificationInProgress: return String(localized: "检测仍在进行") - case .verificationSuperseded: return String(localized: "检测结果已过期") - case .coordinateWriteFailed: return String(localized: "坐标写入失败") - case .patchFailed: return String(localized: "定位改写检测失败") - case .success: return String(localized: "环境检测通过") + case .certNotTrusted: return AppLocalization.string("证书尚未安装或信任") + case .wifiProxyNotConfigured: return AppLocalization.string("Wi-Fi 代理未正确设置") + case .proxyNotRunning: return AppLocalization.string("本地代理未能启动") + case .verificationInProgress: return AppLocalization.string("检测仍在进行") + case .verificationSuperseded: return AppLocalization.string("检测结果已过期") + case .coordinateWriteFailed: return AppLocalization.string("坐标写入失败") + case .patchFailed: return AppLocalization.string("定位改写检测失败") + case .success: return AppLocalization.string("环境检测通过") } } diff --git a/App/MapHomeView.swift b/App/MapHomeView.swift index da896b9..9335c32 100644 --- a/App/MapHomeView.swift +++ b/App/MapHomeView.swift @@ -301,7 +301,7 @@ struct MapHomeView: View { } } message: { Text( - "你正在使用 \(communityContributionClient?.name ?? String(localized: "第三方客户端"))。点击“去提交”会先复制投稿模板,并在 App 内打开社区页面。采纳后将收录到 README,可选择是否匿名署名。" + "你正在使用 \(communityContributionClient?.name ?? AppLocalization.string("第三方客户端"))。点击“去提交”会先复制投稿模板,并在 App 内打开社区页面。采纳后将收录到 README,可选择是否匿名署名。" ) } .alert("已复制投稿模板", isPresented: $showCommunityTemplateCopied) { @@ -483,7 +483,7 @@ struct MapHomeView: View { // 当前选点 HStack { VStack(alignment: .leading, spacing: 3) { - Text(mapState.displayName ?? String(localized: "当前选点")).font(.subheadline.weight(.semibold)).lineLimit(1) + Text(mapState.displayName ?? AppLocalization.string("当前选点")).font(.subheadline.weight(.semibold)).lineLimit(1) coordinateRow(label: "GCJ-02(国内)", system: .gcj02) coordinateRow(label: "WGS-84(国际)", system: .wgs84) } @@ -585,15 +585,15 @@ struct MapHomeView: View { private var buttonTitle: String { if runtimeMode.mode == .thirdParty { switch spoofState { - case .idle: return String(localized: "同步到第三方代理") - case .verifying: return String(localized: "检测并同步中…") - case .active: return String(localized: "停止第三方虚拟定位") + case .idle: return AppLocalization.string("同步到第三方代理") + case .verifying: return AppLocalization.string("检测并同步中…") + case .active: return AppLocalization.string("停止第三方虚拟定位") } } switch spoofState { - case .idle: return String(localized: "开始虚拟定位") - case .verifying: return String(localized: "验证环境中…") - case .active: return String(localized: "停止虚拟定位") + case .idle: return AppLocalization.string("开始虚拟定位") + case .verifying: return AppLocalization.string("验证环境中…") + case .active: return AppLocalization.string("停止虚拟定位") } } @@ -1092,7 +1092,7 @@ struct MapHomeView: View { "请求动作": "WLOC query", "错误": response.error ?? "未知错误" ]) - setup.requestThirdPartySetup(message: response.error ?? String(localized: "第三方代理查询失败")) + setup.requestThirdPartySetup(message: response.error ?? AppLocalization.string("第三方代理查询失败")) } } catch { spoofState = .idle @@ -1145,7 +1145,7 @@ struct MapHomeView: View { "Wi-Fi接口": String(net.isWiFiEnabled) ]) activeTip = nil - setup.requestSetup(message: String(localized: "当前未连接可用的 Wi-Fi,请连接 Wi-Fi 后配置 127.0.0.1:8888 手动代理。")) + setup.requestSetup(message: AppLocalization.string("当前未连接可用的 Wi-Fi,请连接 Wi-Fi 后配置 127.0.0.1:8888 手动代理。")) return } @@ -1520,7 +1520,7 @@ struct MapHomeView: View { } searchResults = (response?.mapItems ?? []).prefix(6).map { item in let r = SearchLocationResult( - name: item.name ?? String(localized: "未命名"), + name: item.name ?? AppLocalization.string("未命名"), subtitle: [item.placemark.locality, item.placemark.subLocality, item.placemark.thoroughfare] .compactMap { $0 } .filter { !$0.isEmpty } @@ -1532,7 +1532,7 @@ struct MapHomeView: View { ]) return r } - if searchResults.isEmpty { searchError = String(localized: "没有找到相关地点") } + if searchResults.isEmpty { searchError = AppLocalization.string("没有找到相关地点") } } } } diff --git a/App/PaopaoLocationSpooferApp.swift b/App/PaopaoLocationSpooferApp.swift index 925301f..971ea61 100644 --- a/App/PaopaoLocationSpooferApp.swift +++ b/App/PaopaoLocationSpooferApp.swift @@ -9,6 +9,7 @@ struct PaopaoLocationSpooferApp: App { var body: some Scene { WindowGroup { ContentView() + .environment(\.locale, AppLocalization.locale) } } } diff --git a/App/ProxyManager.swift b/App/ProxyManager.swift index 2be8a27..503d538 100644 --- a/App/ProxyManager.swift +++ b/App/ProxyManager.swift @@ -154,13 +154,13 @@ final class ProxyManager: ObservableObject { do { if !isRunning { try await start() } guard let url = URL(string: "http://127.0.0.1:8888/cert") else { - error = String(localized: "证书下载地址无效") + error = AppLocalization.string("证书下载地址无效") return nil } error = nil return url } catch { - self.error = String(localized: "启动代理失败: \(error.localizedDescription)") + self.error = AppLocalization.string("启动代理失败: \(error.localizedDescription)") RuntimeLogger.error("APP", "Certificate", "准备证书下载失败", error: error) return nil } @@ -182,5 +182,5 @@ struct ProxyCoordinateSnapshot: Equatable { enum ProxyError: LocalizedError { case startFailed - var errorDescription: String? { String(localized: "Go proxy 启动失败") } + var errorDescription: String? { AppLocalization.string("Go proxy 启动失败") } } diff --git a/App/SettingsView.swift b/App/SettingsView.swift index 0e678c6..4987f5b 100644 --- a/App/SettingsView.swift +++ b/App/SettingsView.swift @@ -30,7 +30,7 @@ struct SettingsView: View { @Environment(\.dismiss) private var dismiss @State private var activeTip: TipKind? @State private var proxyOperationError = "" - @State private var proxyOperationAlertTitle = String(localized: "代理操作失败") + @State private var proxyOperationAlertTitle = AppLocalization.string("代理操作失败") @State private var modeOperationRunning = false @State private var copiedClient: ThirdPartyProxyClient? @State private var copiedMITMHostname: String? @@ -319,12 +319,12 @@ struct SettingsView: View { ) case .available(let prompt): let details = prompt.releaseNotes - ?? String(localized: "更新说明暂时无法加载,请前往最新 Release 页面查看。") + ?? AppLocalization.string("更新说明暂时无法加载,请前往最新 Release 页面查看。") let message: String if prompt.requirement == .required { - message = String(localized: "当前版本 \(prompt.currentVersion) 已停止支持,请更新到 \(prompt.latestVersion) 后继续使用。\n\n\(details)") + message = AppLocalization.string("当前版本 \(prompt.currentVersion) 已停止支持,请更新到 \(prompt.latestVersion) 后继续使用。\n\n\(details)") } else { - message = String(localized: "当前版本 \(prompt.currentVersion),最新版本 \(prompt.latestVersion)。\n\n\(details)") + message = AppLocalization.string("当前版本 \(prompt.currentVersion),最新版本 \(prompt.latestVersion)。\n\n\(details)") } return Alert( title: prompt.requirement == .required ? Text("需要更新") : Text("发现新版本"), @@ -351,7 +351,7 @@ struct SettingsView: View { try await proxy.start() } catch { proxy.error = error.localizedDescription - proxyOperationAlertTitle = String(localized: "代理操作失败") + proxyOperationAlertTitle = AppLocalization.string("代理操作失败") proxyOperationError = error.localizedDescription } } else { @@ -482,27 +482,27 @@ struct SettingsView: View { private var thirdPartyStatusText: String { switch thirdPartyProxy.connectionState { - case .unknown: return String(localized: "未检测") - case .connected(let active): return active ? String(localized: "已连接,有坐标") : String(localized: "已连接,无坐标") - case .failed: return String(localized: "连接失败") + case .unknown: return AppLocalization.string("未检测") + case .connected(let active): return active ? AppLocalization.string("已连接,有坐标") : AppLocalization.string("已连接,无坐标") + case .failed: return AppLocalization.string("连接失败") } } private var virtualLocationStatusText: String { if runtimeMode.mode == .localWiFi { - return actions.virtualLocationEnabled ? String(localized: "已开启") : String(localized: "已关闭") + return actions.virtualLocationEnabled ? AppLocalization.string("已开启") : AppLocalization.string("已关闭") } if case .connected(let active) = thirdPartyProxy.connectionState { - return active ? String(localized: "第三方已保存") : String(localized: "未保存") + return active ? AppLocalization.string("第三方已保存") : AppLocalization.string("未保存") } - return String(localized: "未知") + return AppLocalization.string("未知") } private var workflowDescription: String { if runtimeMode.mode == .thirdParty { - return String(localized: "App 只负责地图选点、收藏和发送 WGS-84 坐标。第三方代理客户端通过模块拦截 Apple WLOC 请求并持久化当前坐标;本模式不启动本机代理,不使用 App 的 CA,也不需要配置 127.0.0.1:8888。") + return AppLocalization.string("App 只负责地图选点、收藏和发送 WGS-84 坐标。第三方代理客户端通过模块拦截 Apple WLOC 请求并持久化当前坐标;本模式不启动本机代理,不使用 App 的 CA,也不需要配置 127.0.0.1:8888。") } - return String(localized: """ + return AppLocalization.string(""" App 在设备本地运行一个代理服务器(127.0.0.1:8888)。 通过 WiFi 手动代理配置,让系统发往 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的定位请求经过这个本地代理。代理使用已安装的 CA 证书对 HTTPS 流量做中间人解密,把 Apple 返回的定位坐标改写为你设置的虚拟坐标,再加密返回给系统,从而实现虚拟定位。 @@ -523,8 +523,8 @@ struct SettingsView: View { if runtimeMode.isInitialized(.thirdParty) { do { _ = try await thirdPartyProxy.query() - proxyOperationAlertTitle = String(localized: "模式已切换") - proxyOperationError = String(localized: "第三方代理模式检测通过。请关闭 Wi-Fi 中的 127.0.0.1:8888 手动代理,避免双重拦截。") + proxyOperationAlertTitle = AppLocalization.string("模式已切换") + proxyOperationError = AppLocalization.string("第三方代理模式检测通过。请关闭 Wi-Fi 中的 127.0.0.1:8888 手动代理,避免双重拦截。") } catch { openThirdPartySetup(for: error) } @@ -546,8 +546,8 @@ struct SettingsView: View { let result = await setup.runVerificationTest() setup.applyVerificationResult(result) if result.isSuccess { - proxyOperationAlertTitle = String(localized: "模式已切换") - proxyOperationError = String(localized: "APP 模式环境检测通过。请停用第三方 WLOC 模块或代理连接,避免双重拦截。") + proxyOperationAlertTitle = AppLocalization.string("模式已切换") + proxyOperationError = AppLocalization.string("APP 模式环境检测通过。请停用第三方 WLOC 模块或代理连接,避免双重拦截。") } else { dismiss() } @@ -608,14 +608,14 @@ struct SettingsView: View { try setup.certificateStore.reset() runtimeMode.resetInitialization(.localWiFi) guard await setup.prepareLocalServices() else { - proxyOperationAlertTitle = String(localized: "证书重置失败") + proxyOperationAlertTitle = AppLocalization.string("证书重置失败") proxyOperationError = setup.message return } setup.requestCertificateSetup() dismiss() } catch { - proxyOperationAlertTitle = String(localized: "证书重置失败") + proxyOperationAlertTitle = AppLocalization.string("证书重置失败") proxyOperationError = error.localizedDescription } } @@ -626,8 +626,8 @@ struct SettingsView: View { UIApplication.shared.open(url, options: [:]) { opened in guard !opened else { return } Task { @MainActor in - proxyOperationAlertTitle = String(localized: "无法打开客户端") - proxyOperationError = String(localized: "无法打开 \(client.name),请确认客户端已安装后手动打开。") + proxyOperationAlertTitle = AppLocalization.string("无法打开客户端") + proxyOperationError = AppLocalization.string("无法打开 \(client.name),请确认客户端已安装后手动打开。") } } } diff --git a/App/SetupCoordinator.swift b/App/SetupCoordinator.swift index c36addd..1f54f70 100644 --- a/App/SetupCoordinator.swift +++ b/App/SetupCoordinator.swift @@ -36,7 +36,7 @@ final class SetupCoordinator: ObservableObject { message = "" return true } catch { - message = String(localized: "本地代理初始化失败:\(error.localizedDescription)") + message = AppLocalization.string("本地代理初始化失败:\(error.localizedDescription)") RuntimeLogger.error("APP", "Startup", "本地服务初始化失败", error: error) return false } @@ -48,19 +48,19 @@ final class SetupCoordinator: ObservableObject { case .success: trustState = .trusted needsSetup = false - message = String(localized: "✓ 定位环境正常") + message = AppLocalization.string("✓ 定位环境正常") case .certNotTrusted: trustState = .unavailable setupStep = .cert needsSetup = true - message = String(localized: "CA 证书未安装或未信任") + message = AppLocalization.string("CA 证书未安装或未信任") case .verificationInProgress, .verificationSuperseded: break default: trustState = .unavailable setupStep = .proxy needsSetup = true - message = String(localized: "Wi-Fi 代理未正确设置,请检查 127.0.0.1:8888") + message = AppLocalization.string("Wi-Fi 代理未正确设置,请检查 127.0.0.1:8888") } } @@ -108,36 +108,36 @@ final class SetupCoordinator: ObservableObject { testLog = "" let log = { (msg: String) in self.testLog += msg + "\n" } - log(String(localized: "======== 代理验证测试 ========")) - log(String(localized: "App 版本: \(appVersion)")) - log(String(localized: "系统版本: iOS \(UIDevice.current.systemVersion)")) + log(AppLocalization.string("======== 代理验证测试 ========")) + log(AppLocalization.string("App 版本: \(appVersion)")) + log(AppLocalization.string("系统版本: iOS \(UIDevice.current.systemVersion)")) log("") // Step A: Proxy running - log(String(localized: "[步骤 A] 检查代理是否运行…")) - log(String(localized: " 端口: 127.0.0.1:8888")) + log(AppLocalization.string("[步骤 A] 检查代理是否运行…")) + log(AppLocalization.string(" 端口: 127.0.0.1:8888")) let stepAStart = Date() if !proxy.isRunning { - log(String(localized: " ⚠ 代理未运行,尝试启动…")) + log(AppLocalization.string(" ⚠ 代理未运行,尝试启动…")) do { try await proxy.start() } catch { - log(String(localized: " ✗ 启动失败: \(error.localizedDescription)")) + log(AppLocalization.string(" ✗ 启动失败: \(error.localizedDescription)")) return .proxyNotRunning } - log(String(localized: " ✓ 代理启动成功")) + log(AppLocalization.string(" ✓ 代理启动成功")) } else { - log(String(localized: " ✓ 代理已在运行中")) + log(AppLocalization.string(" ✓ 代理已在运行中")) } collectProxyLogs(since: stepAStart, to: log) // Step B: Combined CA + WiFi proxy check (single request) log("") - log(String(localized: "[步骤 B] 检测证书与 WiFi 代理…")) - log(String(localized: " 方式: 请求 baidu.com/paopao-verify-")) - log(String(localized: " 结果判定: TLS 错误=证书问题 / 响应不匹配=代理未配置 / 匹配=通过")) + log(AppLocalization.string("[步骤 B] 检测证书与 WiFi 代理…")) + log(AppLocalization.string(" 方式: 请求 baidu.com/paopao-verify-")) + log(AppLocalization.string(" 结果判定: TLS 错误=证书问题 / 响应不匹配=代理未配置 / 匹配=通过")) let stepBStart = Date() let verifyToken = CoreBridge.refreshVerifyToken() guard !verifyToken.isEmpty else { - log(String(localized: " ✗ 无法生成验证 token")) + log(AppLocalization.string(" ✗ 无法生成验证 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(String(localized: " ✓ 证书已信任,WiFi 代理已配置")) + log(AppLocalization.string(" ✓ 证书已信任,WiFi 代理已配置")) } else { - log(String(localized: " ✗ 响应不匹配: HTTP \(statusCode), \(data.count) bytes,WiFi 代理未配置")) + log(AppLocalization.string(" ✗ 响应不匹配: HTTP \(statusCode), \(data.count) bytes,WiFi 代理未配置")) return .wifiProxyNotConfigured } } catch { let ns = error as NSError let msg = error.localizedDescription - log(String(localized: " ✗ 请求失败 [\(ns.domain) code=\(ns.code)]: \(msg)")) + log(AppLocalization.string(" ✗ 请求失败 [\(ns.domain) code=\(ns.code)]: \(msg)")) if isCertificateTrustError(nsError: ns, message: msg) { - log(String(localized: " TLS/证书校验失败,CA 证书未信任")) + log(AppLocalization.string(" TLS/证书校验失败,CA 证书未信任")) return .certNotTrusted } return .wifiProxyNotConfigured @@ -168,7 +168,7 @@ final class SetupCoordinator: ObservableObject { collectProxyLogs(since: stepBStart, to: log) log("") - log(String(localized: "======== 环境检测通过 ✓ ========")) + log(AppLocalization.string("======== 环境检测通过 ✓ ========")) return .success } @@ -202,7 +202,7 @@ final class SetupCoordinator: ObservableObject { $0.source == "CORE" && $0.category == "Proxy" && $0.timestamp >= date } guard !proxyEntries.isEmpty else { return } - log(String(localized: " --- 代理日志 ---")) + log(AppLocalization.string(" --- 代理日志 ---")) for e in proxyEntries { log(" " + e.localizedMessage) } diff --git a/App/SystemSettingsNavigator.swift b/App/SystemSettingsNavigator.swift index fa31e2d..2adfc49 100644 --- a/App/SystemSettingsNavigator.swift +++ b/App/SystemSettingsNavigator.swift @@ -25,13 +25,13 @@ enum SystemSettingsDestination { var manualPath: String { switch self { case .appPermissions: - return String(localized: "请手动打开「设置」,找到本 App 后检查定位权限。") + return AppLocalization.string("请手动打开「设置」,找到本 App 后检查定位权限。") case .general: - return String(localized: "请手动打开「设置 → 通用」。") + return AppLocalization.string("请手动打开「设置 → 通用」。") case .wifi: - return String(localized: "请手动打开「设置 → 无线局域网」,进入当前 Wi-Fi 的详情页。") + return AppLocalization.string("请手动打开「设置 → 无线局域网」,进入当前 Wi-Fi 的详情页。") case .locationServices: - return String(localized: "请手动打开「设置 → 隐私与安全性 → 定位服务」。") + return AppLocalization.string("请手动打开「设置 → 隐私与安全性 → 定位服务」。") } } } diff --git a/README.md b/README.md index 51c084a..a8270eb 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ responses in a controlled test environment. [![iOS 15+](https://img.shields.io/badge/iOS-15%2B-111111?logo=apple)](project.yml) [![Swift 5.9](https://img.shields.io/badge/Swift-5.9-F05138)](project.yml) [![Go 1.23+](https://img.shields.io/badge/Go-1.23%2B-00ADD8?logo=go)](Core/go.mod) -[![Version](https://img.shields.io/badge/version-v1.0.7-2563EB)](docs/CHANGELOG.md) +[![Version](https://img.shields.io/badge/version-v1.0.8-2563EB)](docs/CHANGELOG.md) [Features](#feature-overview) · [How It Works](#how-it-works) · diff --git a/README.zh-CN.md b/README.zh-CN.md index ba1d0e0..9c1d7f0 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -14,7 +14,7 @@ [![iOS 15+](https://img.shields.io/badge/iOS-15%2B-111111?logo=apple)](project.yml) [![Swift 5.9](https://img.shields.io/badge/Swift-5.9-F05138)](project.yml) [![Go 1.23+](https://img.shields.io/badge/Go-1.23%2B-00ADD8?logo=go)](Core/go.mod) -[![Version](https://img.shields.io/badge/version-v1.0.7-2563EB)](docs/CHANGELOG.md) +[![Version](https://img.shields.io/badge/version-v1.0.8-2563EB)](docs/CHANGELOG.md) [功能概览](#功能概览) · [工作原理](#工作原理) · diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 06edd13..749db5d 100644 --- a/Resources/en.lproj/Localizable.strings +++ b/Resources/en.lproj/Localizable.strings @@ -1,8 +1,8 @@ /* ============================================================ - English localization overlay. + English localization and development-language fallback. Keys are the original Simplified-Chinese source strings - (development language = zh-Hans). Any key not found here - falls back to the Chinese key text automatically. + All localized keys are mirrored in zh-Hans and zh-Hant tables. + Untranslated keys still display their Chinese source text. ============================================================ */ /* MARK: - Shared models (ProxyRuntimeMode / VerificationResult) */ @@ -60,6 +60,8 @@ "验证状态" = "Verification Status"; "已复制模块订阅地址" = "Subscription URL copied"; "复制模块订阅地址" = "Copy module subscription URL"; +"复制 %@" = "Copy %@"; +"已复制 %@" = "Copied %@"; "已复制解密域名" = "Decryption hostnames copied"; "复制解密域名" = "Copy decryption hostnames"; "打开 %@" = "Open %@"; diff --git a/Resources/zh-Hans.lproj/Localizable.strings b/Resources/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..eaa2846 --- /dev/null +++ b/Resources/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,668 @@ +/* Generated from en.lproj/Localizable.strings by Scripts/generate-chinese-localizations.swift. */ +"APP模式" = "APP模式"; +"第三方代理模式" = "第三方代理模式"; +"成功" = "成功"; +"已有验证正在进行" = "已有验证正在进行"; +"验证已被新位置取代" = "验证已被新位置取代"; +"证书未信任" = "证书未信任"; +"WiFi代理未配置" = "WiFi代理未配置"; +"坐标写入失败" = "坐标写入失败"; +"改写验证失败" = "改写验证失败"; +"运行模式" = "运行模式"; +"模式" = "模式"; +"状态" = "状态"; +"本机代理" = "本机代理"; +"第三方模块" = "第三方模块"; +"检测连接" = "检测连接"; +"虚拟定位" = "虚拟定位"; +"定位模拟" = "定位模拟"; +"运动状态模拟" = "运动状态模拟"; +"实验性功能,默认关闭。开启后会同时模拟定位响应中的运动状态。" = "实验性功能,默认关闭。开启后会同时模拟定位响应中的运动状态。"; +"随机扰动" = "随机扰动"; +"开启后,下次同步坐标时会给目标点添加随机偏移(默认半径 50 米),避免位置固定在同一点。" = "开启后,下次同步坐标时会给目标点添加随机偏移(默认半径 50 米),避免位置固定在同一点。"; +"说明" = "说明"; +"工作原理" = "工作原理"; +"应用" = "应用"; +"进入引导页" = "进入引导页"; +"正在检查…" = "正在检查…"; +"检查更新" = "检查更新"; +"版本" = "版本"; +"证书" = "证书"; +"重置证书" = "重置证书"; +"仅删除 App 钥匙串中的设备 CA。iOS 中已经安装的旧证书需要在系统设置里手动移除。" = "仅删除 App 钥匙串中的设备 CA。iOS 中已经安装的旧证书需要在系统设置里手动移除。"; +"支持" = "支持"; +"使用帮助" = "使用帮助"; +"功能建议" = "功能建议"; +"分享第三方配置" = "分享第三方配置"; +"关于" = "关于"; +"如果觉得好用,欢迎去 GitHub 给项目点个 Star" = "如果觉得好用,欢迎去 GitHub 给项目点个 Star"; +"致谢" = "致谢"; +"核心定位改写逻辑移植自 Yu9191/wloc" = "核心定位改写逻辑移植自 Yu9191/wloc"; +"设置" = "设置"; +"完成" = "完成"; +"代理操作失败" = "代理操作失败"; +"重置证书?" = "重置证书?"; +"重置并生成新证书" = "重置并生成新证书"; +"当前虚拟定位和本地代理将停止。App 会删除钥匙串中的设备 CA、立即生成新证书,并打开安装与信任引导。你还需要前往 iOS「设置 → 通用 → VPN 与设备管理」手动删除旧证书,然后重新下载安装并完全信任新证书。" = "当前虚拟定位和本地代理将停止。App 会删除钥匙串中的设备 CA、立即生成新证书,并打开安装与信任引导。你还需要前往 iOS「设置 → 通用 → VPN 与设备管理」手动删除旧证书,然后重新下载安装并完全信任新证书。"; +"第三方代理配置" = "第三方代理配置"; +"客户端" = "客户端"; +"使用国内镜像下载模块" = "使用国内镜像下载模块"; +"仅影响之后复制和重新导入的模块地址;已安装模块需要重新导入后切换来源。" = "仅影响之后复制和重新导入的模块地址;已安装模块需要重新导入后切换来源。"; +"验证状态" = "验证状态"; +"已复制模块订阅地址" = "已复制模块订阅地址"; +"复制模块订阅地址" = "复制模块订阅地址"; +"复制 %@" = "复制 %@"; +"已复制 %@" = "已复制 %@"; +"已复制解密域名" = "已复制解密域名"; +"复制解密域名" = "复制解密域名"; +"打开 %@" = "打开 %@"; +"重新打开配置引导" = "重新打开配置引导"; +"Egern 直接使用 Surge 的 .sgmodule 模块。" = "Egern 直接使用 Surge 的 .sgmodule 模块。"; +"Stash 直接订阅 .stoverride,不要通过 Script Hub 转换。" = "Stash 直接订阅 .stoverride,不要通过 Script Hub 转换。"; +"复制模块订阅地址后,在对应代理客户端中添加模块/重写订阅,并为复制的全部域名(含 gsp-ssl.ls.apple.com、bluedot.is.autonavi.com)启用 MITM。第三方客户端保存坐标后,即使关闭本 App,坐标仍由代理客户端持久化并继续生效。" = "复制模块订阅地址后,在对应代理客户端中添加模块/重写订阅,并为复制的全部域名(含 gsp-ssl.ls.apple.com、bluedot.is.autonavi.com)启用 MITM。第三方客户端保存坐标后,即使关闭本 App,坐标仍由代理客户端持久化并继续生效。"; +"已是最新版本" = "已是最新版本"; +"当前版本 %@,远程最新版本 %@。" = "当前版本 %@,远程最新版本 %@。"; +"检查更新失败" = "检查更新失败"; +"无法获取远程版本信息,请检查网络后重试。" = "无法获取远程版本信息,请检查网络后重试。"; +"未检测" = "未检测"; +"已连接,有坐标" = "已连接,有坐标"; +"已连接,无坐标" = "已连接,无坐标"; +"连接失败" = "连接失败"; +"已开启" = "已开启"; +"已关闭" = "已关闭"; +"第三方已保存" = "第三方已保存"; +"未保存" = "未保存"; +"未知" = "未知"; +"App 只负责地图选点、收藏和发送 WGS-84 坐标。第三方代理客户端通过模块拦截 Apple WLOC 请求并持久化当前坐标;本模式不启动本机代理,不使用 App 的 CA,也不需要配置 127.0.0.1:8888。" = "App 只负责地图选点、收藏和发送 WGS-84 坐标。第三方代理客户端通过模块拦截 Apple WLOC 请求并持久化当前坐标;本模式不启动本机代理,不使用 App 的 CA,也不需要配置 127.0.0.1:8888。"; +"App 在设备本地运行一个代理服务器(127.0.0.1:8888)。\n\n通过 WiFi 手动代理配置,让系统发往 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的定位请求经过这个本地代理。代理使用已安装的 CA 证书对 HTTPS 流量做中间人解密,把 Apple 返回的定位坐标改写为你设置的虚拟坐标,再加密返回给系统,从而实现虚拟定位。" = "App 在设备本地运行一个代理服务器(127.0.0.1:8888)。\n\n通过 WiFi 手动代理配置,让系统发往 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的定位请求经过这个本地代理。代理使用已安装的 CA 证书对 HTTPS 流量做中间人解密,把 Apple 返回的定位坐标改写为你设置的虚拟坐标,再加密返回给系统,从而实现虚拟定位。"; +"模式已切换" = "模式已切换"; +"第三方代理模式检测通过。请关闭 Wi-Fi 中的 127.0.0.1:8888 手动代理,避免双重拦截。" = "第三方代理模式检测通过。请关闭 Wi-Fi 中的 127.0.0.1:8888 手动代理,避免双重拦截。"; +"APP 模式环境检测通过。请停用第三方 WLOC 模块或代理连接,避免双重拦截。" = "APP 模式环境检测通过。请停用第三方 WLOC 模块或代理连接,避免双重拦截。"; +"证书重置失败" = "证书重置失败"; +"无法打开客户端" = "无法打开客户端"; +"无法打开 %@,请确认客户端已安装后手动打开。" = "无法打开 %@,请确认客户端已安装后手动打开。"; +"正在初始化地图与本地代理…" = "正在初始化地图与本地代理…"; +"正在初始化地图…" = "正在初始化地图…"; +"更新说明暂时无法加载,请前往最新 Release 页面查看。" = "更新说明暂时无法加载,请前往最新 Release 页面查看。"; +"需要更新" = "需要更新"; +"当前版本 %@ 已停止支持,请更新到 %@ 后继续使用。\n\n%@" = "当前版本 %@ 已停止支持,请更新到 %@ 后继续使用。\n\n%@"; +"立即更新" = "立即更新"; +"发现新版本" = "发现新版本"; +"当前版本 %@,最新版本 %@。\n\n%@" = "当前版本 %@,最新版本 %@。\n\n%@"; +"前往更新" = "前往更新"; +"稍后" = "稍后"; +"遇到问题时,在这里生成 Bug 报告。系统会运行一次诊断测试,并将完整报告复制到剪切板。跳转到 GitHub 后,请粘贴到“App 生成的诊断报告”字段。" = "遇到问题时,在这里生成 Bug 报告。系统会运行一次诊断测试,并将完整报告复制到剪切板。跳转到 GitHub 后,请粘贴到“App 生成的诊断报告”字段。"; +"可复现环境" = "可复现环境"; +"当前设备上问题稳定复现,非偶发性。" = "当前设备上问题稳定复现,非偶发性。"; +"问题描述" = "问题描述"; +"正在生成报告…" = "正在生成报告…"; +"生成 Bug 报告" = "生成 Bug 报告"; +"报告 Bug" = "报告 Bug"; +"已生成" = "已生成"; +"打开 GitHub 表单" = "打开 GitHub 表单"; +"稍后再说" = "稍后再说"; +"Bug 报告已复制到剪切板。请在 GitHub 表单的“App 生成的诊断报告”字段中粘贴并提交。" = "Bug 报告已复制到剪切板。请在 GitHub 表单的“App 生成的诊断报告”字段中粘贴并提交。"; +"过滤日志" = "过滤日志"; +"暂无运行日志" = "暂无运行日志"; +"无匹配日志" = "无匹配日志"; +"运行日志" = "运行日志"; +"日志自动清理,仅保留近 3 天" = "日志自动清理,仅保留近 3 天"; +"关闭" = "关闭"; +"复制全部日志" = "复制全部日志"; +"清空全部日志" = "清空全部日志"; +"清空所有运行日志?" = "清空所有运行日志?"; +"清空日志" = "清空日志"; +"取消" = "取消"; +"正在检测…" = "正在检测…"; +"环境检测" = "环境检测"; +"检查第三方模块能否拦截并响应 query 请求;不会写入测试坐标。" = "检查第三方模块能否拦截并响应 query 请求;不会写入测试坐标。"; +"依次检查:本地代理 → CA 证书信任 → Wi-Fi 代理链路。" = "依次检查:本地代理 → CA 证书信任 → Wi-Fi 代理链路。"; +"测试日志" = "测试日志"; +"已复制" = "已复制"; +"代理运行中" = "代理运行中"; +"代理未运行" = "代理未运行"; +"可修改" = "可修改"; +"不可修改" = "不可修改"; +"环境检测通过" = "环境检测通过"; +"环境检测失败: %@" = "环境检测失败: %@"; +",查看下方日志" = ",查看下方日志"; +"第三方模块连接通过,已有坐标" = "第三方模块连接通过,已有坐标"; +"第三方模块连接通过,暂无坐标" = "第三方模块连接通过,暂无坐标"; +"第三方模块连接失败" = "第三方模块连接失败"; +"======== 第三方代理连接检测 ========" = "======== 第三方代理连接检测 ========"; +"模式: 测试模式" = "模式: 测试模式"; +"请求: wloc-settings/save?action=query" = "请求: wloc-settings/save?action=query"; +"拦截响应: 有效 JSON" = "拦截响应: 有效 JSON"; +"已保存坐标: %@" = "已保存坐标: %@"; +"结果: %@" = "结果: %@"; +"生效说明" = "生效说明"; +"失效说明" = "失效说明"; +"关闭 WiFi 代理" = "关闭 WiFi 代理"; +"知道了" = "知道了"; +"让虚拟定位生效" = "让虚拟定位生效"; +"确认第三方代理已开启" = "确认第三方代理已开启"; +"保持已导入的 WLOC 模块、HTTPS 解密和第三方代理/VPN 连接开启。" = "保持已导入的 WLOC 模块、HTTPS 解密和第三方代理/VPN 连接开启。"; +"开启飞行模式" = "开启飞行模式"; +"从控制中心打开飞行模式(点飞机图标),Wi‑Fi 会自动断开。这是为了清除 iOS 的定位缓存。等待 2 秒。" = "从控制中心打开飞行模式(点飞机图标),Wi‑Fi 会自动断开。这是为了清除 iOS 的定位缓存。等待 2 秒。"; +"关闭 Wi‑Fi" = "关闭 Wi‑Fi"; +"从控制中心再点一下 Wi‑Fi 图标,确认 Wi‑Fi 已关闭。等待 2 秒。" = "从控制中心再点一下 Wi‑Fi 图标,确认 Wi‑Fi 已关闭。等待 2 秒。"; +"关闭系统定位服务" = "关闭系统定位服务"; +"打开系统「设置 → 隐私与安全性 → 定位服务」,关闭顶部的总开关。等待 2 秒。" = "打开系统「设置 → 隐私与安全性 → 定位服务」,关闭顶部的总开关。等待 2 秒。"; +"打开 Wi‑Fi,启动虚拟定位" = "打开 Wi‑Fi,启动虚拟定位"; +"从控制中心打开 Wi‑Fi(飞行模式保持开启),确认第三方代理已连接。坐标已经同步到第三方代理。等待 2 秒。" = "从控制中心打开 Wi‑Fi(飞行模式保持开启),确认第三方代理已连接。坐标已经同步到第三方代理。等待 2 秒。"; +"从控制中心打开 Wi‑Fi(飞行模式保持开启),进入 App 点底部「开始虚拟定位」。等待 2 秒。" = "从控制中心打开 Wi‑Fi(飞行模式保持开启),进入 App 点底部「开始虚拟定位」。等待 2 秒。"; +"关闭飞行模式" = "关闭飞行模式"; +"从控制中心关闭飞行模式。等待 2 秒。" = "从控制中心关闭飞行模式。等待 2 秒。"; +"重新开启定位服务" = "重新开启定位服务"; +"再次进入「设置 → 隐私与安全性 → 定位服务」,打开总开关。完成后打开地图验证定位是否已变化。" = "再次进入「设置 → 隐私与安全性 → 定位服务」,打开总开关。完成后打开地图验证定位是否已变化。"; +"还是无法生效?" = "还是无法生效?"; +"操作到第 3 步时关机重启,开机后从第 4 步继续。这样能彻底清除系统缓存的定位数据。" = "操作到第 3 步时关机重启,开机后从第 4 步继续。这样能彻底清除系统缓存的定位数据。"; +"去设置" = "去设置"; +"取消虚拟定位" = "取消虚拟定位"; +"从控制中心打开飞行模式,Wi‑Fi 会自动断开。等待 2 秒。" = "从控制中心打开飞行模式,Wi‑Fi 会自动断开。等待 2 秒。"; +"从控制中心确认 Wi‑Fi 已关闭。等待 2 秒。" = "从控制中心确认 Wi‑Fi 已关闭。等待 2 秒。"; +"打开「设置 → 隐私与安全性 → 定位服务」,关闭总开关。等待 2 秒。" = "打开「设置 → 隐私与安全性 → 定位服务」,关闭总开关。等待 2 秒。"; +"确认坐标已清除" = "确认坐标已清除"; +"App 已通知第三方代理清除虚拟坐标。保持网络可用并等待 2 秒,让系统重新获取真实定位。" = "App 已通知第三方代理清除虚拟坐标。保持网络可用并等待 2 秒,让系统重新获取真实定位。"; +"打开 Wi‑Fi,移除代理" = "打开 Wi‑Fi,移除代理"; +"从控制中心打开 Wi‑Fi。然后进入「设置 → 无线局域网 → 点 WiFi 右侧 (i) → HTTP 代理」,选择「关闭」后存储。等待 2 秒。" = "从控制中心打开 Wi‑Fi。然后进入「设置 → 无线局域网 → 点 WiFi 右侧 (i) → HTTP 代理」,选择「关闭」后存储。等待 2 秒。"; +"再次进入「设置 → 隐私与安全性 → 定位服务」打开总开关。打开地图验证定位是否恢复。" = "再次进入「设置 → 隐私与安全性 → 定位服务」打开总开关。打开地图验证定位是否恢复。"; +"还是无法取消?" = "还是无法取消?"; +"操作到第 3 步时关机重启,开机后从第 4 步继续。" = "操作到第 3 步时关机重启,开机后从第 4 步继续。"; +"移除代理配置" = "移除代理配置"; +"停止虚拟定位后,需要手动移除 WiFi 代理配置,否则可能无法上网。\n\n1. 打开「设置 → 无线局域网」\n2. 点击当前 WiFi 右侧 (i) 图标\n3. 找到「HTTP 代理」\n4. 选择「关闭」\n5. 点右上角「存储」" = "停止虚拟定位后,需要手动移除 WiFi 代理配置,否则可能无法上网。\n\n1. 打开「设置 → 无线局域网」\n2. 点击当前 WiFi 右侧 (i) 图标\n3. 找到「HTTP 代理」\n4. 选择「关闭」\n5. 点右上角「存储」"; +"社区分享成功配置?" = "社区分享成功配置?"; +"去提交" = "去提交"; +"复制模板" = "复制模板"; +"不再提示" = "不再提示"; +"第三方客户端" = "第三方客户端"; +"你正在使用 %@。点击“去提交”会先复制投稿模板,并在 App 内打开社区页面。采纳后将收录到 README,可选择是否匿名署名。" = "你正在使用 %@。点击“去提交”会先复制投稿模板,并在 App 内打开社区页面。采纳后将收录到 README,可选择是否匿名署名。"; +"已复制投稿模板" = "已复制投稿模板"; +"如果 GitHub 登录或浏览器跳转后模板没有自动填充,可以直接粘贴。" = "如果 GitHub 登录或浏览器跳转后模板没有自动填充,可以直接粘贴。"; +"无法直接跳转" = "无法直接跳转"; +"定位失败" = "定位失败"; +"打开设置" = "打开设置"; +"无法获取当前定位,请检查定位服务是否已开启" = "无法获取当前定位,请检查定位服务是否已开启"; +"编辑收藏名称" = "编辑收藏名称"; +"名称" = "名称"; +"保存" = "保存"; +"修改收藏地点名称" = "修改收藏地点名称"; +"搜索地点或坐标" = "搜索地点或坐标"; +"日志" = "日志"; +"更多" = "更多"; +"当前选点" = "当前选点"; +"GCJ-02(国内)" = "GCJ-02(国内)"; +"WGS-84(国际)" = "WGS-84(国际)"; +"无法生效?" = "无法生效?"; +"无法取消?" = "无法取消?"; +"已收藏,点击取消收藏" = "已收藏,点击取消收藏"; +"收藏当前选点" = "收藏当前选点"; +"搜索或点击地图选点后,保存为收藏。" = "搜索或点击地图选点后,保存为收藏。"; +"切换到此处" = "切换到此处"; +"同步到第三方代理" = "同步到第三方代理"; +"检测并同步中…" = "检测并同步中…"; +"停止第三方虚拟定位" = "停止第三方虚拟定位"; +"开始虚拟定位" = "开始虚拟定位"; +"验证环境中…" = "验证环境中…"; +"停止虚拟定位" = "停止虚拟定位"; +"当前未连接可用的 Wi-Fi,请连接 Wi-Fi 后配置 127.0.0.1:8888 手动代理。" = "当前未连接可用的 Wi-Fi,请连接 Wi-Fi 后配置 127.0.0.1:8888 手动代理。"; +"第三方代理查询失败" = "第三方代理查询失败"; +"未命名" = "未命名"; +"没有找到相关地点" = "没有找到相关地点"; +"虚拟定位已开启" = "虚拟定位已开启"; +"不再提醒" = "不再提醒"; +"虚拟定位已关闭" = "虚拟定位已关闭"; +"选择模式" = "选择模式"; +"配置 Wi-Fi 代理" = "配置 Wi-Fi 代理"; +"初始化 CA 证书" = "初始化 CA 证书"; +"选择客户端" = "选择客户端"; +"导入并检测" = "导入并检测"; +"上一步" = "上一步"; +"开始使用" = "开始使用"; +"操作失败" = "操作失败"; +"选择运行模式" = "选择运行模式"; +"后续可在“设置 → 运行模式”中切换。两种模式不要同时拦截 WLOC 请求。" = "后续可在“设置 → 运行模式”中切换。两种模式不要同时拦截 WLOC 请求。"; +"仅 Wi-Fi" = "仅 Wi-Fi"; +"无外部依赖" = "无外部依赖"; +"App 在设备本地启动代理,通过当前 Wi-Fi 的手动 HTTP 代理改写定位响应。免费自签应用无法使用系统 VPN 的 Network Extension 能力,因此 APP模式不支持蜂窝网络,需要配置 Wi-Fi 代理并安装 App 生成的 CA。" = "App 在设备本地启动代理,通过当前 Wi-Fi 的手动 HTTP 代理改写定位响应。免费自签应用无法使用系统 VPN 的 Network Extension 能力,因此 APP模式不支持蜂窝网络,需要配置 Wi-Fi 代理并安装 App 生成的 CA。"; +"测试模式" = "测试模式"; +"App 负责选点,并通过 WLOC 配置接口查询和同步坐标;第三方代理客户端负责网络代理、模块拦截、MITM 和持久化。证书、VPN 与代理连接均由第三方客户端处理。" = "App 负责选点,并通过 WLOC 配置接口查询和同步坐标;第三方代理客户端负责网络代理、模块拦截、MITM 和持久化。证书、VPN 与代理连接均由第三方客户端处理。"; +"正在准备 APP模式本地服务…" = "正在准备 APP模式本地服务…"; +"先配置 Wi-Fi 系统代理" = "先配置 Wi-Fi 系统代理"; +"在当前 Wi-Fi 的详情页,将「HTTP 代理」设为「手动」:服务器填 127.0.0.1,端口填 8888。配置后点击下方「完成」。检测会自动判断是 Wi-Fi 代理还是证书信任有问题。" = "在当前 Wi-Fi 的详情页,将「HTTP 代理」设为「手动」:服务器填 127.0.0.1,端口填 8888。配置后点击下方「完成」。检测会自动判断是 Wi-Fi 代理还是证书信任有问题。"; +"Wi-Fi 代理设置" = "Wi-Fi 代理设置"; +"1 选择手动,2 填写服务器 127.0.0.1,3 填写端口 8888。" = "1 选择手动,2 填写服务器 127.0.0.1,3 填写端口 8888。"; +"复制地址" = "复制地址"; +"打开 Wi-Fi 设置" = "打开 Wi-Fi 设置"; +"第 1 步:下载证书" = "第 1 步:下载证书"; +"下载本机随机生成的 CA 根证书。私钥仅保存在此设备的钥匙串中,不会随证书文件导出。App 会弹出 Safari 下载页;出现配置描述文件下载提示时,选择「允许」。" = "下载本机随机生成的 CA 根证书。私钥仅保存在此设备的钥匙串中,不会随证书文件导出。App 会弹出 Safari 下载页;出现配置描述文件下载提示时,选择「允许」。"; +"打开下载页" = "打开下载页"; +"无法准备证书下载页面,请查看诊断日志" = "无法准备证书下载页面,请查看诊断日志"; +"第 2 步:安装证书" = "第 2 步:安装证书"; +"下载完成后打开系统「设置」。如果顶部显示「已下载描述文件」,点进去安装;否则进入「通用 → VPN 与设备管理」,找到 Location Spoofer CA 并完成安装。" = "下载完成后打开系统「设置」。如果顶部显示「已下载描述文件」,点进去安装;否则进入「通用 → VPN 与设备管理」,找到 Location Spoofer CA 并完成安装。"; +"去安装" = "去安装"; +"安装证书" = "安装证书"; +"1 在「VPN 与设备管理」中打开 Location Spoofer CA 描述文件并完成安装。" = "1 在「VPN 与设备管理」中打开 Location Spoofer CA 描述文件并完成安装。"; +"第 3 步:信任证书" = "第 3 步:信任证书"; +"安装后进入「设置 → 通用 → 关于本机 → 证书信任设置」,找到 Location Spoofer CA 并开启完全信任。iOS 保留钥匙串数据时,重装 App 会继续复用同一证书。" = "安装后进入「设置 → 通用 → 关于本机 → 证书信任设置」,找到 Location Spoofer CA 并开启完全信任。iOS 保留钥匙串数据时,重装 App 会继续复用同一证书。"; +"去信任" = "去信任"; +"信任证书" = "信任证书"; +"1 在「证书信任设置」中为 Location Spoofer CA 开启完全信任。" = "1 在「证书信任设置」中为 Location Spoofer CA 开启完全信任。"; +"已完成" = "已完成"; +"已完成 ✓" = "已完成 ✓"; +"iOS 27 beta 6 起,系统已禁止对 gs-loc.apple.com 进行 MITM 拦截。该版本及之后的 beta 版本暂时无法使用本项目,等待后续适配方案。" = "iOS 27 beta 6 起,系统已禁止对 gs-loc.apple.com 进行 MITM 拦截。该版本及之后的 beta 版本暂时无法使用本项目,等待后续适配方案。"; +"选择第三方代理客户端" = "选择第三方代理客户端"; +"除 Shadowrocket 外,当前客户端配置尚未完成真机验证,页面只提供模块导入入口和通用配置提醒。" = "除 Shadowrocket 外,当前客户端配置尚未完成真机验证,页面只提供模块导入入口和通用配置提醒。"; +"第三方客户端适配说明" = "第三方客户端适配说明"; +"App 不连接远程坐标服务器,而是向 Apple 域名发起一个约定请求。第三方客户端需要在本机拦截该请求、保存 WGS-84 坐标并返回 JSON;定位模块再读取同一份数据,修改 Apple WLOC 响应。" = "App 不连接远程坐标服务器,而是向 Apple 域名发起一个约定请求。第三方客户端需要在本机拦截该请求、保存 WGS-84 坐标并返回 JSON;定位模块再读取同一份数据,修改 Apple WLOC 响应。"; +"配置接口" = "配置接口"; +"查询:GET ?action=query\n保存:GET ?lon=<经度>&lat=<纬度>&acc=<精度>\n清除:GET ?action=clear" = "查询:GET ?action=query\n保存:GET ?lon=<经度>&lat=<纬度>&acc=<精度>\n清除:GET ?action=clear"; +"返回格式" = "返回格式"; +"适配要求" = "适配要求"; +"客户端需要支持请求脚本、持久化存储、HTTP 200 JSON 响应、Apple WLOC 响应脚本,以及 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的 HTTPS 解密。保存接口和 WLOC 响应脚本必须读取同一份持久化数据。" = "客户端需要支持请求脚本、持久化存储、HTTP 200 JSON 响应、Apple WLOC 响应脚本,以及 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的 HTTPS 解密。保存接口和 WLOC 响应脚本必须读取同一份持久化数据。"; +"检测到第三方代理连接异常,请检查模块、MITM 和代理连接后重新检测。" = "检测到第三方代理连接异常,请检查模块、MITM 和代理连接后重新检测。"; +"第 1 步:导入 %@ 模块" = "第 1 步:导入 %@ 模块"; +"复制 %@ 的模块订阅地址。" = "复制 %@ 的模块订阅地址。"; +"打开 Shadowrocket,进入“配置 → 模块”。" = "打开 Shadowrocket,进入“配置 → 模块”。"; +"打开 %@。" = "打开 %@。"; +"进入 Shadowrocket 配置" = "进入 Shadowrocket 配置"; +"1 点击「模块」进入模块列表,2 可打开当前本地配置详情。" = "1 点击「模块」进入模块列表,2 可打开当前本地配置详情。"; +"点击右上角“+”,粘贴模块订阅地址并导入,然后确认模块已启用。" = "点击右上角“+”,粘贴模块订阅地址并导入,然后确认模块已启用。"; +"导入 Shadowrocket 模块" = "导入 Shadowrocket 模块"; +"1 点击右上角加号导入模块,2 确认模块已启用。" = "1 点击右上角加号导入模块,2 确认模块已启用。"; +"在 %@ 中导入刚才复制的模块订阅地址。" = "在 %@ 中导入刚才复制的模块订阅地址。"; +"第 2 步:完成 %@ 配置" = "第 2 步:完成 %@ 配置"; +"请在 %@ 中完成相应配置。" = "请在 %@ 中完成相应配置。"; +"配置时请复制下方全部解密域名(含 gsp-ssl.ls.apple.com、bluedot.is.autonavi.com)。" = "配置时请复制下方全部解密域名(含 gsp-ssl.ls.apple.com、bluedot.is.autonavi.com)。"; +"第 2 步:配置 HTTPS 解密" = "第 2 步:配置 HTTPS 解密"; +"进入“配置 → 本地文件”,找到带黄点的配置,点击右侧 i 图标。" = "进入“配置 → 本地文件”,找到带黄点的配置,点击右侧 i 图标。"; +"进入“HTTPS 解密”,开启解密开关。" = "进入“HTTPS 解密”,开启解密开关。"; +"在域名列表中添加下方复制的全部解密域名。" = "在域名列表中添加下方复制的全部解密域名。"; +"配置 HTTPS 解密" = "配置 HTTPS 解密"; +"1 开启 HTTPS 解密,2 添加复制的全部解密域名,3 打开证书设置。" = "1 开启 HTTPS 解密,2 添加复制的全部解密域名,3 打开证书设置。"; +"按 Shadowrocket 提示生成并完成证书授权。" = "按 Shadowrocket 提示生成并完成证书授权。"; +"授权 Shadowrocket 证书" = "授权 Shadowrocket 证书"; +"1 打开 Shadowrocket 证书项并按提示安装、授权。" = "1 打开 Shadowrocket 证书项并按提示安装、授权。"; +"返回 HTTPS 解密页面,点击右上角勾号保存,然后开启代理。" = "返回 HTTPS 解密页面,点击右上角勾号保存,然后开启代理。"; +"打开 Shadowrocket 继续配置" = "打开 Shadowrocket 继续配置"; +"App 只能唤起 Shadowrocket,无法通过公开接口直接跳转到“模块”或“HTTPS 解密”页面。" = "App 只能唤起 Shadowrocket,无法通过公开接口直接跳转到“模块”或“HTTPS 解密”页面。"; +"轻点查看大图" = "轻点查看大图"; +"证书尚未安装或信任" = "证书尚未安装或信任"; +"Wi-Fi 代理未正确设置" = "Wi-Fi 代理未正确设置"; +"本地代理未能启动" = "本地代理未能启动"; +"检测仍在进行" = "检测仍在进行"; +"检测结果已过期" = "检测结果已过期"; +"定位改写检测失败" = "定位改写检测失败"; +"接口连接失败" = "接口连接失败"; +"本地代理初始化失败:%@" = "本地代理初始化失败:%@"; +"✓ 定位环境正常" = "✓ 定位环境正常"; +"CA 证书未安装或未信任" = "CA 证书未安装或未信任"; +"Wi-Fi 代理未正确设置,请检查 127.0.0.1:8888" = "Wi-Fi 代理未正确设置,请检查 127.0.0.1:8888"; +"请手动打开「设置」,找到本 App 后检查定位权限。" = "请手动打开「设置」,找到本 App 后检查定位权限。"; +"请手动打开「设置 → 通用」。" = "请手动打开「设置 → 通用」。"; +"请手动打开「设置 → 无线局域网」,进入当前 Wi-Fi 的详情页。" = "请手动打开「设置 → 无线局域网」,进入当前 Wi-Fi 的详情页。"; +"请手动打开「设置 → 隐私与安全性 → 定位服务」。" = "请手动打开「设置 → 隐私与安全性 → 定位服务」。"; +"第三方代理返回了无法识别的数据" = "第三方代理返回了无法识别的数据"; +"请求未被第三方代理模块拦截,请检查模块、MITM 和代理连接" = "请求未被第三方代理模块拦截,请检查模块、MITM 和代理连接"; +"第三方代理保存的坐标与当前选点不一致" = "第三方代理保存的坐标与当前选点不一致"; +"第三方代理请求失败:%@" = "第三方代理请求失败:%@"; +"检查模块、MITM、证书和代理/VPN连接" = "检查模块、MITM、证书和代理/VPN连接"; +"第三方代理拒绝保存坐标" = "第三方代理拒绝保存坐标"; +"第三方代理清除坐标失败" = "第三方代理清除坐标失败"; +"已有第三方代理请求正在执行" = "已有第三方代理请求正在执行"; +"配置已提供,尚未验证" = "配置已提供,尚未验证"; +"已连接,有保存坐标" = "已连接,有保存坐标"; +"已连接,无保存坐标" = "已连接,无保存坐标"; +"连接失败(%@)" = "连接失败(%@)"; +"当前客户端:%@" = "当前客户端:%@"; +"配置接口:/wloc-settings/save" = "配置接口:/wloc-settings/save"; +"请求动作:WLOC query" = "请求动作:WLOC query"; +"检查范围:模块拦截、MITM、证书、代理/VPN 连接" = "检查范围:模块拦截、MITM、证书、代理/VPN 连接"; +"连接状态:%@" = "连接状态:%@"; +"检测结果:失败" = "检测结果:失败"; +"耗时:%lld ms" = "耗时:%lld ms"; +"错误类型:%@" = "错误类型:%@"; +"错误详情:%@" = "错误详情:%@"; +"处理建议:%@。" = "处理建议:%@。"; +"======== 第三方代理运行检测 ========" = "======== 第三方代理运行检测 ========"; +"触发来源:地图或设置中的第三方代理操作" = "触发来源:地图或设置中的第三方代理操作"; +"请求动作:WLOC 配置接口" = "请求动作:WLOC 配置接口"; +"处理建议:确认模块已启用,并检查 MITM、证书和代理/VPN 连接。" = "处理建议:确认模块已启用,并检查 MITM、证书和代理/VPN 连接。"; +"环境信息" = "环境信息"; +"App 版本" = "App 版本"; +"系统版本" = "系统版本"; +"诊断日志" = "诊断日志"; +"不适用" = "不适用"; +"是" = "是"; +"否" = "否"; +"(无诊断数据)" = "(无诊断数据)"; +"第三方代理测试模式:模块连接成功;已保存坐标=%@" = "第三方代理测试模式:模块连接成功;已保存坐标=%@"; +"第三方代理测试模式:模块连接失败;%@" = "第三方代理测试模式:模块连接失败;%@"; +"======== 代理验证测试 ========" = "======== 代理验证测试 ========"; +"App 版本: %@" = "App 版本: %@"; +"系统版本: iOS %@" = "系统版本: iOS %@"; +"[步骤 A] 检查代理是否运行…" = "[步骤 A] 检查代理是否运行…"; +" 端口: 127.0.0.1:8888" = " 端口: 127.0.0.1:8888"; +" ⚠ 代理未运行,尝试启动…" = " ⚠ 代理未运行,尝试启动…"; +" ✗ 启动失败: %@" = " ✗ 启动失败: %@"; +" ✓ 代理启动成功" = " ✓ 代理启动成功"; +" ✓ 代理已在运行中" = " ✓ 代理已在运行中"; +"[步骤 B] 检测证书与 WiFi 代理…" = "[步骤 B] 检测证书与 WiFi 代理…"; +" 方式: 请求 baidu.com/paopao-verify-" = " 方式: 请求 baidu.com/paopao-verify-"; +" 结果判定: TLS 错误=证书问题 / 响应不匹配=代理未配置 / 匹配=通过" = " 结果判定: TLS 错误=证书问题 / 响应不匹配=代理未配置 / 匹配=通过"; +" ✗ 无法生成验证 token" = " ✗ 无法生成验证 token"; +" ✓ 证书已信任,WiFi 代理已配置" = " ✓ 证书已信任,WiFi 代理已配置"; +" ✗ 响应不匹配: HTTP %lld, %lld bytes,WiFi 代理未配置" = " ✗ 响应不匹配: HTTP %lld, %lld bytes,WiFi 代理未配置"; +" ✗ 请求失败 [%@ code=%lld]: %@" = " ✗ 请求失败 [%@ code=%lld]: %@"; +" TLS/证书校验失败,CA 证书未信任" = " TLS/证书校验失败,CA 证书未信任"; +"======== 环境检测通过 ✓ ========" = "======== 环境检测通过 ✓ ========"; +" --- 代理日志 ---" = " --- 代理日志 ---"; +"成功:{\"success\":true,\"longitude\":113.0,\"latitude\":22.0,\"accuracy\":25}\n失败:{\"success\":false,\"error\":\"错误说明\"}" = "成功:{\"success\":true,\"longitude\":113.0,\"latitude\":22.0,\"accuracy\":25}\n失败:{\"success\":false,\"error\":\"错误说明\"}"; +"定位改写脚本源自 Yu9191/wloc,现由本项目维护" = "定位改写脚本源自 Yu9191/wloc,现由本项目维护"; +"地图" = "地图"; +"坐标转换" = "坐标转换"; +"定位" = "定位"; +"实时定位" = "实时定位"; +"提醒" = "提醒"; +"搜索" = "搜索"; +"收藏" = "收藏"; +"缩放" = "缩放"; +"========== App 启动 ==========" = "========== App 启动 =========="; +"尚未选择运行模式,跳过本地 CA 和代理初始化" = "尚未选择运行模式,跳过本地 CA 和代理初始化"; +"第三方代理测试模式:跳过本地 CA、代理和环境检测" = "第三方代理测试模式:跳过本地 CA、代理和环境检测"; +"旧坐标数据迁移失败,将在下次启动重试" = "旧坐标数据迁移失败,将在下次启动重试"; +"地图坐标标准初始化完成,开始后续启动流程" = "地图坐标标准初始化完成,开始后续启动流程"; +"没有持久化图钉,地图创建前请求实时定位" = "没有持久化图钉,地图创建前请求实时定位"; +"已使用实时定位准备唯一初始地图状态" = "已使用实时定位准备唯一初始地图状态"; +"地图创建前取得的初始实时位置(WGS-84)" = "地图创建前取得的初始实时位置(WGS-84)"; +"地图创建前无法取得实时定位,唯一初始位置使用深圳" = "地图创建前无法取得实时定位,唯一初始位置使用深圳"; +"已找到持久化图钉,直接准备唯一初始地图状态" = "已找到持久化图钉,直接准备唯一初始地图状态"; +"启动门禁全部完成,现在创建 MapHomeView" = "启动门禁全部完成,现在创建 MapHomeView"; +"初始化" = "初始化"; +"启动代理 127.0.0.1:8888" = "启动代理 127.0.0.1:8888"; +"启动代理: 恢复上次 WGS-84 定位" = "启动代理: 恢复上次 WGS-84 定位"; +"启动成功" = "启动成功"; +"启动失败" = "启动失败"; +"写入坐标" = "写入坐标"; +"跳过过期坐标写入" = "跳过过期坐标写入"; +"跳过旧验证坐标恢复" = "跳过旧验证坐标恢复"; +"运动状态模拟设置已更新" = "运动状态模拟设置已更新"; +"准备证书下载失败" = "准备证书下载失败"; +"设置虚拟定位坐标" = "设置虚拟定位坐标"; +"apply失败" = "apply失败"; +"保存收藏失败" = "保存收藏失败"; +"本地服务初始化失败" = "本地服务初始化失败"; +"代理运行模式已切换" = "代理运行模式已切换"; +"已迁移旧版模式初始化状态" = "已迁移旧版模式初始化状态"; +"地图坐标标准检测已有请求进行中" = "地图坐标标准检测已有请求进行中"; +"地图坐标标准检测开始" = "地图坐标标准检测开始"; +"地图坐标标准检测获得明确结果" = "地图坐标标准检测获得明确结果"; +"地图坐标标准检测不可用,开始实时定位兜底" = "地图坐标标准检测不可用,开始实时定位兜底"; +"地图坐标标准检测使用兜底结果" = "地图坐标标准检测使用兜底结果"; +"地图坐标标准检测被取消,保留默认国内标准" = "地图坐标标准检测被取消,保留默认国内标准"; +"地图坐标标准已确定,允许创建地图" = "地图坐标标准已确定,允许创建地图"; +"地图坐标标准运行期检测合并到进行中请求" = "地图坐标标准运行期检测合并到进行中请求"; +"地图坐标标准运行期检测开始" = "地图坐标标准运行期检测开始"; +"地图坐标标准运行期检测结果已过期,取消写入" = "地图坐标标准运行期检测结果已过期,取消写入"; +"地图坐标标准运行期检测完成,标准未变化" = "地图坐标标准运行期检测完成,标准未变化"; +"地图坐标标准运行期检测发现切换" = "地图坐标标准运行期检测发现切换"; +"地图坐标标准运行期检测失败,保留当前标准" = "地图坐标标准运行期检测失败,保留当前标准"; +"地图坐标标准运行期检测已取消" = "地图坐标标准运行期检测已取消"; +"实时定位不覆盖固定锚点的明确检测结果" = "实时定位不覆盖固定锚点的明确检测结果"; +"实时定位确认兜底地图坐标标准无需修正" = "实时定位确认兜底地图坐标标准无需修正"; +"实时定位修正启动兜底地图坐标标准" = "实时定位修正启动兜底地图坐标标准"; +"第三方代理已保存 WGS-84 坐标" = "第三方代理已保存 WGS-84 坐标"; +"第三方代理坐标已清除" = "第三方代理坐标已清除"; +"第三方代理请求失败" = "第三方代理请求失败"; +"第三方代理坐标同步成功" = "第三方代理坐标同步成功"; +"同步坐标到第三方客户端失败" = "同步坐标到第三方客户端失败"; +"验证结果" = "验证结果"; +"验证失败" = "验证失败"; +"开启前检测失败,进入对应环境引导" = "开启前检测失败,进入对应环境引导"; +"清除第三方客户端坐标失败" = "清除第三方客户端坐标失败"; +"累计虚拟定位操作次数" = "累计虚拟定位操作次数"; +"已复制坐标" = "已复制坐标"; +"地图坐标标准切换时未找到当前选点缓存" = "地图坐标标准切换时未找到当前选点缓存"; +"地图坐标标准切换后已使用缓存坐标对回显当前选点" = "地图坐标标准切换后已使用缓存坐标对回显当前选点"; +"地图坐标类型已变化" = "地图坐标类型已变化"; +"取消保存收藏:检测期间当前选点已变化" = "取消保存收藏:检测期间当前选点已变化"; +"保存当前选点为收藏" = "保存当前选点为收藏"; +"第三方代理查询返回失败" = "第三方代理查询返回失败"; +"启动后第三方代理状态查询失败" = "启动后第三方代理状态查询失败"; +"检测到 Wi-Fi 网络变化" = "检测到 Wi-Fi 网络变化"; +"网络仍在变化,重新计算环境检测等待时间" = "网络仍在变化,重新计算环境检测等待时间"; +"等待 Wi-Fi 连接稳定后检测" = "等待 Wi-Fi 连接稳定后检测"; +"延时检测已被更新的网络事件取消" = "延时检测已被更新的网络事件取消"; +"稳定等待结束后仍未连接 Wi-Fi,提示检查代理" = "稳定等待结束后仍未连接 Wi-Fi,提示检查代理"; +"开始后台环境检测" = "开始后台环境检测"; +"已有环境检测运行,1 秒后重试" = "已有环境检测运行,1 秒后重试"; +"后台环境检测完成" = "后台环境检测完成"; +"环境检测连续被占用,本次不重复弹窗" = "环境检测连续被占用,本次不重复弹窗"; +"用户点击实时定位" = "用户点击实时定位"; +"MapKit 蓝点尚不可用,启动 CLLocationManager 兜底" = "MapKit 蓝点尚不可用,启动 CLLocationManager 兜底"; +"MapKit 蓝点抢先完成请求,取消 CLLocationManager 兜底" = "MapKit 蓝点抢先完成请求,取消 CLLocationManager 兜底"; +"虚拟定位开启后的 MapKit 蓝点标准判定" = "虚拟定位开启后的 MapKit 蓝点标准判定"; +"登记实时定位请求上下文" = "登记实时定位请求上下文"; +"复用进行中的 CLLocationManager 请求并更新意图上下文" = "复用进行中的 CLLocationManager 请求并更新意图上下文"; +"CLLocationManager 兜底未返回坐标" = "CLLocationManager 兜底未返回坐标"; +"丢弃 CLLocationManager 结果:任务已取消或蓝点已抢先完成" = "丢弃 CLLocationManager 结果:任务已取消或蓝点已抢先完成"; +"实时定位坐标完成标准判断并提交到地图" = "实时定位坐标完成标准判断并提交到地图"; +"MKLocalSearch 返回地点结果" = "MKLocalSearch 返回地点结果"; +"反向地理编码网络失败,准备重试" = "反向地理编码网络失败,准备重试"; +"反向地理编码失败" = "反向地理编码失败"; +"获得搜索结果" = "获得搜索结果"; +"点击收藏点并回显到地图" = "点击收藏点并回显到地图"; +"忽略重复 CLLocationManager 请求" = "忽略重复 CLLocationManager 请求"; +"CLLocationManager 请求入口" = "CLLocationManager 请求入口"; +"授权状态不允许定位" = "授权状态不允许定位"; +"创建 CLLocationManager 请求" = "创建 CLLocationManager 请求"; +"请求前台定位授权" = "请求前台定位授权"; +"定位授权状态变化" = "定位授权状态变化"; +"CLLocationManager 返回样本批次" = "CLLocationManager 返回样本批次"; +"本批次没有可完成当前请求的样本" = "本批次没有可完成当前请求的样本"; +"接受 CLLocationManager 样本并完成请求" = "接受 CLLocationManager 样本并完成请求"; +"定位回调失败" = "定位回调失败"; +"跳过 CLLocationManager 缓存样本" = "跳过 CLLocationManager 缓存样本"; +"等待定位授权超时" = "等待定位授权超时"; +"单次定位超时,切换持续定位" = "单次定位超时,切换持续定位"; +"持续定位超时" = "持续定位超时"; +"开始 CLLocationManager 单次定位" = "开始 CLLocationManager 单次定位"; +"开始 CLLocationManager 持续定位兜底" = "开始 CLLocationManager 持续定位兜底"; +"CLLocationManager 请求完成" = "CLLocationManager 请求完成"; +"CLLocationManager 请求结束但没有坐标" = "CLLocationManager 请求结束但没有坐标"; +"使用 CLLocationManager 新鲜缓存" = "使用 CLLocationManager 新鲜缓存"; +"实时定位按钮直接使用 MapKit 蓝点缓存" = "实时定位按钮直接使用 MapKit 蓝点缓存"; +"主页收到待处理请求所需的 MapKit 蓝点回调" = "主页收到待处理请求所需的 MapKit 蓝点回调"; +"主页收到 CLLocationManager 兜底坐标" = "主页收到 CLLocationManager 兜底坐标"; +"原始实时定位坐标" = "原始实时定位坐标"; +"检查 CLLocationManager 样本" = "检查 CLLocationManager 样本"; +"拒绝 CLLocationManager 样本:坐标或精度无效" = "拒绝 CLLocationManager 样本:坐标或精度无效"; +"MapKit 蓝点更新但 location 为空" = "MapKit 蓝点更新但 location 为空"; +"拒绝 MapKit 蓝点样本:坐标无效" = "拒绝 MapKit 蓝点样本:坐标无效"; +"拒绝 MapKit 蓝点样本:水平精度无效" = "拒绝 MapKit 蓝点样本:水平精度无效"; +"音频中断恢复" = "音频中断恢复"; +"音频会话失败" = "音频会话失败"; +"无法创建静音音频缓冲区" = "无法创建静音音频缓冲区"; +"引擎启动失败" = "引擎启动失败"; +"后台保活已启动(静音音频)" = "后台保活已启动(静音音频)"; +"后台保活已停止" = "后台保活已停止"; +"保存当前图钉失败" = "保存当前图钉失败"; +"存储缩放" = "存储缩放"; +"旧坐标数据迁移完成" = "旧坐标数据迁移完成"; +"远程版本配置加载成功" = "远程版本配置加载成功"; +"版本配置源不可用,尝试下一地址" = "版本配置源不可用,尝试下一地址"; +"版本配置加载失败,继续使用内置配置" = "版本配置加载失败,继续使用内置配置"; +"版本说明源不可用,尝试下一地址" = "版本说明源不可用,尝试下一地址"; +"版本说明加载失败,将使用最新 Release 页面" = "版本说明加载失败,将使用最新 Release 页面"; +"复用设备钥匙串中的 CA" = "复用设备钥匙串中的 CA"; +"旧 CA 已迁移到设备钥匙串" = "旧 CA 已迁移到设备钥匙串"; +"已生成并保存设备专属 CA" = "已生成并保存设备专属 CA"; +"已删除设备 CA,等待重新生成" = "已删除设备 CA,等待重新生成"; +"钥匙串中的 CA 无效,准备回退" = "钥匙串中的 CA 无效,准备回退"; +"删除旧 CA 文件失败,将在下次启动重试" = "删除旧 CA 文件失败,将在下次启动重试"; +"无法解析 CA 证书 PEM" = "无法解析 CA 证书 PEM"; +"无法创建 SecTrust" = "无法创建 SecTrust"; +"SecTrust 评估返回错误" = "SecTrust 评估返回错误"; +"CA 证书已被系统信任" = "CA 证书已被系统信任"; +"CA 证书未被系统信任" = "CA 证书未被系统信任"; +"调用 Go Core 生成 CA" = "调用 Go Core 生成 CA"; +"Go Core CA 生成成功" = "Go Core CA 生成成功"; +"本地证书服务已在运行" = "本地证书服务已在运行"; +"调用 Go Core 启动本地证书服务" = "调用 Go Core 启动本地证书服务"; +"本地证书服务启动成功" = "本地证书服务启动成功"; +"停止本地证书服务" = "停止本地证书服务"; +"开始第三方代理连接检测" = "开始第三方代理连接检测"; +"第三方代理连接检测通过" = "第三方代理连接检测通过"; +"第三方代理连接检测失败" = "第三方代理连接检测失败"; +"关闭代理前已同步关闭虚拟定位" = "关闭代理前已同步关闭虚拟定位"; +"切换 APP 模式前无法清除第三方坐标" = "切换 APP 模式前无法清除第三方坐标"; +"设置页第三方连接检测通过" = "设置页第三方连接检测通过"; +"设置页第三方连接检测失败" = "设置页第三方连接检测失败"; +"地图实际显示坐标" = "地图实际显示坐标"; +"App回到前台" = "App回到前台"; +"App已确认地图标准" = "App已确认地图标准"; +"CLLocationManager请求中" = "CLLocationManager请求中"; +"Go proxy 启动失败" = "Go proxy 启动失败"; +"MapKit地图蓝点" = "MapKit地图蓝点"; +"MapKit蓝点新样本" = "MapKit蓝点新样本"; +"MapKit蓝点缓存" = "MapKit蓝点缓存"; +"SSID可读取" = "SSID可读取"; +"WLOC写入标准" = "WLOC写入标准"; +"WLOC目标标准" = "WLOC目标标准"; +"Wi-Fi接口" = "Wi-Fi接口"; +"intent选点revision" = "intent选点revision"; +"manager请求中" = "manager请求中"; +"上下文存在" = "上下文存在"; +"事件原因" = "事件原因"; +"任务已取消" = "任务已取消"; +"任务已存在" = "任务已存在"; +"使用兜底" = "使用兜底"; +"保存收藏" = "保存收藏"; +"保存数据包含" = "保存数据包含"; +"保持未启用" = "保持未启用"; +"保留原第三方坐标" = "保留原第三方坐标"; +"保留已启用状态" = "保留已启用状态"; +"保留标准" = "保留标准"; +"修正兜底标准" = "修正兜底标准"; +"内存缓存存在" = "内存缓存存在"; +"初始坐标来源" = "初始坐标来源"; +"初始来源" = "初始来源"; +"初始阶段" = "初始阶段"; +"判定规则" = "判定规则"; +"原兜底来源" = "原兜底来源"; +"原因" = "原因"; +"取值字段" = "取值字段"; +"可显示不再提醒" = "可显示不再提醒"; +"启动代理…" = "启动代理…"; +"命中林士街" = "命中林士街"; +"固定锚点" = "固定锚点"; +"固定锚点查询超过5秒" = "固定锚点查询超过5秒"; +"固定锚点查询返回空结果" = "固定锚点查询返回空结果"; +"国内标准(GCJ-02)" = "国内标准(GCJ-02)"; +"国内转换区域" = "国内转换区域"; +"国外非转换区域" = "国外非转换区域"; +"国际标准(WGS-84)" = "国际标准(WGS-84)"; +"国际标准(WGS-84)+国内标准(GCJ-02)" = "国际标准(WGS-84)+国内标准(GCJ-02)"; +"图钉已按新类型重设" = "图钉已按新类型重设"; +"地图取值字段" = "地图取值字段"; +"地图标准" = "地图标准"; +"坐标有效" = "坐标有效"; +"坐标标准" = "坐标标准"; +"垂直精度米" = "垂直精度米"; +"基础校验通过" = "基础校验通过"; +"处理建议" = "处理建议"; +"失败时提示" = "失败时提示"; +"实时定位存在" = "实时定位存在"; +"实时定位服务区域" = "实时定位服务区域"; +"客户端模式" = "客户端模式"; +"尝试" = "尝试"; +"已取消位置更新" = "已取消位置更新"; +"已恢复真实定位" = "已恢复真实定位"; +"已清理" = "已清理"; +"已重置" = "已重置"; +"开启" = "开启"; +"异步地理编码" = "异步地理编码"; +"当前地图标准" = "当前地图标准"; +"当前客户端" = "当前客户端"; +"当前标准" = "当前标准"; +"当前选点revision" = "当前选点revision"; +"恢复状态" = "恢复状态"; +"批次索引" = "批次索引"; +"持久化字段" = "持久化字段"; +"授权状态" = "授权状态"; +"授权状态rawValue" = "授权状态rawValue"; +"探测失败原因" = "探测失败原因"; +"搜索结果" = "搜索结果"; +"操作" = "操作"; +"新类型" = "新类型"; +"无已保存" = "无已保存"; +"无法判定" = "无法判定"; +"无法启动本地证书服务" = "无法启动本地证书服务"; +"无法生成本地证书" = "无法生成本地证书"; +"日志策略" = "日志策略"; +"旧类型" = "旧类型"; +"显示坐标字段" = "显示坐标字段"; +"最低版本" = "最低版本"; +"最新版本" = "最新版本"; +"最终标准" = "最终标准"; +"最终阶段" = "最终阶段"; +"有坐标" = "有坐标"; +"有效样本数" = "有效样本数"; +"有缓存" = "有缓存"; +"未知错误" = "未知错误"; +"本地 CA 证书或私钥无效" = "本地 CA 证书或私钥无效"; +"无法写入设备钥匙串(%d)" = "无法写入设备钥匙串(%d)"; +"来源" = "来源"; +"来源类型" = "来源类型"; +"林士街" = "林士街"; +"查看诊断日志" = "查看诊断日志"; +"样本年龄秒" = "样本年龄秒"; +"样本数" = "样本数"; +"样本时间" = "样本时间"; +"检查范围" = "检查范围"; +"检测前标准" = "检测前标准"; +"模块拦截、MITM、代理/VPN连接" = "模块拦截、MITM、代理/VPN连接"; +"次数" = "次数"; +"每次开启首次或判定变化" = "每次开启首次或判定变化"; +"水平精度米" = "水平精度米"; +"活动requestID" = "活动requestID"; +"活动阶段" = "活动阶段"; +"海拔米" = "海拔米"; +"满足当前请求时间窗" = "满足当前请求时间窗"; +"点击实时定位" = "点击实时定位"; +"目标所在区域" = "目标所在区域"; +"确认标准" = "确认标准"; +"社区征集客户端数" = "社区征集客户端数"; +"等待秒数" = "等待秒数"; +"系统缓存存在" = "系统缓存存在"; +"结果" = "结果"; +"结果数" = "结果数"; +"结果来源" = "结果来源"; +"缓存" = "缓存"; +"缓存上限秒" = "缓存上限秒"; +"缓存时效通过" = "缓存时效通过"; +"缩放米" = "缩放米"; +"网络可用" = "网络可用"; +"耗时毫秒" = "耗时毫秒"; +"蓝点回调更接近" = "蓝点回调更接近"; +"蓝点缓存" = "蓝点缓存"; +"蓝点缓存存在" = "蓝点缓存存在"; +"蓝点距GCJ目标米" = "蓝点距GCJ目标米"; +"蓝点距WGS目标米" = "蓝点距WGS目标米"; +"触发原因" = "触发原因"; +"诊断位置" = "诊断位置"; +"请求动作" = "请求动作"; +"超时毫秒" = "超时毫秒"; +"输入坐标标准" = "输入坐标标准"; +"连接状态" = "连接状态"; +"选点revision" = "选点revision"; +"选点期间发生变化" = "选点期间发生变化"; +"错误" = "错误"; +"错误类型" = "错误类型"; +"锚点" = "锚点"; +"阶段" = "阶段"; +"首条名称" = "首条名称"; +"首条名称=林士街→GCJ-02,否则→WGS-84" = "首条名称=林士街→GCJ-02,否则→WGS-84"; +"默认国内标准" = "默认国内标准"; +"证书下载地址无效" = "证书下载地址无效"; +"启动代理失败: %@" = "启动代理失败: %@"; diff --git a/Resources/zh-Hant.lproj/InfoPlist.strings b/Resources/zh-Hant.lproj/InfoPlist.strings new file mode 100644 index 0000000..c100f38 --- /dev/null +++ b/Resources/zh-Hant.lproj/InfoPlist.strings @@ -0,0 +1,6 @@ +/* App display name */ +"CFBundleDisplayName" = "Location Spoofer"; + +/* Location permission prompts */ +"NSLocationWhenInUseUsageDescription" = "用於顯示和驗證虛擬定位是否生效"; +"NSLocationAlwaysAndWhenInUseUsageDescription" = "用於顯示和驗證虛擬定位是否生效"; diff --git a/Resources/zh-Hant.lproj/Localizable.strings b/Resources/zh-Hant.lproj/Localizable.strings new file mode 100644 index 0000000..948e6e9 --- /dev/null +++ b/Resources/zh-Hant.lproj/Localizable.strings @@ -0,0 +1,668 @@ +/* Generated from en.lproj/Localizable.strings by Scripts/generate-chinese-localizations.swift. */ +"APP模式" = "APP模式"; +"第三方代理模式" = "第三方代理模式"; +"成功" = "成功"; +"已有验证正在进行" = "已有驗證正在進行"; +"验证已被新位置取代" = "驗證已被新位置取代"; +"证书未信任" = "證書未信任"; +"WiFi代理未配置" = "WiFi代理未配置"; +"坐标写入失败" = "坐標寫入失敗"; +"改写验证失败" = "改寫驗證失敗"; +"运行模式" = "運行模式"; +"模式" = "模式"; +"状态" = "狀態"; +"本机代理" = "本機代理"; +"第三方模块" = "第三方模塊"; +"检测连接" = "檢測連接"; +"虚拟定位" = "虛擬定位"; +"定位模拟" = "定位模擬"; +"运动状态模拟" = "運動狀態模擬"; +"实验性功能,默认关闭。开启后会同时模拟定位响应中的运动状态。" = "實驗性功能,默認關閉。開啓後會同時模擬定位響應中的運動狀態。"; +"随机扰动" = "隨機擾動"; +"开启后,下次同步坐标时会给目标点添加随机偏移(默认半径 50 米),避免位置固定在同一点。" = "開啓後,下次同步坐標時會給目標點添加隨機偏移(默認半徑 50 米),避免位置固定在同一點。"; +"说明" = "說明"; +"工作原理" = "工作原理"; +"应用" = "應用"; +"进入引导页" = "進入引導頁"; +"正在检查…" = "正在檢查…"; +"检查更新" = "檢查更新"; +"版本" = "版本"; +"证书" = "證書"; +"重置证书" = "重置證書"; +"仅删除 App 钥匙串中的设备 CA。iOS 中已经安装的旧证书需要在系统设置里手动移除。" = "僅刪除 App 鑰匙串中的設備 CA。iOS 中已經安裝的舊證書需要在系統設置裡手動移除。"; +"支持" = "支持"; +"使用帮助" = "使用幫助"; +"功能建议" = "功能建議"; +"分享第三方配置" = "分享第三方配置"; +"关于" = "關於"; +"如果觉得好用,欢迎去 GitHub 给项目点个 Star" = "如果覺得好用,歡迎去 GitHub 給項目點個 Star"; +"致谢" = "致謝"; +"核心定位改写逻辑移植自 Yu9191/wloc" = "核心定位改寫邏輯移植自 Yu9191/wloc"; +"设置" = "設置"; +"完成" = "完成"; +"代理操作失败" = "代理操作失敗"; +"重置证书?" = "重置證書?"; +"重置并生成新证书" = "重置並生成新證書"; +"当前虚拟定位和本地代理将停止。App 会删除钥匙串中的设备 CA、立即生成新证书,并打开安装与信任引导。你还需要前往 iOS「设置 → 通用 → VPN 与设备管理」手动删除旧证书,然后重新下载安装并完全信任新证书。" = "當前虛擬定位和本地代理將停止。App 會刪除鑰匙串中的設備 CA、立即生成新證書,並打開安裝與信任引導。你還需要前往 iOS「設置 → 通用 → VPN 與設備管理」手動刪除舊證書,然後重新下載安裝並完全信任新證書。"; +"第三方代理配置" = "第三方代理配置"; +"客户端" = "客戶端"; +"使用国内镜像下载模块" = "使用國內鏡像下載模塊"; +"仅影响之后复制和重新导入的模块地址;已安装模块需要重新导入后切换来源。" = "僅影響之後複製和重新導入的模塊地址;已安裝模塊需要重新導入後切換來源。"; +"验证状态" = "驗證狀態"; +"已复制模块订阅地址" = "已複製模塊訂閱地址"; +"复制模块订阅地址" = "複製模塊訂閱地址"; +"复制 %@" = "複製 %@"; +"已复制 %@" = "已複製 %@"; +"已复制解密域名" = "已複製解密域名"; +"复制解密域名" = "複製解密域名"; +"打开 %@" = "打開 %@"; +"重新打开配置引导" = "重新打開配置引導"; +"Egern 直接使用 Surge 的 .sgmodule 模块。" = "Egern 直接使用 Surge 的 .sgmodule 模塊。"; +"Stash 直接订阅 .stoverride,不要通过 Script Hub 转换。" = "Stash 直接訂閱 .stoverride,不要通過 Script Hub 轉換。"; +"复制模块订阅地址后,在对应代理客户端中添加模块/重写订阅,并为复制的全部域名(含 gsp-ssl.ls.apple.com、bluedot.is.autonavi.com)启用 MITM。第三方客户端保存坐标后,即使关闭本 App,坐标仍由代理客户端持久化并继续生效。" = "複製模塊訂閱地址後,在對應代理客戶端中添加模塊/重寫訂閱,並為複製的全部域名(含 gsp-ssl.ls.apple.com、bluedot.is.autonavi.com)啓用 MITM。第三方客戶端保存坐標後,即使關閉本 App,坐標仍由代理客戶端持久化並繼續生效。"; +"已是最新版本" = "已是最新版本"; +"当前版本 %@,远程最新版本 %@。" = "當前版本 %@,遠程最新版本 %@。"; +"检查更新失败" = "檢查更新失敗"; +"无法获取远程版本信息,请检查网络后重试。" = "無法獲取遠程版本信息,請檢查網絡後重試。"; +"未检测" = "未檢測"; +"已连接,有坐标" = "已連接,有坐標"; +"已连接,无坐标" = "已連接,無坐標"; +"连接失败" = "連接失敗"; +"已开启" = "已開啓"; +"已关闭" = "已關閉"; +"第三方已保存" = "第三方已保存"; +"未保存" = "未保存"; +"未知" = "未知"; +"App 只负责地图选点、收藏和发送 WGS-84 坐标。第三方代理客户端通过模块拦截 Apple WLOC 请求并持久化当前坐标;本模式不启动本机代理,不使用 App 的 CA,也不需要配置 127.0.0.1:8888。" = "App 只負責地圖選點、收藏和發送 WGS-84 坐標。第三方代理客戶端通過模塊攔截 Apple WLOC 請求並持久化當前坐標;本模式不啓動本機代理,不使用 App 的 CA,也不需要配置 127.0.0.1:8888。"; +"App 在设备本地运行一个代理服务器(127.0.0.1:8888)。\n\n通过 WiFi 手动代理配置,让系统发往 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的定位请求经过这个本地代理。代理使用已安装的 CA 证书对 HTTPS 流量做中间人解密,把 Apple 返回的定位坐标改写为你设置的虚拟坐标,再加密返回给系统,从而实现虚拟定位。" = "App 在設備本地運行一個代理服務器(127.0.0.1:8888)。\n\n通過 WiFi 手動代理配置,讓系統發往 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的定位請求經過這個本地代理。代理使用已安裝的 CA 證書對 HTTPS 流量做中間人解密,把 Apple 返回的定位坐標改寫為你設置的虛擬坐標,再加密返回給系統,從而實現虛擬定位。"; +"模式已切换" = "模式已切換"; +"第三方代理模式检测通过。请关闭 Wi-Fi 中的 127.0.0.1:8888 手动代理,避免双重拦截。" = "第三方代理模式檢測通過。請關閉 Wi-Fi 中的 127.0.0.1:8888 手動代理,避免雙重攔截。"; +"APP 模式环境检测通过。请停用第三方 WLOC 模块或代理连接,避免双重拦截。" = "APP 模式環境檢測通過。請停用第三方 WLOC 模塊或代理連接,避免雙重攔截。"; +"证书重置失败" = "證書重置失敗"; +"无法打开客户端" = "無法打開客戶端"; +"无法打开 %@,请确认客户端已安装后手动打开。" = "無法打開 %@,請確認客戶端已安裝後手動打開。"; +"正在初始化地图与本地代理…" = "正在初始化地圖與本地代理…"; +"正在初始化地图…" = "正在初始化地圖…"; +"更新说明暂时无法加载,请前往最新 Release 页面查看。" = "更新說明暫時無法加載,請前往最新 Release 頁面查看。"; +"需要更新" = "需要更新"; +"当前版本 %@ 已停止支持,请更新到 %@ 后继续使用。\n\n%@" = "當前版本 %@ 已停止支持,請更新到 %@ 後繼續使用。\n\n%@"; +"立即更新" = "立即更新"; +"发现新版本" = "發現新版本"; +"当前版本 %@,最新版本 %@。\n\n%@" = "當前版本 %@,最新版本 %@。\n\n%@"; +"前往更新" = "前往更新"; +"稍后" = "稍後"; +"遇到问题时,在这里生成 Bug 报告。系统会运行一次诊断测试,并将完整报告复制到剪切板。跳转到 GitHub 后,请粘贴到“App 生成的诊断报告”字段。" = "遇到問題時,在這裡生成 Bug 報告。系統會運行一次診斷測試,並將完整報告複製到剪切板。跳轉到 GitHub 後,請粘貼到“App 生成的診斷報告”字段。"; +"可复现环境" = "可復現環境"; +"当前设备上问题稳定复现,非偶发性。" = "當前設備上問題穩定復現,非偶發性。"; +"问题描述" = "問題描述"; +"正在生成报告…" = "正在生成報告…"; +"生成 Bug 报告" = "生成 Bug 報告"; +"报告 Bug" = "報告 Bug"; +"已生成" = "已生成"; +"打开 GitHub 表单" = "打開 GitHub 表單"; +"稍后再说" = "稍後再說"; +"Bug 报告已复制到剪切板。请在 GitHub 表单的“App 生成的诊断报告”字段中粘贴并提交。" = "Bug 報告已複製到剪切板。請在 GitHub 表單的“App 生成的診斷報告”字段中粘貼並提交。"; +"过滤日志" = "過濾日誌"; +"暂无运行日志" = "暫無運行日誌"; +"无匹配日志" = "無匹配日誌"; +"运行日志" = "運行日誌"; +"日志自动清理,仅保留近 3 天" = "日誌自動清理,僅保留近 3 天"; +"关闭" = "關閉"; +"复制全部日志" = "複製全部日誌"; +"清空全部日志" = "清空全部日誌"; +"清空所有运行日志?" = "清空所有運行日誌?"; +"清空日志" = "清空日誌"; +"取消" = "取消"; +"正在检测…" = "正在檢測…"; +"环境检测" = "環境檢測"; +"检查第三方模块能否拦截并响应 query 请求;不会写入测试坐标。" = "檢查第三方模塊能否攔截並響應 query 請求;不會寫入測試坐標。"; +"依次检查:本地代理 → CA 证书信任 → Wi-Fi 代理链路。" = "依次檢查:本地代理 → CA 證書信任 → Wi-Fi 代理鏈路。"; +"测试日志" = "測試日誌"; +"已复制" = "已複製"; +"代理运行中" = "代理運行中"; +"代理未运行" = "代理未運行"; +"可修改" = "可修改"; +"不可修改" = "不可修改"; +"环境检测通过" = "環境檢測通過"; +"环境检测失败: %@" = "環境檢測失敗: %@"; +",查看下方日志" = ",查看下方日誌"; +"第三方模块连接通过,已有坐标" = "第三方模塊連接通過,已有坐標"; +"第三方模块连接通过,暂无坐标" = "第三方模塊連接通過,暫無坐標"; +"第三方模块连接失败" = "第三方模塊連接失敗"; +"======== 第三方代理连接检测 ========" = "======== 第三方代理連接檢測 ========"; +"模式: 测试模式" = "模式: 測試模式"; +"请求: wloc-settings/save?action=query" = "請求: wloc-settings/save?action=query"; +"拦截响应: 有效 JSON" = "攔截響應: 有效 JSON"; +"已保存坐标: %@" = "已保存坐標: %@"; +"结果: %@" = "結果: %@"; +"生效说明" = "生效說明"; +"失效说明" = "失效說明"; +"关闭 WiFi 代理" = "關閉 WiFi 代理"; +"知道了" = "知道了"; +"让虚拟定位生效" = "讓虛擬定位生效"; +"确认第三方代理已开启" = "確認第三方代理已開啓"; +"保持已导入的 WLOC 模块、HTTPS 解密和第三方代理/VPN 连接开启。" = "保持已導入的 WLOC 模塊、HTTPS 解密和第三方代理/VPN 連接開啓。"; +"开启飞行模式" = "開啓飛行模式"; +"从控制中心打开飞行模式(点飞机图标),Wi‑Fi 会自动断开。这是为了清除 iOS 的定位缓存。等待 2 秒。" = "從控制中心打開飛行模式(點飛機圖標),Wi‑Fi 會自動斷開。這是為了清除 iOS 的定位緩存。等待 2 秒。"; +"关闭 Wi‑Fi" = "關閉 Wi‑Fi"; +"从控制中心再点一下 Wi‑Fi 图标,确认 Wi‑Fi 已关闭。等待 2 秒。" = "從控制中心再點一下 Wi‑Fi 圖標,確認 Wi‑Fi 已關閉。等待 2 秒。"; +"关闭系统定位服务" = "關閉系統定位服務"; +"打开系统「设置 → 隐私与安全性 → 定位服务」,关闭顶部的总开关。等待 2 秒。" = "打開系統「設置 → 隱私與安全性 → 定位服務」,關閉頂部的總開關。等待 2 秒。"; +"打开 Wi‑Fi,启动虚拟定位" = "打開 Wi‑Fi,啓動虛擬定位"; +"从控制中心打开 Wi‑Fi(飞行模式保持开启),确认第三方代理已连接。坐标已经同步到第三方代理。等待 2 秒。" = "從控制中心打開 Wi‑Fi(飛行模式保持開啓),確認第三方代理已連接。坐標已經同步到第三方代理。等待 2 秒。"; +"从控制中心打开 Wi‑Fi(飞行模式保持开启),进入 App 点底部「开始虚拟定位」。等待 2 秒。" = "從控制中心打開 Wi‑Fi(飛行模式保持開啓),進入 App 點底部「開始虛擬定位」。等待 2 秒。"; +"关闭飞行模式" = "關閉飛行模式"; +"从控制中心关闭飞行模式。等待 2 秒。" = "從控制中心關閉飛行模式。等待 2 秒。"; +"重新开启定位服务" = "重新開啓定位服務"; +"再次进入「设置 → 隐私与安全性 → 定位服务」,打开总开关。完成后打开地图验证定位是否已变化。" = "再次進入「設置 → 隱私與安全性 → 定位服務」,打開總開關。完成後打開地圖驗證定位是否已變化。"; +"还是无法生效?" = "還是無法生效?"; +"操作到第 3 步时关机重启,开机后从第 4 步继续。这样能彻底清除系统缓存的定位数据。" = "操作到第 3 步時關機重啓,開機後從第 4 步繼續。這樣能徹底清除系統緩存的定位數據。"; +"去设置" = "去設置"; +"取消虚拟定位" = "取消虛擬定位"; +"从控制中心打开飞行模式,Wi‑Fi 会自动断开。等待 2 秒。" = "從控制中心打開飛行模式,Wi‑Fi 會自動斷開。等待 2 秒。"; +"从控制中心确认 Wi‑Fi 已关闭。等待 2 秒。" = "從控制中心確認 Wi‑Fi 已關閉。等待 2 秒。"; +"打开「设置 → 隐私与安全性 → 定位服务」,关闭总开关。等待 2 秒。" = "打開「設置 → 隱私與安全性 → 定位服務」,關閉總開關。等待 2 秒。"; +"确认坐标已清除" = "確認坐標已清除"; +"App 已通知第三方代理清除虚拟坐标。保持网络可用并等待 2 秒,让系统重新获取真实定位。" = "App 已通知第三方代理清除虛擬坐標。保持網絡可用並等待 2 秒,讓系統重新獲取真實定位。"; +"打开 Wi‑Fi,移除代理" = "打開 Wi‑Fi,移除代理"; +"从控制中心打开 Wi‑Fi。然后进入「设置 → 无线局域网 → 点 WiFi 右侧 (i) → HTTP 代理」,选择「关闭」后存储。等待 2 秒。" = "從控制中心打開 Wi‑Fi。然後進入「設置 → 無線局域網 → 點 WiFi 右側 (i) → HTTP 代理」,選擇「關閉」後存儲。等待 2 秒。"; +"再次进入「设置 → 隐私与安全性 → 定位服务」打开总开关。打开地图验证定位是否恢复。" = "再次進入「設置 → 隱私與安全性 → 定位服務」打開總開關。打開地圖驗證定位是否恢復。"; +"还是无法取消?" = "還是無法取消?"; +"操作到第 3 步时关机重启,开机后从第 4 步继续。" = "操作到第 3 步時關機重啓,開機後從第 4 步繼續。"; +"移除代理配置" = "移除代理配置"; +"停止虚拟定位后,需要手动移除 WiFi 代理配置,否则可能无法上网。\n\n1. 打开「设置 → 无线局域网」\n2. 点击当前 WiFi 右侧 (i) 图标\n3. 找到「HTTP 代理」\n4. 选择「关闭」\n5. 点右上角「存储」" = "停止虛擬定位後,需要手動移除 WiFi 代理配置,否則可能無法上網。\n\n1. 打開「設置 → 無線局域網」\n2. 點擊當前 WiFi 右側 (i) 圖標\n3. 找到「HTTP 代理」\n4. 選擇「關閉」\n5. 點右上角「存儲」"; +"社区分享成功配置?" = "社區分享成功配置?"; +"去提交" = "去提交"; +"复制模板" = "複製模板"; +"不再提示" = "不再提示"; +"第三方客户端" = "第三方客戶端"; +"你正在使用 %@。点击“去提交”会先复制投稿模板,并在 App 内打开社区页面。采纳后将收录到 README,可选择是否匿名署名。" = "你正在使用 %@。點擊“去提交”會先複製投稿模板,並在 App 內打開社區頁面。採納後將收錄到 README,可選擇是否匿名署名。"; +"已复制投稿模板" = "已複製投稿模板"; +"如果 GitHub 登录或浏览器跳转后模板没有自动填充,可以直接粘贴。" = "如果 GitHub 登錄或瀏覽器跳轉後模板沒有自動填充,可以直接粘貼。"; +"无法直接跳转" = "無法直接跳轉"; +"定位失败" = "定位失敗"; +"打开设置" = "打開設置"; +"无法获取当前定位,请检查定位服务是否已开启" = "無法獲取當前定位,請檢查定位服務是否已開啓"; +"编辑收藏名称" = "編輯收藏名稱"; +"名称" = "名稱"; +"保存" = "保存"; +"修改收藏地点名称" = "修改收藏地點名稱"; +"搜索地点或坐标" = "搜索地點或坐標"; +"日志" = "日誌"; +"更多" = "更多"; +"当前选点" = "當前選點"; +"GCJ-02(国内)" = "GCJ-02(國內)"; +"WGS-84(国际)" = "WGS-84(國際)"; +"无法生效?" = "無法生效?"; +"无法取消?" = "無法取消?"; +"已收藏,点击取消收藏" = "已收藏,點擊取消收藏"; +"收藏当前选点" = "收藏當前選點"; +"搜索或点击地图选点后,保存为收藏。" = "搜索或點擊地圖選點後,保存為收藏。"; +"切换到此处" = "切換到此處"; +"同步到第三方代理" = "同步到第三方代理"; +"检测并同步中…" = "檢測並同步中…"; +"停止第三方虚拟定位" = "停止第三方虛擬定位"; +"开始虚拟定位" = "開始虛擬定位"; +"验证环境中…" = "驗證環境中…"; +"停止虚拟定位" = "停止虛擬定位"; +"当前未连接可用的 Wi-Fi,请连接 Wi-Fi 后配置 127.0.0.1:8888 手动代理。" = "當前未連接可用的 Wi-Fi,請連接 Wi-Fi 後配置 127.0.0.1:8888 手動代理。"; +"第三方代理查询失败" = "第三方代理查詢失敗"; +"未命名" = "未命名"; +"没有找到相关地点" = "沒有找到相關地點"; +"虚拟定位已开启" = "虛擬定位已開啓"; +"不再提醒" = "不再提醒"; +"虚拟定位已关闭" = "虛擬定位已關閉"; +"选择模式" = "選擇模式"; +"配置 Wi-Fi 代理" = "配置 Wi-Fi 代理"; +"初始化 CA 证书" = "初始化 CA 證書"; +"选择客户端" = "選擇客戶端"; +"导入并检测" = "導入並檢測"; +"上一步" = "上一步"; +"开始使用" = "開始使用"; +"操作失败" = "操作失敗"; +"选择运行模式" = "選擇運行模式"; +"后续可在“设置 → 运行模式”中切换。两种模式不要同时拦截 WLOC 请求。" = "後續可在“設置 → 運行模式”中切換。兩種模式不要同時攔截 WLOC 請求。"; +"仅 Wi-Fi" = "僅 Wi-Fi"; +"无外部依赖" = "無外部依賴"; +"App 在设备本地启动代理,通过当前 Wi-Fi 的手动 HTTP 代理改写定位响应。免费自签应用无法使用系统 VPN 的 Network Extension 能力,因此 APP模式不支持蜂窝网络,需要配置 Wi-Fi 代理并安装 App 生成的 CA。" = "App 在設備本地啓動代理,通過當前 Wi-Fi 的手動 HTTP 代理改寫定位響應。免費自簽應用無法使用系統 VPN 的 Network Extension 能力,因此 APP模式不支持蜂窩網絡,需要配置 Wi-Fi 代理並安裝 App 生成的 CA。"; +"测试模式" = "測試模式"; +"App 负责选点,并通过 WLOC 配置接口查询和同步坐标;第三方代理客户端负责网络代理、模块拦截、MITM 和持久化。证书、VPN 与代理连接均由第三方客户端处理。" = "App 負責選點,並通過 WLOC 配置接口查詢和同步坐標;第三方代理客戶端負責網絡代理、模塊攔截、MITM 和持久化。證書、VPN 與代理連接均由第三方客戶端處理。"; +"正在准备 APP模式本地服务…" = "正在準備 APP模式本地服務…"; +"先配置 Wi-Fi 系统代理" = "先配置 Wi-Fi 系統代理"; +"在当前 Wi-Fi 的详情页,将「HTTP 代理」设为「手动」:服务器填 127.0.0.1,端口填 8888。配置后点击下方「完成」。检测会自动判断是 Wi-Fi 代理还是证书信任有问题。" = "在當前 Wi-Fi 的詳情頁,將「HTTP 代理」設為「手動」:服務器填 127.0.0.1,端口填 8888。配置後點擊下方「完成」。檢測會自動判斷是 Wi-Fi 代理還是證書信任有問題。"; +"Wi-Fi 代理设置" = "Wi-Fi 代理設置"; +"1 选择手动,2 填写服务器 127.0.0.1,3 填写端口 8888。" = "1 選擇手動,2 填寫服務器 127.0.0.1,3 填寫端口 8888。"; +"复制地址" = "複製地址"; +"打开 Wi-Fi 设置" = "打開 Wi-Fi 設置"; +"第 1 步:下载证书" = "第 1 步:下載證書"; +"下载本机随机生成的 CA 根证书。私钥仅保存在此设备的钥匙串中,不会随证书文件导出。App 会弹出 Safari 下载页;出现配置描述文件下载提示时,选择「允许」。" = "下載本機隨機生成的 CA 根證書。私鑰僅保存在此設備的鑰匙串中,不會隨證書文件導出。App 會彈出 Safari 下載頁;出現配置描述文件下載提示時,選擇「允許」。"; +"打开下载页" = "打開下載頁"; +"无法准备证书下载页面,请查看诊断日志" = "無法準備證書下載頁面,請查看診斷日誌"; +"第 2 步:安装证书" = "第 2 步:安裝證書"; +"下载完成后打开系统「设置」。如果顶部显示「已下载描述文件」,点进去安装;否则进入「通用 → VPN 与设备管理」,找到 Location Spoofer CA 并完成安装。" = "下載完成後打開系統「設置」。如果頂部顯示「已下載描述文件」,點進去安裝;否則進入「通用 → VPN 與設備管理」,找到 Location Spoofer CA 並完成安裝。"; +"去安装" = "去安裝"; +"安装证书" = "安裝證書"; +"1 在「VPN 与设备管理」中打开 Location Spoofer CA 描述文件并完成安装。" = "1 在「VPN 與設備管理」中打開 Location Spoofer CA 描述文件並完成安裝。"; +"第 3 步:信任证书" = "第 3 步:信任證書"; +"安装后进入「设置 → 通用 → 关于本机 → 证书信任设置」,找到 Location Spoofer CA 并开启完全信任。iOS 保留钥匙串数据时,重装 App 会继续复用同一证书。" = "安裝後進入「設置 → 通用 → 關於本機 → 證書信任設置」,找到 Location Spoofer CA 並開啓完全信任。iOS 保留鑰匙串數據時,重裝 App 會繼續復用同一證書。"; +"去信任" = "去信任"; +"信任证书" = "信任證書"; +"1 在「证书信任设置」中为 Location Spoofer CA 开启完全信任。" = "1 在「證書信任設置」中為 Location Spoofer CA 開啓完全信任。"; +"已完成" = "已完成"; +"已完成 ✓" = "已完成 ✓"; +"iOS 27 beta 6 起,系统已禁止对 gs-loc.apple.com 进行 MITM 拦截。该版本及之后的 beta 版本暂时无法使用本项目,等待后续适配方案。" = "iOS 27 beta 6 起,系統已禁止對 gs-loc.apple.com 進行 MITM 攔截。該版本及之後的 beta 版本暫時無法使用本項目,等待後續適配方案。"; +"选择第三方代理客户端" = "選擇第三方代理客戶端"; +"除 Shadowrocket 外,当前客户端配置尚未完成真机验证,页面只提供模块导入入口和通用配置提醒。" = "除 Shadowrocket 外,當前客戶端配置尚未完成真機驗證,頁面只提供模塊導入入口和通用配置提醒。"; +"第三方客户端适配说明" = "第三方客戶端適配說明"; +"App 不连接远程坐标服务器,而是向 Apple 域名发起一个约定请求。第三方客户端需要在本机拦截该请求、保存 WGS-84 坐标并返回 JSON;定位模块再读取同一份数据,修改 Apple WLOC 响应。" = "App 不連接遠程坐標服務器,而是向 Apple 域名發起一個約定請求。第三方客戶端需要在本機攔截該請求、保存 WGS-84 坐標並返回 JSON;定位模塊再讀取同一份數據,修改 Apple WLOC 響應。"; +"配置接口" = "配置接口"; +"查询:GET ?action=query\n保存:GET ?lon=<经度>&lat=<纬度>&acc=<精度>\n清除:GET ?action=clear" = "查詢:GET ?action=query\n保存:GET ?lon=<經度>&lat=<緯度>&acc=<精度>\n清除:GET ?action=clear"; +"返回格式" = "返回格式"; +"适配要求" = "適配要求"; +"客户端需要支持请求脚本、持久化存储、HTTP 200 JSON 响应、Apple WLOC 响应脚本,以及 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的 HTTPS 解密。保存接口和 WLOC 响应脚本必须读取同一份持久化数据。" = "客戶端需要支持請求腳本、持久化存儲、HTTP 200 JSON 響應、Apple WLOC 響應腳本,以及 Apple 定位域名(gs-loc.apple.com、gsp-ssl.ls.apple.com、bluedot.is.autonavi.com 等)的 HTTPS 解密。保存接口和 WLOC 響應腳本必須讀取同一份持久化數據。"; +"检测到第三方代理连接异常,请检查模块、MITM 和代理连接后重新检测。" = "檢測到第三方代理連接異常,請檢查模塊、MITM 和代理連接後重新檢測。"; +"第 1 步:导入 %@ 模块" = "第 1 步:導入 %@ 模塊"; +"复制 %@ 的模块订阅地址。" = "複製 %@ 的模塊訂閱地址。"; +"打开 Shadowrocket,进入“配置 → 模块”。" = "打開 Shadowrocket,進入“配置 → 模塊”。"; +"打开 %@。" = "打開 %@。"; +"进入 Shadowrocket 配置" = "進入 Shadowrocket 配置"; +"1 点击「模块」进入模块列表,2 可打开当前本地配置详情。" = "1 點擊「模塊」進入模塊列表,2 可打開當前本地配置詳情。"; +"点击右上角“+”,粘贴模块订阅地址并导入,然后确认模块已启用。" = "點擊右上角“+”,粘貼模塊訂閱地址並導入,然後確認模塊已啓用。"; +"导入 Shadowrocket 模块" = "導入 Shadowrocket 模塊"; +"1 点击右上角加号导入模块,2 确认模块已启用。" = "1 點擊右上角加號導入模塊,2 確認模塊已啓用。"; +"在 %@ 中导入刚才复制的模块订阅地址。" = "在 %@ 中導入剛才複製的模塊訂閱地址。"; +"第 2 步:完成 %@ 配置" = "第 2 步:完成 %@ 配置"; +"请在 %@ 中完成相应配置。" = "請在 %@ 中完成相應配置。"; +"配置时请复制下方全部解密域名(含 gsp-ssl.ls.apple.com、bluedot.is.autonavi.com)。" = "配置時請複製下方全部解密域名(含 gsp-ssl.ls.apple.com、bluedot.is.autonavi.com)。"; +"第 2 步:配置 HTTPS 解密" = "第 2 步:配置 HTTPS 解密"; +"进入“配置 → 本地文件”,找到带黄点的配置,点击右侧 i 图标。" = "進入“配置 → 本地文件”,找到帶黃點的配置,點擊右側 i 圖標。"; +"进入“HTTPS 解密”,开启解密开关。" = "進入“HTTPS 解密”,開啓解密開關。"; +"在域名列表中添加下方复制的全部解密域名。" = "在域名列表中添加下方複製的全部解密域名。"; +"配置 HTTPS 解密" = "配置 HTTPS 解密"; +"1 开启 HTTPS 解密,2 添加复制的全部解密域名,3 打开证书设置。" = "1 開啓 HTTPS 解密,2 添加複製的全部解密域名,3 打開證書設置。"; +"按 Shadowrocket 提示生成并完成证书授权。" = "按 Shadowrocket 提示生成並完成證書授權。"; +"授权 Shadowrocket 证书" = "授權 Shadowrocket 證書"; +"1 打开 Shadowrocket 证书项并按提示安装、授权。" = "1 打開 Shadowrocket 證書項並按提示安裝、授權。"; +"返回 HTTPS 解密页面,点击右上角勾号保存,然后开启代理。" = "返回 HTTPS 解密頁面,點擊右上角勾號保存,然後開啓代理。"; +"打开 Shadowrocket 继续配置" = "打開 Shadowrocket 繼續配置"; +"App 只能唤起 Shadowrocket,无法通过公开接口直接跳转到“模块”或“HTTPS 解密”页面。" = "App 只能喚起 Shadowrocket,無法通過公開接口直接跳轉到“模塊”或“HTTPS 解密”頁面。"; +"轻点查看大图" = "輕點查看大圖"; +"证书尚未安装或信任" = "證書尚未安裝或信任"; +"Wi-Fi 代理未正确设置" = "Wi-Fi 代理未正確設置"; +"本地代理未能启动" = "本地代理未能啓動"; +"检测仍在进行" = "檢測仍在進行"; +"检测结果已过期" = "檢測結果已過期"; +"定位改写检测失败" = "定位改寫檢測失敗"; +"接口连接失败" = "接口連接失敗"; +"本地代理初始化失败:%@" = "本地代理初始化失敗:%@"; +"✓ 定位环境正常" = "✓ 定位環境正常"; +"CA 证书未安装或未信任" = "CA 證書未安裝或未信任"; +"Wi-Fi 代理未正确设置,请检查 127.0.0.1:8888" = "Wi-Fi 代理未正確設置,請檢查 127.0.0.1:8888"; +"请手动打开「设置」,找到本 App 后检查定位权限。" = "請手動打開「設置」,找到本 App 後檢查定位權限。"; +"请手动打开「设置 → 通用」。" = "請手動打開「設置 → 通用」。"; +"请手动打开「设置 → 无线局域网」,进入当前 Wi-Fi 的详情页。" = "請手動打開「設置 → 無線局域網」,進入當前 Wi-Fi 的詳情頁。"; +"请手动打开「设置 → 隐私与安全性 → 定位服务」。" = "請手動打開「設置 → 隱私與安全性 → 定位服務」。"; +"第三方代理返回了无法识别的数据" = "第三方代理返回了無法識別的數據"; +"请求未被第三方代理模块拦截,请检查模块、MITM 和代理连接" = "請求未被第三方代理模塊攔截,請檢查模塊、MITM 和代理連接"; +"第三方代理保存的坐标与当前选点不一致" = "第三方代理保存的坐標與當前選點不一致"; +"第三方代理请求失败:%@" = "第三方代理請求失敗:%@"; +"检查模块、MITM、证书和代理/VPN连接" = "檢查模塊、MITM、證書和代理/VPN連接"; +"第三方代理拒绝保存坐标" = "第三方代理拒絕保存坐標"; +"第三方代理清除坐标失败" = "第三方代理清除坐標失敗"; +"已有第三方代理请求正在执行" = "已有第三方代理請求正在執行"; +"配置已提供,尚未验证" = "配置已提供,尚未驗證"; +"已连接,有保存坐标" = "已連接,有保存坐標"; +"已连接,无保存坐标" = "已連接,無保存坐標"; +"连接失败(%@)" = "連接失敗(%@)"; +"当前客户端:%@" = "當前客戶端:%@"; +"配置接口:/wloc-settings/save" = "配置接口:/wloc-settings/save"; +"请求动作:WLOC query" = "請求動作:WLOC query"; +"检查范围:模块拦截、MITM、证书、代理/VPN 连接" = "檢查範圍:模塊攔截、MITM、證書、代理/VPN 連接"; +"连接状态:%@" = "連接狀態:%@"; +"检测结果:失败" = "檢測結果:失敗"; +"耗时:%lld ms" = "耗時:%lld ms"; +"错误类型:%@" = "錯誤類型:%@"; +"错误详情:%@" = "錯誤詳情:%@"; +"处理建议:%@。" = "處理建議:%@。"; +"======== 第三方代理运行检测 ========" = "======== 第三方代理運行檢測 ========"; +"触发来源:地图或设置中的第三方代理操作" = "觸發來源:地圖或設置中的第三方代理操作"; +"请求动作:WLOC 配置接口" = "請求動作:WLOC 配置接口"; +"处理建议:确认模块已启用,并检查 MITM、证书和代理/VPN 连接。" = "處理建議:確認模塊已啓用,並檢查 MITM、證書和代理/VPN 連接。"; +"环境信息" = "環境信息"; +"App 版本" = "App 版本"; +"系统版本" = "系統版本"; +"诊断日志" = "診斷日誌"; +"不适用" = "不適用"; +"是" = "是"; +"否" = "否"; +"(无诊断数据)" = "(無診斷數據)"; +"第三方代理测试模式:模块连接成功;已保存坐标=%@" = "第三方代理測試模式:模塊連接成功;已保存坐標=%@"; +"第三方代理测试模式:模块连接失败;%@" = "第三方代理測試模式:模塊連接失敗;%@"; +"======== 代理验证测试 ========" = "======== 代理驗證測試 ========"; +"App 版本: %@" = "App 版本: %@"; +"系统版本: iOS %@" = "系統版本: iOS %@"; +"[步骤 A] 检查代理是否运行…" = "[步驟 A] 檢查代理是否運行…"; +" 端口: 127.0.0.1:8888" = " 端口: 127.0.0.1:8888"; +" ⚠ 代理未运行,尝试启动…" = " ⚠ 代理未運行,嘗試啓動…"; +" ✗ 启动失败: %@" = " ✗ 啓動失敗: %@"; +" ✓ 代理启动成功" = " ✓ 代理啓動成功"; +" ✓ 代理已在运行中" = " ✓ 代理已在運行中"; +"[步骤 B] 检测证书与 WiFi 代理…" = "[步驟 B] 檢測證書與 WiFi 代理…"; +" 方式: 请求 baidu.com/paopao-verify-" = " 方式: 請求 baidu.com/paopao-verify-"; +" 结果判定: TLS 错误=证书问题 / 响应不匹配=代理未配置 / 匹配=通过" = " 結果判定: TLS 錯誤=證書問題 / 響應不匹配=代理未配置 / 匹配=通過"; +" ✗ 无法生成验证 token" = " ✗ 無法生成驗證 token"; +" ✓ 证书已信任,WiFi 代理已配置" = " ✓ 證書已信任,WiFi 代理已配置"; +" ✗ 响应不匹配: HTTP %lld, %lld bytes,WiFi 代理未配置" = " ✗ 響應不匹配: HTTP %lld, %lld bytes,WiFi 代理未配置"; +" ✗ 请求失败 [%@ code=%lld]: %@" = " ✗ 請求失敗 [%@ code=%lld]: %@"; +" TLS/证书校验失败,CA 证书未信任" = " TLS/證書校驗失敗,CA 證書未信任"; +"======== 环境检测通过 ✓ ========" = "======== 環境檢測通過 ✓ ========"; +" --- 代理日志 ---" = " --- 代理日誌 ---"; +"成功:{\"success\":true,\"longitude\":113.0,\"latitude\":22.0,\"accuracy\":25}\n失败:{\"success\":false,\"error\":\"错误说明\"}" = "成功:{\"success\":true,\"longitude\":113.0,\"latitude\":22.0,\"accuracy\":25}\n失敗:{\"success\":false,\"error\":\"錯誤說明\"}"; +"定位改写脚本源自 Yu9191/wloc,现由本项目维护" = "定位改寫腳本源自 Yu9191/wloc,現由本項目維護"; +"地图" = "地圖"; +"坐标转换" = "坐標轉換"; +"定位" = "定位"; +"实时定位" = "實時定位"; +"提醒" = "提醒"; +"搜索" = "搜索"; +"收藏" = "收藏"; +"缩放" = "縮放"; +"========== App 启动 ==========" = "========== App 啓動 =========="; +"尚未选择运行模式,跳过本地 CA 和代理初始化" = "尚未選擇運行模式,跳過本地 CA 和代理初始化"; +"第三方代理测试模式:跳过本地 CA、代理和环境检测" = "第三方代理測試模式:跳過本地 CA、代理和環境檢測"; +"旧坐标数据迁移失败,将在下次启动重试" = "舊坐標數據遷移失敗,將在下次啓動重試"; +"地图坐标标准初始化完成,开始后续启动流程" = "地圖坐標標準初始化完成,開始後續啓動流程"; +"没有持久化图钉,地图创建前请求实时定位" = "沒有持久化圖釘,地圖創建前請求實時定位"; +"已使用实时定位准备唯一初始地图状态" = "已使用實時定位準備唯一初始地圖狀態"; +"地图创建前取得的初始实时位置(WGS-84)" = "地圖創建前取得的初始實時位置(WGS-84)"; +"地图创建前无法取得实时定位,唯一初始位置使用深圳" = "地圖創建前無法取得實時定位,唯一初始位置使用深圳"; +"已找到持久化图钉,直接准备唯一初始地图状态" = "已找到持久化圖釘,直接準備唯一初始地圖狀態"; +"启动门禁全部完成,现在创建 MapHomeView" = "啓動門禁全部完成,現在創建 MapHomeView"; +"初始化" = "初始化"; +"启动代理 127.0.0.1:8888" = "啓動代理 127.0.0.1:8888"; +"启动代理: 恢复上次 WGS-84 定位" = "啓動代理: 恢復上次 WGS-84 定位"; +"启动成功" = "啓動成功"; +"启动失败" = "啓動失敗"; +"写入坐标" = "寫入坐標"; +"跳过过期坐标写入" = "跳過過期坐標寫入"; +"跳过旧验证坐标恢复" = "跳過舊驗證坐標恢復"; +"运动状态模拟设置已更新" = "運動狀態模擬設置已更新"; +"准备证书下载失败" = "準備證書下載失敗"; +"设置虚拟定位坐标" = "設置虛擬定位坐標"; +"apply失败" = "apply失敗"; +"保存收藏失败" = "保存收藏失敗"; +"本地服务初始化失败" = "本地服務初始化失敗"; +"代理运行模式已切换" = "代理運行模式已切換"; +"已迁移旧版模式初始化状态" = "已遷移舊版模式初始化狀態"; +"地图坐标标准检测已有请求进行中" = "地圖坐標標準檢測已有請求進行中"; +"地图坐标标准检测开始" = "地圖坐標標準檢測開始"; +"地图坐标标准检测获得明确结果" = "地圖坐標標準檢測獲得明確結果"; +"地图坐标标准检测不可用,开始实时定位兜底" = "地圖坐標標準檢測不可用,開始實時定位兜底"; +"地图坐标标准检测使用兜底结果" = "地圖坐標標準檢測使用兜底結果"; +"地图坐标标准检测被取消,保留默认国内标准" = "地圖坐標標準檢測被取消,保留默認國內標準"; +"地图坐标标准已确定,允许创建地图" = "地圖坐標標準已確定,允許創建地圖"; +"地图坐标标准运行期检测合并到进行中请求" = "地圖坐標標準運行期檢測合併到進行中請求"; +"地图坐标标准运行期检测开始" = "地圖坐標標準運行期檢測開始"; +"地图坐标标准运行期检测结果已过期,取消写入" = "地圖坐標標準運行期檢測結果已過期,取消寫入"; +"地图坐标标准运行期检测完成,标准未变化" = "地圖坐標標準運行期檢測完成,標準未變化"; +"地图坐标标准运行期检测发现切换" = "地圖坐標標準運行期檢測發現切換"; +"地图坐标标准运行期检测失败,保留当前标准" = "地圖坐標標準運行期檢測失敗,保留當前標準"; +"地图坐标标准运行期检测已取消" = "地圖坐標標準運行期檢測已取消"; +"实时定位不覆盖固定锚点的明确检测结果" = "實時定位不覆蓋固定錨點的明確檢測結果"; +"实时定位确认兜底地图坐标标准无需修正" = "實時定位確認兜底地圖坐標標準無需修正"; +"实时定位修正启动兜底地图坐标标准" = "實時定位修正啓動兜底地圖坐標標準"; +"第三方代理已保存 WGS-84 坐标" = "第三方代理已保存 WGS-84 坐標"; +"第三方代理坐标已清除" = "第三方代理坐標已清除"; +"第三方代理请求失败" = "第三方代理請求失敗"; +"第三方代理坐标同步成功" = "第三方代理坐標同步成功"; +"同步坐标到第三方客户端失败" = "同步坐標到第三方客戶端失敗"; +"验证结果" = "驗證結果"; +"验证失败" = "驗證失敗"; +"开启前检测失败,进入对应环境引导" = "開啓前檢測失敗,進入對應環境引導"; +"清除第三方客户端坐标失败" = "清除第三方客戶端坐標失敗"; +"累计虚拟定位操作次数" = "累計虛擬定位操作次數"; +"已复制坐标" = "已複製坐標"; +"地图坐标标准切换时未找到当前选点缓存" = "地圖坐標標準切換時未找到當前選點緩存"; +"地图坐标标准切换后已使用缓存坐标对回显当前选点" = "地圖坐標標準切換後已使用緩存坐標對回顯當前選點"; +"地图坐标类型已变化" = "地圖坐標類型已變化"; +"取消保存收藏:检测期间当前选点已变化" = "取消保存收藏:檢測期間當前選點已變化"; +"保存当前选点为收藏" = "保存當前選點為收藏"; +"第三方代理查询返回失败" = "第三方代理查詢返回失敗"; +"启动后第三方代理状态查询失败" = "啓動後第三方代理狀態查詢失敗"; +"检测到 Wi-Fi 网络变化" = "檢測到 Wi-Fi 網絡變化"; +"网络仍在变化,重新计算环境检测等待时间" = "網絡仍在變化,重新計算環境檢測等待時間"; +"等待 Wi-Fi 连接稳定后检测" = "等待 Wi-Fi 連接穩定後檢測"; +"延时检测已被更新的网络事件取消" = "延時檢測已被更新的網絡事件取消"; +"稳定等待结束后仍未连接 Wi-Fi,提示检查代理" = "穩定等待結束後仍未連接 Wi-Fi,提示檢查代理"; +"开始后台环境检测" = "開始後台環境檢測"; +"已有环境检测运行,1 秒后重试" = "已有環境檢測運行,1 秒後重試"; +"后台环境检测完成" = "後台環境檢測完成"; +"环境检测连续被占用,本次不重复弹窗" = "環境檢測連續被佔用,本次不重復彈窗"; +"用户点击实时定位" = "用戶點擊實時定位"; +"MapKit 蓝点尚不可用,启动 CLLocationManager 兜底" = "MapKit 藍點尚不可用,啓動 CLLocationManager 兜底"; +"MapKit 蓝点抢先完成请求,取消 CLLocationManager 兜底" = "MapKit 藍點搶先完成請求,取消 CLLocationManager 兜底"; +"虚拟定位开启后的 MapKit 蓝点标准判定" = "虛擬定位開啓後的 MapKit 藍點標準判定"; +"登记实时定位请求上下文" = "登記實時定位請求上下文"; +"复用进行中的 CLLocationManager 请求并更新意图上下文" = "復用進行中的 CLLocationManager 請求並更新意圖上下文"; +"CLLocationManager 兜底未返回坐标" = "CLLocationManager 兜底未返回坐標"; +"丢弃 CLLocationManager 结果:任务已取消或蓝点已抢先完成" = "丟棄 CLLocationManager 結果:任務已取消或藍點已搶先完成"; +"实时定位坐标完成标准判断并提交到地图" = "實時定位坐標完成標準判斷並提交到地圖"; +"MKLocalSearch 返回地点结果" = "MKLocalSearch 返回地點結果"; +"反向地理编码网络失败,准备重试" = "反向地理編碼網絡失敗,準備重試"; +"反向地理编码失败" = "反向地理編碼失敗"; +"获得搜索结果" = "獲得搜索結果"; +"点击收藏点并回显到地图" = "點擊收藏點並回顯到地圖"; +"忽略重复 CLLocationManager 请求" = "忽略重復 CLLocationManager 請求"; +"CLLocationManager 请求入口" = "CLLocationManager 請求入口"; +"授权状态不允许定位" = "授權狀態不允許定位"; +"创建 CLLocationManager 请求" = "創建 CLLocationManager 請求"; +"请求前台定位授权" = "請求前台定位授權"; +"定位授权状态变化" = "定位授權狀態變化"; +"CLLocationManager 返回样本批次" = "CLLocationManager 返回樣本批次"; +"本批次没有可完成当前请求的样本" = "本批次沒有可完成當前請求的樣本"; +"接受 CLLocationManager 样本并完成请求" = "接受 CLLocationManager 樣本並完成請求"; +"定位回调失败" = "定位回調失敗"; +"跳过 CLLocationManager 缓存样本" = "跳過 CLLocationManager 緩存樣本"; +"等待定位授权超时" = "等待定位授權超時"; +"单次定位超时,切换持续定位" = "單次定位超時,切換持續定位"; +"持续定位超时" = "持續定位超時"; +"开始 CLLocationManager 单次定位" = "開始 CLLocationManager 單次定位"; +"开始 CLLocationManager 持续定位兜底" = "開始 CLLocationManager 持續定位兜底"; +"CLLocationManager 请求完成" = "CLLocationManager 請求完成"; +"CLLocationManager 请求结束但没有坐标" = "CLLocationManager 請求結束但沒有坐標"; +"使用 CLLocationManager 新鲜缓存" = "使用 CLLocationManager 新鮮緩存"; +"实时定位按钮直接使用 MapKit 蓝点缓存" = "實時定位按鈕直接使用 MapKit 藍點緩存"; +"主页收到待处理请求所需的 MapKit 蓝点回调" = "主頁收到待處理請求所需的 MapKit 藍點回調"; +"主页收到 CLLocationManager 兜底坐标" = "主頁收到 CLLocationManager 兜底坐標"; +"原始实时定位坐标" = "原始實時定位坐標"; +"检查 CLLocationManager 样本" = "檢查 CLLocationManager 樣本"; +"拒绝 CLLocationManager 样本:坐标或精度无效" = "拒絕 CLLocationManager 樣本:坐標或精度無效"; +"MapKit 蓝点更新但 location 为空" = "MapKit 藍點更新但 location 為空"; +"拒绝 MapKit 蓝点样本:坐标无效" = "拒絕 MapKit 藍點樣本:坐標無效"; +"拒绝 MapKit 蓝点样本:水平精度无效" = "拒絕 MapKit 藍點樣本:水平精度無效"; +"音频中断恢复" = "音頻中斷恢復"; +"音频会话失败" = "音頻會話失敗"; +"无法创建静音音频缓冲区" = "無法創建靜音音頻緩衝區"; +"引擎启动失败" = "引擎啓動失敗"; +"后台保活已启动(静音音频)" = "後台保活已啓動(靜音音頻)"; +"后台保活已停止" = "後台保活已停止"; +"保存当前图钉失败" = "保存當前圖釘失敗"; +"存储缩放" = "存儲縮放"; +"旧坐标数据迁移完成" = "舊坐標數據遷移完成"; +"远程版本配置加载成功" = "遠程版本配置加載成功"; +"版本配置源不可用,尝试下一地址" = "版本配置源不可用,嘗試下一地址"; +"版本配置加载失败,继续使用内置配置" = "版本配置加載失敗,繼續使用內置配置"; +"版本说明源不可用,尝试下一地址" = "版本說明源不可用,嘗試下一地址"; +"版本说明加载失败,将使用最新 Release 页面" = "版本說明加載失敗,將使用最新 Release 頁面"; +"复用设备钥匙串中的 CA" = "復用設備鑰匙串中的 CA"; +"旧 CA 已迁移到设备钥匙串" = "舊 CA 已遷移到設備鑰匙串"; +"已生成并保存设备专属 CA" = "已生成並保存設備專屬 CA"; +"已删除设备 CA,等待重新生成" = "已刪除設備 CA,等待重新生成"; +"钥匙串中的 CA 无效,准备回退" = "鑰匙串中的 CA 無效,準備回退"; +"删除旧 CA 文件失败,将在下次启动重试" = "刪除舊 CA 文件失敗,將在下次啓動重試"; +"无法解析 CA 证书 PEM" = "無法解析 CA 證書 PEM"; +"无法创建 SecTrust" = "無法創建 SecTrust"; +"SecTrust 评估返回错误" = "SecTrust 評估返回錯誤"; +"CA 证书已被系统信任" = "CA 證書已被系統信任"; +"CA 证书未被系统信任" = "CA 證書未被系統信任"; +"调用 Go Core 生成 CA" = "調用 Go Core 生成 CA"; +"Go Core CA 生成成功" = "Go Core CA 生成成功"; +"本地证书服务已在运行" = "本地證書服務已在運行"; +"调用 Go Core 启动本地证书服务" = "調用 Go Core 啓動本地證書服務"; +"本地证书服务启动成功" = "本地證書服務啓動成功"; +"停止本地证书服务" = "停止本地證書服務"; +"开始第三方代理连接检测" = "開始第三方代理連接檢測"; +"第三方代理连接检测通过" = "第三方代理連接檢測通過"; +"第三方代理连接检测失败" = "第三方代理連接檢測失敗"; +"关闭代理前已同步关闭虚拟定位" = "關閉代理前已同步關閉虛擬定位"; +"切换 APP 模式前无法清除第三方坐标" = "切換 APP 模式前無法清除第三方坐標"; +"设置页第三方连接检测通过" = "設置頁第三方連接檢測通過"; +"设置页第三方连接检测失败" = "設置頁第三方連接檢測失敗"; +"地图实际显示坐标" = "地圖實際顯示坐標"; +"App回到前台" = "App回到前台"; +"App已确认地图标准" = "App已確認地圖標準"; +"CLLocationManager请求中" = "CLLocationManager請求中"; +"Go proxy 启动失败" = "Go proxy 啓動失敗"; +"MapKit地图蓝点" = "MapKit地圖藍點"; +"MapKit蓝点新样本" = "MapKit藍點新樣本"; +"MapKit蓝点缓存" = "MapKit藍點緩存"; +"SSID可读取" = "SSID可讀取"; +"WLOC写入标准" = "WLOC寫入標準"; +"WLOC目标标准" = "WLOC目標標準"; +"Wi-Fi接口" = "Wi-Fi接口"; +"intent选点revision" = "intent選點revision"; +"manager请求中" = "manager請求中"; +"上下文存在" = "上下文存在"; +"事件原因" = "事件原因"; +"任务已取消" = "任務已取消"; +"任务已存在" = "任務已存在"; +"使用兜底" = "使用兜底"; +"保存收藏" = "保存收藏"; +"保存数据包含" = "保存數據包含"; +"保持未启用" = "保持未啓用"; +"保留原第三方坐标" = "保留原第三方坐標"; +"保留已启用状态" = "保留已啓用狀態"; +"保留标准" = "保留標準"; +"修正兜底标准" = "修正兜底標準"; +"内存缓存存在" = "內存緩存存在"; +"初始坐标来源" = "初始坐標來源"; +"初始来源" = "初始來源"; +"初始阶段" = "初始階段"; +"判定规则" = "判定規則"; +"原兜底来源" = "原兜底來源"; +"原因" = "原因"; +"取值字段" = "取值字段"; +"可显示不再提醒" = "可顯示不再提醒"; +"启动代理…" = "啓動代理…"; +"命中林士街" = "命中林士街"; +"固定锚点" = "固定錨點"; +"固定锚点查询超过5秒" = "固定錨點查詢超過5秒"; +"固定锚点查询返回空结果" = "固定錨點查詢返回空結果"; +"国内标准(GCJ-02)" = "國內標準(GCJ-02)"; +"国内转换区域" = "國內轉換區域"; +"国外非转换区域" = "國外非轉換區域"; +"国际标准(WGS-84)" = "國際標準(WGS-84)"; +"国际标准(WGS-84)+国内标准(GCJ-02)" = "國際標準(WGS-84)+國內標準(GCJ-02)"; +"图钉已按新类型重设" = "圖釘已按新類型重設"; +"地图取值字段" = "地圖取值字段"; +"地图标准" = "地圖標準"; +"坐标有效" = "坐標有效"; +"坐标标准" = "坐標標準"; +"垂直精度米" = "垂直精度米"; +"基础校验通过" = "基礎校驗通過"; +"处理建议" = "處理建議"; +"失败时提示" = "失敗時提示"; +"实时定位存在" = "實時定位存在"; +"实时定位服务区域" = "實時定位服務區域"; +"客户端模式" = "客戶端模式"; +"尝试" = "嘗試"; +"已取消位置更新" = "已取消位置更新"; +"已恢复真实定位" = "已恢復真實定位"; +"已清理" = "已清理"; +"已重置" = "已重置"; +"开启" = "開啓"; +"异步地理编码" = "異步地理編碼"; +"当前地图标准" = "當前地圖標準"; +"当前客户端" = "當前客戶端"; +"当前标准" = "當前標準"; +"当前选点revision" = "當前選點revision"; +"恢复状态" = "恢復狀態"; +"批次索引" = "批次索引"; +"持久化字段" = "持久化字段"; +"授权状态" = "授權狀態"; +"授权状态rawValue" = "授權狀態rawValue"; +"探测失败原因" = "探測失敗原因"; +"搜索结果" = "搜索結果"; +"操作" = "操作"; +"新类型" = "新類型"; +"无已保存" = "無已保存"; +"无法判定" = "無法判定"; +"无法启动本地证书服务" = "無法啓動本地證書服務"; +"无法生成本地证书" = "無法生成本地證書"; +"日志策略" = "日誌策略"; +"旧类型" = "舊類型"; +"显示坐标字段" = "顯示坐標字段"; +"最低版本" = "最低版本"; +"最新版本" = "最新版本"; +"最终标准" = "最終標準"; +"最终阶段" = "最終階段"; +"有坐标" = "有坐標"; +"有效样本数" = "有效樣本數"; +"有缓存" = "有緩存"; +"未知错误" = "未知錯誤"; +"本地 CA 证书或私钥无效" = "本地 CA 證書或私鑰無效"; +"无法写入设备钥匙串(%d)" = "無法寫入設備鑰匙串(%d)"; +"来源" = "來源"; +"来源类型" = "來源類型"; +"林士街" = "林士街"; +"查看诊断日志" = "查看診斷日誌"; +"样本年龄秒" = "樣本年齡秒"; +"样本数" = "樣本數"; +"样本时间" = "樣本時間"; +"检查范围" = "檢查範圍"; +"检测前标准" = "檢測前標準"; +"模块拦截、MITM、代理/VPN连接" = "模塊攔截、MITM、代理/VPN連接"; +"次数" = "次數"; +"每次开启首次或判定变化" = "每次開啓首次或判定變化"; +"水平精度米" = "水平精度米"; +"活动requestID" = "活動requestID"; +"活动阶段" = "活動階段"; +"海拔米" = "海拔米"; +"满足当前请求时间窗" = "滿足當前請求時間窗"; +"点击实时定位" = "點擊實時定位"; +"目标所在区域" = "目標所在區域"; +"确认标准" = "確認標準"; +"社区征集客户端数" = "社區徵集客戶端數"; +"等待秒数" = "等待秒數"; +"系统缓存存在" = "系統緩存存在"; +"结果" = "結果"; +"结果数" = "結果數"; +"结果来源" = "結果來源"; +"缓存" = "緩存"; +"缓存上限秒" = "緩存上限秒"; +"缓存时效通过" = "緩存時效通過"; +"缩放米" = "縮放米"; +"网络可用" = "網絡可用"; +"耗时毫秒" = "耗時毫秒"; +"蓝点回调更接近" = "藍點回調更接近"; +"蓝点缓存" = "藍點緩存"; +"蓝点缓存存在" = "藍點緩存存在"; +"蓝点距GCJ目标米" = "藍點距GCJ目標米"; +"蓝点距WGS目标米" = "藍點距WGS目標米"; +"触发原因" = "觸發原因"; +"诊断位置" = "診斷位置"; +"请求动作" = "請求動作"; +"超时毫秒" = "超時毫秒"; +"输入坐标标准" = "輸入坐標標準"; +"连接状态" = "連接狀態"; +"选点revision" = "選點revision"; +"选点期间发生变化" = "選點期間發生變化"; +"错误" = "錯誤"; +"错误类型" = "錯誤類型"; +"锚点" = "錨點"; +"阶段" = "階段"; +"首条名称" = "首條名稱"; +"首条名称=林士街→GCJ-02,否则→WGS-84" = "首條名稱=林士街→GCJ-02,否則→WGS-84"; +"默认国内标准" = "默認國內標準"; +"证书下载地址无效" = "證書下載地址無效"; +"启动代理失败: %@" = "啓動代理失敗: %@"; diff --git a/Scripts/generate-chinese-localizations.swift b/Scripts/generate-chinese-localizations.swift new file mode 100644 index 0000000..0ab1579 --- /dev/null +++ b/Scripts/generate-chinese-localizations.swift @@ -0,0 +1,34 @@ +import Foundation + +// Chinese source keys are extracted from the maintained English table so all +// shipped languages resolve the same keys. Keep both Chinese tables explicit: +// an absent table falls back to the development language (English), not the key. +let root = URL(fileURLWithPath: #filePath).deletingLastPathComponent().deletingLastPathComponent() +let resources = root.appendingPathComponent("Resources") +let english = try String( + contentsOf: resources.appendingPathComponent("en.lproj/Localizable.strings"), + encoding: .utf8 +) +let pattern = try NSRegularExpression( + pattern: #"^"((?:\\.|[^"\\])*)"\s*=\s*"(?:\\.|[^"\\])*";"#, + options: .anchorsMatchLines +) +let range = NSRange(english.startIndex.. String? in + guard let keyRange = Range(match.range(at: 1), in: english) else { return nil } + return String(english[keyRange]) +} +precondition(!keys.isEmpty && Set(keys).count == keys.count, "English keys must be nonempty and unique") + +for (locale, transform) in [("zh-Hans", false), ("zh-Hant", true)] { + var lines = ["/* Generated from en.lproj/Localizable.strings by Scripts/generate-chinese-localizations.swift. */"] + lines += keys.map { key in + let value = transform + ? (key.applyingTransform(StringTransform(rawValue: "Hans-Hant"), reverse: false) ?? key) + : key + return "\"\(key)\" = \"\(value)\";" + } + let path = resources.appendingPathComponent("\(locale).lproj/Localizable.strings") + try FileManager.default.createDirectory(at: path.deletingLastPathComponent(), withIntermediateDirectories: true) + try (lines.joined(separator: "\n") + "\n").write(to: path, atomically: true, encoding: .utf8) +} diff --git a/Shared/AppLocalization.swift b/Shared/AppLocalization.swift new file mode 100644 index 0000000..f8714a4 --- /dev/null +++ b/Shared/AppLocalization.swift @@ -0,0 +1,33 @@ +import Foundation + +/// Chooses the app language from the first preferred language only. iOS normally +/// scans the whole preference list, which can select Chinese when Italian is first +/// and Chinese is second; this app intentionally falls back to English instead. +enum AppLocalization { + static func identifier(for preferredLanguages: [String]) -> String { + guard let first = preferredLanguages.first, + Locale(identifier: first).languageCode == "zh" else { + return "en" + } + return Bundle.preferredLocalizations( + from: ["zh-Hans", "zh-Hant"], forPreferences: [first] + ).first ?? "zh-Hans" + } + + static let identifier = identifier(for: Locale.preferredLanguages) + static let locale = Locale(identifier: identifier) + + // An explicit .lproj bundle also covers String(localized:) calls made outside + // SwiftUI views, where the view's locale environment is not available. + private static let localizedBundle: Bundle = { + guard let path = Bundle.main.path(forResource: identifier, ofType: "lproj"), + let bundle = Bundle(path: path) else { + return .main + } + return bundle + }() + + static func string(_ value: String.LocalizationValue) -> String { + String(localized: value, bundle: localizedBundle) + } +} diff --git a/Shared/AppRemoteConfiguration.swift b/Shared/AppRemoteConfiguration.swift index 507a6b8..de8de37 100644 --- a/Shared/AppRemoteConfiguration.swift +++ b/Shared/AppRemoteConfiguration.swift @@ -23,7 +23,7 @@ struct AppRemoteConfiguration: Decodable, Equatable { let communityPromptClients: [String] static let fallback = AppRemoteConfiguration( - latestVersion: "1.0.7", + latestVersion: "1.0.8", minimumSupportedVersion: "1.0.0", communityPromptClients: [ ThirdPartyProxyClient.surge.rawValue, diff --git a/Shared/CertificateAuthorityStore.swift b/Shared/CertificateAuthorityStore.swift index 8c4af76..1f75317 100644 --- a/Shared/CertificateAuthorityStore.swift +++ b/Shared/CertificateAuthorityStore.swift @@ -13,8 +13,8 @@ enum CertificateAuthorityStoreError: LocalizedError { var errorDescription: String? { switch self { - case .invalidAuthority: return String(localized: "本地 CA 证书或私钥无效") - case let .keychain(status): return String(localized: "无法写入设备钥匙串(\(status))") + case .invalidAuthority: return AppLocalization.string("本地 CA 证书或私钥无效") + case let .keychain(status): return AppLocalization.string("无法写入设备钥匙串(\(status))") } } } diff --git a/Shared/CoreBridge.swift b/Shared/CoreBridge.swift index 13d5c0e..73d6e10 100644 --- a/Shared/CoreBridge.swift +++ b/Shared/CoreBridge.swift @@ -12,8 +12,8 @@ enum CoreBridgeError: LocalizedError { var errorDescription: String? { switch self { - case .generationFailed: return String(localized: "无法生成本地证书") - case .serverStartFailed: return String(localized: "无法启动本地证书服务") + case .generationFailed: return AppLocalization.string("无法生成本地证书") + case .serverStartFailed: return AppLocalization.string("无法启动本地证书服务") } } } diff --git a/Shared/ProxyRuntimeMode.swift b/Shared/ProxyRuntimeMode.swift index e1ca921..1854529 100644 --- a/Shared/ProxyRuntimeMode.swift +++ b/Shared/ProxyRuntimeMode.swift @@ -8,8 +8,8 @@ enum ProxyRuntimeMode: String, CaseIterable, Codable, Identifiable { var displayName: String { switch self { - case .localWiFi: return String(localized: "APP模式") - case .thirdParty: return String(localized: "第三方代理模式") + case .localWiFi: return AppLocalization.string("APP模式") + case .thirdParty: return AppLocalization.string("第三方代理模式") } } } diff --git a/Shared/RuntimeLog.swift b/Shared/RuntimeLog.swift index 16164bc..991ce6e 100644 --- a/Shared/RuntimeLog.swift +++ b/Shared/RuntimeLog.swift @@ -58,13 +58,13 @@ struct RuntimeLogEntry: Codable, Identifiable, Equatable { } private func localizedDiagnosticText(_ text: String) -> String { - String(localized: String.LocalizationValue(text)) + AppLocalization.string(String.LocalizationValue(text)) } private func localizedDiagnosticValue(_ value: String) -> String { switch value { - case "true": return String(localized: "是") - case "false": return String(localized: "否") + case "true": return AppLocalization.string("是") + case "false": return AppLocalization.string("否") default: return localizedDiagnosticText(value) } } diff --git a/Shared/ThirdPartyProxyManager.swift b/Shared/ThirdPartyProxyManager.swift index f8bca7a..f018836 100644 --- a/Shared/ThirdPartyProxyManager.swift +++ b/Shared/ThirdPartyProxyManager.swift @@ -25,25 +25,25 @@ enum ThirdPartyProxyError: LocalizedError, Equatable { var errorDescription: String? { switch self { case .invalidResponse: - return String(localized: "第三方代理返回了无法识别的数据") + return AppLocalization.string("第三方代理返回了无法识别的数据") case .moduleNotIntercepted: - return String(localized: "请求未被第三方代理模块拦截,请检查模块、MITM 和代理连接") + return AppLocalization.string("请求未被第三方代理模块拦截,请检查模块、MITM 和代理连接") case .rejected(let message): return message case .coordinateMismatch: - return String(localized: "第三方代理保存的坐标与当前选点不一致") + return AppLocalization.string("第三方代理保存的坐标与当前选点不一致") case .network(let message): - return String(localized: "第三方代理请求失败:\(message)") + return AppLocalization.string("第三方代理请求失败:\(message)") } } var recoverySuggestion: String { - return String(localized: "检查模块、MITM、证书和代理/VPN连接") + return AppLocalization.string("检查模块、MITM、证书和代理/VPN连接") } static func recoverySuggestion(for error: Error) -> String { (error as? Self)?.recoverySuggestion - ?? String(localized: "检查模块、MITM、证书和代理/VPN连接") + ?? AppLocalization.string("检查模块、MITM、证书和代理/VPN连接") } } @@ -105,7 +105,7 @@ final class ThirdPartyProxyManager: ObservableObject { randomRadius: RandomRadiusStore.shared.isEnabled ? RandomRadiusStore.shared.radius : 0 )) guard response.success else { - throw ThirdPartyProxyError.rejected(response.error ?? String(localized: "第三方代理拒绝保存坐标")) + throw ThirdPartyProxyError.rejected(response.error ?? AppLocalization.string("第三方代理拒绝保存坐标")) } guard let latitude = response.latitude, let longitude = response.longitude, @@ -126,7 +126,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 ?? String(localized: "第三方代理清除坐标失败")) + throw ThirdPartyProxyError.rejected(response.error ?? AppLocalization.string("第三方代理清除坐标失败")) } activeSettings = nil connectionState = .connected(active: false) @@ -142,7 +142,7 @@ final class ThirdPartyProxyManager: ObservableObject { if response.error?.contains("无已保存") == true { return false } - throw ThirdPartyProxyError.rejected(response.error ?? String(localized: "第三方代理查询失败")) + throw ThirdPartyProxyError.rejected(response.error ?? AppLocalization.string("第三方代理查询失败")) } private enum Action { @@ -153,7 +153,7 @@ final class ThirdPartyProxyManager: ObservableObject { private func perform(action: Action) async throws -> ThirdPartyProxySettingsResponse { guard !isRequesting else { - throw ThirdPartyProxyError.rejected(String(localized: "已有第三方代理请求正在执行")) + throw ThirdPartyProxyError.rejected(AppLocalization.string("已有第三方代理请求正在执行")) } isRequesting = true defer { isRequesting = false } @@ -229,7 +229,7 @@ enum ThirdPartyProxyClient: String, CaseIterable, Identifiable { } var verificationText: String? { - self == .shadowrocket ? nil : String(localized: "配置已提供,尚未验证") + self == .shadowrocket ? nil : AppLocalization.string("配置已提供,尚未验证") } var moduleFileName: String { diff --git a/Shared/VerificationResult.swift b/Shared/VerificationResult.swift index 4976af4..d8ac801 100644 --- a/Shared/VerificationResult.swift +++ b/Shared/VerificationResult.swift @@ -29,14 +29,14 @@ enum VerificationResult: Equatable, Identifiable { /// 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: "改写验证失败") + case .success: return AppLocalization.string("成功") + case .proxyNotRunning: return AppLocalization.string("代理未运行") + case .verificationInProgress: return AppLocalization.string("已有验证正在进行") + case .verificationSuperseded: return AppLocalization.string("验证已被新位置取代") + case .certNotTrusted: return AppLocalization.string("证书未信任") + case .wifiProxyNotConfigured: return AppLocalization.string("WiFi代理未配置") + case .coordinateWriteFailed: return AppLocalization.string("坐标写入失败") + case .patchFailed: return AppLocalization.string("改写验证失败") } } diff --git a/Tests/PaopaoLocationSpooferTests/AppLocalizationTests.swift b/Tests/PaopaoLocationSpooferTests/AppLocalizationTests.swift new file mode 100644 index 0000000..40cceae --- /dev/null +++ b/Tests/PaopaoLocationSpooferTests/AppLocalizationTests.swift @@ -0,0 +1,12 @@ +import XCTest +@testable import PaopaoLocationSpoofer + +final class AppLocalizationTests: XCTestCase { + func testOnlyFirstPreferredLanguageSelectsTheAppLanguage() { + XCTAssertEqual(AppLocalization.identifier(for: ["it-IT", "zh-Hans-CN"]), "en") + XCTAssertEqual(AppLocalization.identifier(for: ["fr-FR", "zh-Hant-TW"]), "en") + XCTAssertEqual(AppLocalization.identifier(for: ["zh-Hans-CN", "it-IT"]), "zh-Hans") + XCTAssertEqual(AppLocalization.identifier(for: ["zh-Hant-TW", "en-US"]), "zh-Hant") + XCTAssertEqual(AppLocalization.identifier(for: []), "en") + } +} diff --git a/Tests/PaopaoLocationSpooferTests/AppRemoteConfigurationTests.swift b/Tests/PaopaoLocationSpooferTests/AppRemoteConfigurationTests.swift index 2f73c3f..d8617fe 100644 --- a/Tests/PaopaoLocationSpooferTests/AppRemoteConfigurationTests.swift +++ b/Tests/PaopaoLocationSpooferTests/AppRemoteConfigurationTests.swift @@ -62,7 +62,7 @@ final class AppRemoteConfigurationTests: XCTestCase { func testFallbackMatchesCurrentProjectPolicy() { let configuration = AppRemoteConfiguration.fallback - XCTAssertEqual(configuration.latestVersion, "1.0.7") + XCTAssertEqual(configuration.latestVersion, "1.0.8") XCTAssertEqual(configuration.minimumSupportedVersion, "1.0.0") XCTAssertFalse(configuration.requestsCommunityPrompt(for: .shadowrocket)) for client in ThirdPartyProxyClient.allCases where client != .shadowrocket { diff --git a/Tests/PaopaoLocationSpooferTests/ThirdPartyProxyManagerTests.swift b/Tests/PaopaoLocationSpooferTests/ThirdPartyProxyManagerTests.swift index 58c3c99..2a58bac 100644 --- a/Tests/PaopaoLocationSpooferTests/ThirdPartyProxyManagerTests.swift +++ b/Tests/PaopaoLocationSpooferTests/ThirdPartyProxyManagerTests.swift @@ -139,7 +139,7 @@ final class ThirdPartyProxyManagerTests: XCTestCase { XCTAssertNil(ThirdPartyProxyClient.shadowrocket.verificationText) XCTAssertEqual( ThirdPartyProxyClient.surge.verificationText, - String(localized: "配置已提供,尚未验证") + AppLocalization.string("配置已提供,尚未验证") ) XCTAssertEqual(ThirdPartyProxyClient.egern.subscriptionURL, ThirdPartyProxyClient.surge.subscriptionURL) XCTAssertTrue(ThirdPartyProxyClient.stash.subscriptionURL.absoluteString.hasPrefix( diff --git a/Tests/localization_contract_test.sh b/Tests/localization_contract_test.sh index c451e2f..307335e 100755 --- a/Tests/localization_contract_test.sh +++ b/Tests/localization_contract_test.sh @@ -31,6 +31,8 @@ RUBY for key in \ '环境信息' \ + '复制 %@' \ + '已复制 %@' \ '诊断日志' \ '======== 代理验证测试 ========' \ '======== 第三方代理连接检测 ========' \ @@ -44,7 +46,7 @@ grep -q 'localizedCategory' "$ROOT/Shared/RuntimeLog.swift" \ || fail "runtime log categories must be localized when rendered" grep -q 'localizedDetailsText' "$ROOT/App/DiagnosticsView.swift" \ || fail "runtime log details must be localized in the diagnostics UI" -grep -q 'String(localized: "诊断日志")' "$ROOT/App/BugReportView.swift" \ +grep -q 'AppLocalization.string("诊断日志")' "$ROOT/App/BugReportView.swift" \ || fail "generated bug reports must localize their diagnostic section" grep -q 'log(" " + e.localizedMessage)' "$ROOT/App/SetupCoordinator.swift" \ || fail "bug-report verification logs must render stored messages in the active language" @@ -55,4 +57,43 @@ if grep -R -n 'raw.githubusercontent.com/Yu9191/wloc' \ fail "deleted Yu9191/wloc repository must not remain a runtime dependency" fi +# Check the real Foundation lookup path, not just the existence of locale files. +grep -q 'developmentLanguage: en' "$ROOT/project.yml" \ + || fail "English must be the development-language fallback" +grep -q ' - zh-Hant' "$ROOT/project.yml" \ + || fail "Traditional Chinese must be a supported region" +for locale in zh-Hans zh-Hant; do + plutil -lint "$ROOT/Resources/$locale.lproj/Localizable.strings" >/dev/null \ + || fail "$locale localization file is invalid" + plutil -lint "$ROOT/Resources/$locale.lproj/InfoPlist.strings" >/dev/null \ + || fail "$locale permission prompts are invalid" +done + +ruby - "$STRINGS" "$ROOT/Resources/zh-Hans.lproj/Localizable.strings" \ + "$ROOT/Resources/zh-Hant.lproj/Localizable.strings" <<'RUBY' || exit 1 +paths = ARGV +keys = paths.map { |path| File.readlines(path).map { |line| line[/^"((?:\\.|[^"\\])*)"\s*=/, 1] }.compact } +abort "FAIL: Chinese tables must cover every English key" unless keys[1] == keys[0] && keys[2] == keys[0] +RUBY + +grep -Fq '"虚拟定位" = "虚拟定位";' "$ROOT/Resources/zh-Hans.lproj/Localizable.strings" \ + || fail "Simplified Chinese must resolve the source key" +grep -Fq '"虚拟定位" = "虛擬定位";' "$ROOT/Resources/zh-Hant.lproj/Localizable.strings" \ + || fail "Traditional Chinese must use Traditional characters" + +swift - <<'SWIFT' || fail "language selection differs from expected behavior" +import Foundation +let available = ["en", "zh-Hans", "zh-Hant"] +for (language, expected) in [ + ("zh-CN", "zh-Hans"), ("zh-TW", "zh-Hant"), ("zh-HK", "zh-Hant"), + ("it-IT", "en"), ("fr-FR", "en") +] { + let selected = Bundle.preferredLocalizations(from: available, forPreferences: [language]).first + guard selected == expected else { + fputs("FAIL: \(language) selected \(selected ?? "nil")\n", stderr) + exit(1) + } +} +SWIFT + echo "PASS: localization and diagnostic export contract" diff --git a/Tests/third_party_mode_contract_test.sh b/Tests/third_party_mode_contract_test.sh index 1d66257..5d89a81 100755 --- a/Tests/third_party_mode_contract_test.sh +++ b/Tests/third_party_mode_contract_test.sh @@ -10,8 +10,8 @@ CONTENT="$ROOT/App/ContentView.swift" SETUP="$ROOT/App/FirstSetupView.swift" SETTINGS="$ROOT/App/SettingsView.swift" -grep -q 'String(localized: "APP模式")' "$MODE" || fail "localized APP mode display name is missing" -grep -q 'String(localized: "第三方代理模式")' "$MODE" || fail "localized third-party mode display name is missing" +grep -q 'AppLocalization.string("APP模式")' "$MODE" || fail "localized APP mode display name is missing" +grep -q 'AppLocalization.string("第三方代理模式")' "$MODE" || fail "localized third-party mode display name is missing" grep -q 'hasSelectedMode' "$MODE" || fail "first-launch mode selection must be persisted" grep -q 'guard runtimeMode.hasSelectedMode else' "$CONTENT" || fail "mode selection must gate startup" grep -q 'phase = .setup' "$CONTENT" || fail "first launch must enter setup before map construction" @@ -106,7 +106,7 @@ grep -q 'setup.requestThirdPartySetup(message: error.localizedDescription)' "$RO || fail "third-party coordinate sync failures must open the import guide" grep -q '检测到第三方代理连接异常,请检查模块、MITM 和代理连接后重新检测' "$SETUP" \ || fail "runtime repair must explain why the import guide opened" -test "$(grep -c 'title: String(localized: \"接口连接失败\")' "$SETUP")" -eq 1 \ +test "$(grep -c 'title: AppLocalization.string(\"接口连接失败\")' "$SETUP")" -eq 1 \ || fail "third-party failure details must render in one shared result area" grep -Fq '当前客户端:\(client.name)' "$SETUP" \ || fail "third-party failure logs must identify the selected client" @@ -142,7 +142,7 @@ test -s "$ROOT/docs/onboarding-screenshots/shadowrocket/shadowrocket-module-impo grep -q 'presentSuccessfulOperationTip(.activation)' "$ROOT/App/MapHomeView.swift" || fail "third-party save must present the activation tip" grep -q 'presentSuccessfulOperationTip(.deactivation)' "$ROOT/App/MapHomeView.swift" || fail "third-party clear must present the deactivation tip" grep -q 'if spoofState == .active' "$ROOT/App/MapHomeView.swift" || fail "manual help must follow the shared spoof state" -grep -q 'MARKETING_VERSION: "1.0.7"' "$ROOT/project.yml" || fail "marketing version must be 1.0.7" -grep -q 'CURRENT_PROJECT_VERSION: "8"' "$ROOT/project.yml" || fail "build version must be 8" +grep -q 'MARKETING_VERSION: "1.0.8"' "$ROOT/project.yml" || fail "marketing version must be 1.0.8" +grep -q 'CURRENT_PROJECT_VERSION: "9"' "$ROOT/project.yml" || fail "build version must be 9" echo "PASS: third-party proxy mode contract" diff --git a/Tests/update_and_contribution_contract_test.sh b/Tests/update_and_contribution_contract_test.sh index afd0054..b6198a8 100644 --- a/Tests/update_and_contribution_contract_test.sh +++ b/Tests/update_and_contribution_contract_test.sh @@ -25,7 +25,7 @@ import sys with open(sys.argv[1], encoding="utf-8") as handle: config = json.load(handle) -assert config["latestVersion"] == "1.0.7" +assert config["latestVersion"] == "1.0.8" assert config["minimumSupportedVersion"] == "1.0.0" assert "shadowrocket" not in config["communityPromptClients"] assert set(config["communityPromptClients"]) == { @@ -130,7 +130,7 @@ grep -Fq 'SafariView(url: destination.url)' "$BUG_REPORT" \ || fail "the App bug report must not be handed to an external GitHub client" grep -Fq 'App 生成的诊断报告' "$BUG_REPORT" \ || fail "the App must tell users where to paste the generated report" -grep -Fq 'String(localized: "第三方客户端")' "$BUG_REPORT" \ +grep -Fq 'AppLocalization.string("第三方客户端")' "$BUG_REPORT" \ || fail "the generated report must identify the selected third-party client" grep -Fq 'Label("报告 Bug"' "$SETTINGS" \ || fail "Settings must identify the support action as a bug report" diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d4e700a..5e89fc1 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,7 @@ ## 已发布 +- [v1.0.8](https://github.com/xweiba/location-spoofer/releases/tag/v1.0.8) — 2026-09-24 - [v1.0.7](https://github.com/xweiba/location-spoofer/releases/tag/v1.0.7) — 2026-09-11 - [v1.0.6](https://github.com/xweiba/location-spoofer/releases/tag/v1.0.6) — 2026-09-01 - [v1.0.5](https://github.com/xweiba/location-spoofer/releases/tag/v1.0.5) — 2026-08-10 diff --git a/project.yml b/project.yml index e44bdbd..9b12e14 100644 --- a/project.yml +++ b/project.yml @@ -4,18 +4,19 @@ options: deploymentTarget: iOS: "15.0" createIntermediateGroups: true - developmentLanguage: zh-Hans + developmentLanguage: en knownRegions: - - zh-Hans - en + - zh-Hans + - zh-Hant - Base settings: base: SWIFT_VERSION: "5.9" - MARKETING_VERSION: "1.0.7" - CURRENT_PROJECT_VERSION: "8" + MARKETING_VERSION: "1.0.8" + CURRENT_PROJECT_VERSION: "9" CODE_SIGN_STYLE: Manual CODE_SIGNING_ALLOWED: "NO" CODE_SIGNING_REQUIRED: "NO" diff --git a/version.txt b/version.txt index 70671d6..6534c54 100644 --- a/version.txt +++ b/version.txt @@ -1,5 +1,5 @@ { - "latestVersion": "1.0.7", + "latestVersion": "1.0.8", "minimumSupportedVersion": "1.0.0", "communityPromptClients": ["surge", "quantumultX", "loon", "stash", "egern"] }