Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .tx/config
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
[main]
host = https://www.transifex.com

[o:nextcloud:p:nextcloud:r:nextcloudkit]
file_filter = translations/nextcloudkit/<lang>.xcstrings
source_file = Sources/NextcloudKit/Localizable.xcstrings
source_lang = en
type = XCSTRINGS

[o:nextcloud:p:nextcloud:r:nextcloudkitui]
file_filter = translations/<lang>.xcstrings
file_filter = translations/nextcloudkitui/<lang>.xcstrings
source_file = Sources/NextcloudKitUI/Localizable.xcstrings
source_lang = en
type = XCSTRINGS
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Networking is built on Alamofire; responses are parsed with SwiftyJSON and Swift
| Directory | Description | Agent Action |
|-----------------|-----------------------------------------------------|----------------------|
| `.github` | GitHub CI workflows (build & test, lint, REUSE compliance, documentation). | Keep all four checks green: build & test (`xcode.yml`), SwiftLint (`lint.yml`), REUSE compliance (`reuse.yml`), DocC build (`documentation.yml`). |
| `Sources/NextcloudKit` | Core library. Server APIs live in one `NextcloudKit+<Area>.swift` extension file per API area (e.g. `NextcloudKit+Share.swift`), next to core types like `NextcloudKit`, `NKCommon`, `NKSession` and `NKError`. Shared helpers live in `Extensions/`, `Log/`, `Utils/` and `TypeIdentifiers/`. | Add new server APIs as a dedicated `NextcloudKit+<Area>.swift` extension file. |
| `Sources/NextcloudKit` | Core library. Server APIs live in one `NextcloudKit+<Area>.swift` extension file per API area (e.g. `NextcloudKit+Share.swift`), next to core types like `NextcloudKit`, `NKCommon`, `NKSession` and `NKError`. Shared helpers live in `Extensions/`, `Log/`, `Utils/` and `TypeIdentifiers/`. `Localizable.xcstrings` holds the user-facing strings: `NKError.localizedGenericMessage`, file name rule messages and log level names. NKError's own descriptions (the presets and `getErrorDescription(for:)`) stay plain English, for logs. | Add new server APIs as a dedicated `NextcloudKit+<Area>.swift` extension file. Only add new localized strings to `Localizable.xcstrings` in English, with `NSLocalizedString(…, bundle: .module, comment:)` since `String(localized:)` needs newer deployment targets. |
| `Sources/NextcloudKit/Models` | `NK*` data models returned by the APIs. | Place each new model in its own file; group related models for one feature in a subfolder (see `Models/Governance`). |
| `Sources/NextcloudKitUI` | SwiftUI login and account UI used by client apps. Depends on CodeScanner for QR-code login. | Only add new localized strings to `Localizable.xcstrings` in English. |
| `Tests/NextcloudKitUnitTests` | Unit tests; network requests are mocked with Mocker (see `LoginUnitTests.swift`). | Prefer this target for new tests. Try to add unit tests for new features, where applicable and makes sense; do not overcomplicate them. |
Expand Down
2 changes: 1 addition & 1 deletion REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ SPDX-FileCopyrightText = "2023 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "GPL-3.0-or-later"

[[annotations]]
path = [".tx/config", "Sources/NextcloudKitUI/Documentation.docc/Documentation.md", "Sources/NextcloudKitUI/Documentation.docc/theme-settings.json", "Sources/NextcloudKitUI/Localizable.xcstrings"]
path = [".tx/config", "Sources/NextcloudKitUI/Documentation.docc/Documentation.md", "Sources/NextcloudKitUI/Documentation.docc/theme-settings.json", "Sources/NextcloudKitUI/Localizable.xcstrings", "Sources/NextcloudKit/Localizable.xcstrings"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2026 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "GPL-3.0-or-later"
325 changes: 325 additions & 0 deletions Sources/NextcloudKit/Localizable.xcstrings
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
{
"sourceLanguage" : "en",
"strings" : {
"\"%@\" is a forbidden name." : {
"comment" : "Error message when the server reserves a name. %@ is the name.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "\"%@\" is a forbidden name."
}
}
}
},
"\".%@\" is a forbidden file extension." : {
"comment" : "Error message when the server forbids a file extension. %@ is the extension.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "\".%@\" is a forbidden file extension."
}
}
}
},
"A secure connection to the server couldn't be established." : {
"comment" : "Error message for TLS and certificate failures.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "A secure connection to the server couldn't be established."
}
}
}
},
"An item with this name already exists." : {
"comment" : "Error message when a file or folder with the same name already exists.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "An item with this name already exists."
}
}
}
},
"Can't reach the server. Check the address or try again later." : {
"comment" : "Error message when the server cannot be reached.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Can't reach the server. Check the address or try again later."
}
}
}
},
"Compact" : {
"comment" : "Log level that logs only the essentials.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Compact"
}
}
}
},
"Disabled" : {
"comment" : "Log level that turns logging off.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Disabled"
}
}
}
},
"File name cannot be empty." : {
"comment" : "Error message when a file or folder name is empty.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "File name cannot be empty."
}
}
}
},
"Name contains an invalid character: \"%@\"." : {
"comment" : "Error message when a name contains a forbidden character. %@ is the character.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Name contains an invalid character: \"%@\"."
}
}
}
},
"Name must not contain spaces at the beginning or end." : {
"comment" : "Error message when a name starts or ends with a space.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Name must not contain spaces at the beginning or end."
}
}
}
},
"Normal" : {
"comment" : "Default log level.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Normal"
}
}
}
},
"Something went wrong. Please try again." : {
"comment" : "Error message when the cause of the error is unknown.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Something went wrong. Please try again."
}
}
}
},
"The file is locked. Try again later." : {
"comment" : "Error message when the file is locked on the server.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The file is locked. Try again later."
}
}
}
},
"The file is too large for the server." : {
"comment" : "Error message when the server rejects a file because of its size.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The file is too large for the server."
}
}
}
},
"The item could not be found on the server." : {
"comment" : "Error message when the requested file, folder or share does not exist on the server.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The item could not be found on the server."
}
}
}
},
"The item was changed on the server. Please refresh and try again." : {
"comment" : "Error message when the request conflicts with the current state on the server.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The item was changed on the server. Please refresh and try again."
}
}
}
},
"The request was cancelled." : {
"comment" : "Error message when a request was cancelled.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The request was cancelled."
}
}
}
},
"The server is temporarily unavailable. Try again later." : {
"comment" : "Error message when the server is unavailable, e.g. in maintenance mode.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The server is temporarily unavailable. Try again later."
}
}
}
},
"The server ran into a problem. Try again later." : {
"comment" : "Error message for internal server errors.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The server ran into a problem. Try again later."
}
}
}
},
"The server sent an unexpected response. Try again later." : {
"comment" : "Error message when the server's response cannot be read.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The server sent an unexpected response. Try again later."
}
}
}
},
"The server took too long to respond. Try again later." : {
"comment" : "Error message when a request to the server timed out.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The server took too long to respond. Try again later."
}
}
}
},
"There is not enough storage space left on the server." : {
"comment" : "Error message when the account's storage quota is used up.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "There is not enough storage space left on the server."
}
}
}
},
"There is not enough storage space left on this device." : {
"comment" : "Error message when the device runs out of storage space.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "There is not enough storage space left on this device."
}
}
}
},
"This name isn't allowed." : {
"comment" : "Error message when the server rejects a file or folder name.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "This name isn't allowed."
}
}
}
},
"Too many requests. Please wait a moment and try again." : {
"comment" : "Error message when the server rate-limits the requests.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Too many requests. Please wait a moment and try again."
}
}
}
},
"Verbose" : {
"comment" : "Log level that logs everything, for debugging.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Verbose"
}
}
}
},
"You don't have permission to do this." : {
"comment" : "Error message when the server forbids the action.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "You don't have permission to do this."
}
}
}
},
"You're offline. Please check your internet connection." : {
"comment" : "Error message when the device has no internet connection.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "You're offline. Please check your internet connection."
}
}
}
},
"Your login is no longer valid. Please log in again." : {
"comment" : "Error message when the server rejects the account's credentials.",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Your login is no longer valid. Please log in again."
}
}
}
}
},
"version" : "1.0"
}
8 changes: 4 additions & 4 deletions Sources/NextcloudKit/Log/NKLogFileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable {
// For Picker display
public var displayText: String {
switch self {
case .disabled: return NSLocalizedString("_disabled_", comment: "")
case .compact: return NSLocalizedString("_compact_", comment: "")
case .normal: return NSLocalizedString("_normal_", comment: "")
case .verbose: return NSLocalizedString("_verbose_", comment: "")
case .disabled: return NSLocalizedString("Disabled", bundle: .module, comment: "Log level that turns logging off.")
case .compact: return NSLocalizedString("Compact", bundle: .module, comment: "Log level that logs only the essentials.")
case .normal: return NSLocalizedString("Normal", bundle: .module, comment: "Default log level.")
case .verbose: return NSLocalizedString("Verbose", bundle: .module, comment: "Log level that logs everything, for debugging.")
}
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/NextcloudKit/NKCommon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public struct NKCommon: Sendable {
@inline(__always)
func checkCancelled() throws {
if Task.isCancelled {
throw NKError(errorCode: -5, errorDescription: "Chunking was cancelled.")
throw NKError(errorCode: -5, errorDescription: "Chunking was cancelled.", kind: .cancelled)
}
}

Expand Down Expand Up @@ -247,11 +247,11 @@ public struct NKCommon: Sendable {
case -2:
throw NKError(errorCode: -2, errorDescription: "Failed to open the output chunk file for writing.")
case -3:
throw NKError(errorCode: -3, errorDescription: "There is not enough available disk space to proceed.")
throw NKError(errorCode: -3, errorDescription: "There is not enough available disk space to proceed.", kind: .localStorageFull)
case -4:
throw NKError(errorCode: -4, errorDescription: "Failed to write data to chunk file.")
case -5:
throw NKError(errorCode: -5, errorDescription: "Chunking was cancelled.")
throw NKError(errorCode: -5, errorDescription: "Chunking was cancelled.", kind: .cancelled)
default:
continue
}
Expand Down
Loading
Loading