From 8ddeb9baad4872d9897a6b8c68a0b5278fe09482 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Sat, 5 Aug 2023 22:33:52 +0200 Subject: [PATCH 1/5] Update StringResource to introduce a LoadingStrategy type to replace Source --- .../StringResource+Integrations.swift | 104 +++++++----------- Sources/RswiftResources/StringResource.swift | 104 +++++++++++------- 2 files changed, 99 insertions(+), 109 deletions(-) diff --git a/Sources/RswiftResources/Integrations/StringResource+Integrations.swift b/Sources/RswiftResources/Integrations/StringResource+Integrations.swift index a7c6eec6..2841fce2 100644 --- a/Sources/RswiftResources/Integrations/StringResource+Integrations.swift +++ b/Sources/RswiftResources/Integrations/StringResource+Integrations.swift @@ -9,112 +9,95 @@ import Foundation import SwiftUI extension String { - init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, locale overrideLocale: Locale?, arguments: [CVarArg]) { - switch source { - case let .hosting(bundle): - // With fallback to developmentValue - let format = NSLocalizedString(key.description, tableName: tableName, bundle: bundle, value: developmentValue ?? "", comment: "") - self = String(format: format, locale: overrideLocale, arguments: arguments) - - case let .selected(bundle, locale): - // Don't use developmentValue with selected bundle/locale - let format = NSLocalizedString(key.description, tableName: tableName, bundle: bundle, value: "", comment: "") - self = String(format: format, locale: overrideLocale ?? locale, arguments: arguments) - - case .none: - self = key.description - } + init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, locale overrideLocale: Locale?, arguments: [CVarArg]) { + self = loadingStrategy.load(key: key, tableName: tableName, bundle: bundle, developmentValue: developmentValue, locale: overrideLocale, arguments: arguments) } - init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, preferredLanguages: [String], locale overrideLocale: Locale?, arguments: [CVarArg]) { - guard let (bundle, locale) = source.bundle?.firstBundleAndLocale(tableName: tableName, preferredLanguages: preferredLanguages) else { - self = key.description - return - } - - self.init(key: key, tableName: tableName, source: .selected(bundle, locale), developmentValue: developmentValue, locale: overrideLocale, arguments: arguments) + init(key: StaticString, tableName: String, bundle: Bundle, developmentValue: String?, preferredLanguages: [String], locale overrideLocale: Locale?, arguments: [CVarArg]) { + let loadingStrategy = StringResource.LoadingStrategy.preferredLanguages(preferredLanguages, locale: overrideLocale) + self.init(key: key, tableName: tableName, bundle: bundle, loadingStrategy: loadingStrategy, developmentValue: nil, locale: overrideLocale, arguments: arguments) } } extension String { public init(resource: StringResource) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: []) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: []) } public init(resource: StringResource, preferredLanguages: [String], locale overrideLocale: Locale? = nil) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: nil, arguments: []) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: nil, arguments: []) } public init(format resource: StringResource1, locale overrideLocale: Locale? = nil, _ arg1: Arg1) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1]) } public init(format resource: StringResource1, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1]) } public init(format resource: StringResource2, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2]) } public init(format resource: StringResource2, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2]) } public init(format resource: StringResource3, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3]) } public init(format resource: StringResource3, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3]) } public init(format resource: StringResource4, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4]) } public init(format resource: StringResource4, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4]) } public init(format resource: StringResource5, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5]) } public init(format resource: StringResource5, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5]) } public init(format resource: StringResource6, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6]) } public init(format resource: StringResource6, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6]) } public init(format resource: StringResource7, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7]) } public init(format resource: StringResource7, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7]) } public init(format resource: StringResource8, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8]) } public init(format resource: StringResource8, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8]) } public init(format resource: StringResource9, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, _ arg9: Arg9) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) } public init(format resource: StringResource9, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, _ arg9: Arg9) { - self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) + self.init(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) } } @@ -126,58 +109,45 @@ extension Text { } public init(_ resource: StringResource1, _ arg1: Arg1) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1])) } public init(_ resource: StringResource2, _ arg1: Arg1, _ arg2: Arg2) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2])) } public init(_ resource: StringResource3, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3])) } public init(_ resource: StringResource4, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4])) } public init(_ resource: StringResource5, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5])) } public init(_ resource: StringResource6, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6])) } public init(_ resource: StringResource7, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7])) } public init(_ resource: StringResource8, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8])) } public init(_ resource: StringResource9, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, _ arg9: Arg9) { - self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9])) + self.init(String(key: resource.key, tableName: resource.tableName, bundle: resource.bundle, loadingStrategy: resource.loadingStrategy, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9])) } } -extension StringResource.Source { - public init(bundle: Bundle, tableName: String, preferredLanguages: [String]?, locale overrideLocale: Locale?) { - guard let preferredLanguages = preferredLanguages else { - if let locale = overrideLocale { - self = .selected(bundle, locale) - } else { - self = .hosting(bundle) - } - - return - } - if let (bundle, locale) = bundle.firstBundleAndLocale(tableName: tableName, preferredLanguages: preferredLanguages) { - self = .selected(bundle, overrideLocale ?? locale) - } else { - self = .none - } +extension StringResource.LoadingStrategy { + public func load(key: StaticString, tableName: String, bundle: Bundle, developmentValue: String?, locale overrideLocale: Locale?, arguments: [CVarArg]) -> String { + fatalError() } } diff --git a/Sources/RswiftResources/StringResource.swift b/Sources/RswiftResources/StringResource.swift index 7e9d0192..81ba64a4 100644 --- a/Sources/RswiftResources/StringResource.swift +++ b/Sources/RswiftResources/StringResource.swift @@ -8,30 +8,32 @@ import Foundation public struct StringResource { - public enum Source { - case hosting(Bundle) - case selected(Bundle, Locale) - case none - - public var bundle: Bundle? { - switch self { - case .hosting(let bundle): return bundle - case .selected(let bundle, _): return bundle - case .none: return nil - } - } + public enum LoadingStrategy { + /// Load strings directly using `NSLocalizedString` without changing the locale used for formatting + public static let `default`: LoadingStrategy = .default(locale: nil) + + /// Load strings directly using `NSLocalizedString` using a custom `Locale` to format arguments + case `default`(locale: Locale?) + + /// Load strings in the preferred languages only + case preferredLanguages([String], locale: Locale? = nil) + + /// Load strings using a custom implementation + case custom((_ key: StaticString, _ tableName: String, _ bundle: Bundle, _ developmentValue: String?, _ overrideLocale: Locale?, _ arguments: [CVarArg]) -> String) } public let key: StaticString public let tableName: String - public let source: Source + public let bundle: Bundle + public let loadingStrategy: LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -40,14 +42,16 @@ public struct StringResource { public struct StringResource1 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -56,14 +60,16 @@ public struct StringResource1 { public struct StringResource2 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -72,14 +78,16 @@ public struct StringResource2 { public struct StringResource3 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -88,14 +96,16 @@ public struct StringResource3 { public struct StringResource4 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -104,14 +114,16 @@ public struct StringResource4 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -120,14 +132,16 @@ public struct StringResource5 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -136,14 +150,16 @@ public struct StringResource6 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -152,14 +168,16 @@ public struct StringResource7 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } @@ -168,14 +186,16 @@ public struct StringResource8 { public let key: StaticString public let tableName: String - public let source: StringResource.Source + public let bundle: Bundle + public let loadingStrategy: StringResource.LoadingStrategy public let developmentValue: String? public let comment: StaticString? - public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { + public init(key: StaticString, tableName: String, bundle: Bundle, loadingStrategy: StringResource.LoadingStrategy, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy self.developmentValue = developmentValue self.comment = comment } From 987796483e8055e09f1e0cb10e2b8cdf13c21bc5 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Sat, 5 Aug 2023 23:08:01 +0200 Subject: [PATCH 2/5] Update StringsTable generator to generate source code compatible with LoadingStrategy (preserve current API) --- .../StringsTable+Generator.swift | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Sources/RswiftGenerators/StringsTable+Generator.swift b/Sources/RswiftGenerators/StringsTable+Generator.swift index edf07aef..08833910 100644 --- a/Sources/RswiftGenerators/StringsTable+Generator.swift +++ b/Sources/RswiftGenerators/StringsTable+Generator.swift @@ -15,7 +15,7 @@ extension Struct { deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: name), typeReference: TypeReference(module: .host, rawName: self.name.value), - valueCodeString: ".init(bundle: bundle, preferredLanguages: nil, locale: nil)" + valueCodeString: ".init(bundle: bundle, loadingStrategy: .default)" ) } @@ -26,7 +26,7 @@ extension Struct { name: SwiftIdentifier(name: name), params: [.init(name: "bundle", localName: nil, typeReference: .bundle, defaultValue: nil)], returnType: TypeReference(module: .host, rawName: self.name.value), - valueCodeString: ".init(bundle: bundle, preferredLanguages: nil, locale: nil)" + valueCodeString: ".init(bundle: bundle, loadingStrategy: .default)" ) } @@ -37,7 +37,7 @@ extension Struct { name: SwiftIdentifier(name: name), params: [.init(name: "locale", localName: nil, typeReference: .locale, defaultValue: nil)], returnType: TypeReference(module: .host, rawName: self.name.value), - valueCodeString: ".init(bundle: bundle, preferredLanguages: nil, locale: locale)" + valueCodeString: ".init(bundle: bundle, loadingStrategy: .default(locale: locale))" ) } @@ -51,7 +51,7 @@ extension Struct { .init(name: "locale", localName: nil, typeReference: .init(module: .stdLib, rawName: "Locale?"), defaultValue: "nil") ], returnType: TypeReference(module: .host, rawName: self.name.value), - valueCodeString: ".init(bundle: bundle, preferredLanguages: preferredLanguages, locale: locale)" + valueCodeString: ".init(bundle: bundle, loadingStrategy: .preferredLanguages(preferredLanguages, locale: locale))" ) } } @@ -85,9 +85,9 @@ extension StringsTable { initBundlePreferredLanguages for name in groupedLocalized.uniques.map(\.0) { - generateBundleLocaleVarGetter(name: SwiftIdentifier(name: name), tableName: name) + generateBundleLocaleVarGetter(name: SwiftIdentifier(name: name)) // generateBundleLocaleFunction(name: SwiftIdentifier(name: name)) - generatePreferredLanguagesFunction(name: SwiftIdentifier(name: name), tableName: name) + generatePreferredLanguagesFunction(name: SwiftIdentifier(name: name)) } structs } @@ -98,13 +98,11 @@ extension StringsTable { comments: [], params: [ .init(name: "bundle", localName: nil, typeReference: .bundle, defaultValue: nil), - .init(name: "preferredLanguages", localName: nil, typeReference: .init(module: .stdLib, rawName: "[String]?"), defaultValue: "nil"), - .init(name: "locale", localName: nil, typeReference: .init(module: .stdLib, rawName: "Locale?"), defaultValue: "nil"), + .init(name: "loadingStrategy", localName: nil, typeReference: .init(module: .rswiftResources, rawName: "StringResource.LoadingStrategy"), defaultValue: nil), ], valueCodeString: """ self.bundle = bundle - self.preferredLanguages = preferredLanguages - self.locale = locale + self.loadingStrategy = loadingStrategy """ ) } @@ -135,22 +133,25 @@ extension StringsTable { Init( comments: [], params: [ - .init(name: "source", localName: nil, typeReference: .init(module: .rswiftResources, rawName: "StringResource.Source"), defaultValue: nil), + .init(name: "bundle", localName: nil, typeReference: .init(module: .stdLib, rawName: "Bundle"), defaultValue: nil), + .init(name: "loadingStrategy", localName: nil, typeReference: .init(module: .rswiftResources, rawName: "StringResource.LoadingStrategy"), defaultValue: nil), ], valueCodeString: """ - self.source = source + self.bundle = bundle + self.loadingStrategy = loadingStrategy """ ) } - public static func generateBundleLocaleVarGetter(name: SwiftIdentifier, tableName: String) -> VarGetter { + public static func generateBundleLocaleVarGetter(name: SwiftIdentifier) -> VarGetter { VarGetter( name: name, typeReference: TypeReference(module: .host, rawName: name.value), - valueCodeString: #".init(source: .init(bundle: bundle, tableName: "\#(tableName.escapedStringLiteral)", preferredLanguages: preferredLanguages, locale: locale))"# + valueCodeString: ".init(bundle: bundle, loadingStrategy: loadingStrategy)" ) } + // TODO: Liam - Remove public static func generateBundleLocaleFunction(name: SwiftIdentifier) -> Function { Function( comments: [], @@ -164,7 +165,8 @@ extension StringsTable { ) } - public static func generatePreferredLanguagesFunction(name: SwiftIdentifier, tableName: String) -> Function { + // TODO: Liam - Deprecate and replace with `loadingStrategy` alternative + public static func generatePreferredLanguagesFunction(name: SwiftIdentifier) -> Function { Function( comments: [], name: name, @@ -172,7 +174,7 @@ extension StringsTable { .init(name: "preferredLanguages", localName: nil, typeReference: TypeReference(module: .stdLib, rawName: "[String]"), defaultValue: nil), ], returnType: TypeReference(module: .host, rawName: name.value), - valueCodeString: #".init(source: .init(bundle: bundle, tableName: "\#(tableName.escapedStringLiteral)", preferredLanguages: preferredLanguages, locale: locale))"# + valueCodeString: #".init(bundle: bundle, loadingStrategy: .preferredLanguages(preferredLanguages, locale: nil))"# ) } @@ -363,7 +365,7 @@ private struct StringWithParams { let typeReference = TypeReference(module: .rswiftResources, name: "StringResource\(params.isEmpty ? "" : "\(params.count)")", genericArgs: params.map(\.spec.typeReference)) - let varValueCodeString = #".init(key: "\#(key.escapedStringLiteral)", tableName: "\#(tableName)", source: source, developmentValue: \#(developmentValue), comment: nil)"# + let varValueCodeString = #".init(key: "\#(key.escapedStringLiteral)", tableName: "\#(tableName)", bundle: bundle, loadingStrategy: loadingStrategy, developmentValue: \#(developmentValue), comment: nil)"# return VarGetter( comments: self.comments, From 0eadc501bd0b632f9d877889791e0256ae825889 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Sat, 5 Aug 2023 23:26:56 +0200 Subject: [PATCH 3/5] Add StringResource.LoadingStrategy load(...) method implementation --- .../StringResource+Integrations.swift | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Sources/RswiftResources/Integrations/StringResource+Integrations.swift b/Sources/RswiftResources/Integrations/StringResource+Integrations.swift index 2841fce2..1a0d6c71 100644 --- a/Sources/RswiftResources/Integrations/StringResource+Integrations.swift +++ b/Sources/RswiftResources/Integrations/StringResource+Integrations.swift @@ -147,7 +147,26 @@ extension Text { extension StringResource.LoadingStrategy { public func load(key: StaticString, tableName: String, bundle: Bundle, developmentValue: String?, locale overrideLocale: Locale?, arguments: [CVarArg]) -> String { - fatalError() + switch self { + case .default(let formatLocale): + // With fallback to developmentValue + let format = NSLocalizedString(key.description, tableName: tableName, bundle: bundle, value: developmentValue ?? "", comment: "") + return String(format: format, locale: overrideLocale ?? formatLocale ?? .current, arguments: arguments) + + case .preferredLanguages(let preferredLanguages, let formatLocale): + if let (bundle, locale) = bundle.firstBundleAndLocale(tableName: tableName, preferredLanguages: preferredLanguages) { + // Don't use developmentValue with selected bundle/locale + let format = NSLocalizedString(key.description, tableName: tableName, bundle: bundle, value: "", comment: "") + return String(format: format, locale: overrideLocale ?? formatLocale ?? locale, arguments: arguments) + } else { + // A localization doesn't exist in the given languages, fallback to the key instead + return key.description + } + + case .custom(let loader): + // Use the custom loader implementation + return loader(key, tableName, bundle, developmentValue, overrideLocale, arguments) + } } } From 147ba86cdf8beac63ee133f1a4519cd7bd1df8fa Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Sat, 5 Aug 2023 23:41:29 +0200 Subject: [PATCH 4/5] Update generator to expose new LoadingStrategy methods and deprecate legacy methods --- .../StringsTable+Generator.swift | 31 +++++++++++++++++-- Sources/rswift/RswiftCore.swift | 1 + 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Sources/RswiftGenerators/StringsTable+Generator.swift b/Sources/RswiftGenerators/StringsTable+Generator.swift index 08833910..9130bb01 100644 --- a/Sources/RswiftGenerators/StringsTable+Generator.swift +++ b/Sources/RswiftGenerators/StringsTable+Generator.swift @@ -34,6 +34,7 @@ extension Struct { Function( comments: [], deploymentTarget: deploymentTarget, + deprecated: "Use \(name)(loadingStrategy: .default(locale: myLocale)) instead", name: SwiftIdentifier(name: name), params: [.init(name: "locale", localName: nil, typeReference: .locale, defaultValue: nil)], returnType: TypeReference(module: .host, rawName: self.name.value), @@ -45,6 +46,7 @@ extension Struct { Function( comments: [], deploymentTarget: deploymentTarget, + deprecated: "Use \(name)(loadingStrategy: .preferredLanguages(myLanguages, locale: myLocale)) instead", name: SwiftIdentifier(name: name), params: [ .init(name: "preferredLanguages", localName: nil, typeReference: .init(module: .stdLib, rawName: "[String]"), defaultValue: nil), @@ -54,6 +56,19 @@ extension Struct { valueCodeString: ".init(bundle: bundle, loadingStrategy: .preferredLanguages(preferredLanguages, locale: locale))" ) } + + public func generateLoadingStrategyFunctionForString(name: String) -> Function { + Function( + comments: [], + deploymentTarget: deploymentTarget, + name: SwiftIdentifier(name: name), + params: [ + .init(name: "loadingStrategy", localName: nil, typeReference: .init(module: .rswiftResources, rawName: "StringResource.LoadingStrategy"), defaultValue: nil) + ], + returnType: TypeReference(module: .host, rawName: self.name.value), + valueCodeString: ".init(bundle: bundle, loadingStrategy: loadingStrategy)" + ) + } } extension StringsTable { @@ -88,6 +103,7 @@ extension StringsTable { generateBundleLocaleVarGetter(name: SwiftIdentifier(name: name)) // generateBundleLocaleFunction(name: SwiftIdentifier(name: name)) generatePreferredLanguagesFunction(name: SwiftIdentifier(name: name)) + generateLoadingStrategyFunction(name: SwiftIdentifier(name: name)) } structs } @@ -151,7 +167,6 @@ extension StringsTable { ) } - // TODO: Liam - Remove public static func generateBundleLocaleFunction(name: SwiftIdentifier) -> Function { Function( comments: [], @@ -165,10 +180,10 @@ extension StringsTable { ) } - // TODO: Liam - Deprecate and replace with `loadingStrategy` alternative public static func generatePreferredLanguagesFunction(name: SwiftIdentifier) -> Function { Function( comments: [], + deprecated: "Use \(name.value)(loadingStrategy: .preferredLanguages(...)) instead", name: name, params: [ .init(name: "preferredLanguages", localName: nil, typeReference: TypeReference(module: .stdLib, rawName: "[String]"), defaultValue: nil), @@ -178,6 +193,18 @@ extension StringsTable { ) } + public static func generateLoadingStrategyFunction(name: SwiftIdentifier) -> Function { + Function( + comments: [], + name: name, + params: [ + .init(name: "loadingStrategy", localName: nil, typeReference: TypeReference(module: .rswiftResources, rawName: "StringResource.LoadingStrategy"), defaultValue: nil), + ], + returnType: TypeReference(module: .host, rawName: name.value), + valueCodeString: #".init(bundle: bundle, loadingStrategy: loadingStrategy)"# + ) + } + // Ahem, this code is a bit of a mess. It might need cleaning up... ;-) private static func computeStringsWithParams(filename: String, tables: [StringsTable], developmentLanguage: String?, warning: (String) -> Void) -> [StringWithParams] { diff --git a/Sources/rswift/RswiftCore.swift b/Sources/rswift/RswiftCore.swift index 0a66e137..96a28179 100644 --- a/Sources/rswift/RswiftCore.swift +++ b/Sources/rswift/RswiftCore.swift @@ -213,6 +213,7 @@ public struct RswiftCore { stringStruct.generateBundleFunctionForString(name: "string") stringStruct.generateLocaleFunctionForString(name: "string") stringStruct.generatePreferredLanguagesFunctionForString(name: "string") + stringStruct.generateLoadingStrategyFunctionForString(name: "string") stringStruct } From c83f8a727948fb4d093b2ff73c39058a15ec4916 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Sun, 6 Aug 2023 00:03:18 +0200 Subject: [PATCH 5/5] Add unit test coverage --- .../LocalizedStringAppTests/LocalizedStringAppTests.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Examples/LocalizedStringApp/LocalizedStringAppTests/LocalizedStringAppTests.swift b/Examples/LocalizedStringApp/LocalizedStringAppTests/LocalizedStringAppTests.swift index a180e156..e0b65378 100644 --- a/Examples/LocalizedStringApp/LocalizedStringAppTests/LocalizedStringAppTests.swift +++ b/Examples/LocalizedStringApp/LocalizedStringAppTests/LocalizedStringAppTests.swift @@ -904,6 +904,14 @@ class LocalizedStringAppTests: XCTestCase { "ten 1 - 1 thing, localized french") } + func testCustom() { + XCTAssertEqual(R.string(loadingStrategy: .custom({ key, tableName, _, _, _, _ in "\(tableName)/\(key)" })).six.six2(), + "six/six2") + + XCTAssertEqual(R.string.six(loadingStrategy: .custom({ key, tableName, _, _, _, _ in "\(tableName)/\(key)" })).six2(), + "six/six2") + } + func testPrefferedLanguages(myprefs: [String]) {