From 4aa4c6aa6cf0ae0d134c317c4c36eb90f21b21b7 Mon Sep 17 00:00:00 2001 From: xweiba Date: Thu, 24 Sep 2026 23:36:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(update):=20=E6=8C=89=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E4=B8=89=E8=AF=AD=E6=9B=B4=E6=96=B0=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E5=B9=B6=E9=87=8D=E5=8F=91=20v1.0.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 30 ++++++++++----- README.md | 4 +- Scripts/generate-release-notes.sh | 1 + Shared/AppRemoteConfiguration.swift | 27 +++++++++---- .../AppRemoteConfigurationTests.swift | 38 ++++++++++++++++++- Tests/third_party_mode_contract_test.sh | 2 +- .../update_and_contribution_contract_test.sh | 12 +++++- docs/CHANGELOG.en.md | 11 ++++++ docs/CHANGELOG.md | 2 + docs/CHANGELOG.zh-Hant.md | 11 ++++++ docs/releases/v1.0.8.en.md | 29 ++++++++++++++ docs/releases/v1.0.8.md | 4 ++ docs/releases/v1.0.8.zh-Hant.md | 29 ++++++++++++++ project.yml | 2 +- 14 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 docs/CHANGELOG.en.md create mode 100644 docs/CHANGELOG.zh-Hant.md create mode 100644 docs/releases/v1.0.8.en.md create mode 100644 docs/releases/v1.0.8.zh-Hant.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2a40389..abc5ac6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,16 +40,26 @@ jobs: - name: Validate archived release notes run: | VERSION="${{ github.ref_name }}" - NOTES_FILE="docs/releases/${VERSION}.md" - if [ ! -s "$NOTES_FILE" ]; then - echo "::error::缺少版本归档 $NOTES_FILE。请在打 tag 前运行 ./Scripts/generate-release-notes.sh $VERSION 并提交。" - exit 1 - fi - if ! grep -Fq "# ${VERSION}" "$NOTES_FILE"; then - echo "::error::$NOTES_FILE 的标题必须包含 # ${VERSION}" - exit 1 - fi - cp "$NOTES_FILE" /tmp/release_notes.md + for NOTES_FILE in \ + "docs/releases/${VERSION}.en.md" \ + "docs/releases/${VERSION}.md" \ + "docs/releases/${VERSION}.zh-Hant.md"; do + if [ ! -s "$NOTES_FILE" ]; then + echo "::error::Missing localized release notes: $NOTES_FILE" + exit 1 + fi + if ! grep -Fq "# ${VERSION}" "$NOTES_FILE"; then + echo "::error::$NOTES_FILE must contain the # ${VERSION} heading" + exit 1 + fi + done + { + cat "docs/releases/${VERSION}.en.md" + printf '\n---\n\n' + cat "docs/releases/${VERSION}.md" + printf '\n---\n\n' + cat "docs/releases/${VERSION}.zh-Hant.md" + } > /tmp/release_notes.md - name: Create Release uses: softprops/action-gh-release@v2 diff --git a/README.md b/README.md index a8270eb..4438572 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.8-2563EB)](docs/CHANGELOG.md) +[![Version](https://img.shields.io/badge/version-v1.0.8-2563EB)](docs/CHANGELOG.en.md) [Features](#feature-overview) · [How It Works](#how-it-works) · @@ -415,7 +415,7 @@ Paste it into the **App-generated diagnostic report** field in the GitHub Issue - [Build guide](docs/BUILD.md) - [Third-party module documentation](docs/THIRD_PARTY_MODULES.md) -- [Changelog](docs/CHANGELOG.md) +- [Changelog](docs/CHANGELOG.en.md) - [中文文档](README.zh-CN.md) - [GitHub Issues](https://github.com/xweiba/location-spoofer/issues) diff --git a/Scripts/generate-release-notes.sh b/Scripts/generate-release-notes.sh index 618cbe4..32fc6d9 100755 --- a/Scripts/generate-release-notes.sh +++ b/Scripts/generate-release-notes.sh @@ -49,3 +49,4 @@ ${COMMITS} EOF echo "Generated $OUTPUT from $RANGE" +echo "Before tagging, add docs/releases/${VERSION}.en.md and docs/releases/${VERSION}.zh-Hant.md." diff --git a/Shared/AppRemoteConfiguration.swift b/Shared/AppRemoteConfiguration.swift index de8de37..c71c348 100644 --- a/Shared/AppRemoteConfiguration.swift +++ b/Shared/AppRemoteConfiguration.swift @@ -153,11 +153,13 @@ enum AppRemoteConfigurationService { return nil } - static func fetchReleaseNotes(version: String) async -> String? { + static func fetchReleaseNotes( + version: String, language: String = AppLocalization.identifier + ) async -> String? { let session = makeSession() defer { session.finishTasksAndInvalidate() } - for url in releaseNotesURLs(version: version) { + for url in releaseNotesURLs(version: version, language: language) { var request = URLRequest(url: url) request.timeoutInterval = 1.5 @@ -166,7 +168,7 @@ enum AppRemoteConfigurationService { guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200, let markdown = String(data: data, encoding: .utf8), - let summary = releaseNotesSummary(markdown) else { + let summary = releaseNotesSummary(markdown, language: language) else { continue } return summary @@ -185,8 +187,17 @@ enum AppRemoteConfigurationService { return nil } - static func releaseNotesURLs(version: String) -> [URL] { - let path = "https://raw.githubusercontent.com/xweiba/location-spoofer/main/docs/releases/v\(version).md" + static func releaseNotesURLs( + version: String, language: String = AppLocalization.identifier + ) -> [URL] { + // The unsuffixed archive remains Simplified Chinese for older clients. + let suffix: String + switch language { + case "zh-Hans": suffix = "" + case "zh-Hant": suffix = ".zh-Hant" + default: suffix = ".en" + } + let path = "https://raw.githubusercontent.com/xweiba/location-spoofer/main/docs/releases/v\(version)\(suffix).md" return [ URL(string: "https://gh-proxy.org/\(path)")!, URL(string: path)! @@ -202,12 +213,14 @@ enum AppRemoteConfigurationService { return URLSession(configuration: sessionConfiguration) } - private static func releaseNotesSummary(_ markdown: String) -> String? { + static func releaseNotesSummary(_ markdown: String, language: String) -> String? { var items: [String] = [] var inMainUpdates = false for rawLine in markdown.components(separatedBy: .newlines) { let line = rawLine.trimmingCharacters(in: .whitespacesAndNewlines) - if line == "## 主要更新" { + let heading = language == "zh-Hans" || language == "zh-Hant" + ? "## 主要更新" : "## Highlights" + if line == heading { inMainUpdates = true continue } diff --git a/Tests/PaopaoLocationSpooferTests/AppRemoteConfigurationTests.swift b/Tests/PaopaoLocationSpooferTests/AppRemoteConfigurationTests.swift index d8617fe..02f713a 100644 --- a/Tests/PaopaoLocationSpooferTests/AppRemoteConfigurationTests.swift +++ b/Tests/PaopaoLocationSpooferTests/AppRemoteConfigurationTests.swift @@ -77,8 +77,44 @@ final class AppRemoteConfigurationTests: XCTestCase { "raw.githubusercontent.com" ) - let releaseNotesURLs = AppRemoteConfigurationService.releaseNotesURLs(version: "1.0.5") + let releaseNotesURLs = AppRemoteConfigurationService.releaseNotesURLs(version: "1.0.8", language: "en") XCTAssertEqual(releaseNotesURLs.first?.host, "gh-proxy.org") XCTAssertEqual(releaseNotesURLs.last?.host, "raw.githubusercontent.com") + XCTAssertTrue(releaseNotesURLs.last?.path.hasSuffix("/docs/releases/v1.0.8.en.md") == true) + XCTAssertTrue(AppRemoteConfigurationService.releaseNotesURLs( + version: "1.0.8", language: "zh-Hans" + ).last?.path.hasSuffix("/docs/releases/v1.0.8.md") == true) + XCTAssertTrue(AppRemoteConfigurationService.releaseNotesURLs( + version: "1.0.8", language: "zh-Hant" + ).last?.path.hasSuffix("/docs/releases/v1.0.8.zh-Hant.md") == true) + XCTAssertTrue(AppRemoteConfigurationService.releaseNotesURLs( + version: "1.0.8", language: "it" + ).last?.path.hasSuffix("/docs/releases/v1.0.8.en.md") == true) + } + + func testReleaseNotesSummaryUsesTheSelectedLanguageHeading() { + let english = "# v1.0.8\n\n## Highlights\n\n- English update\n\n## Installation" + let chinese = "# v1.0.8\n\n## 主要更新\n\n- 中文更新\n\n## 安装" + XCTAssertEqual(AppRemoteConfigurationService.releaseNotesSummary(english, language: "en"), "• English update") + XCTAssertEqual(AppRemoteConfigurationService.releaseNotesSummary(chinese, language: "zh-Hans"), "• 中文更新") + XCTAssertEqual(AppRemoteConfigurationService.releaseNotesSummary(chinese, language: "zh-Hant"), "• 中文更新") + XCTAssertNil(AppRemoteConfigurationService.releaseNotesSummary(chinese, language: "en")) + XCTAssertEqual(AppRemoteConfigurationService.releaseNotesSummary(english, language: "it"), "• English update") + } + + func testArchivedReleaseNotesParseInEachLanguage() throws { + let root = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() + for (language, name) in [ + ("en", "v1.0.8.en.md"), + ("zh-Hans", "v1.0.8.md"), + ("zh-Hant", "v1.0.8.zh-Hant.md") + ] { + let markdown = try String( + contentsOf: root.appendingPathComponent("docs/releases/\(name)"), + encoding: .utf8 + ) + XCTAssertNotNil(AppRemoteConfigurationService.releaseNotesSummary(markdown, language: language)) + } } } diff --git a/Tests/third_party_mode_contract_test.sh b/Tests/third_party_mode_contract_test.sh index 5d89a81..dc9261a 100755 --- a/Tests/third_party_mode_contract_test.sh +++ b/Tests/third_party_mode_contract_test.sh @@ -143,6 +143,6 @@ grep -q 'presentSuccessfulOperationTip(.activation)' "$ROOT/App/MapHomeView.swif 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.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" +grep -q 'CURRENT_PROJECT_VERSION: "10"' "$ROOT/project.yml" || fail "build version must be 10" 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 b6198a8..53273de 100644 --- a/Tests/update_and_contribution_contract_test.sh +++ b/Tests/update_and_contribution_contract_test.sh @@ -54,8 +54,16 @@ grep -q 'static let configurationURLs = \[' "$CONFIG" \ || fail "update detection must retain multiple configuration sources" ! grep -q 'data.count' "$CONFIG" \ || fail "the client must not impose a remote configuration file-size limit" -grep -q 'docs/releases/v\\(version).md' "$CONFIG" \ - || fail "update notes must come from the archived release document" +grep -Fq 'docs/releases/v\(version)\(suffix).md' "$CONFIG" \ + || fail "update notes must come from the language-specific archived release document" +for locale in '' .en .zh-Hant; do + test -s "$ROOT/docs/releases/v${LATEST_VERSION}${locale}.md" \ + || fail "missing localized v${LATEST_VERSION}${locale} release notes" +done +grep -Fq '## Highlights' "$ROOT/docs/releases/v${LATEST_VERSION}.en.md" \ + || fail "English update highlights are missing" +grep -Fq '## 主要更新' "$ROOT/docs/releases/v${LATEST_VERSION}.zh-Hant.md" \ + || fail "Traditional Chinese update highlights are missing" grep -q '/releases/latest' "$CONFIG" \ || fail "missing release notes must fall back to the latest Release page" grep -q '.task { await checkForUpdates() }' "$CONTENT" \ diff --git a/docs/CHANGELOG.en.md b/docs/CHANGELOG.en.md new file mode 100644 index 0000000..339557b --- /dev/null +++ b/docs/CHANGELOG.en.md @@ -0,0 +1,11 @@ +# Changelog + +Release notes are archived under [`docs/releases/`](releases/). + +## Releases + +- [v1.0.8](releases/v1.0.8.en.md) — September 24, 2026 ([简体中文](releases/v1.0.8.md) · [繁體中文](releases/v1.0.8.zh-Hant.md)) +- [v1.0.7](releases/v1.0.7.md) — September 11, 2026 (Chinese) +- [v1.0.6](releases/v1.0.6.md) — September 1, 2026 (Chinese) + +Earlier releases: [GitHub Releases](https://github.com/xweiba/location-spoofer/releases). diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5e89fc1..e1c3a33 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,8 @@ 各版本发布说明见 `docs/releases/` 目录。 +[English](CHANGELOG.en.md) · [繁體中文](CHANGELOG.zh-Hant.md) + ## 已发布 - [v1.0.8](https://github.com/xweiba/location-spoofer/releases/tag/v1.0.8) — 2026-09-24 diff --git a/docs/CHANGELOG.zh-Hant.md b/docs/CHANGELOG.zh-Hant.md new file mode 100644 index 0000000..47cce9b --- /dev/null +++ b/docs/CHANGELOG.zh-Hant.md @@ -0,0 +1,11 @@ +# 更新紀錄 + +各版本的說明存放於 [`docs/releases/`](releases/) 目錄。 + +## 已發佈 + +- [v1.0.8](releases/v1.0.8.zh-Hant.md) — 2026-09-24([English](releases/v1.0.8.en.md) · [简体中文](releases/v1.0.8.md)) +- [v1.0.7](releases/v1.0.7.md) — 2026-09-11(簡體中文) +- [v1.0.6](releases/v1.0.6.md) — 2026-09-01(簡體中文) + +更早的版本:[GitHub Releases](https://github.com/xweiba/location-spoofer/releases)。 diff --git a/docs/releases/v1.0.8.en.md b/docs/releases/v1.0.8.en.md new file mode 100644 index 0000000..56da013 --- /dev/null +++ b/docs/releases/v1.0.8.en.md @@ -0,0 +1,29 @@ +# v1.0.8 + +Release date: September 24, 2026 + +[简体中文](https://github.com/xweiba/location-spoofer/blob/v1.0.8/docs/releases/v1.0.8.md) · [繁體中文](https://github.com/xweiba/location-spoofer/blob/v1.0.8/docs/releases/v1.0.8.zh-Hant.md) + +This re-release replaces build 9 with **build 10** while keeping the v1.0.8 version. + +## Highlights + +- Fixed the app showing Chinese when a non-Chinese language is preferred: the app now uses only the **first** preferred language. Simplified and Traditional Chinese display Chinese; Italian and other non-Chinese languages display English even if Chinese is second in the preference list. +- Added explicit Simplified and Traditional Chinese resources and made English the development-language fallback. Diagnostics, prompts, and generated bug reports follow the same language choice. +- Added missing English translations for two hostname-copy messages and regression tests for language selection. +- Made English the default repository README, retained a separate Chinese README, added the project's AGPL-3.0 license, and preserved third-party script license and provenance information. +- Added contract tests to CI and synchronized the remote-version fallback with the release version. + +## Changes since v1.0.7 + +- `5b9fedf` Fix first-preferred-language fallback and prepare v1.0.8 +- `228b67b` Make English the default README and add AGPL licensing +- `f4712f7` Run contract tests in CI and via make test +- `393c7cc` Align the built-in fallback version and add consistency checks + +## Self-signing and installation + +- The Release attachment is an **unsigned IPA**. Sign it before installing it on an iPhone. +- A free Apple ID and Impactor can be used; a paid developer account is not required. +- Keep the Bundle ID `com.paopaolabs.location-spoofer`, App Group `group.com.paopaolabs.location-spoofer`, and existing entitlements when signing. +- Free Apple ID signing usually expires after seven days, after which the app needs to be signed and installed again. diff --git a/docs/releases/v1.0.8.md b/docs/releases/v1.0.8.md index 8fae4a3..daa78ea 100644 --- a/docs/releases/v1.0.8.md +++ b/docs/releases/v1.0.8.md @@ -2,6 +2,10 @@ 发布日期:2026-09-24 +[English](https://github.com/xweiba/location-spoofer/blob/v1.0.8/docs/releases/v1.0.8.en.md) · [繁體中文](https://github.com/xweiba/location-spoofer/blob/v1.0.8/docs/releases/v1.0.8.zh-Hant.md) + +本次重新发布以**构建号 10** 替换原构建号 9,版本号仍为 v1.0.8。 + ## 主要更新 - 修复非中文系统语言下错误显示中文的问题:只根据首选语言的**第一项**选择 App 界面语言。简体中文和繁体中文分别显示中文;意大利语及其他非中文语言统一显示英文,即使中文排在首选语言列表的后面。 diff --git a/docs/releases/v1.0.8.zh-Hant.md b/docs/releases/v1.0.8.zh-Hant.md new file mode 100644 index 0000000..0a5cc48 --- /dev/null +++ b/docs/releases/v1.0.8.zh-Hant.md @@ -0,0 +1,29 @@ +# v1.0.8 + +發佈日期:2026-09-24 + +[English](https://github.com/xweiba/location-spoofer/blob/v1.0.8/docs/releases/v1.0.8.en.md) · [简体中文](https://github.com/xweiba/location-spoofer/blob/v1.0.8/docs/releases/v1.0.8.md) + +本次重新發佈以**建置版本 10** 取代原有的建置版本 9,版本號仍為 v1.0.8。 + +## 主要更新 + +- 修正非中文系統語言下錯誤顯示中文的問題:App 現在只根據偏好語言的**第一項**選擇介面語言。簡體和繁體中文顯示中文;義大利文及其他非中文語言顯示英文,即使中文排在語言清單的第二項。 +- 補齊簡體與繁體中文本地化資源,並將英文設為開發語言及預設回退語言。診斷資訊、提示與產生的 Bug 回報也遵循相同的語言選擇規則。 +- 補上兩處主機名稱複製提示的英文翻譯,並加入語言選擇的迴歸測試。 +- 將英文設為儲存庫的預設 README,保留獨立的中文文件;加入專案的 AGPL-3.0 授權,並保留第三方腳本原有的授權及來源說明。 +- 將契約測試加入 CI,並統一遠端版本設定與內建回退版本號。 + +## 提交變更摘要 + +- `5b9fedf` 修正偏好語言回退邏輯並準備 v1.0.8 +- `228b67b` 將英文 README 設為預設並加入 AGPL 授權 +- `f4712f7` 在 CI 與 make test 執行契約測試 +- `393c7cc` 修正內建回退版本號並加入一致性檢查 + +## 自行簽署與安裝 + +- Release 附件是**未簽署的 IPA**,安裝到 iPhone 前必須先簽署。 +- 可以使用免費 Apple ID 和 Impactor 簽署安裝,無須付費開發者帳號。 +- 簽署時請保留 Bundle ID `com.paopaolabs.location-spoofer`、App Group `group.com.paopaolabs.location-spoofer` 及原有 entitlements。 +- 免費 Apple ID 的簽署通常只有七天有效期,到期後需要重新簽署並安裝。 diff --git a/project.yml b/project.yml index 9b12e14..d4e3890 100644 --- a/project.yml +++ b/project.yml @@ -16,7 +16,7 @@ settings: base: SWIFT_VERSION: "5.9" MARKETING_VERSION: "1.0.8" - CURRENT_PROJECT_VERSION: "9" + CURRENT_PROJECT_VERSION: "10" CODE_SIGN_STYLE: Manual CODE_SIGNING_ALLOWED: "NO" CODE_SIGNING_REQUIRED: "NO"