import Foundation import RastrilloNative /// The words the kit's sync views say. `.kit` reads the package's own /// catalog, in the same twelve languages as the apps; an app overrides any /// of them, for example to count cells instead of documents, by changing a /// copy. public struct NativeSyncStrings: Sendable { public var saving: String public var retrying: String /// "Offline ยท N pending". public var offline: @Sendable (Int) -> String /// "Sign in to send N pending". public var needsSignIn: @Sendable (Int) -> String public var signIn: String /// A held entry's words are the app's; this is the fallback. public var failed: @Sendable (SyncFailure) -> String /// The banner while the path or server is down and edits are not durable. public var offlineWaiting: String /// The banner once edits are kept on this device. public var offlineDurable: String /// Reported once after a lost key or corrupt entry removed unsent changes. public var unsentLost: String public init(saving: String, retrying: String, offline: @escaping @Sendable (Int) -> String, needsSignIn: @escaping @Sendable (Int) -> String, signIn: String, failed: @escaping @Sendable (SyncFailure) -> String, offlineWaiting: String, offlineDurable: String, unsentLost: String) { self.saving = saving; self.retrying = retrying; self.offline = offline; self.needsSignIn = needsSignIn self.signIn = signIn; self.failed = failed; self.offlineWaiting = offlineWaiting self.offlineDurable = offlineDurable; self.unsentLost = unsentLost } public static var kit: NativeSyncStrings { kit(localization: Bundle.module.preferredLocalizations.first ?? "en") } public static func kit(localization: String) -> NativeSyncStrings { let path = Bundle.module.path(forResource: localization, ofType: "lproj") ?? Bundle.module.path(forResource: "en", ofType: "lproj")! let bundle = Bundle(path: path)! @Sendable func text(_ key: String) -> String { bundle.localizedString(forKey: key, value: nil, table: nil) } @Sendable func plural(_ key: String, _ count: Int) -> String { String(format: text(key), locale: Locale(identifier: localization), arguments: [count]) } return NativeSyncStrings(saving: text("sync.saving"), retrying: text("sync.retrying"), offline: { plural("sync.offline", $0) }, needsSignIn: { plural("sync.needsSignIn", $0) }, signIn: text("sync.signIn"), failed: { reason in switch reason { case .cannotSaveOnDevice: return text("sync.failed.cannotSave") case .tooManyUnsent: return text("sync.failed.tooManyUnsent") case .held: return text("sync.failed.held") } }, offlineWaiting: text("offline.waiting"), offlineDurable: text("offline.durable"), unsentLost: text("sync.unsentLost")) } public func text(for status: SyncStatus) -> String? { switch status { case .saved: return nil case .saving: return saving case .retrying: return retrying case .offline(let count): return offline(count) case .needsSignIn(let count): return needsSignIn(count) case .failed(_, let reason): return failed(reason) } } }