I've solved it using DateComponentsFormatter, that saves you a lot of time localizing in different languages and handling plurals and whatnot.
This might seem like a lot of code, but I hope it will save me time in the future.
import Foundation
class PeriodFormatter {
static var componentFormatter: DateComponentsFormatter {
let formatter = DateComponentsFormatter()
formatter.maximumUnitCount = 1
formatter.unitsStyle = .full
formatter.zeroFormattingBehavior = .dropAll
return formatter
}
static func format(unit: NSCalendar.Unit, numberOfUnits: Int) -> String? {
var dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
componentFormatter.allowedUnits = [unit]
switch unit {
case .day:
dateComponents.setValue(numberOfUnits, for: .day)
case .weekOfMonth:
dateComponents.setValue(numberOfUnits, for: .weekOfMonth)
case .month:
dateComponents.setValue(numberOfUnits, for: .month)
case .year:
dateComponents.setValue(numberOfUnits, for: .year)
default:
return nil
}
return componentFormatter.string(from: dateComponents)
}
}
It requires to convert the SKProduct period unit into a NSCalendarUnit
import StoreKit
@available(iOS 11.2, *)
extension SKProduct.PeriodUnit {
func toCalendarUnit() -> NSCalendar.Unit {
switch self {
case .day:
return .day
case .month:
return .month
case .week:
return .weekOfMonth
case .year:
return .year
@unknown default:
debugPrint("Unknown period unit")
}
return .day
}
}
And you can call it from a SubscriptionPeriod like this:
import StoreKit
@available(iOS 11.2, *)
extension SKProductSubscriptionPeriod {
func localizedPeriod() -> String? {
return PeriodFormatter.format(unit: unit.toCalendarUnit(), numberOfUnits: numberOfUnits)
}
}
Which you can in turn call from a SKProductDiscount like so. Please note I didn't implement the other PaymentModes for now.
import StoreKit
@available(iOS 11.2, *)
extension SKProductDiscount {
func localizedDiscount() -> String? {
switch paymentMode {
case PaymentMode.freeTrial:
return "Free trial for \(subscriptionPeriod.localizedPeriod() ?? "a period")"
default:
return nil
}
}
}