diff --git a/Xcodes/Backend/AppState+Runtimes.swift b/Xcodes/Backend/AppState+Runtimes.swift index 009279d..f39c105 100644 --- a/Xcodes/Backend/AppState+Runtimes.swift +++ b/Xcodes/Backend/AppState+Runtimes.swift @@ -46,16 +46,33 @@ extension AppState { } func downloadRuntime(runtime: DownloadableRuntime) { - Task { + runtimePublishers[runtime.identifier] = Task { do { - try await downloadRunTimeFull(runtime: runtime) + let downloadedURL = try await downloadRunTimeFull(runtime: runtime) + if !Task.isCancelled { + Logger.appState.debug("Installing rungtime: \(runtime.name)") + DispatchQueue.main.async { + self.setInstallationStep(of: runtime, to: .installing) + } + switch runtime.contentType { + case .package: + // not supported yet (do we need to for old packages?) + throw "Installing via package not support - please install manually from \(downloadedURL.description)" + case .diskImage: + try await self.installFromImage(dmgURL: downloadedURL) + DispatchQueue.main.async { + self.setInstallationStep(of: runtime, to: .trashingArchive) + } + try Current.files.removeItem(at: downloadedURL) + } - DispatchQueue.main.async { - guard let index = self.downloadableRuntimes.firstIndex(where: { $0.identifier == runtime.identifier }) else { return } - self.downloadableRuntimes[index].installState = .installed + DispatchQueue.main.async { + guard let index = self.downloadableRuntimes.firstIndex(where: { $0.identifier == runtime.identifier }) else { return } + self.downloadableRuntimes[index].installState = .installed + } + updateInstalledRuntimes() } - - updateInstalledRuntimes() + } catch { Logger.appState.error("Error downloading runtime: \(error.localizedDescription)") @@ -67,38 +84,44 @@ extension AppState { } } - func downloadRunTimeFull(runtime: DownloadableRuntime) async throws { + func downloadRunTimeFull(runtime: DownloadableRuntime) async throws -> URL { // sets a proper cookie for runtimes try await validateADCSession(path: runtime.downloadPath) let downloader = Downloader(rawValue: UserDefaults.standard.string(forKey: "downloader") ?? "aria2") ?? .aria2 + + let url = URL(string: runtime.source)! + let expectedRuntimePath = Path.xcodesApplicationSupport/"\(url.lastPathComponent)" + // aria2 downloads directly to the destination (instead of into /tmp first) so we need to make sure that the download isn't incomplete + let aria2DownloadMetadataPath = expectedRuntimePath.parent/(expectedRuntimePath.basename() + ".aria2") + var aria2DownloadIsIncomplete = false + if case .aria2 = downloader, aria2DownloadMetadataPath.exists { + aria2DownloadIsIncomplete = true + } + if Current.files.fileExistsAtPath(expectedRuntimePath.string), aria2DownloadIsIncomplete == false { + Logger.appState.info("Found existing runtime that will be used for installation at \(expectedRuntimePath).") + return expectedRuntimePath.url + } + Logger.appState.info("Downloading \(runtime.visibleIdentifier) with \(downloader)") - - - let url = try await self.downloadRuntime(for: runtime, downloader: downloader, progressChanged: { [unowned self] progress in - DispatchQueue.main.async { - self.setInstallationStep(of: runtime, to: .downloading(progress: progress)) - } - }).async() - - Logger.appState.debug("Done downloading: \(url)") - DispatchQueue.main.async { - self.setInstallationStep(of: runtime, to: .installing) - } - switch runtime.contentType { - case .package: - // not supported yet (do we need to for old packages?) - throw "Installing via package not support - please install manually from \(url.description)" - case .diskImage: - try await self.installFromImage(dmgURL: url) - DispatchQueue.main.async { - self.setInstallationStep(of: runtime, to: .trashingArchive) - } - try Current.files.removeItem(at: url) + switch downloader { + case .aria2: + let aria2Path = Path(url: Bundle.main.url(forAuxiliaryExecutable: "aria2c")!)! + for try await progress in downloadRuntimeWithAria2(runtime, to: expectedRuntimePath, aria2Path: aria2Path) { + DispatchQueue.main.async { + Logger.appState.debug("Downloading: \(progress.fractionCompleted)") + self.setInstallationStep(of: runtime, to: .downloading(progress: progress)) + } + } + Logger.appState.debug("Done downloading") + + case .urlSession: + throw "Downloading runtimes with URLSession is not supported. Please use aria2" } + return expectedRuntimePath.url } + - @MainActor func downloadRuntime(for runtime: DownloadableRuntime, downloader: Downloader, progressChanged: @escaping (Progress) -> Void) -> AnyPublisher { // Check to see if the dmg is in the expected path in case it was downloaded but failed to install @@ -156,9 +179,36 @@ extension AppState { .eraseToAnyPublisher() } + public func downloadRuntimeWithAria2(_ runtime: DownloadableRuntime, to destination: Path, aria2Path: Path) -> AsyncThrowingStream { + let cookies = AppleAPI.Current.network.session.configuration.httpCookieStorage?.cookies(for: runtime.url) ?? [] + + return Current.shell.downloadWithAria2Async(aria2Path, runtime.url, destination, cookies) + } + + public func installFromImage(dmgURL: URL) async throws { try await self.runtimeService.installRuntimeImage(dmgURL: dmgURL) } + + func cancelRuntimeInstall(runtime: DownloadableRuntime) { + // Cancel the publisher + + runtimePublishers[runtime.identifier]?.cancel() + runtimePublishers[runtime.identifier] = nil + + // If the download is cancelled by the user, clean up the download files that aria2 creates. + let url = URL(string: runtime.source)! + let expectedRuntimePath = Path.xcodesApplicationSupport/"\(url.lastPathComponent)" + let aria2DownloadMetadataPath = expectedRuntimePath.parent/(expectedRuntimePath.basename() + ".aria2") + + try? Current.files.removeItem(at: expectedRuntimePath.url) + try? Current.files.removeItem(at: aria2DownloadMetadataPath.url) + + guard let index = self.downloadableRuntimes.firstIndex(where: { $0.identifier == runtime.identifier }) else { return } + self.downloadableRuntimes[index].installState = .notInstalled + + updateInstalledRuntimes() + } } extension AnyPublisher { @@ -181,3 +231,42 @@ extension AnyPublisher { } } } +extension AnyPublisher where Failure: Error { + struct Subscriber { + fileprivate let send: (Output) -> Void + fileprivate let complete: (Subscribers.Completion) -> Void + + func send(_ value: Output) { self.send(value) } + func send(completion: Subscribers.Completion) { self.complete(completion) } + } + + init(_ closure: (Subscriber) -> AnyCancellable) { + let subject = PassthroughSubject() + + let subscriber = Subscriber( + send: subject.send, + complete: subject.send(completion:) + ) + let cancel = closure(subscriber) + + self = subject + .handleEvents(receiveCancel: cancel.cancel) + .eraseToAnyPublisher() + } +} + +extension AnyPublisher where Failure == Error { + init(taskPriority: TaskPriority? = nil, asyncFunc: @escaping () async throws -> Output) { + self.init { subscriber in + let task = Task(priority: taskPriority) { + do { + subscriber.send(try await asyncFunc()) + subscriber.send(completion: .finished) + } catch { + subscriber.send(completion: .failure(error)) + } + } + return AnyCancellable { task.cancel() } + } + } +} diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift index 9db4dbe..7de4af7 100644 --- a/Xcodes/Backend/AppState.swift +++ b/Xcodes/Backend/AppState.swift @@ -112,7 +112,7 @@ class AppState: ObservableObject { var cancellables = Set() private var installationPublishers: [Version: AnyCancellable] = [:] - internal var runtimePublishers: [String: AnyCancellable] = [:] + internal var runtimePublishers: [String: Task<(), any Error>] = [:] private var selectPublisher: AnyCancellable? private var uninstallPublisher: AnyCancellable? private var autoInstallTimer: Timer? diff --git a/Xcodes/Backend/Environment.swift b/Xcodes/Backend/Environment.swift index 6d77108..8470913 100644 --- a/Xcodes/Backend/Environment.swift +++ b/Xcodes/Backend/Environment.swift @@ -111,9 +111,84 @@ public struct Shell { return (progress, publisher) } - // TODO: Support using aria2 using AysncStream/AsyncSequence -// public var downloadWithAria2Async: (Path, URL, Path, [HTTPCookie]) async throws -> Progress = { aria2Path, url, destination, cookies in - + + public var downloadWithAria2Async: (Path, URL, Path, [HTTPCookie]) -> AsyncThrowingStream = { aria2Path, url, destination, cookies in + return AsyncThrowingStream { continuation in + + Task { + var progress = Progress() + progress.kind = .file + progress.fileOperationKind = .downloading + + let process = Process() + process.executableURL = aria2Path.url + process.arguments = [ + "--header=Cookie: \(cookies.map { "\($0.name)=\($0.value)" }.joined(separator: "; "))", + "--max-connection-per-server=16", + "--split=16", + "--summary-interval=1", + "--stop-with-process=\(ProcessInfo.processInfo.processIdentifier)", // if xcodes quits, stop aria2 process + "--dir=\(destination.parent.string)", + "--out=\(destination.basename())", + "--human-readable=false", // sets the output to use bytes instead of formatting + url.absoluteString, + ] + let stdOutPipe = Pipe() + process.standardOutput = stdOutPipe + let stdErrPipe = Pipe() + process.standardError = stdErrPipe + + let observer = NotificationCenter.default.addObserver( + forName: .NSFileHandleDataAvailable, + object: nil, + queue: OperationQueue.main + ) { note in + guard + // This should always be the case for Notification.Name.NSFileHandleDataAvailable + let handle = note.object as? FileHandle, + handle === stdOutPipe.fileHandleForReading || handle === stdErrPipe.fileHandleForReading + else { return } + + defer { handle.waitForDataInBackgroundAndNotify() } + + let string = String(decoding: handle.availableData, as: UTF8.self) + // TODO: fix warning. ObservingProgressView is currently tied to an updating progress + progress.updateFromAria2(string: string) + + continuation.yield(progress) + } + + stdOutPipe.fileHandleForReading.waitForDataInBackgroundAndNotify() + stdErrPipe.fileHandleForReading.waitForDataInBackgroundAndNotify() + + continuation.onTermination = { @Sendable _ in + process.terminate() + NotificationCenter.default.removeObserver(observer, name: .NSFileHandleDataAvailable, object: nil) + } + + do { + try process.run() + } catch { + continuation.finish(throwing: error) + } + + process.waitUntilExit() + + NotificationCenter.default.removeObserver(observer, name: .NSFileHandleDataAvailable, object: nil) + + guard process.terminationReason == .exit, process.terminationStatus == 0 else { + if let aria2cError = Aria2CError(exitStatus: process.terminationStatus) { + continuation.finish(throwing: aria2cError) + } else { + continuation.finish(throwing: ProcessExecutionError(process: process, standardOutput: "", standardError: "")) + } + return + } + continuation.finish() + } + } + } + public var unxipExperiment: (URL) -> AnyPublisher = { url in let unxipPath = Path(url: Bundle.main.url(forAuxiliaryExecutable: "unxip")!)! diff --git a/Xcodes/Backend/XcodeCommands.swift b/Xcodes/Backend/XcodeCommands.swift index ce36399..2913af5 100644 --- a/Xcodes/Backend/XcodeCommands.swift +++ b/Xcodes/Backend/XcodeCommands.swift @@ -67,6 +67,23 @@ struct CancelInstallButton: View { } } +struct CancelRuntimeInstallButton: View { + @EnvironmentObject var appState: AppState + let runtime: DownloadableRuntime? + + var body: some View { + Button(action: cancelInstall) { + Text("Cancel") + .help(localizeString("StopInstallation")) + } + } + + private func cancelInstall() { + guard let runtime = runtime else { return } + appState.presentedAlert = .cancelRuntimeInstall(runtime: runtime) + } +} + struct SelectButton: View { @EnvironmentObject var appState: AppState let xcode: Xcode? diff --git a/Xcodes/Frontend/Common/XcodesAlert.swift b/Xcodes/Frontend/Common/XcodesAlert.swift index c928501..38636cb 100644 --- a/Xcodes/Frontend/Common/XcodesAlert.swift +++ b/Xcodes/Frontend/Common/XcodesAlert.swift @@ -1,7 +1,9 @@ import Foundation +import XcodesKit enum XcodesAlert: Identifiable { case cancelInstall(xcode: Xcode) + case cancelRuntimeInstall(runtime: DownloadableRuntime) case privilegedHelper case generic(title: String, message: String) case checkMinSupportedVersion(xcode: AvailableXcode, macOS: String) @@ -12,6 +14,7 @@ enum XcodesAlert: Identifiable { case .privilegedHelper: return 2 case .generic: return 3 case .checkMinSupportedVersion: return 4 + case .cancelRuntimeInstall: return 5 } } } diff --git a/Xcodes/Frontend/InfoPane/RuntimesView.swift b/Xcodes/Frontend/InfoPane/RuntimesView.swift index e9e894e..5148c71 100644 --- a/Xcodes/Frontend/InfoPane/RuntimesView.swift +++ b/Xcodes/Frontend/InfoPane/RuntimesView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import XcodesKit struct RuntimesView: View { @EnvironmentObject var appState: AppState @@ -14,49 +15,61 @@ struct RuntimesView: View { var body: some View { VStack(alignment: .leading) { - Text("Platforms") - .font(.headline) - .frame(maxWidth: .infinity, alignment: .leading) - - let builds = xcode.sdks?.allBuilds() - let runtimes = builds?.flatMap { sdkBuild in - appState.downloadableRuntimes.filter { - $0.sdkBuildUpdate == sdkBuild - } - } - - ForEach(runtimes ?? [], id: \.simulatorVersion.buildUpdate) { runtime in - VStack { - HStack { - Text("\(runtime.visibleIdentifier)") - .font(.subheadline) - Spacer() - Text(runtime.downloadFileSizeString) - .font(.subheadline) - - // it's installed if we have a path - if let path = appState.runtimeInstallPath(xcode: xcode, runtime: runtime) { - Button(action: { appState.reveal(path: path.string) }) { - Image(systemName: "arrow.right.circle.fill") - } - .buttonStyle(PlainButtonStyle()) - .help("RevealInFinder") - } else { - DownloadRuntimeButton(runtime: runtime) - } - } - switch runtime.installState { - - case .installing(let installationStep): - RuntimeInstallationStepDetailView(installationStep: installationStep) - .fixedSize(horizontal: false, vertical: true) - default: - EmptyView() - } - } - - } + Text("Platforms") + .font(.headline) + .frame(maxWidth: .infinity, alignment: .leading) + + let builds = xcode.sdks?.allBuilds() + let runtimes = builds?.flatMap { sdkBuild in + appState.downloadableRuntimes.filter { + $0.sdkBuildUpdate == sdkBuild } + } + + ForEach(runtimes ?? [], id: \.simulatorVersion.buildUpdate) { runtime in + VStack { + runtimeRow(runtime: runtime) + } + + } + } + } + + @ViewBuilder + func runtimeRow(runtime: DownloadableRuntime) -> some View { + HStack { + Text("\(runtime.visibleIdentifier)") + .font(.subheadline) + Spacer() + Text(runtime.downloadFileSizeString) + .font(.subheadline) + + switch runtime.installState { + case .installed, .notInstalled: + // it's installed if we have a path + if let path = appState.runtimeInstallPath(xcode: xcode, runtime: runtime) { + Button(action: { appState.reveal(path: path.string) }) { + Image(systemName: "arrow.right.circle.fill") + } + .buttonStyle(PlainButtonStyle()) + .help("RevealInFinder") + } else { + DownloadRuntimeButton(runtime: runtime) + } + case .installing(_): + CancelRuntimeInstallButton(runtime: runtime) + } + + } + + switch runtime.installState { + + case .installing(let installationStep): + RuntimeInstallationStepDetailView(installationStep: installationStep) + .fixedSize(horizontal: false, vertical: true) + default: + EmptyView() + } } } diff --git a/Xcodes/Frontend/MainWindow.swift b/Xcodes/Frontend/MainWindow.swift index 5c74ea4..b8df774 100644 --- a/Xcodes/Frontend/MainWindow.swift +++ b/Xcodes/Frontend/MainWindow.swift @@ -1,5 +1,6 @@ import ErrorHandling import SwiftUI +import XcodesKit struct MainWindow: View { @EnvironmentObject var appState: AppState @@ -176,7 +177,21 @@ struct MainWindow: View { ), secondaryButton: .cancel(Text("Cancel")) ) + + case let .cancelRuntimeInstall(runtime): + return Alert( + title: Text(String(format: localizeString("Alert.CancelInstall.Runtimes.Title"), runtime.name)), + message: Text("Alert.CancelInstall.Message"), + primaryButton: .destructive( + Text("Alert.CancelInstall.PrimaryButton"), + action: { + self.appState.cancelRuntimeInstall(runtime: runtime) + } + ), + secondaryButton: .cancel(Text("Cancel")) + ) } + } } diff --git a/Xcodes/Resources/Localizable.xcstrings b/Xcodes/Resources/Localizable.xcstrings index ede84f6..b816f46 100644 --- a/Xcodes/Resources/Localizable.xcstrings +++ b/Xcodes/Resources/Localizable.xcstrings @@ -1,8 +1,26 @@ { "sourceLanguage" : "en", "strings" : { + "" : { + + }, + "%@" : { + + }, + "%@ %@ %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ %2$@ %3$@" + } + } + } + }, + "• %@" : { + + }, "AccessDenied" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -116,7 +134,6 @@ }, "AccessGranted" : { "comment" : "Notifications", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -229,7 +246,6 @@ } }, "Acknowledgements" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -243,12 +259,6 @@ "value" : "Anerkennungen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Acknowledgements" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -342,7 +352,6 @@ } }, "Active" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -356,12 +365,6 @@ "value" : "Aktiv" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Active" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -455,7 +458,6 @@ } }, "Active/Select" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -469,12 +471,6 @@ "value" : "Aktiv/Auswählen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Active/Select" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -569,7 +565,6 @@ }, "ActiveVersionDescription" : { "comment" : "List", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -683,7 +678,6 @@ }, "Advanced" : { "comment" : "Advanced Preference Pane", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -697,12 +691,6 @@ "value" : "Erweitert" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Advanced" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -796,7 +784,6 @@ } }, "Alert.CancelInstall.Message" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -909,7 +896,6 @@ } }, "Alert.CancelInstall.PrimaryButton" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -1021,9 +1007,21 @@ } } }, + "Alert.CancelInstall.Runtimes.Title" : { + "comment" : "Cancel Runtime Install", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to stop the installation of Xcode %@?" + } + } + } + }, "Alert.CancelInstall.Title" : { "comment" : "Cancel Install", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -1137,7 +1135,7 @@ }, "Alert.Install.Error.Title" : { "comment" : "Install", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -1250,7 +1248,7 @@ } }, "Alert.InstallArchive.Error.Title" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -1363,7 +1361,7 @@ } }, "Alert.MinSupported.Message" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -1477,7 +1475,6 @@ }, "Alert.MinSupported.Title" : { "comment" : "Min MacOS Supported", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -1591,7 +1588,7 @@ }, "Alert.PostInstall.Title" : { "comment" : "Post install", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -1704,7 +1701,7 @@ } }, "Alert.PrivilegedHelper.Error.Title" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -1817,7 +1814,6 @@ } }, "Alert.PrivilegedHelper.Message" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -1931,7 +1927,6 @@ }, "Alert.PrivilegedHelper.Title" : { "comment" : "Privileged Helper", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -2045,7 +2040,7 @@ }, "Alert.Select.Error.Title" : { "comment" : "Active/Select", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -2158,7 +2153,7 @@ } }, "Alert.SymLink.Message" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -2272,7 +2267,7 @@ }, "Alert.SymLink.Title" : { "comment" : "Symbolic Links", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -2385,7 +2380,7 @@ } }, "Alert.Uninstall.Error.Message.FileNotFound" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "de" : { "stringUnit" : { @@ -2426,7 +2421,7 @@ } }, "Alert.Uninstall.Error.Title" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -2539,7 +2534,6 @@ } }, "Alert.Uninstall.Message" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -2653,7 +2647,7 @@ }, "Alert.Uninstall.Title" : { "comment" : "Uninstall", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -2767,7 +2761,7 @@ }, "Alert.Update.Error.Title" : { "comment" : "Update", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -2880,7 +2874,6 @@ } }, "All" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -2894,12 +2887,6 @@ "value" : "Alle" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "All" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -2991,9 +2978,11 @@ } } } + }, + "Apple Silicon" : { + }, "AppleID" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -3106,7 +3095,6 @@ } }, "AppUpdates" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -3219,7 +3207,6 @@ } }, "AutomaticallyCreateSymbolicLink" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -3332,7 +3319,6 @@ } }, "AutomaticallyCreateSymbolicLinkDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -3445,7 +3431,6 @@ } }, "AutomaticInstallNewVersion" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -3558,7 +3543,7 @@ } }, "Beta" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -3671,7 +3656,6 @@ } }, "BetaOnly" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -3784,7 +3768,6 @@ } }, "Cancel" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -3798,12 +3781,6 @@ "value" : "Abbrechen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Cancel" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -3897,7 +3874,6 @@ } }, "Change" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -3911,12 +3887,6 @@ "value" : "Ändern" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Change" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -4010,7 +3980,6 @@ } }, "CheckForAppUpdates" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -4123,7 +4092,7 @@ } }, "CheckingSecurity" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -4236,7 +4205,6 @@ } }, "CheckNow" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -4349,7 +4317,6 @@ } }, "Close" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -4363,12 +4330,6 @@ "value" : "Schließen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -4462,7 +4423,6 @@ } }, "Compatibility" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -4476,12 +4436,6 @@ "value" : "Kompatibilität" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Compatibility" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -4575,7 +4529,6 @@ } }, "Compilers" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -4589,12 +4542,6 @@ "value" : "Compiler" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Compilers" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -4688,7 +4635,6 @@ } }, "Continue" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -4702,12 +4648,6 @@ "value" : "Fortfahren" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Continue" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -4801,7 +4741,6 @@ } }, "CopyPath" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -4914,7 +4853,6 @@ } }, "CopyReleaseNoteURL" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -5009,7 +4947,6 @@ } }, "CreateSymLink" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -5122,7 +5059,6 @@ } }, "CreateSymLinkBeta" : { - "extractionState" : "migrated", "localizations" : { "de" : { "stringUnit" : { @@ -5205,7 +5141,6 @@ } }, "DataSource" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -5318,7 +5253,7 @@ } }, "DataSourceDescription" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -5432,7 +5367,7 @@ }, "DigitCodeDescription" : { "comment" : "SMS/2FA", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -5545,7 +5480,6 @@ } }, "Downloader" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -5559,12 +5493,6 @@ "value" : "Downloader" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Downloader" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -5658,7 +5586,7 @@ } }, "DownloaderDescription" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -5772,7 +5700,7 @@ }, "Downloading" : { "comment" : "Installation Steps", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -5885,7 +5813,7 @@ } }, "DownloadingError" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -5998,7 +5926,7 @@ } }, "DownloadingPercentDescription" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -6112,7 +6040,6 @@ }, "Downloads" : { "comment" : "Download Preference Pane", - "extractionState" : "migrated", "localizations" : { "de" : { "stringUnit" : { @@ -6120,12 +6047,6 @@ "value" : "Downloads" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Downloads" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -6207,7 +6128,6 @@ } }, "DownloadSize" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -6320,7 +6240,6 @@ } }, "EnableNotifications" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -6433,7 +6352,7 @@ } }, "EnterDigitCodeDescription" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -6544,10 +6463,12 @@ } } } + }, + "example@icloud.com" : { + }, "Experiments" : { "comment" : "Experiment Preference Pane", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -6561,12 +6482,6 @@ "value" : "Experimente" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Experiments" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -6660,7 +6575,6 @@ } }, "FasterUnxip" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -6773,7 +6687,7 @@ } }, "FasterUnxipDescription" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -6886,7 +6800,6 @@ } }, "Filter" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -6900,12 +6813,6 @@ "value" : "Filter" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Filter" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -6999,7 +6906,6 @@ } }, "FilterAvailableDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -7112,7 +7018,6 @@ } }, "FilterInstalledDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -7225,7 +7130,7 @@ } }, "Finishing" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -7339,7 +7244,6 @@ }, "General" : { "comment" : "General Preference Pane", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -7353,12 +7257,6 @@ "value" : "Allgemein" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "General" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -7452,7 +7350,6 @@ } }, "GithubRepo" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -7565,7 +7462,7 @@ } }, "HelperClient.error" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -7678,7 +7575,6 @@ } }, "HelperInstalled" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -7791,7 +7687,6 @@ } }, "HelperNotInstalled" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -7902,10 +7797,12 @@ } } } + }, + "Hidden" : { + }, "IdenticalBuilds" : { "comment" : "Info Pane", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -8018,7 +7915,6 @@ } }, "IdenticalBuilds.help" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -8131,7 +8027,6 @@ } }, "IncludePreRelease" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -8244,7 +8139,6 @@ } }, "Info" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -8258,12 +8152,6 @@ "value" : "Info" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Info" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -8357,7 +8245,6 @@ } }, "InfoDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -8471,7 +8358,6 @@ }, "Install" : { "comment" : "Common", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -8485,12 +8371,6 @@ "value" : "Installieren" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Install" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -8582,9 +8462,12 @@ } } } + }, + "INSTALL" : { + }, "InstallationError.CodesignVerifyFailed" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -8698,7 +8581,7 @@ }, "InstallationError.DamagedXIP" : { "comment" : "InstallationErrors", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -8811,7 +8694,7 @@ } }, "InstallationError.FailedSecurityAssessment" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -8924,7 +8807,7 @@ } }, "InstallationError.FailedToMoveXcodeToApplications" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9037,7 +8920,7 @@ } }, "InstallationError.InvalidVersion" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9150,7 +9033,7 @@ } }, "InstallationError.MissingSudoerPassword" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9263,7 +9146,7 @@ } }, "InstallationError.MissingUsernameOrPassword" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9376,7 +9259,7 @@ } }, "InstallationError.NoNonPrereleaseVersionAvailable" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9489,7 +9372,7 @@ } }, "InstallationError.NoPrereleaseVersionAvailable" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9602,7 +9485,7 @@ } }, "InstallationError.NotEnoughFreeSpaceToExpandArchive" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9715,7 +9598,7 @@ } }, "InstallationError.PostInstallStepsNotPerformed.Installed" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9828,7 +9711,7 @@ } }, "InstallationError.PostInstallStepsNotPerformed.NotInstalled" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -9941,7 +9824,7 @@ } }, "InstallationError.UnavailableVersion" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -10054,7 +9937,7 @@ } }, "InstallationError.UnexpectedCodeSigningIdentity" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -10167,7 +10050,7 @@ } }, "InstallationError.UnsupportedFileFormat" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -10280,7 +10163,7 @@ } }, "InstallationError.VersionAlreadyInstalled" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -10393,7 +10276,7 @@ } }, "InstallationError.VersionNotInstalled" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -10507,7 +10390,7 @@ }, "InstallationStepDescription" : { "comment" : "So if changing order, make sure the positional specficier is retained. ex: \"%3$@: Step %1$d of %2$d\"", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -10620,7 +10503,6 @@ } }, "InstallDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -10733,7 +10615,6 @@ } }, "InstallDirectory" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -10798,7 +10679,6 @@ } }, "InstallHelper" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -10911,7 +10791,6 @@ } }, "InstallPathDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -10970,7 +10849,7 @@ } }, "LastChecked" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -11083,7 +10962,6 @@ } }, "License" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -11097,12 +10975,6 @@ "value" : "Lizenz" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "License" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -11196,7 +11068,6 @@ } }, "LocalCachePath" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -11309,7 +11180,6 @@ } }, "LocalCachePathDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -11423,7 +11293,6 @@ }, "Login" : { "comment" : "ToolBar", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -11437,12 +11306,6 @@ "value" : "Login" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Login" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -11536,7 +11399,6 @@ } }, "LoginDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -11649,7 +11511,7 @@ } }, "MacOSRequirement" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -11762,7 +11624,6 @@ } }, "MakeActive" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -11875,7 +11736,6 @@ } }, "MakeActiveVersionDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -11989,7 +11849,6 @@ }, "Menu.About" : { "comment" : "Menu", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -12102,7 +11961,7 @@ } }, "Menu.Acknowledgements" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -12215,7 +12074,6 @@ } }, "Menu.CheckForUpdates" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -12328,7 +12186,6 @@ } }, "Menu.GitHubRepo" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -12441,7 +12298,6 @@ } }, "Menu.ReportABug" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -12554,7 +12410,6 @@ } }, "Menu.RequestNewFeature" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -12667,7 +12522,7 @@ } }, "Moving" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -12780,7 +12635,7 @@ } }, "Never" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -12893,7 +12748,6 @@ } }, "Next" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -12907,12 +12761,6 @@ "value" : "Nächstes" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Next" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -13004,9 +12852,12 @@ } } } + }, + "Not Hidden" : { + }, "Notification.FinishedInstalling" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -13120,7 +12971,7 @@ }, "Notification.NewVersionAvailable" : { "comment" : "Notifications", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -13233,7 +13084,7 @@ } }, "Notification.NewXcodeVersion.Body" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -13347,7 +13198,7 @@ }, "Notification.NewXcodeVersion.Title" : { "comment" : "Notifications", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -13460,7 +13311,6 @@ } }, "Notifications" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -13474,12 +13324,6 @@ "value" : "Benachrichtigungen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Notifications" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -13573,7 +13417,6 @@ } }, "NotificationSettings" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -13686,7 +13529,7 @@ } }, "NoTrustedPhones" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -13799,7 +13642,6 @@ } }, "NoXcodeSelected" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -13912,7 +13754,6 @@ } }, "OK" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -13926,12 +13767,6 @@ "value" : "OK" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "OK" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -14017,9 +13852,12 @@ } } } + }, + "OnSelect" : { + }, "OnSelectDoNothing" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -14096,7 +13934,7 @@ } }, "OnSelectDoNothingDescription" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -14161,7 +13999,7 @@ } }, "OnSelectRenameXcode" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "de" : { "stringUnit" : { @@ -14226,7 +14064,7 @@ } }, "OnSelectRenameXcodeDescription" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -14297,7 +14135,6 @@ } }, "Open" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -14311,12 +14148,6 @@ "value" : "Öffnen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Open" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -14408,9 +14239,14 @@ } } } + }, + "OPEN" : { + + }, + "Open In Rosetta" : { + }, "OpenDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -14523,7 +14359,6 @@ } }, "Password" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -14634,20 +14469,14 @@ } } } + }, + "Perform post-install steps" : { + }, "Platforms" : { - "extractionState" : "migrated", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Platforms" - } - } - } + }, "Preferences" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -14661,12 +14490,6 @@ "value" : "Einstellungen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Preferences" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -14760,7 +14583,6 @@ } }, "PreferencesDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -14873,7 +14695,6 @@ } }, "PrivilegedHelper" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -14986,7 +14807,6 @@ } }, "PrivilegedHelperDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -15099,7 +14919,6 @@ } }, "Refresh" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -15113,12 +14932,6 @@ "value" : "Aktualisieren" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Refresh" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -15212,7 +15025,6 @@ } }, "RefreshDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -15325,7 +15137,7 @@ } }, "Release" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -15438,7 +15250,6 @@ } }, "ReleaseDate" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -15551,7 +15362,6 @@ } }, "ReleaseNotes" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -15664,7 +15474,6 @@ } }, "ReleaseNotes.help" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -15777,7 +15586,6 @@ } }, "ReleaseOnly" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -15890,7 +15698,6 @@ } }, "Required" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -15904,12 +15711,6 @@ "value" : "Erforderlich" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Required" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -16003,7 +15804,6 @@ } }, "RevealInFinder" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -16116,7 +15916,6 @@ } }, "SDKs" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -16130,12 +15929,6 @@ "value" : "SDKs" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "SDKs" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -16229,7 +16022,6 @@ } }, "Search" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -16342,7 +16134,6 @@ } }, "SearchDescription" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -16455,7 +16246,6 @@ } }, "Select" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -16469,12 +16259,6 @@ "value" : "Auswählen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Select" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -16568,7 +16352,6 @@ } }, "Selected" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -16582,12 +16365,6 @@ "value" : "Ausgewählt" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Selected" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -16681,7 +16458,7 @@ } }, "SelectTrustedPhone" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -16794,7 +16571,6 @@ } }, "SendSMS" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -16907,7 +16683,6 @@ } }, "ShowOpenInRosetta" : { - "extractionState" : "migrated", "localizations" : { "en" : { "stringUnit" : { @@ -16948,7 +16723,6 @@ } }, "ShowOpenInRosettaDescription" : { - "extractionState" : "migrated", "localizations" : { "en" : { "stringUnit" : { @@ -16989,7 +16763,6 @@ } }, "SignIn" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -17103,7 +16876,6 @@ }, "SignInWithApple" : { "comment" : "SignIn", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -17216,7 +16988,6 @@ } }, "SignOut" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -17329,7 +17100,6 @@ } }, "StopInstallation" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -17442,7 +17212,7 @@ } }, "TrashingArchive" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -17555,7 +17325,7 @@ } }, "Unarchiving" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -17668,7 +17438,6 @@ } }, "Uninstall" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -17682,12 +17451,6 @@ "value" : "Deinstallieren" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Uninstall" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -17781,7 +17544,6 @@ } }, "UnxipExperiment" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -17895,7 +17657,7 @@ }, "UpdatedAt" : { "comment" : "MainWindow", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -18009,7 +17771,6 @@ }, "Updates" : { "comment" : "Updates Preference Pane", - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -18023,12 +17784,6 @@ "value" : "Updates" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Updates" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -18122,7 +17877,6 @@ } }, "UseUnxipExperiment" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -18235,7 +17989,6 @@ } }, "Versions" : { - "extractionState" : "migrated", "localizations" : { "ca" : { "stringUnit" : { @@ -18249,12 +18002,6 @@ "value" : "Versionen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Versions" - } - }, "es" : { "stringUnit" : { "state" : "translated", @@ -18349,7 +18096,7 @@ }, "VersionWithBuild" : { "comment" : "About", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -18463,7 +18210,7 @@ }, "WWDC.Message" : { "comment" : "WWDC", - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "ca" : { "stringUnit" : { @@ -18568,6 +18315,12 @@ } } } + }, + "Xcode" : { + + }, + "Xcodes" : { + } }, "version" : "1.0"