diff --git a/.tx/config b/.tx/config index 5a64101d60..6a5dfba228 100644 --- a/.tx/config +++ b/.tx/config @@ -14,3 +14,14 @@ source_file = mirall.desktop.in source_lang = en type = DESKTOP +[o:nextcloud:p:nextcloud:r:client-fileprovider] +file_filter = shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Localizable.xcstrings +source_file = shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Localizable.xcstrings +source_lang = en +type = XCSTRINGS + +[o:nextcloud:p:nextcloud:r:client-fileproviderui] +file_filter = shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Localizable.xcstrings +source_file = shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Localizable.xcstrings +source_lang = en +type = XCSTRINGS diff --git a/REUSE.toml b/REUSE.toml index 528537d7ad..54f8c67b17 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -44,6 +44,12 @@ SPDX-License-Identifier = "GPL-2.0-or-later" [[annotations]] path = ["shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj", "shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata", "shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist", "shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/xcshareddata/xcschemes/FinderSyncExt.xcscheme"] precedence = "aggregate" +SPDX-FileCopyrightText = "2025 Nextcloud GmbH and Nextcloud contributors" +SPDX-License-Identifier = "GPL-2.0-or-later" + +[[annotations]] +path = ["shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Localizable.xcstrings", "shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Localizable.xcstrings"] +precedence = "aggregate" SPDX-FileCopyrightText = "2015 ownCloud GmbH, 2022 Nextcloud GmbH and Nextcloud contributors" SPDX-License-Identifier = "GPL-2.0-or-later" diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Localizable.xcstrings b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Localizable.xcstrings new file mode 100644 index 0000000000..3ed6edaa4a --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Localizable.xcstrings @@ -0,0 +1,28 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "Allow automatic freeing up space" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatische Freigabe von Speicherplatz erlauben" + } + } + } + }, + "Always keep downloaded" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immer heruntergeladen" + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Localizable.xcstrings b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Localizable.xcstrings new file mode 100644 index 0000000000..a7d630d61a --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Localizable.xcstrings @@ -0,0 +1,462 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "Account data is unavailable, cannot reload data!" : { + + }, + "Allow upload and editing" : { + "comment" : "Checkbox title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hochladen und bearbeiten erlauben" + } + } + } + }, + "Cancel" : { + "comment" : "Button title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abbrechen" + } + } + } + }, + "Close" : { + "comment" : "Button title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Schließen" + } + } + } + }, + "Communicating with server, locking file…" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kommuniziere mit Server, sperre Datei…" + } + } + } + }, + "Communicating with server, unlocking file…" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kommuniziere mit Server, entsperre Datei…" + } + } + } + }, + "Could not fetch capabilities as account is invalid." : { + "comment" : "Error message" + }, + "Could not get identifier for item, no shares can be acquired." : { + "comment" : "Error message" + }, + "Could not lock unknown item…" : { + "comment" : "Text label" + }, + "Could not reload data: %@, will try again." : { + "comment" : "Error message" + }, + "Create new share" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Neue Freigabe erstellen" + } + } + } + }, + "Delete" : { + "comment" : "Button title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Löschen" + } + } + } + }, + "Dismiss" : { + "comment" : "Button title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Schließen" + } + } + } + }, + "Email share" : { + "comment" : "Menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail Freigabe" + } + } + } + }, + "Enter a new password" : { + "comment" : "Text field placeholder", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ein neues Passwort eingeben" + } + } + } + }, + "Error creating: %@" : { + "comment" : "Error message" + }, + "Error fetching shares: %@" : { + "comment" : "Error message" + }, + "Error getting server caps: %@" : { + "comment" : "Error message" + }, + "Expiration date" : { + "comment" : "Checkbox title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ablaufdatum" + } + } + } + }, + "Failed to get details from File Provider Extension. Retrying." : { + "comment" : "Error message" + }, + "Federated cloud share" : { + "comment" : "Menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Föderierte Cloudfreigabe" + } + } + } + }, + "File \"%@\" locked!" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datei „%@“ wurde gesperrt!" + } + } + } + }, + "File \"%@\" unlocked!" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datei „%@“ wurde entsperrt!" + } + } + } + }, + "Free up space" : { + "comment" : "Context menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Speicherplatz freigeben" + } + } + } + }, + "Group share" : { + "comment" : "Menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gruppenfreigabe" + } + } + } + }, + "Hide download" : { + "comment" : "Checkbox title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Downloadoption verstecken" + } + } + } + }, + "Last modified: %@" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zuletzt geändert: %@" + } + } + } + }, + "Lock file" : { + "comment" : "Context menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datei sperren" + } + } + } + }, + "Locking file \"%@\"…" : { + + }, + "NextcloudKit instance or account is unavailable, cannot fetch shares!" : { + "comment" : "Error message" + }, + "No item URL, cannot reload data!" : { + "comment" : "Error message" + }, + "Note for the recipient" : { + "comment" : "Checkbox title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notiz für Empfänger" + } + } + } + }, + "Password protect" : { + "comment" : "Checkbox title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwortschutz" + } + } + } + }, + "Public link has been copied icon" : { + "comment" : "Accessibility description for button" + }, + "Public link share" : { + "comment" : "Menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öffentliche Linkfreigabe" + } + } + } + }, + "Save" : { + "comment" : "Button title", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Speichern" + } + } + } + }, + "Server does not support shares." : { + "comment" : "Error message" + }, + "Share label" : { + "comment" : "Text field placeholder", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Freigabename" + } + } + } + }, + "Share options" : { + "comment" : "Text label; Context menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Freigabeoptionen" + } + } + } + }, + "Share recipient" : { + "comment" : "Text field placeholder", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Freigabeempfänger" + } + } + } + }, + "Talk conversation share" : { + "comment" : "Menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Talk Konversationsfreigabe" + } + } + } + }, + "Team share" : { + "comment" : "Menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teamfreigabe" + } + } + } + }, + "This file cannot be shared." : { + "comment" : "Error message" + }, + "Unable to retrieve file metadata…" : { + + }, + "Unknown item" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unbekannte Datei" + } + } + } + }, + "Unknown modification date" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unbekanntes Änderungsdatum" + } + } + } + }, + "Unknown size" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unbekannte Größe" + } + } + } + }, + "Unlock file" : { + "comment" : "Context menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datei entsperren" + } + } + } + }, + "Unlocking file \"%@\"…" : { + "comment" : "Text label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entsperre Datei „%@“…" + } + } + } + }, + "User share" : { + "comment" : "Menu item label", + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benutzerfreigabe" + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 7207147d96..d68224baaf 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -60,6 +60,8 @@ class LockViewController: NSViewController { Task { await processItemIdentifier(firstItem) } + + closeButton.title = String(localized: "Close") } @IBAction func closeAction(_ sender: Any) { @@ -109,14 +111,13 @@ class LockViewController: NSViewController { } catch let error { let errorString = "Error processing item: \(error)" Logger.lockViewController.error("\(errorString, privacy: .public)") - fileNameLabel.stringValue = "Could not lock unknown item…" - descriptionLabel.stringValue = errorString + fileNameLabel.stringValue = String(localized: "Could not lock unknown item…") + descriptionLabel.stringValue = error.localizedDescription } } private func updateFileDetailsDisplay(itemUrl: URL) async { - let lockAction = locking ? "Locking" : "Unlocking" - fileNameLabel.stringValue = "\(lockAction) file \(itemUrl.lastPathComponent)…" + fileNameLabel.stringValue = locking ? String(format: String(localized: "Locking file \"%@\"…"), itemUrl.lastPathComponent) : String(format: String(localized: "Unlocking file \"%@\"…"), itemUrl.lastPathComponent) let request = QLThumbnailGenerator.Request( fileAt: itemUrl, @@ -210,10 +211,10 @@ class LockViewController: NSViewController { } } - descriptionLabel.stringValue = - "Communicating with server, \(locking ? "locking" : "unlocking") file…" + descriptionLabel.stringValue = locking ? String(localized: "Communicating with server, locking file…") : String(localized: "Communicating with server, unlocking file…") let serverUrlFileName = itemMetadata.serverUrl + "/" + itemMetadata.fileName + Logger.lockViewController.info( """ Locking file: \(serverUrlFileName, privacy: .public) @@ -231,13 +232,12 @@ class LockViewController: NSViewController { } ) } + if error == .success { - descriptionLabel.stringValue = "File \(self.locking ? "locked" : "unlocked")!" - warnImage.image = NSImage( - systemSymbolName: "checkmark.circle.fill", - accessibilityDescription: "checkmark.circle.fill" - ) + descriptionLabel.stringValue = String(format: self.locking ? String(localized: "File \"%@\" locked!") : String(localized: "File \"%@\" unlocked!"), itemMetadata.fileName) + warnImage.image = NSImage(systemSymbolName: "checkmark.circle.fill", accessibilityDescription: "checkmark.circle.fill") stopIndicatingLoading() + if let manager = NSFileProviderManager(for: actionViewController.domain) { do { try await manager.signalEnumerator(for: itemIdentifier) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib index 6df0fea32b..e8950c909f 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib @@ -1,8 +1,8 @@ - + - + @@ -35,7 +35,7 @@ - + diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareOptionsView.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareOptionsView.swift index f2df121f57..0ad2852d72 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareOptionsView.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareOptionsView.swift @@ -28,6 +28,8 @@ class ShareOptionsView: NSView { @IBOutlet private weak var saveButton: NSButton! @IBOutlet private weak var deleteButton: NSButton! @IBOutlet private weak var shareTypePicker: NSPopUpButton! + + // Share type picker options @IBOutlet private weak var publicLinkShareMenuItem: NSMenuItem! @IBOutlet private weak var userShareMenuItem: NSMenuItem! @IBOutlet private weak var groupShareMenuItem: NSMenuItem! @@ -60,11 +62,9 @@ class ShareOptionsView: NSView { var controller: ShareController? { didSet { guard controller != nil else { return } - optionsTitleTextField.stringValue = "Share options" - deleteButton.title = "Delete" - deleteButton.image = NSImage( - systemSymbolName: "trash", accessibilityDescription: "Delete trash icon" - ) + optionsTitleTextField.stringValue = String(localized: "Share options") + deleteButton.title = String(localized: "Delete") + deleteButton.image = NSImage(systemSymbolName: "trash", accessibilityDescription: "Delete trash icon") deleteButton.bezelColor = NSColor.systemRed cancellable?.cancel() createMode = false @@ -79,8 +79,8 @@ class ShareOptionsView: NSView { shareRecipientTextField.isHidden = !createMode labelTextField.isHidden = createMode // Cannot set label on create API call guard createMode else { return } - optionsTitleTextField.stringValue = "Create new share" - deleteButton.title = "Cancel" + optionsTitleTextField.stringValue = String(localized: "Create new share") + deleteButton.title = String(localized: "Cancel") deleteButton.image = NSImage( systemSymbolName: "xmark.bin", accessibilityDescription: "Cancel create icon" ) @@ -105,6 +105,28 @@ class ShareOptionsView: NSView { return } + // Programmatically update localizable texts. + publicLinkShareMenuItem.title = String(localized: "Public link share") + userShareMenuItem.title = String(localized: "User share") + groupShareMenuItem.title = String(localized: "Group share") + emailShareMenuItem.title = String(localized: "Email share") + federatedCloudShareMenuItem.title = String(localized: "Federated cloud share") + circleShare.title = String(localized: "Team share") + talkConversationShare.title = String(localized: "Talk conversation share") + + shareRecipientTextField.placeholderString = String(localized: "Share recipient") + labelTextField.placeholderString = String(localized: "Share label") + uploadEditPermissionCheckbox.title = String(localized: "Allow upload and editing") + hideDownloadCheckbox.title = String(localized: "Hide download") + passwordProtectCheckbox.title = String(localized: "Password protect") + passwordSecureField.placeholderString = String(localized: "Enter a new password") + expirationDateCheckbox.title = String(localized: "Expiration date") + noteForRecipientCheckbox.title = String(localized: "Note for the recipient") + noteTextField.placeholderString = String(localized: "Note for the recipient") + + deleteButton.title = String(localized: "Delete") + saveButton.title = String(localized: "Save") + deleteButton.isEnabled = share.canDelete saveButton.isEnabled = share.canEdit @@ -296,7 +318,7 @@ class ShareOptionsView: NSView { hideDownload: hideDownload ) if let error = error, error != .success { - dataSource.uiDelegate?.showError("Error creating: \(error.errorDescription)") + dataSource.uiDelegate?.showError(String(localized: "Error creating: \(error.errorDescription)")) setAllFields(enabled: true) } else { dataSource.uiDelegate?.hideOptions(self) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.swift index 3801883ace..c1a2314a4b 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.swift @@ -49,7 +49,7 @@ class ShareTableItemView: NSTableCellView { originalCopyImage = copyLinkButton.image copiedButtonImage = NSImage( systemSymbolName: "checkmark.circle.fill", - accessibilityDescription: "Public link has been copied icon" + accessibilityDescription: String(localized: "Public link has been copied icon") ) var config = NSImage.SymbolConfiguration(scale: .medium) if #available(macOS 12.0, *) { diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.xib index 026f2acf21..7455fad43c 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.xib +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.xib @@ -1,8 +1,8 @@ - + - + diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift index c4446db1b3..d452335406 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift @@ -72,7 +72,7 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele func reload() async { guard let itemURL else { - presentError("No item URL, cannot reload data!") + presentError(String(localized: "No item URL, cannot reload data!")) return } guard let itemIdentifier = await withCheckedContinuation({ @@ -87,7 +87,7 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele } } }) else { - presentError("Could not get identifier for item, no shares can be acquired.") + presentError(String(localized: "Could not get identifier for item, no shares can be acquired.")) return } @@ -103,7 +103,7 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele let convertedAccount = Account(dictionary: credentials), !convertedAccount.password.isEmpty else { - presentError("Failed to get details from File Provider Extension. Retrying.") + presentError(String(localized: "Failed to get details from File Provider Extension. Retrying.")) reattempt() return } @@ -114,21 +114,21 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele capabilities = await fetchCapabilities() guard capabilities != nil else { return } guard capabilities?.filesSharing?.apiEnabled == true else { - presentError("Server does not support shares.") + presentError(String(localized: "Server does not support shares.")) return } guard let account else { - presentError("Account data is unavailable, cannot reload data!") + presentError(String(localized: "Account data is unavailable, cannot reload data!")) return } guard let itemMetadata = await fetchItemMetadata( itemRelativePath: serverPathString, account: account, kit: kit ) else { - presentError("Unable to retrieve file metadata...") + presentError(String(localized: "Unable to retrieve file metadata…")) return } guard itemMetadata.permissions.contains("R") == true else { - presentError("This file cannot be shared.") + presentError(String(localized: "This file cannot be shared.")) return } shares = await fetch( @@ -136,7 +136,7 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele ) shares.append(Self.generateInternalShare(for: itemMetadata)) } catch let error { - presentError("Could not reload data: \(error), will try again.") + presentError(String(format: String(localized: "Could not reload data: %@, will try again."), error.localizedDescription)) reattempt() } } @@ -151,7 +151,7 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele Logger.sharesDataSource.info("Fetching shares for item \(rawIdentifier, privacy: .public)") guard let account else { - self.presentError("NextcloudKit instance or account is unavailable, cannot fetch shares!") + self.presentError(String(localized: "NextcloudKit instance or account is unavailable, cannot fetch shares!")) return [] } @@ -165,7 +165,7 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele Logger.sharesDataSource.info("Received \(shareCount, privacy: .public) shares") defer { continuation.resume(returning: shares ?? []) } guard error == .success else { - self.presentError("Error fetching shares: \(error.errorDescription)") + self.presentError(String(localized: "Error fetching shares: \(error.errorDescription)")) return } } @@ -185,14 +185,14 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele private func fetchCapabilities() async -> Capabilities? { guard let account else { - self.presentError("Could not fetch capabilities as account is invalid.") + self.presentError(String(localized: "Could not fetch capabilities as account is invalid.")) return nil } return await withCheckedContinuation { continuation in kit.getCapabilities(account: account.ncKitAccount) { account, data, error in guard error == .success, let capabilitiesJson = data?.data else { - self.presentError("Error getting server caps: \(error.errorDescription)") + self.presentError(String(localized: "Error getting server caps: \(error.errorDescription)")) continuation.resume(returning: nil) return } diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.swift index 6463ec67ec..7d98edac30 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.swift @@ -28,6 +28,7 @@ class ShareViewController: NSViewController, ShareViewDataSourceUIDelegate { @IBOutlet weak var loadingIndicator: NSProgressIndicator! @IBOutlet weak var errorMessageStackView: NSStackView! @IBOutlet weak var errorTextLabel: NSTextField! + @IBOutlet weak var errorDismissButton: NSButton! @IBOutlet weak var noSharesLabel: NSTextField! public override var nibName: NSNib.Name? { @@ -65,6 +66,7 @@ class ShareViewController: NSViewController, ShareViewDataSourceUIDelegate { } override func viewDidLoad() { + errorDismissButton.title = String(localized: "Dismiss") dismissError(self) hideOptions(self) } @@ -93,7 +95,7 @@ class ShareViewController: NSViewController, ShareViewDataSourceUIDelegate { } catch let error { let errorString = "Error processing item: \(error)" Logger.shareViewController.error("\(errorString, privacy: .public)") - fileNameLabel.stringValue = "Unknown item" + fileNameLabel.stringValue = String(localized: "Unknown item") descriptionLabel.stringValue = errorString } } @@ -126,17 +128,19 @@ class ShareViewController: NSViewController, ShareViewDataSourceUIDelegate { let resourceValues = try? itemUrl.resourceValues( forKeys: [.fileSizeKey, .contentModificationDateKey] ) - var sizeDesc = "Unknown size" - var modDesc = "Unknown modification date" + + var sizeDesc = String(localized: "Unknown size") + var modDesc = String(localized: "Unknown modification date") + if let fileSize = resourceValues?.fileSize { sizeDesc = ByteCountFormatter().string(fromByteCount: Int64(fileSize)) } + if let modificationDate = resourceValues?.contentModificationDate { - let modDateString = DateFormatter.localizedString( - from: modificationDate, dateStyle: .short, timeStyle: .short - ) - modDesc = "Last modified: \(modDateString)" + let modDateString = DateFormatter.localizedString(from: modificationDate, dateStyle: .short, timeStyle: .short) + modDesc = String(format: String(localized: "Last modified: %@"), modDateString) } + descriptionLabel.stringValue = "\(sizeDesc) · \(modDesc)" } diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.xib index dab6a6f283..7921a0011d 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.xib +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.xib @@ -1,8 +1,8 @@ - + - + @@ -13,6 +13,7 @@ + @@ -41,7 +42,7 @@ - + @@ -50,7 +51,7 @@ - + @@ -58,7 +59,7 @@ - + @@ -124,8 +125,8 @@ - - + + @@ -133,7 +134,7 @@ - + @@ -327,16 +328,16 @@ - - + + - + @@ -479,7 +480,7 @@ - + diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj index c7d05eeafd..3f0ae0fe39 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj @@ -55,6 +55,8 @@ 53FE145B2B8F1305006C4193 /* NKShare+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FE145A2B8F1305006C4193 /* NKShare+Extensions.swift */; }; 53FE14652B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */; }; 53FE14672B8F78B6006C4193 /* ShareOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FE14662B8F78B6006C4193 /* ShareOptionsView.swift */; }; + AAA69D932E3BB09900BBD44D /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = AAA69D922E3BB09900BBD44D /* Localizable.xcstrings */; }; + AAC00D2A2E37B29D006010FE /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = AAC00D292E37B29D006010FE /* Localizable.xcstrings */; }; C2B573BA1B1CD91E00303B36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; }; C2B573D21B1CD94B00303B36 /* main.m in Resources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; }; C2B573DE1B1CD9CE00303B36 /* FinderSync.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573DD1B1CD9CE00303B36 /* FinderSync.m */; }; @@ -197,6 +199,8 @@ 53FE145A2B8F1305006C4193 /* NKShare+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKShare+Extensions.swift"; sourceTree = ""; }; 53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewDataSourceUIDelegate.swift; sourceTree = ""; }; 53FE14662B8F78B6006C4193 /* ShareOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareOptionsView.swift; sourceTree = ""; }; + AAA69D922E3BB09900BBD44D /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; + AAC00D292E37B29D006010FE /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; C2B573B11B1CD91E00303B36 /* desktopclient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = desktopclient.app; sourceTree = BUILT_PRODUCTS_DIR; }; C2B573B51B1CD91E00303B36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C2B573B91B1CD91E00303B36 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -345,6 +349,7 @@ 538E397327F4765000FA63D5 /* FileProviderExt.entitlements */, 538E397227F4765000FA63D5 /* Info.plist */, 5350E4EA2B0C9CE100F276CB /* FileProviderExt-Bridging-Header.h */, + AAA69D922E3BB09900BBD44D /* Localizable.xcstrings */, ); path = FileProviderExt; sourceTree = ""; @@ -372,6 +377,7 @@ 537BD6812C58F72E00446ED0 /* MetadataProvider.swift */, 53FE14572B8E3A7C006C4193 /* FileProviderUIExt.entitlements */, 53B979852B84C81F002DA742 /* Info.plist */, + AAC00D292E37B29D006010FE /* Localizable.xcstrings */, ); path = FileProviderUIExt; sourceTree = ""; @@ -616,6 +622,7 @@ English, en, Base, + de, ); mainGroup = C2B573941B1CD88000303B36; packageReferences = ( @@ -642,6 +649,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + AAA69D932E3BB09900BBD44D /* Localizable.xcstrings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -657,6 +665,7 @@ buildActionMask = 2147483647; files = ( 537BD67C2C58D7B700446ED0 /* LockViewController.xib in Resources */, + AAC00D2A2E37B29D006010FE /* Localizable.xcstrings in Resources */, 531522822B8E01C6002E31BE /* ShareTableItemView.xib in Resources */, 537630912B85F4980026BFAB /* ShareViewController.xib in Resources */, ); @@ -1192,6 +1201,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + SWIFT_EMIT_LOC_STRINGS = YES; }; name = Debug; }; @@ -1225,6 +1235,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + SWIFT_EMIT_LOC_STRINGS = YES; }; name = Release; };