diff --git a/.github/workflows/appcast.yml b/.github/workflows/appcast.yml index fe8b09e..ce61d3f 100644 --- a/.github/workflows/appcast.yml +++ b/.github/workflows/appcast.yml @@ -15,15 +15,15 @@ jobs: persist-credentials: false - name: Cache šŸ“¦ - uses: actions/cache@v3.0.11 + uses: actions/cache@v3.3.1 with: path: AppCast/vendor/bundle key: ${{ runner.os }}-gems-v1.0-${{ hashFiles('AppCast/Gemfile') }} restore-keys: | ${{ runner.os }}-gems- - - name: Ruby ā™¦ļø - uses: actions/setup-ruby@v1.1.3 + - name: Setup Ruby, JRuby and TruffleRuby + uses: ruby/setup-ruby@v1.149.0 with: ruby-version: '2.7' diff --git a/README.md b/README.md index 96107ce..9ce57a1 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,17 @@ The easiest way to install and switch between multiple versions of Xcode. -_If you're looking for a command-line version of Xcodes.app, try [`xcodes`](https://github.com/RobotsAndPencils/xcodes)._ +_If you're looking for a command-line version of Xcodes.app, try [`xcodes`](https://github.com/XcodesOrg/xcodes)._ -![CI](https://github.com/RobotsAndPencils/Xcodes.app/workflows/CI/badge.svg) +![CI](https://github.com/XcodesOrg/XcodesApp/workflows/CI/badge.svg) ![](screenshot_light.png#gh-light-mode-only) ![](screenshot_dark.png#gh-dark-mode-only) +### :tada: Announcment + +XcodesApp is now part of the `XcodesOrg` - [read more here](nextstep.md) + ## Features - List all available Xcode versions from [Xcode Releases'](https://xcodereleases.com) data or the Apple Developer website. @@ -21,14 +25,14 @@ _If you're looking for a command-line version of Xcodes.app, try [`xcodes`](http ## Experiments -- Thanks to the wonderful work of [https://github.com/saagarjha/unxip](https://github.com/saagarjha/unxip), turn on the experiment to increase your unxipping time by up to 70%! More can be found on his repo, but bugs, high memory may occur if used. +- Thanks to the wonderful work of [https://github.com/saagarjha/unxip](https://github.com/saagarjha/unxip), turn on the experiment to increase your unxipping time by up to 70%! More can be found on his repo, but bugs, high memory may occur if used. -![](experiment_light.jpg#gh-light-mode-only) -![](experiment_dark.jpg#gh-dark-mode-only) +![](experiment_light.png#gh-light-mode-only) +![](experiment_dark.png#gh-dark-mode-only) ## Localization -Xcodes supports localization in several languages. +Xcodes supports localization in several languages. The following languages are supported because of the following community users! @@ -36,37 +40,36 @@ The following languages are supported because of the following community users! |-|-|-|-| |French šŸ‡«šŸ‡· |[@dompepin](https://github.com/dompepin)|Italian šŸ‡®šŸ‡¹ |[gualtierofrigerio](https://github.com/gualtierofrigerio)| |Spanish šŸ‡ŖšŸ‡øšŸ‡² |[@cesartru88](https://github.com/cesartru88)|Korean šŸ‡°šŸ‡· |[@ryan-son](https://github.com/ryan-son)| -|Russian šŸ‡·šŸ‡ŗ |[@alexmazlov](https://github.com/alexmazlov)|Turkish šŸ‡¹šŸ‡· |[@egrimo](https://github.com/egrimo)| +|Russian šŸ‡·šŸ‡ŗ |[@alexmazlov](https://github.com/alexmazlov)|Turkish šŸ‡¹šŸ‡· |[@egesucu](https://github.com/egesucu)| |Hindi šŸ‡®šŸ‡³ |[@KGurpreet](https://github.com/KGurpreet)|Chinese-Simplified šŸ‡ØšŸ‡³|[@megabitsenmzq](https://github.com/megabitsenmzq)| |Finnish šŸ‡«šŸ‡® |[@marcusziade](https://github.com/marcusziade)|Chinese-Traditional šŸ‡¹šŸ‡¼|[@itszero](https://github.com/itszero)| |Ukranian šŸ‡ŗšŸ‡¦ |[@gelosi](https://github.com/gelosi)|Japanese šŸ‡ÆšŸ‡µ|[@tatsuz0u](https://github.com/tatsuz0u)| |German šŸ‡©šŸ‡Ŗ|[@drct](https://github.com/drct)|Dutch šŸ‡³šŸ‡±|[@jfversluis](https://github/com/jfversluis)| -|Brazilian Portuguese šŸ‡§šŸ‡·|[@brunomunizaf](https://github.com/brunomunizaf)|Catalan|[@ferranabello](https://github.com/ferranabello)|| +|Brazilian Portuguese šŸ‡§šŸ‡·|[@brunomunizaf](https://github.com/brunomunizaf)|Polish šŸ‡µšŸ‡±|[@jakex7](https://github.com/jakex7)| +|Catalan|[@ferranabello](https://github.com/ferranabello)| -Want to add more languages? Simply create a PR with the updated strings file. +Want to add more languages? Simply create a PR with the updated strings file. ## Installation Xcodes.app runs on macOS Big Sur 11.0 or later. -### Homebrew Cask +### Install with Homebrew + +Developer ID-signed and notarized release builds are available on Homebrew. These don't require Xcode to already be installed in order to use. ```sh brew install --cask xcodes - -# These are Developer ID-signed and notarized release builds and don't require Xcode to already be installed in order to use. ``` -### Download a release +### Manually install -1. Download the latest version [here](https://github.com/RobotsAndPencils/XcodesApp/releases/latest) using the **Xcodes.zip** asset. These are Developer ID-signed and notarized release builds and don't require Xcode to already be installed in order to use. +1. Download the latest version [here](https://github.com/XcodesOrg/XcodesApp/releases/latest) using the **Xcodes.zip** asset. These are Developer ID-signed and notarized release builds and don't require Xcode to already be installed in order to use. 2. Move the unzipped `Xcodes.app` to your `/Applications` directory ## Development You'll need macOS 12 Big Sur and Xcode 13 in order to build and run Xcodes.app. -If you aren't a Robots and Pencils employee you'll need to change the CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT build setting to your Apple Developer team ID in order for code signing validation to succeed between the main app and the privileged helper. - `Unxip` and `aria2` must be compiled as a universal binary ``` # compile for Intel @@ -77,7 +80,7 @@ If you aren't a Robots and Pencils employee you'll need to change the CODE_SIGNI # combine for universal binary lipo -create -output unxip unxip_intel unxip_m1 # check it - lipo -archs unxip + lipo -archs unxip ``` Notable design decisions are recorded in [DECISIONS.md](./DECISIONS.md). The Apple authentication flow is described in [Apple.paw](./Apple.paw), which will allow you to play with the API endpoints that are involved using the [Paw](https://paw.cloud) app. @@ -133,7 +136,7 @@ pushd Product ../scripts/sign_update Xcodes.zip popd -# Go to https://github.com/RobotsAndPencils/XcodesApp/releases +# Go to https://github.com/XcodesOrg/XcodesApp/releases # If there are uncategorized PRs, add the appropriate label and run the Release Drafter action manually # Edit the latest draft release # Set its tag to the tag you just pushed @@ -152,9 +155,4 @@ popd [Matt Kiazyk](https://github.com/mattkiazyk) - [Twitter](https://www.twitter.com/mattkiazyk) - - - -Made with ā¤ļø by [Robots & Pencils](http://www.robotsandpencils.com) - -[Twitter](https://twitter.com/xcodesApp) | [GitHub](https://github.com/robotsandpencils) +[Twitter](https://twitter.com/xcodesApp) | [GitHub](https://github.com/xcodesOrg) diff --git a/Xcodes.xcodeproj/project.pbxproj b/Xcodes.xcodeproj/project.pbxproj index a298a5f..8f15b47 100644 --- a/Xcodes.xcodeproj/project.pbxproj +++ b/Xcodes.xcodeproj/project.pbxproj @@ -172,6 +172,7 @@ /* Begin PBXFileReference section */ 15FAD1652811D15600B63259 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; + 23703D6E29EBF63500DFA346 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; 25E2FA26284769A00014A318 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 327DF109286ABE6B00D694D5 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; 36741BFC291E4FDB00A85AAE /* DownloadPreferencePane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadPreferencePane.swift; sourceTree = ""; }; @@ -736,6 +737,7 @@ ca, "pt-BR", nl, + pl, ); mainGroup = CAD2E7952449574E00113D76; packageReferences = ( @@ -955,6 +957,7 @@ 5C3927ED28E4B486007B5119 /* ca */, 327DF109286ABE6B00D694D5 /* pt-BR */, E2AFDCCA28F024D000864ADD /* nl */, + 23703D6E29EBF63500DFA346 /* pl */, ); name = Localizable.strings; sourceTree = ""; @@ -1033,7 +1036,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 18; DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\""; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = NO; @@ -1043,7 +1046,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.9.0; + MARKETING_VERSION = 1.10.0; PRODUCT_BUNDLE_IDENTIFIER = com.robotsandpencils.XcodesApp; PRODUCT_NAME = Xcodes; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1274,7 +1277,7 @@ CODE_SIGN_ENTITLEMENTS = Xcodes/Resources/Xcodes.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 18; DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\""; DEVELOPMENT_TEAM = PBH8V487HB; ENABLE_HARDENED_RUNTIME = YES; @@ -1284,7 +1287,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.9.0; + MARKETING_VERSION = 1.10.0; PRODUCT_BUNDLE_IDENTIFIER = com.robotsandpencils.XcodesApp; PRODUCT_NAME = Xcodes; SWIFT_VERSION = 5.0; @@ -1298,7 +1301,7 @@ CODE_SIGN_ENTITLEMENTS = Xcodes/Resources/Xcodes.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 18; DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\""; DEVELOPMENT_TEAM = PBH8V487HB; ENABLE_HARDENED_RUNTIME = YES; @@ -1308,7 +1311,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.9.0; + MARKETING_VERSION = 1.10.0; PRODUCT_BUNDLE_IDENTIFIER = com.robotsandpencils.XcodesApp; PRODUCT_NAME = Xcodes; SWIFT_VERSION = 5.0; diff --git a/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift b/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift index c8e2810..6f33a4a 100644 --- a/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift +++ b/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift @@ -14,12 +14,22 @@ public class Client { return Current.network.dataTask(with: URLRequest.itcServiceKey) .map(\.data) .decode(type: ServiceKeyResponse.self, decoder: JSONDecoder()) - .flatMap { serviceKeyResponse -> AnyPublisher in + .flatMap { serviceKeyResponse -> AnyPublisher<(String, String), Swift.Error> in serviceKey = serviceKeyResponse.authServiceKey - return Current.network.dataTask(with: URLRequest.signIn(serviceKey: serviceKey, accountName: accountName, password: password)) - .mapError { $0 as Swift.Error } + + // Fixes issue https://github.com/RobotsAndPencils/XcodesApp/issues/360 + // On 2023-02-23, Apple added a custom implementation of hashcash to their auth flow + // Without this addition, Apple ID's would get set to locked + return self.loadHashcash(accountName: accountName, serviceKey: serviceKey) + .map { return (serviceKey, $0)} .eraseToAnyPublisher() } + .flatMap { (serviceKey, hashcash) -> AnyPublisher in + + return Current.network.dataTask(with: URLRequest.signIn(serviceKey: serviceKey, accountName: accountName, password: password, hashcash: hashcash)) + .mapError { $0 as Swift.Error } + .eraseToAnyPublisher() + } .flatMap { result -> AnyPublisher in let (data, response) = result return Just(data) @@ -56,6 +66,44 @@ public class Client { .mapError { $0 as Swift.Error } .eraseToAnyPublisher() } + + func loadHashcash(accountName: String, serviceKey: String) -> AnyPublisher { + + Result { + try URLRequest.federate(account: accountName, serviceKey: serviceKey) + } + .publisher + .flatMap { request in + Current.network.dataTask(with: request) + .mapError { $0 as Error } + .tryMap { (data, response) throws -> (String) in + guard let urlResponse = response as? HTTPURLResponse else { + throw AuthenticationError.invalidSession + } + switch urlResponse.statusCode { + case 200..<300: + + let httpResponse = response as! HTTPURLResponse + guard let bitsString = httpResponse.allHeaderFields["X-Apple-HC-Bits"] as? String, let bits = UInt(bitsString) else { + throw AuthenticationError.invalidHashcash + } + guard let challenge = httpResponse.allHeaderFields["X-Apple-HC-Challenge"] as? String else { + throw AuthenticationError.invalidHashcash + } + guard let hashcash = Hashcash().mint(resource: challenge, bits: bits) else { + throw AuthenticationError.invalidHashcash + } + return (hashcash) + case 400, 401: + throw AuthenticationError.invalidHashcash + case let code: + throw AuthenticationError.badStatusCode(statusCode: code, data: data, response: urlResponse) + } + } + } + .eraseToAnyPublisher() + + } func handleTwoStepOrFactor(data: Data, response: URLResponse, serviceKey: String) -> AnyPublisher { let httpResponse = response as! HTTPURLResponse @@ -190,6 +238,7 @@ public enum AuthenticationState: Equatable { public enum AuthenticationError: Swift.Error, LocalizedError, Equatable { case invalidSession + case invalidHashcash case invalidUsernameOrPassword(username: String) case incorrectSecurityCode case unexpectedSignInResponse(statusCode: Int, message: String?) @@ -206,6 +255,8 @@ public enum AuthenticationError: Swift.Error, LocalizedError, Equatable { switch self { case .invalidSession: return "Your authentication session is invalid. Try signing in again." + case .invalidHashcash: + return "Could not create a hashcash for the session." case .invalidUsernameOrPassword: return "Invalid username and password combination." case .incorrectSecurityCode: diff --git a/Xcodes/AppleAPI/Sources/AppleAPI/Hashcash.swift b/Xcodes/AppleAPI/Sources/AppleAPI/Hashcash.swift new file mode 100644 index 0000000..135f1ea --- /dev/null +++ b/Xcodes/AppleAPI/Sources/AppleAPI/Hashcash.swift @@ -0,0 +1,96 @@ +// +// Hashcash.swift +// +// +// Created by Matt Kiazyk on 2023-02-23. +// + +import Foundation +import CryptoKit +import CommonCrypto + +/* +# This App Store Connect hashcash spec was generously donated by... + # + # __ _ + # __ _ _ __ _ __ / _|(_) __ _ _ _ _ __ ___ ___ + # / _` || '_ \ | '_ \ | |_ | | / _` || | | || '__|/ _ \/ __| + # | (_| || |_) || |_) || _|| || (_| || |_| || | | __/\__ \ + # \__,_|| .__/ | .__/ |_| |_| \__, | \__,_||_| \___||___/ + # |_| |_| |___/ + # + # +*/ +public struct Hashcash { + /// A function to returned a minted hash, using a bit and resource string + /// + /** + X-APPLE-HC: 1:11:20230223170600:4d74fb15eb23f465f1f6fcbf534e5877::6373 + ^ ^ ^ ^ ^ + | | | | +-- Counter + | | | +-- Resource + | | +-- Date YYMMDD[hhmm[ss]] + | +-- Bits (number of leading zeros) + +-- Version + + We can't use an off-the-shelf Hashcash because Apple's implementation is not quite the same as the spec/convention. + 1. The spec calls for a nonce called "Rand" to be inserted between the Ext and Counter. They don't do that at all. + 2. The Counter conventionally encoded as base-64 but Apple just uses the decimal number's string representation. + + Iterate from Counter=0 to Counter=N finding an N that makes the SHA1(X-APPLE-HC) lead with Bits leading zero bits + We get the "Resource" from the X-Apple-HC-Challenge header and Bits from X-Apple-HC-Bits + */ + /// - Parameters: + /// - resource: a string to be used for minting + /// - bits: grabbed from `X-Apple-HC-Bits` header + /// - date: Default uses Date() otherwise used for testing to check. + /// - Returns: A String hash to use in `X-Apple-HC` header on /signin + public func mint(resource: String, + bits: UInt = 10, + date: String? = nil) -> String? { + + let ver = "1" + + var ts: String + if let date = date { + ts = date + } else { + let formatter = DateFormatter() + formatter.dateFormat = "yyMMddHHmmss" + ts = formatter.string(from: Date()) + } + + let challenge = "\(ver):\(bits):\(ts):\(resource):" + + var counter = 0 + + while true { + guard let digest = ("\(challenge):\(counter)").sha1 else { + print("ERROR: Can't generate SHA1 digest") + return nil + } + + if digest == bits { + return "\(challenge):\(counter)" + } + counter += 1 + } + } +} + +extension String { + var sha1: Int? { + + let data = Data(self.utf8) + var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH)) + data.withUnsafeBytes { + _ = CC_SHA1($0.baseAddress, CC_LONG(data.count), &digest) + } + let bigEndianValue = digest.withUnsafeBufferPointer { + ($0.baseAddress!.withMemoryRebound(to: UInt32.self, capacity: 1) { $0 }) + }.pointee + let value = UInt32(bigEndian: bigEndianValue) + return value.leadingZeroBitCount + } +} + diff --git a/Xcodes/AppleAPI/Sources/AppleAPI/URLRequest+Apple.swift b/Xcodes/AppleAPI/Sources/AppleAPI/URLRequest+Apple.swift index 01b98fb..d052d63 100644 --- a/Xcodes/AppleAPI/Sources/AppleAPI/URLRequest+Apple.swift +++ b/Xcodes/AppleAPI/Sources/AppleAPI/URLRequest+Apple.swift @@ -7,6 +7,7 @@ public extension URL { static let requestSecurityCode = URL(string: "https://idmsa.apple.com/appleauth/auth/verify/phone")! static func submitSecurityCode(_ code: SecurityCode) -> URL { URL(string: "https://idmsa.apple.com/appleauth/auth/verify/\(code.urlPathComponent)/securitycode")! } static let trust = URL(string: "https://idmsa.apple.com/appleauth/auth/2sv/trust")! + static let federate = URL(string: "https://idmsa.apple.com/appleauth/auth/federate")! static let olympusSession = URL(string: "https://appstoreconnect.apple.com/olympus/v1/session")! } @@ -15,7 +16,7 @@ public extension URLRequest { return URLRequest(url: .itcServiceKey) } - static func signIn(serviceKey: String, accountName: String, password: String) -> URLRequest { + static func signIn(serviceKey: String, accountName: String, password: String, hashcash: String) -> URLRequest { struct Body: Encodable { let accountName: String let password: String @@ -27,6 +28,7 @@ public extension URLRequest { request.allHTTPHeaderFields?["Content-Type"] = "application/json" request.allHTTPHeaderFields?["X-Requested-With"] = "XMLHttpRequest" request.allHTTPHeaderFields?["X-Apple-Widget-Key"] = serviceKey + request.allHTTPHeaderFields?["X-Apple-HC"] = hashcash request.allHTTPHeaderFields?["Accept"] = "application/json, text/javascript" request.httpMethod = "POST" request.httpBody = try! JSONEncoder().encode(Body(accountName: accountName, password: password)) @@ -117,4 +119,21 @@ public extension URLRequest { static var olympusSession: URLRequest { return URLRequest(url: .olympusSession) } + + static func federate(account: String, serviceKey: String) throws -> URLRequest { + struct FederateRequest: Encodable { + let accountName: String + let rememberMe: Bool + } + var request = URLRequest(url: .signIn) + request.allHTTPHeaderFields?["Accept"] = "application/json" + request.allHTTPHeaderFields?["Content-Type"] = "application/json" + request.httpMethod = "GET" + +// let encoder = JSONEncoder() +// encoder.outputFormatting = .withoutEscapingSlashes +// request.httpBody = try encoder.encode(FederateRequest(accountName: account, rememberMe: true)) + + return request + } } diff --git a/Xcodes/AppleAPI/Tests/AppleAPITests/AppleAPITests.swift b/Xcodes/AppleAPI/Tests/AppleAPITests/AppleAPITests.swift index 283dbc6..ecb93e7 100644 --- a/Xcodes/AppleAPI/Tests/AppleAPITests/AppleAPITests.swift +++ b/Xcodes/AppleAPI/Tests/AppleAPITests/AppleAPITests.swift @@ -2,14 +2,26 @@ import XCTest @testable import AppleAPI final class AppleAPITests: XCTestCase { - func testExample() { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct - // results. - XCTAssertEqual(AppleAPI().text, "Hello, World!") + + func testValidHashCashMint() { + let bits: UInt = 11 + let resource = "4d74fb15eb23f465f1f6fcbf534e5877" + let testDate = "20230223170600" + + let stamp = Hashcash().mint(resource: resource, bits: bits, date: testDate) + XCTAssertEqual(stamp, "1:11:20230223170600:4d74fb15eb23f465f1f6fcbf534e5877::6373") + } + func testValidHashCashMint2() { + let bits: UInt = 10 + let resource = "bb63edf88d2f9c39f23eb4d6f0281158" + let testDate = "20230224001754" + + let stamp = Hashcash().mint(resource: resource, bits: bits, date: testDate) + XCTAssertEqual(stamp, "1:10:20230224001754:bb63edf88d2f9c39f23eb4d6f0281158::866") } static var allTests = [ - ("testExample", testExample), + ("testValidHashCashMint", testValidHashCashMint), + ("testValidHashCashMint2", testValidHashCashMint2), ] } diff --git a/Xcodes/Backend/DateFormatter+.swift b/Xcodes/Backend/DateFormatter+.swift index 5aed8ab..a0073de 100644 --- a/Xcodes/Backend/DateFormatter+.swift +++ b/Xcodes/Backend/DateFormatter+.swift @@ -6,6 +6,7 @@ extension DateFormatter { let formatter = DateFormatter() formatter.dateFormat = "MM/dd/yy HH:mm" formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.calendar = .init(identifier: .iso8601) return formatter }() diff --git a/Xcodes/Frontend/Preferences/UpdatesPreferencePane.swift b/Xcodes/Frontend/Preferences/UpdatesPreferencePane.swift index 282b806..349d9be 100644 --- a/Xcodes/Frontend/Preferences/UpdatesPreferencePane.swift +++ b/Xcodes/Frontend/Preferences/UpdatesPreferencePane.swift @@ -117,8 +117,8 @@ class ObservableUpdater: ObservableObject { } extension URL { - static let appcast = URL(string: "https://robotsandpencils.github.io/XcodesApp/appcast.xml")! - static let prereleaseAppcast = URL(string: "https://robotsandpencils.github.io/XcodesApp/appcast_pre.xml")! + static let appcast = URL(string: "https://www.xcodes.app/appcast.xml")! + static let prereleaseAppcast = URL(string: "https://www.xcodes.app/appcast_pre.xml")! } struct UpdatesPreferencePane_Previews: PreviewProvider { diff --git a/Xcodes/Frontend/XcodeList/BottomStatusBar.swift b/Xcodes/Frontend/XcodeList/BottomStatusBar.swift index ed74fe6..cd38c3b 100644 --- a/Xcodes/Frontend/XcodeList/BottomStatusBar.swift +++ b/Xcodes/Frontend/XcodeList/BottomStatusBar.swift @@ -9,27 +9,27 @@ import Foundation import SwiftUI - struct BottomStatusModifier: ViewModifier { @EnvironmentObject var appState: AppState func body(content: Content) -> some View { - content VStack(spacing: 0) { - Divider() - HStack { - Text(appState.bottomStatusBarMessage) - .font(.subheadline) - Spacer() - Text(Bundle.main.shortVersion!) - .font(.subheadline) + content + VStack(spacing: 0) { + Divider() + HStack { + Text(appState.bottomStatusBarMessage) + .font(.subheadline) + Spacer() + Text(Bundle.main.shortVersion!) + .font(.subheadline) + } + .frame(maxWidth: .infinity, maxHeight: 30, alignment: .leading) + .padding([.leading, .trailing], 10) } .frame(maxWidth: .infinity, maxHeight: 30, alignment: .leading) - .padding([.leading, .trailing], 10) } - .frame(maxWidth: .infinity, maxHeight: 30, alignment: .leading) } - } extension View { diff --git a/Xcodes/Frontend/XcodeList/MainToolbar.swift b/Xcodes/Frontend/XcodeList/MainToolbar.swift index dcff73a..69a48f2 100644 --- a/Xcodes/Frontend/XcodeList/MainToolbar.swift +++ b/Xcodes/Frontend/XcodeList/MainToolbar.swift @@ -13,12 +13,12 @@ struct MainToolbarModifier: ViewModifier { } private var toolbar: some ToolbarContent { - ToolbarItemGroup(placement: .status) { + ToolbarItemGroup { Button(action: { appState.presentedSheet = .signIn }, label: { Label("Login", systemImage: "person.circle") }) .help("LoginDescription") - + ProgressButton( isInProgress: appState.isUpdating, action: appState.update @@ -85,7 +85,7 @@ struct MainToolbarModifier: ViewModifier { } .keyboardShortcut(KeyboardShortcut("i", modifiers: [.command, .option])) .help("InfoDescription") - + Button(action: { if #available(macOS 13, *) { NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil) diff --git a/Xcodes/Resources/Info.plist b/Xcodes/Resources/Info.plist index 58e8717..49fe676 100644 --- a/Xcodes/Resources/Info.plist +++ b/Xcodes/Resources/Info.plist @@ -25,7 +25,7 @@ LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright - Copyright Ā© 2022 Robots and Pencils. + Copyright Ā© 2023 Robots and Pencils. NSPrincipalClass NSApplication NSSupportsAutomaticTermination @@ -38,7 +38,7 @@ identifier "com.robotsandpencils.XcodesApp.Helper" and info [CFBundleShortVersionString] >= "1.0.0" and anchor apple generic and certificate leaf[subject.OU] = "$(CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT)" SUFeedURL - https://robotsandpencils.github.io/XcodesApp/appcast.xml + https://www.xcodes.app/appcast.xml SUPublicEDKey SEcz0vgUSeBTOoAXYe+64zea95G6lIf5NgzFs3InYJQ= diff --git a/Xcodes/Resources/ja.lproj/Localizable.strings b/Xcodes/Resources/ja.lproj/Localizable.strings index 33cb1c9..90aa86f 100644 --- a/Xcodes/Resources/ja.lproj/Localizable.strings +++ b/Xcodes/Resources/ja.lproj/Localizable.strings @@ -86,14 +86,25 @@ "LocalCachePathDescription" = "XcodesćÆć€åˆ©ē”ØåÆčƒ½ćŖXcodeć®ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’ć‚­ćƒ£ćƒƒć‚·ćƒ„ć—ć€ę–°ć—ć„ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’ćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć«äø€ę™‚ēš„ć«ćƒ€ć‚¦ćƒ³ćƒ­ćƒ¼ćƒ‰ć—ć¾ć™ć€‚"; "Change" = "変曓"; "Active/Select" = "ć‚¢ć‚Æćƒ†ć‚£ćƒ–"; +"InstallDirectory" = "ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«å…ˆ"; +"InstallPathDescription" = "Xcodesは1ć¤ć®ćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć‚’ę¤œē“¢ć—ć€ćć“ć«ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¾ć™ć€‚ćƒ‡ćƒ•ć‚©ćƒ«ćƒˆ (ęŽØå„Ø) は /Applications 恧恙怂Xcodeć®ę ¼ē“å “ę‰€ć‚’å¤‰ę›“ć™ć‚‹ćØć€ä»–ć®ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć‚„ć‚µćƒ¼ćƒ“ć‚¹ćŒå‹•ä½œć—ćŖććŖć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚"; + +"OnSelectDoNothing" = "åå‰ć‚’Xcode-X.X.X.appć®ć¾ć¾ē¶­ęŒć™ć‚‹"; +"OnSelectDoNothingDescription" = "éøęŠžę™‚ć€ćƒćƒ¼ć‚øćƒ§ćƒ³ä»˜ćć®åå‰ć‚’ē¶­ęŒć—ć¾ć™ć€‚ä¾‹) Xcode-13.4.1.app"; "AutomaticallyCreateSymbolicLink" = "Xcode.appćøć®ć‚·ćƒ³ćƒœćƒŖćƒƒć‚ÆćƒŖćƒ³ć‚Æć®č‡Ŗå‹•ē”Ÿęˆ"; "AutomaticallyCreateSymbolicLinkDescription" = "Xcodeć®ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’ć‚¢ć‚Æćƒ†ć‚£ćƒ–ć«ć™ć‚‹ę™‚ć€ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«å…ˆć§Xcode.appć®ć‚·ćƒ³ćƒœćƒŖćƒƒć‚ÆćƒŖćƒ³ć‚Æć®ä½œęˆć‚’č©¦ćæć¾ć™ć€‚"; +"OnSelectRenameXcode" = "åå‰ć‚’åøøć«Xcode.appに変曓する"; +"OnSelectRenameXcodeDescription" = "éøęŠžę™‚ć€č‡Ŗå‹•ēš„ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖXcode悒Xcode.appć«ć€ä»„å‰ć®Xcode.appć‚’ćƒćƒ¼ć‚øćƒ§ćƒ³ä»˜ćć®åå‰ć«å¤‰ę›“ć—ć¾ć™ć€‚"; + "PrivilegedHelper" = "ęØ©é™ć®ć‚ć‚‹ćƒ˜ćƒ«ćƒ‘ćƒ¼"; "PrivilegedHelperDescription" = "Xcodesは、rootćØć—ć¦ć‚æć‚¹ć‚Æć‚’å®Ÿč”Œć™ć‚‹ćŸć‚ć«ć€åˆ„ć®ęØ©é™ć®ć‚ć‚‹ćƒ˜ćƒ«ćƒ‘ćƒ¼ć‚’ä½æē”Øć—ć¾ć™ć€‚ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«å¾Œć®ę‰‹é †ć‚„ xcode-select ć«ć‚ˆć‚‹ Xcode ć®ćƒćƒ¼ć‚øćƒ§ćƒ³åˆ‡ć‚Šę›æćˆćŖć©ć€ć‚³ćƒžćƒ³ćƒ‰ćƒ©ć‚¤ćƒ³ć§ sudo を必要とするものです。\n\nć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć«ćÆć€macOS ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ćƒ‘ć‚¹ćƒÆćƒ¼ćƒ‰ć®å…„åŠ›ćŒåæ…č¦ć§ć™ć€‚"; "HelperInstalled" = "ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ęøˆćæ"; "HelperNotInstalled" = "ęœŖć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«"; "InstallHelper" = "ćƒ˜ćƒ«ćƒ‘ćƒ¼ć®ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«"; +"ShowOpenInRosetta" = "Rosettać§é–‹ćć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć‚’č”Øē¤ŗć™ć‚‹"; +"ShowOpenInRosettaDescription" = "Rosettać§é–‹ćć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ćÆ \"開恏\" ę©Ÿčƒ½ćŒåˆ©ē”Øć§ćć‚‹å “ę‰€ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚ę³Øę„: ć“ć‚ŒćÆApple Siliconćƒžć‚·ćƒ³ć«ć®ćæč”Øē¤ŗć•ć‚Œć¾ć™ć€‚"; + // Experiment Preference Pane "Experiments" = "č©¦éØ“ēš„ćŖę©Ÿčƒ½"; "FasterUnxip" = "é«˜é€ŸćŖ Unxip"; @@ -152,6 +163,7 @@ "Alert.Uninstall.Title" = "Xcode %@ ć‚’ć‚¢ćƒ³ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹ļ¼Ÿ"; "Alert.Uninstall.Message" = "ć‚“ćƒŸē®±ć«ē§»å‹•ć•ć‚Œć¾ć™ćŒć€ć‚“ćƒŸē®±ć‚’č‡Ŗå‹•ēš„ć«ē©ŗć«ć™ć‚‹ć“ćØćÆć‚ć‚Šć¾ć›ć‚“ć€‚"; "Alert.Uninstall.Error.Title" = "Xcode ć‚’ć‚¢ćƒ³ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć§ćć¾ć›ć‚“ć§ć—ćŸ"; +"Alert.Uninstall.Error.Message.FileNotFound" = "ćƒ•ć‚”ć‚¤ćƒ« \"%@\" ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć§ć—ćŸć€‚"; // Cancel Install "Alert.CancelInstall.Title" = "Xcode %@ ć®ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć‚’äø­ę­¢ć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹ļ¼Ÿ"; @@ -221,3 +233,6 @@ // Notifications "Notification.NewXcodeVersion.Title" = "ꖰ恗恄Xcodeć®ćƒćƒ¼ć‚øćƒ§ćƒ³"; "Notification.NewXcodeVersion.Body" = "ę–°ć—ć„ćƒćƒ¼ć‚øćƒ§ćƒ³ćŒćƒ€ć‚¦ćƒ³ćƒ­ćƒ¼ćƒ‰ć§ćć¾ć™ć€‚"; + +// WWDC +"WWDC.Message" = "šŸ‘ØšŸ»ā€šŸ’»šŸ‘©šŸ¼ā€šŸ’» Happy WWDC %@! šŸ‘ØšŸ½ā€šŸ’»šŸ§‘šŸ»ā€šŸ’»"; diff --git a/Xcodes/Resources/pl.lproj/Localizable.strings b/Xcodes/Resources/pl.lproj/Localizable.strings new file mode 100644 index 0000000..c505451 --- /dev/null +++ b/Xcodes/Resources/pl.lproj/Localizable.strings @@ -0,0 +1,239 @@ +// Menu +"Menu.About" = "O Xcodes"; +"Menu.CheckForUpdates" = "SprawdÅŗ aktualizacje..."; +"Menu.Acknowledgements" = "Podziękowania Xcodes"; +"Menu.GitHubRepo" = "Repozytorium Xcodes na GitHubie"; +"Menu.ReportABug" = "Zgłoś błąd"; +"Menu.RequestNewFeature" = "Poproś o nową funkcję"; + +// Common +"Install" = "Zainstaluj"; +"InstallDescription" = "Zainstaluj tę wersję"; +"RevealInFinder" = "Pokaż w Finderze"; +"Active" = "Aktywny"; +"MakeActive" = "Ustaw jako aktywny"; +"Open" = "Otwórz"; +"OpenDescription" = "Otwórz tę wersję"; +"CopyPath" = "Kopiuj ścieżkę"; +"CreateSymLink" = "Utwórz Symlink jako Xcode.app"; +"CreateSymLinkBeta" = "Utwórz Symlink jako Xcode-Beta.app"; +"Uninstall" = "Odinstaluj"; +"Selected" = "Wybrany"; +"Select" = "Wybierz"; +"Cancel" = "Anuluj"; +"Next" = "Dalej"; +"Continue" = "Kontynuuj"; +"Close" = "Zamknij"; +"OK" = "OK"; + +// Info Pane +"IdenticalBuilds" = "Takie same wersje"; +"IdenticalBuilds.help" = "Czasami wersja przedpremierowa i wydana są dokładnie takie same. Xcodes automatycznie wyświetla te wersje razem."; + +"ReleaseDate" = "Data wydania"; +"ReleaseNotes" = "Notatki wydania"; +"ReleaseNotes.help" = "Wyświetl notatki wydania"; +"CopyReleaseNoteURL" = "Kopiuj adres URL"; +"Compatibility" = "Kompatybilność"; +"MacOSRequirement" = "Wymaga systemu macOS %@ lub nowszego"; +"SDKs" = "SDK"; +"Compilers" = "Kompilatory"; +"DownloadSize" = "Wielkość pobierania"; +"NoXcodeSelected" = "Nie wybrano Xcode"; + +// Installation Steps +// When localizing. Items will be replaced in order. ie "Step 1 of 6: Downloading" +// So if changing order, make sure the positional specficier is retained. ex: "%3$@: Step %1$d of %2$d" +"InstallationStepDescription" = "Krok %1$d z %2$d: %3$@"; +"DownloadingPercentDescription" = "Pobieranie: %d%% ukończone"; +"StopInstallation" = "Przerwij instalację"; +"DownloadingError" = "Nie znaleziono informacji o pobieraniu"; + +// About +"VersionWithBuild" = "Wersja %@ (%@)"; +"GithubRepo" = "Repozytorium GitHub"; +"Acknowledgements" = "Podziękowania"; +"UnxipExperiment" = "Eksperyment Unxip"; +"License" = "Licencja"; + +// General Preference Pane +"General" = "Ogólne"; +"AppleID" = "Apple ID"; +"SignIn" = "Zaloguj się"; +"Notifications" = "Powiadomienia"; + +// Updates Preference Pane +"Updates" = "Aktualizacje"; +"Versions" = "Wersje"; +"AutomaticInstallNewVersion" = "Automatycznie instaluj nowe wersje Xcode"; +"IncludePreRelease" = "Dołącz wersje beta/wstępne"; +"AppUpdates" = "Aktualizacje Xcodes.app"; +"CheckForAppUpdates" = "Automatycznie sprawdzaj aktualizacje aplikacji"; +"CheckNow" = "SprawdÅŗ teraz"; +"LastChecked" = "Ostatnio sprawdzono: %@"; +"Never" = "Nigdy"; + +// Download Preference Pane +"Downloads" = "Pobieranie"; +"DataSource" = "Źródło danych"; +"DataSourceDescription" = "Źródło danych Apple przeszukuje stronę internetową Apple Developer. Zawsze wyświetla najnowsze dostępne wydania, ale jest bardziej podatne na problemy.\n\nXcode Releases to nieoficjalna lista wydań Xcode. Udostępnia ona dobrze sformatowane dane, zawiera dodatkowe informacje, które nie są łatwo dostępne w Apple, i jest mniej podatna na problemy, gdy Apple zmienia swoją stronę dla deweloperów."; +"Downloader" = "Pobieranie"; +"DownloaderDescription" = "aria2 używa do pobierania do 16 połączeń, co pozwala na pobieranie Xcode 3-5x szybciej niż URLSession. Jest on dostarczany jako plik wykonywalny wraz ze swoim kodem Åŗródłowym w ramach Xcodes w celu przestrzegania jego licencji GPLv2.\n\nURLSession to domyślne API Apple do tworzenia żądań URL."; + +// Advanced Preference Pane +"Advanced" = "Zaawansowane"; +"LocalCachePath" = "Katalog cache"; +"LocalCachePathDescription" = "Xcodes przechowuje w cache dostępne wersje Xcode oraz tymczasowo pobiera nowe pliki do tego katalogu."; +"Change" = "Zmień"; +"Active/Select" = "Aktywny/wybrany"; +"InstallDirectory" = "Katalog instalacji"; +"InstallPathDescription" = "Xcodes wyszukuje i instaluje w jednym katalogu. Domyślnie (i zalecane) jest to /Applications. Wszelkie zmiany w miejscu przechowywania Xcode mogą spowodować, że inne aplikacje/usługi przestaną działać."; + +"OnSelectDoNothing" = "Zachowaj nazwę jako Xcode-X.X.X.app"; +"OnSelectDoNothingDescription" = "Po wybraniu, nazwa pozostanie w formacie z numerem wersji, np. Xcode-13.4.1.app"; +"AutomaticallyCreateSymbolicLink" = "Automatycznie twórz symboliczne połączenie do Xcode.app"; +"AutomaticallyCreateSymbolicLinkDescription" = "Przy ustawianiu Xcode jako aktywny/wybrany, próbuj automatycznie stworzyć symboliczne połączenie o nazwie Xcode.app w katalogu instalacji."; +"OnSelectRenameXcode" = "Zawsze zmieniaj nazwę na Xcode.app"; +"OnSelectRenameXcodeDescription" = "Po wybraniu, automatycznie zmienia aktywną wersję Xcode na Xcode.app, a poprzednie Xcode.app zostanie zmienione na nazwę wersji."; + +"PrivilegedHelper" = "Helper z uprawnieniami"; +"PrivilegedHelperDescription" = "Xcodes używa oddzielnego helpera z uprawnieniami do wykonywania zadań jako root. Są to rzeczy, które wymagałyby użycia komendy sudo w wierszu poleceń, w tym kroki po instalacji oraz przełączanie wersji Xcode za pomocą xcode-select.\n\nZostaniesz poproszony o podanie hasła do swojego konta macOS, aby go zainstalować."; +"HelperInstalled" = "Helper jest zainstalowany"; +"HelperNotInstalled" = "Helper nie jest zainstalowany"; +"InstallHelper" = "Zainstaluj helpera"; + +"ShowOpenInRosetta" = "Pokaż opcję Otwórz w Rosetta"; +"ShowOpenInRosettaDescription" = "Opcja Otwórz w Rosetta będzie wyświetlana, gdy dostępne są inne funkcje \"Otwórz\". Uwaga: Będzie to działać tylko na urządzeniach z Apple Silicon."; + +// Experiment Preference Pane +"Experiments" = "Eksperymenty"; +"FasterUnxip" = "Szybsze Unxip"; +"UseUnxipExperiment" = "Podczas rozpakowywania, użyj wersji eksperymentalnej"; +"FasterUnxipDescription" = "Dzięki @_saagarjha, wersja eksperymentalna może zwiększyć prędkość rozpakowywania o nawet 70% dla niektórych systemów.\n\nWięcej informacji na temat tego, jak to jest osiągane, można znaleźć w repozytorium unxip - https://github.com/saagarjha/unxip"; + +// Notifications +"AccessGranted" = "Dostęp przyznany. Będziesz otrzymywać powiadomienia z Xcodes."; +"AccessDenied" = "āš ļø Dostęp zabroniony āš ļø\n\nOtwórz ustawienia powiadomień i wybierz Xcodes, jeśli chcesz zezwolić na dostęp."; +"NotificationSettings" = "Ustawienia powiadomień"; +"EnableNotifications" = "Włącz powiadomienia"; + +// SignIn +"SignInWithApple" = "Zaloguj się przy użyciu Apple ID."; +"AppleID" = "AppleID:"; +"Password" = "Hasło:"; +"Required" = "Wymagane"; +"SignOut" = "Wyloguj się"; + +// SMS/2FA +"DigitCodeDescription" = "WprowadÅŗ %d-cyfrowy kod z jednego ze swoich zaufanych urządzeń:"; +"SendSMS" = "Wyślij SMS"; +"EnterDigitCodeDescription" = "WprowadÅŗ %d-cyfrowy kod wysłany do %@: "; +"SelectTrustedPhone" = "Wybierz zaufany numer telefonu, aby otrzymać %d-cyfrowy kod przez SMS:"; +"NoTrustedPhones" = "Twoje konto nie ma żadnych zaufanych numerów telefonów, ale są one wymagane do autoryzacji dwuskładnikowej.\n\nZobacz https://support.apple.com/HT204915."; + +// MainWindow +"UpdatedAt" = "Zaktualizowano o"; + +// ToolBar +"Login" = "Zaloguj się"; +"LoginDescription" = "Otwórz okno logowania"; +"Refresh" = "Odśwież"; +"RefreshDescription" = "Odśwież listę Xcode"; +"All" = "Wszystkie"; +"Release" = "Stabilne"; +"ReleaseOnly" = "Tylko stabilne"; +"Beta" = "Beta"; +"BetaOnly" = "Tylko beta"; +"Filter" = "Filtr"; +"FilterAvailableDescription" = "Filtruj dostępne wersje"; +"FilterInstalledDescription" = "Filtruj zainstalowane wersje"; +"Info" = "Informacje"; +"InfoDescription" = "Pokaż lub ukryj okno informacji"; +"Preferences" = "Ustawienia"; +"PreferencesDescription" = "Otwórz ustawienia"; +"Search" = "Szukaj..."; +"SearchDescription" = "Przeszukaj listę"; + +// List +"ActiveVersionDescription" = "To jest aktywna wersja"; +"MakeActiveVersionDescription" = "Ustaw jako aktywną wersję"; + +// Alerts +// Uninstall +"Alert.Uninstall.Title" = "Odinstalować Xcode %@?"; +"Alert.Uninstall.Message" = "Zostanie przeniesiony do kosza, ale nie zostanie opróżniony."; +"Alert.Uninstall.Error.Title" = "Nie można odinstalować Xcode"; +"Alert.Uninstall.Error.Message.FileNotFound" = "Nie znaleziono pliku \"%@\"."; + +// Cancel Install +"Alert.CancelInstall.Title" = "Czy na pewno chcesz przerwać instalację Xcode %@?"; +"Alert.CancelInstall.Message" = "Postęp zostanie utracony."; +"Alert.CancelInstall.PrimaryButton" = "Przerwij instalację"; + +// Privileged Helper +"Alert.PrivilegedHelper.Title" = "Helper z uprawnieniami"; +"Alert.PrivilegedHelper.Message" = "Xcodes używa oddzielnego helpera z uprawnieniami, aby wykonywać zadania jako root. Są to rzeczy, które wymagałyby sudo w wierszu poleceń, w tym kroki po instalacji i przełączanie wersji Xcode z xcode-select.\n\nBędziesz proszony o podanie hasła do konta macOS, aby go zainstalować."; +"Alert.PrivilegedHelper.Error.Title" = "Nie można zainstalować helpera"; + +// Min MacOS Supported +"Alert.MinSupported.Title" = "Niezgodność z minimalnymi wymaganiami"; +"Alert.MinSupported.Message" = "Xcode %@ wymaga macOS %@, a ty masz macOS %@. Czy nadal chcesz go zainstalować?"; + +// Install +"Alert.Install.Error.Title" = "Nie można zainstalować Xcode"; +"Alert.InstallArchive.Error.Title" = "Nie można zainstalować zarchiwizowanego Xcode"; + +// Update +"Alert.Update.Error.Title" = "Nie można zaktualizować wybranej wersji Xcode"; + +// Active/Select +"Alert.Select.Error.Title" = "Nie można wybrać Xcode"; + +// Symbolic Links +"Alert.SymLink.Title" = "Nie można utworzyć linku symbolicznego"; +"Alert.SymLink.Message" = "Xcode.app istnieje i nie jest linkiem symbolicznym"; + +// Post install +"Alert.PostInstall.Title" = "Nie można wykonać czynności po-instalacyjnych"; + +// InstallationErrors +"InstallationError.DamagedXIP" = "Archiwum \"%@\" jest uszkodzone i nie może zostać rozpakowane."; +"InstallationError.NotEnoughFreeSpaceToExpandArchive" = "Nie można rozpakować archiwum \"%@\", ponieważ wolumin nie ma wystarczającej ilości wolnego miejsca.\n\nZrób więcej miejsca, aby rozpakować archiwum, a następnie zainstaluj ponownie Xcode %@, aby kontynuować instalację od miejsca, w którym została wstrzymana."; +"InstallationError.FailedToMoveXcodeToApplications" = "Nie udało się przenieść Xcode do katalogu %@."; +"InstallationError.FailedSecurityAssessment" = "Xcode %@ nie przeszedł testu bezpieczeństwa z następującym wynikiem:\n%@\nPozostaje zainstalowany w %@, jeśli mimo to chcesz go używać."; +"InstallationError.CodesignVerifyFailed" = "Pobrany Xcode nie przeszedł weryfikacji sygnatury kodu z wynikiem:\n%@"; +"InstallationError.UnexpectedCodeSigningIdentity" = "Pobrany Xcode nie ma oczekiwanej sygnatury kodu.\nOtrzymano:\n%@\n%@\nOczekiwano:\n%@\n%@"; +"InstallationError.UnsupportedFileFormat" = "Xcodes nie obsługuje (jeszcze) instalowania Xcode z formatu %@."; + +"InstallationError.MissingSudoerPassword" = "Brak hasła. Spróbuj ponownie."; +"InstallationError.UnavailableVersion" = "Nie można znaleźć wersji %@."; +"InstallationError.NoNonPrereleaseVersionAvailable" = "Brak wersji nie-przedpremierowych."; +"InstallationError.NoPrereleaseVersionAvailable" = "Brak wersji przedpremierowych."; +"InstallationError.MissingUsernameOrPassword" = "Brak nazwy użytkownika lub hasła. Spróbuj ponownie."; +"InstallationError.VersionAlreadyInstalled" = "%@ jest już zainstalowany w %@."; +"InstallationError.InvalidVersion" = "%@ nie jest prawidłowym numerem wersji."; +"InstallationError.VersionNotInstalled" = "%@ nie jest zainstalowany."; +"InstallationError.PostInstallStepsNotPerformed.Installed" = "Instalacja została zakończona, ale niektóre kroki po instalacji nie zostały wykonane automatycznie. Zostaną one wykonane przy pierwszym uruchomieniu Xcode %@."; +"InstallationError.PostInstallStepsNotPerformed.NotInstalled" = "Instalacja została zakończona, ale niektóre kroki po instalacji nie zostały wykonane automatycznie. Xcodes wykonuje te kroki z pomocą helpera z uprawnieniami, który nie jest zainstalowany. Możesz go zainstalować w Ustawienia > Zaawansowane.\n\nTe kroki zostaną wykonane przy pierwszym uruchomieniu Xcode %@."; + +// Installation Steps +"Downloading" = "Pobieranie"; +"Unarchiving" = "Rozpakowywanie (To może chwilę potrwać)"; +"Moving" = "Przenoszenie do %@"; +"TrashingArchive" = "Przenoszenie archiwum do kosza"; +"CheckingSecurity" = "Weryfikacja zabezpieczeń"; +"Finishing" = "Kończenie"; + +// Notifications +"Notification.NewVersionAvailable" = "Dostępna jest nowa wersja"; +"Notification.FinishedInstalling" = "Zakończono instalację"; + + +"HelperClient.error" = "Nie można komunikować się z helperem z uprawnieniami."; +///++ +// Notifications +"Notification.NewXcodeVersion.Title" = "Nowe wersje Xcode"; +"Notification.NewXcodeVersion.Body" = "Dostępne są nowe wersje Xcode do pobrania."; + +// WWDC +"WWDC.Message" = "šŸ‘ØšŸ»ā€šŸ’»šŸ‘©šŸ¼ā€šŸ’» Wesołego WWDC %@! šŸ‘ØšŸ½ā€šŸ’»šŸ§‘šŸ»ā€šŸ’»"; diff --git a/Xcodes/Resources/pt-BR.lproj/Localizable.strings b/Xcodes/Resources/pt-BR.lproj/Localizable.strings index 68e69cf..9eb73a3 100644 --- a/Xcodes/Resources/pt-BR.lproj/Localizable.strings +++ b/Xcodes/Resources/pt-BR.lproj/Localizable.strings @@ -81,7 +81,7 @@ "AutomaticallyCreateSymbolicLink" = "Criar link simbólico para o Xcode.app automaticamente"; "AutomaticallyCreateSymbolicLinkDescription" = "Quando ativar/selecionar uma versĆ£o do Xcode, tentar criar um link simbólico chamado Xcode.app no diretório de instalação"; "DataSource" = "Fonte de dados"; -"DataSourceDescription" = "A fonte de dados da Apple copia o site Apple Developer. Sempre mostrarĆ” os lanƧamentos mais recentes que estĆ£o disponĆ­veis, porĆ©m Ć© mais frĆ”gil.\n\nLanƧamentos do Xcode Ć© uma lista de lanƧamentos do Xcode nĆ£o-oficial. Ɖ provido como dado formatado, contem informação extra que nĆ£o estĆ” prontamente disponĆ­vel pela Apple, e Ć© menos provĆ”vel que quebre se a Apple redesenhar o seu site de desenvolvedores."; +"DataSourceDescription" = "A fonte de dados da Apple copia o site Apple Developer. Sempre mostrarĆ” os lanƧamentos mais recentes que estĆ£o disponĆ­veis, porĆ©m Ć© mais frĆ”gil.\n\nLanƧamentos do Xcode (Xcode Releases) Ć© uma lista de lanƧamentos do Xcode nĆ£o-oficial. Ɖ provido como dado formatado, contem informação extra que nĆ£o estĆ” prontamente disponĆ­vel pela Apple, e Ć© menos provĆ”vel que quebre se a Apple redesenhar o seu site de desenvolvedores."; "Downloader" = "Baixador"; "DownloaderDescription" = "aria2 usa atĆ© 16 conexƵes para baixar o Xcode 3-5x mais rĆ”pido que URLSession. EstĆ” empacotado como um executĆ”vel junto com o seu código fonte dentro do Xcodes para conformar com a licensa GPLv2.\n\nURLSession Ć© a API padrĆ£o da Apple para performar requisiƧƵes URL."; "PrivilegedHelper" = "Ajudante privilegiado"; @@ -89,6 +89,11 @@ "HelperInstalled" = "Ajudante estĆ” instalado"; "HelperNotInstalled" = "Ajudante nĆ£o estĆ” instalado"; "InstallHelper" = "Instalar ajudante"; +"OnSelectDoNothing" = "Manter nome como Xcode-X.X.X.app"; +"OnSelectRenameXcode" = "Sempre renomear para Xcode.app"; +"OnSelectRenameXcodeDescription" = "Ao selecionar, tentar renomear o Xcode ativo para Xcode.app, renomeando o Xcode.app anterior para um nome com a versĆ£o."; +"ShowOpenInRosetta" = "Mostrar opƧao abrir com Rosetta"; +"ShowOpenInRosettaDescription" = "Opção de abrir com o Rosetta serĆ” mostrar onde outras opƧƵes \"Abrir\" estĆ£o disponĆ­veis. Nota: Isso só serĆ” mostrado pra mĆ”quinas Apple Silicon."; // Experiment Preference Pane "Experiments" = "Experiments"; diff --git a/Xcodes/Resources/tr.lproj/Localizable.strings b/Xcodes/Resources/tr.lproj/Localizable.strings index fd192fd..1cbb514 100644 --- a/Xcodes/Resources/tr.lproj/Localizable.strings +++ b/Xcodes/Resources/tr.lproj/Localizable.strings @@ -95,12 +95,16 @@ "AutomaticallyCreateSymbolicLinkDescription" = "Bir Xcode sürümünü Aktif/SeƧ yaparken Xcode.app ismindeki uygulamanın sembolik linkini yükleme klasƶrüne otomatik oluşturmayı dene"; "OnSelectRenameXcode" = "Her zaman Xcode.app şeklinde ismi değiştir"; "OnSelectRenameXcodeDescription" = "SeƧildiğinde, aktif olan Xcode'u Xcode.app olarak isimlendirmeye Ƨalışır ve eski Xcode ismine sürüm ismi ekler."; + "PrivilegedHelper" = "Ayrıcalıklı Yardımcı"; "PrivilegedHelperDescription" ="Xcodes, root gƶrevlerini yerine getirmek iƧin bir Ayrıcalıklı yardımcı aracı kullanır. Bunlar komut satırındaki sudo gerektiren, yükleme sonrası adımlarını sağlayan ve Xcode sürümü değiştiren xcode-select gibi komutlardan ibarettir.\n\nBunu yüklemek iƧin macOS hesap şifrenizi girmeniz istenecektir."; "HelperInstalled" = "Yardımcı yüklendi"; "HelperNotInstalled" = "Yardımcı yüklenmedi"; "InstallHelper" = "Yardımcıyı yükle"; +"ShowOpenInRosetta" = "Rosetta ile aƧma seƧeneğini gƶster"; +"ShowOpenInRosettaDescription" = "Rosetta ile aƧma opsiyonu diğer uygun \"AƧma\" fonksiyonlarını gƶsterecektir. Not: Bu sadece Apple Silikon makinelerinde gƶzükecektir."; + // Experiment Preference Pane "Experiments" = "Deneyler"; "FasterUnxip" = "Daha Hızlı Unxip"; @@ -159,6 +163,7 @@ "Alert.Uninstall.Title" = "Xcode %@ sürümünü Kaldır?"; "Alert.Uninstall.Message" = "Uygulama Ƈƶp Kutusuna taşınacaktır, fakat silinmeyecektir."; "Alert.Uninstall.Error.Title" = "Xcode Kaldırılamadı"; +"Alert.Uninstall.Error.Message.FileNotFound" = "\"%@\" dosyası bulunamadı."; // Cancel Install "Alert.CancelInstall.Title" = "Xcode %@ sürümünün yüklenmesini durdurmak istediğinize emin misiniz?"; diff --git a/Xcodes/Resources/unxip b/Xcodes/Resources/unxip index d8ce15e..46a7f31 100755 Binary files a/Xcodes/Resources/unxip and b/Xcodes/Resources/unxip differ diff --git a/Xcodes/Resources/zh-Hans.lproj/Localizable.strings b/Xcodes/Resources/zh-Hans.lproj/Localizable.strings index c18bb9d..3bea058 100644 --- a/Xcodes/Resources/zh-Hans.lproj/Localizable.strings +++ b/Xcodes/Resources/zh-Hans.lproj/Localizable.strings @@ -90,7 +90,7 @@ "InstallPathDescription" = "Xcodesä¼šåœØäø€äøŖē›®å½•äø­ę£€ē“¢åŠå®‰č£…ć€‚é»˜č®¤ļ¼ˆęŽØčļ¼‰äæęŒ/Applications。任何对Xcodeå­˜å‚Øä½ē½®ēš„å˜ę›“éƒ½åÆčƒ½ä¼šåÆ¼č‡“å…¶ä»–Appęˆ–ęœåŠ”åœę­¢å·„ä½œć€‚"; "OnSelectDoNothing" = "äæęŒåē§°äøŗXcode-X.X.X.app"; -"OnSelectDoNothingDescription" = "é€‰äø­ę—¶ļ¼Œå°†ä¼šå°†ä¼šäæęŒå„ē‰ˆęœ¬ēš„åē§°ć€‚ä¾‹å¦‚Xcode-13.4.1.app怂"; +"OnSelectDoNothingDescription" = "é€‰äø­ę—¶ļ¼Œå°†ä¼šäæęŒå„ē‰ˆęœ¬ēš„åē§°ć€‚ä¾‹å¦‚Xcode-13.4.1.app怂"; "AutomaticallyCreateSymbolicLink" = "č‡ŖåŠØåˆ›å»ŗåäøŗXcode.appēš„č½ÆčæžęŽ„"; "AutomaticallyCreateSymbolicLinkDescription" = "当激擻/é€‰å®šęŸäøŖXcodeē‰ˆęœ¬ę—¶ļ¼Œå°čÆ•åœØå®‰č£…ē›®å½•åˆ›å»ŗäø€äøŖåäøŗXcode.appēš„č½Æé“¾ęŽ„ć€‚"; "OnSelectRenameXcode" = "ę€»ę˜Æé‡å‘½åäøŗXcode.app"; diff --git a/experiment_dark.jpg b/experiment_dark.jpg deleted file mode 100644 index b71f79b..0000000 Binary files a/experiment_dark.jpg and /dev/null differ diff --git a/experiment_dark.png b/experiment_dark.png new file mode 100644 index 0000000..bfb498a Binary files /dev/null and b/experiment_dark.png differ diff --git a/experiment_light.jpg b/experiment_light.jpg deleted file mode 100644 index a547328..0000000 Binary files a/experiment_light.jpg and /dev/null differ diff --git a/experiment_light.png b/experiment_light.png new file mode 100644 index 0000000..fc71b91 Binary files /dev/null and b/experiment_light.png differ diff --git a/nextstep.md b/nextstep.md new file mode 100644 index 0000000..79aa13d --- /dev/null +++ b/nextstep.md @@ -0,0 +1,15 @@ +## The next step + +As Xcodes continues to grow beyond a small little utility used by Apple Developers all over the world to make their lives easier when it comes to downloading, managing and saving their sanity with Xcode, it was time to move the repo away from Robots and Pencils and into it's own managed org. + +Starting April 21, 2023, all Xcodes repos are now contained under the `XcodesOrg` organization. https://github.com/XcodesOrg + +This change will have no effect on the tools at all, but allows the utilites to grow to the next level. I'm (Matt Kiazyk) still the owner and current sole maintainer, and have no plans to stop. + +Xcodes would not be where it is without contributors over the years. It would also not be where it is without each and every one of you sharing the tool. + +So from myself - thank you! + +Matt Kiazyk - maintainer +@XcodesApp +@mattkiazyk \ No newline at end of file diff --git a/screenshot_dark.png b/screenshot_dark.png index 3de73e4..cf4a6d7 100644 Binary files a/screenshot_dark.png and b/screenshot_dark.png differ diff --git a/screenshot_light.png b/screenshot_light.png index 62989ca..b4d2dec 100644 Binary files a/screenshot_light.png and b/screenshot_light.png differ