feat(l10n): Set up string catalogs for file provider and file provider UI extensions.

Signed-off-by: Iva Horn <iva.horn@icloud.com>
This commit is contained in:
Iva Horn 2025-07-28 16:27:56 +02:00
parent f93b012e54
commit c78bd2f2e6
13 changed files with 609 additions and 64 deletions

View File

@ -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

View File

@ -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"

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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)

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23727" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22690"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23727"/>
<capability name="Image references" minToolsVersion="12.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -35,7 +35,7 @@
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="exclamationmark.circle.fill" catalog="system" id="Yym-fE-Cdh"/>
</imageView>
<imageView horizontalHuggingPriority="1000" verticalHuggingPriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="KlP-OW-SKo">
<rect key="frame" x="52" y="16.5" width="48" height="55"/>
<rect key="frame" x="52" y="17" width="48" height="55"/>
<constraints>
<constraint firstAttribute="width" secondItem="KlP-OW-SKo" secondAttribute="height" multiplier="1:1" id="u2z-cf-k5P"/>
<constraint firstAttribute="width" constant="48" id="ucZ-Lb-C49"/>

View File

@ -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)

View File

@ -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, *) {

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23727" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23727"/>
<capability name="Image references" minToolsVersion="12.0"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>

View File

@ -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
}

View File

@ -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)"
}

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23727" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22689"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23727"/>
<capability name="Image references" minToolsVersion="12.0"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -13,6 +13,7 @@
<outlet property="closeButton" destination="aDA-n9-Zly" id="niR-Ad-FEa"/>
<outlet property="createButton" destination="BMA-BP-wHc" id="HEq-bN-i9V"/>
<outlet property="descriptionLabel" destination="gX0-nE-MrU" id="RoY-u1-1on"/>
<outlet property="errorDismissButton" destination="qfq-F1-w0b" id="ceg-cS-Tku"/>
<outlet property="errorMessageStackView" destination="dFs-Gh-2WQ" id="kkQ-Uq-xk7"/>
<outlet property="errorTextLabel" destination="770-HW-oC7" id="gfn-SV-TNM"/>
<outlet property="fileNameIcon" destination="zSV-DV-Ray" id="336-e0-CEo"/>
@ -41,7 +42,7 @@
<rect key="frame" x="0.0" y="437" width="480" height="43"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zSV-DV-Ray">
<rect key="frame" x="0.0" y="-3.5" width="43" height="50"/>
<rect key="frame" x="0.0" y="-3" width="43" height="50"/>
<constraints>
<constraint firstAttribute="width" secondItem="zSV-DV-Ray" secondAttribute="height" multiplier="1:1" id="NSH-gA-7lL"/>
</constraints>
@ -50,7 +51,7 @@
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oSY-fV-uws">
<rect key="frame" x="51" y="0.0" width="375" height="43"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="slV-H6-zJ3">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="slV-H6-zJ3">
<rect key="frame" x="-2" y="24" width="78" height="19"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="File name" id="Uuo-1j-to8">
<font key="font" metaFont="systemBold" size="16"/>
@ -58,7 +59,7 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gX0-nE-MrU">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gX0-nE-MrU">
<rect key="frame" x="-2" y="0.0" width="146" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="File size · Last modified" id="1GC-Gr-x29">
<font key="font" usesAppearanceFont="YES"/>
@ -124,8 +125,8 @@
<rect key="frame" x="0.0" y="308" width="480" height="40"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="770-HW-oC7">
<rect key="frame" x="0.0" y="0.0" width="411" height="40"/>
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="770-HW-oC7">
<rect key="frame" x="0.0" y="0.0" width="405" height="40"/>
<textFieldCell key="cell" selectable="YES" borderStyle="border" alignment="left" title="A long error message that provides detail about why some operations with the shares failed" drawsBackground="YES" id="Jvl-L9-x8K">
<font key="font" metaFont="systemSemibold" size="13"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
@ -133,7 +134,7 @@
</textFieldCell>
</textField>
<button translatesAutoresizingMaskIntoConstraints="NO" id="qfq-F1-w0b">
<rect key="frame" x="416" y="-4" width="67" height="47"/>
<rect key="frame" x="410" y="-4" width="73" height="47"/>
<buttonCell key="cell" type="bevel" title="Dismiss" bezelStyle="regularSquare" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="dLP-yX-dyk">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -192,7 +193,7 @@
<constraint firstAttribute="height" constant="300" id="FAW-Ws-zy7"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="hQs-hA-bDq">
<rect key="frame" x="1" y="284" width="478" height="15"/>
<rect key="frame" x="1" y="283" width="478" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="ryi-jk-XFM">
@ -225,7 +226,7 @@
<stackView distribution="fill" orientation="vertical" alignment="leading" spacing="5" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T4D-9c-PyA">
<rect key="frame" x="10" y="10" width="460" height="308"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" verticalCompressionResistancePriority="749" translatesAutoresizingMaskIntoConstraints="NO" id="AWy-Qo-wHH">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" verticalCompressionResistancePriority="749" translatesAutoresizingMaskIntoConstraints="NO" id="AWy-Qo-wHH">
<rect key="frame" x="-2" y="292" width="464" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Share options" id="fzf-0v-uHo">
<font key="font" metaFont="systemBold"/>
@ -237,7 +238,7 @@
<rect key="frame" x="-3" y="263" width="467" height="25"/>
<popUpButtonCell key="cell" type="push" title="Public link share" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="JhA-rv-1xy" id="S60-Qi-URJ">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<font key="font" metaFont="message"/>
<menu key="menu" id="yag-Vc-J7Y">
<items>
<menuItem title="Public link share" state="on" id="JhA-rv-1xy"/>
@ -262,7 +263,7 @@
<action selector="shareTypePickerAction:" target="EXb-m8-yzj" id="LN7-TC-RvV"/>
</connections>
</popUpButton>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="f8k-Ae-oQc">
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="f8k-Ae-oQc">
<rect key="frame" x="0.0" y="240" width="460" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Share recipient" bezelStyle="round" id="Ahi-gU-lmO">
<font key="font" metaFont="system"/>
@ -270,7 +271,7 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CXW-ZO-B2f">
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CXW-ZO-B2f">
<rect key="frame" x="0.0" y="213" width="460" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Share label" bezelStyle="round" id="ZsJ-zc-mFT">
<font key="font" metaFont="system"/>
@ -302,7 +303,7 @@
<action selector="passwordCheckboxAction:" target="EXb-m8-yzj" id="QMn-RM-jdf"/>
</connections>
</button>
<secureTextField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pkv-9L-nhv">
<secureTextField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pkv-9L-nhv">
<rect key="frame" x="0.0" y="123" width="460" height="22"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Enter a new password" usesSingleLineMode="YES" bezelStyle="round" id="hcA-we-oYG">
<font key="font" metaFont="system"/>
@ -327,16 +328,16 @@
<rect key="frame" x="0.0" y="73" width="463" height="28"/>
<datePickerCell key="cell" borderStyle="bezel" alignment="left" useCurrentDate="YES" id="EHU-Gu-Dfh">
<font key="font" metaFont="system"/>
<date key="date" timeIntervalSinceReferenceDate="734115148.45631897">
<!--2024-04-06 16:52:28 +0000-->
<date key="date" timeIntervalSinceReferenceDate="775403508.62005496">
<!--2025-07-28 13:51:48 +0000-->
</date>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
</datePickerCell>
</datePicker>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="c10-ub-U31">
<rect key="frame" x="-2" y="51" width="132" height="18"/>
<buttonCell key="cell" type="check" title="Note for recipient" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="oLA-Nu-fzO">
<rect key="frame" x="-2" y="51" width="156" height="18"/>
<buttonCell key="cell" type="check" title="Note for the recipient" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="oLA-Nu-fzO">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@ -344,7 +345,7 @@
<action selector="noteForRecipientCheckboxAction:" target="EXb-m8-yzj" id="j7a-Tc-uiu"/>
</connections>
</button>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="io6-Kg-fLl">
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="io6-Kg-fLl">
<rect key="frame" x="0.0" y="25" width="460" height="22"/>
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Note for the recipient" bezelStyle="round" id="z5W-BH-NnM">
<font key="font" metaFont="system"/>
@ -479,7 +480,7 @@
<real value="250"/>
</holdingPriorities>
</splitView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="K3D-6U-Cbr">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="K3D-6U-Cbr">
<rect key="frame" x="8" y="474" width="484" height="31"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="No shares" id="byC-34-Vtu">
<font key="font" textStyle="largeTitle" name=".SFNS-Regular"/>

View File

@ -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 = "<group>"; };
53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewDataSourceUIDelegate.swift; sourceTree = "<group>"; };
53FE14662B8F78B6006C4193 /* ShareOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareOptionsView.swift; sourceTree = "<group>"; };
AAA69D922E3BB09900BBD44D /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
AAC00D292E37B29D006010FE /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
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 = "<group>"; };
C2B573B91B1CD91E00303B36 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@ -345,6 +349,7 @@
538E397327F4765000FA63D5 /* FileProviderExt.entitlements */,
538E397227F4765000FA63D5 /* Info.plist */,
5350E4EA2B0C9CE100F276CB /* FileProviderExt-Bridging-Header.h */,
AAA69D922E3BB09900BBD44D /* Localizable.xcstrings */,
);
path = FileProviderExt;
sourceTree = "<group>";
@ -372,6 +377,7 @@
537BD6812C58F72E00446ED0 /* MetadataProvider.swift */,
53FE14572B8E3A7C006C4193 /* FileProviderUIExt.entitlements */,
53B979852B84C81F002DA742 /* Info.plist */,
AAC00D292E37B29D006010FE /* Localizable.xcstrings */,
);
path = FileProviderUIExt;
sourceTree = "<group>";
@ -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;
};