Skip to content

Commit

Permalink
Paywalls: {{ price_per_period }} now takes `SubscriptionPeriod.va…
Browse files Browse the repository at this point in the history
…lue` into account (#3133)

This was incorrect for `PackageType.threeMonth` and
`PackageType.sixMonth`.


![image](https://github.com/RevenueCat/purchases-ios/assets/685609/87b1ec00-04a0-4baa-ba73-edc4ce138388)
  • Loading branch information
NachoSoto committed Sep 7, 2023
1 parent 102c265 commit 44d0cb1
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 14 deletions.
20 changes: 13 additions & 7 deletions RevenueCatUI/Data/Localization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ enum Localization {

/// - Returns: an appropriately short abbreviation for the given `unit`.
static func abbreviatedUnitLocalizedString(
for unit: SubscriptionPeriod.Unit,
for period: SubscriptionPeriod,
locale: Locale = .current
) -> String {
let (full, brief, abbreviated) = self.unitLocalizedString(for: unit.calendarUnit, locale: locale)
let (full, brief, abbreviated) = self.unitLocalizedString(for: period, locale: locale)

let options = [
full,
Expand Down Expand Up @@ -123,15 +123,16 @@ enum Localization {
private extension Localization {

static func unitLocalizedString(
for unit: NSCalendar.Unit,
for period: SubscriptionPeriod,
locale: Locale = .current
) -> (full: String, brief: String, abbreviated: String) {
var calendar: Calendar = .current
calendar.locale = locale

let date = Date()
let value = 1
let unit = period.unit.calendarUnit
let component = unit.component
let value = period.value

guard let sinceUnits = calendar.date(byAdding: component,
value: value,
Expand All @@ -145,9 +146,14 @@ private extension Localization {
formatter.unitsStyle = style
guard let string = formatter.string(from: date, to: sinceUnits) else { return "" }

return string
.replacingOccurrences(of: String(value), with: "")
.trimmingCharacters(in: .whitespaces)
if value == 1 {
return string
.replacingOccurrences(of: String(value), with: "")
.trimmingCharacters(in: .whitespaces)
} else {
return string
.replacingOccurrences(of: " ", with: "")
}
}

return (full: result(for: .full),
Expand Down
23 changes: 20 additions & 3 deletions RevenueCatUI/Data/TestData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,21 @@ internal enum TestData {
subscriptionPeriod: .init(value: 1, unit: .month),
introductoryDiscount: Self.intro(7, .day)
)
static let threeMonthProduct = TestStoreProduct(
localizedTitle: "3 months",
price: 4.99,
localizedPriceString: "$4.99",
productIdentifier: "com.revenuecat.product_5",
productType: .autoRenewableSubscription,
localizedDescription: "PRO monthly",
subscriptionGroupIdentifier: "group",
subscriptionPeriod: .init(value: 3, unit: .month),
introductoryDiscount: Self.intro(7, .day)
)
static let sixMonthProduct = TestStoreProduct(
localizedTitle: "Monthly",
price: 34.99,
localizedPriceString: "$34.99",
localizedTitle: "6 months",
price: 7.99,
localizedPriceString: "$7.99",
productIdentifier: "com.revenuecat.product_5",
productType: .autoRenewableSubscription,
localizedDescription: "PRO monthly",
Expand Down Expand Up @@ -112,6 +123,12 @@ internal enum TestData {
storeProduct: Self.monthlyProduct.toStoreProduct(),
offeringIdentifier: Self.offeringIdentifier
)
static let threeMonthPackage = Package(
identifier: PackageType.threeMonth.identifier,
packageType: .threeMonth,
storeProduct: Self.threeMonthProduct.toStoreProduct(),
offeringIdentifier: Self.offeringIdentifier
)
static let sixMonthPackage = Package(
identifier: PackageType.sixMonth.identifier,
packageType: .sixMonth,
Expand Down
5 changes: 3 additions & 2 deletions RevenueCatUI/Helpers/Package+VariableDataProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,16 @@ extension Package: VariableDataProvider {
return self.localizedPrice
}

let unit = Localization.abbreviatedUnitLocalizedString(for: period.unit, locale: locale)
let unit = Localization.abbreviatedUnitLocalizedString(for: period, locale: locale)
return "\(self.localizedPrice)/\(unit)"
}

func localizedPriceAndPerMonth(_ locale: Locale) -> String {
if !self.isSubscription || self.isMonthly {
return self.localizedPricePerPeriod(locale)
} else {
let unit = Localization.abbreviatedUnitLocalizedString(for: .month, locale: locale)
let unit = Localization.abbreviatedUnitLocalizedString(for: .init(value: 1, unit: .month),
locale: locale)
return "\(self.localizedPrice) (\(self.localizedPricePerMonth)/\(unit))"
}
}
Expand Down
102 changes: 102 additions & 0 deletions Tests/RevenueCatUITests/Data/PackageVariablesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,55 +33,105 @@ class PackageVariablesTests: TestCase {
func testLocalizedPricePerMonth() {
expect(TestData.weeklyPackage.localizedPricePerMonth) == "$7.96"
expect(TestData.monthlyPackage.localizedPricePerMonth) == "$6.99"
expect(TestData.threeMonthPackage.localizedPricePerMonth) == "$1.66"
expect(TestData.sixMonthPackage.localizedPricePerMonth) == "$1.33"
expect(TestData.annualPackage.localizedPricePerMonth) == "$4.49"
expect(TestData.lifetimePackage.localizedPricePerMonth) == "$119.49"
}

func testEnglishLocalizedPricePerPeriod() {
expect(TestData.weeklyPackage.localizedPricePerPeriod(Self.english)) == "$1.99/wk"
expect(TestData.monthlyPackage.localizedPricePerPeriod(Self.english)) == "$6.99/mo"
expect(TestData.threeMonthPackage.localizedPricePerPeriod(Self.english)) == "$4.99/3mo"
expect(TestData.sixMonthPackage.localizedPricePerPeriod(Self.english)) == "$7.99/6mo"
expect(TestData.annualPackage.localizedPricePerPeriod(Self.english)) == "$53.99/yr"
expect(TestData.lifetimePackage.localizedPricePerPeriod(Self.english)) == "$119.49"
}

func testSpanishLocalizedPricePerPeriod() {
expect(TestData.weeklyPackage.localizedPricePerPeriod(Self.spanish)) == "$1.99/sem"
expect(TestData.monthlyPackage.localizedPricePerPeriod(Self.spanish)) == "$6.99/m."
expect(TestData.threeMonthPackage.localizedPricePerPeriod(Self.spanish)) == "$4.99/3m"
expect(TestData.sixMonthPackage.localizedPricePerPeriod(Self.spanish)) == "$7.99/6m"
expect(TestData.annualPackage.localizedPricePerPeriod(Self.spanish)) == "$53.99/año"
expect(TestData.lifetimePackage.localizedPricePerPeriod(Self.spanish)) == "$119.49"
}

func testArabicLocalizedPricePerPeriod() {
let arabicPrice = "٣.٩٩ درهم"

expect(TestData.weeklyPackage.with(arabicPrice, Self.arabic).localizedPricePerPeriod(Self.arabic))
== "٣.٩٩ درهم/أسبوع"
expect(TestData.monthlyPackage.with(arabicPrice, Self.arabic).localizedPricePerPeriod(Self.arabic))
== "٣.٩٩ درهم/شهر"
expect(TestData.threeMonthPackage.with(arabicPrice, Self.arabic).localizedPricePerPeriod(Self.arabic))
== "٣.٩٩ درهم/3شهر"
expect(TestData.sixMonthPackage.with(arabicPrice, Self.arabic).localizedPricePerPeriod(Self.arabic))
== "٣.٩٩ درهم/6شهر"
expect(TestData.annualPackage.with(arabicPrice, Self.arabic).localizedPricePerPeriod(Self.arabic))
== "٣.٩٩ درهم/سنة"
expect(TestData.lifetimePackage.with(arabicPrice, Self.arabic).localizedPricePerPeriod(Self.arabic))
== "٣.٩٩ درهم"
}

func testEnglishLocalizedPriceAndPerMonth() {
expect(TestData.weeklyPackage.localizedPriceAndPerMonth(Self.english)) == "$1.99 ($7.96/mo)"
expect(TestData.monthlyPackage.localizedPriceAndPerMonth(Self.english)) == "$6.99/mo"
expect(TestData.threeMonthPackage.localizedPriceAndPerMonth(Self.english)) == "$4.99 ($1.66/mo)"
expect(TestData.sixMonthPackage.localizedPriceAndPerMonth(Self.english)) == "$7.99 ($1.33/mo)"
expect(TestData.annualPackage.localizedPriceAndPerMonth(Self.english)) == "$53.99 ($4.49/mo)"
expect(TestData.lifetimePackage.localizedPriceAndPerMonth(Self.english)) == "$119.49"
}

func testSpanishLocalizedPriceAndPerMonth() {
expect(TestData.weeklyPackage.localizedPriceAndPerMonth(Self.spanish)) == "$1.99 ($7.96/m.)"
expect(TestData.monthlyPackage.localizedPriceAndPerMonth(Self.spanish)) == "$6.99/m."
expect(TestData.threeMonthPackage.localizedPriceAndPerMonth(Self.spanish)) == "$4.99 ($1.66/m.)"
expect(TestData.sixMonthPackage.localizedPriceAndPerMonth(Self.spanish)) == "$7.99 ($1.33/m.)"
expect(TestData.annualPackage.localizedPriceAndPerMonth(Self.spanish)) == "$53.99 ($4.49/m.)"
expect(TestData.lifetimePackage.localizedPriceAndPerMonth(Self.spanish)) == "$119.49"
}

func testArabicLocalizedPriceAndPerMonth() {
let arabicPrice = "٣.٩٩ درهم"

expect(TestData.weeklyPackage.with(arabicPrice, Self.arabic).localizedPriceAndPerMonth(Self.arabic))
.to(equalIgnoringRTL("٣.٩٩ درهم (‏7.96 ‏د.إ.‏/شهر)"))
expect(TestData.monthlyPackage.with(arabicPrice, Self.arabic).localizedPriceAndPerMonth(Self.arabic))
.to(equalIgnoringRTL("٣.٩٩ درهم/شهر"))
expect(TestData.threeMonthPackage.with(arabicPrice, Self.arabic).localizedPriceAndPerMonth(Self.arabic))
.to(equalIgnoringRTL("٣.٩٩ درهم (‏1.66 ‏د.إ.‏/شهر)"))
expect(TestData.sixMonthPackage.with(arabicPrice, Self.arabic).localizedPriceAndPerMonth(Self.arabic))
.to(equalIgnoringRTL("٣.٩٩ درهم (‏1.33 ‏د.إ.‏/شهر)"))
expect(TestData.annualPackage.with(arabicPrice, Self.arabic).localizedPriceAndPerMonth(Self.arabic))
.to(equalIgnoringRTL("٣.٩٩ درهم (‏4.49 ‏د.إ.‏/شهر)"))
expect(TestData.lifetimePackage.with(arabicPrice, Self.arabic).localizedPriceAndPerMonth(Self.arabic))
== arabicPrice
}

func testProductName() {
expect(TestData.weeklyPackage.productName) == "Weekly"
expect(TestData.monthlyPackage.productName) == "Monthly"
expect(TestData.threeMonthPackage.productName) == "3 months"
expect(TestData.sixMonthPackage.productName) == "6 months"
expect(TestData.annualPackage.productName) == "Annual"
expect(TestData.lifetimePackage.productName) == "Lifetime"
}

func testEnglishPeriodName() {
expect(TestData.weeklyPackage.periodName(Self.english)) == "Weekly"
expect(TestData.monthlyPackage.periodName(Self.english)) == "Monthly"
expect(TestData.threeMonthPackage.periodName(Self.english)) == "3 Month"
expect(TestData.sixMonthPackage.periodName(Self.english)) == "6 Month"
expect(TestData.annualPackage.periodName(Self.english)) == "Annual"
expect(TestData.lifetimePackage.periodName(Self.english)) == "Lifetime"
}

func testSpanishPeriodName() {
expect(TestData.weeklyPackage.periodName(Self.spanish)) == "Semanalmente"
expect(TestData.monthlyPackage.periodName(Self.spanish)) == "Mensual"
expect(TestData.threeMonthPackage.periodName(Self.spanish)) == "3 meses"
expect(TestData.sixMonthPackage.periodName(Self.spanish)) == "6 meses"
expect(TestData.annualPackage.periodName(Self.spanish)) == "Anual"
expect(TestData.lifetimePackage.periodName(Self.spanish)) == "Toda la vida"
}
Expand Down Expand Up @@ -114,5 +164,57 @@ private extension PackageVariablesTests {

static let english: Locale = .init(identifier: "en_US")
static let spanish: Locale = .init(identifier: "es_ES")
static let arabic: Locale = .init(identifier: "ar_AE")

}

// MARK: -

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
private extension Package {

func with(_ newLocalizedPrice: String, _ locale: Locale) -> Package {
return .init(
identifier: self.identifier,
packageType: self.packageType,
storeProduct: self.storeProduct
.toTestProduct()
.with(newLocalizedPrice, locale)
.toStoreProduct(),
offeringIdentifier: self.offeringIdentifier
)
}

}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
private extension TestStoreProduct {

func with(_ newLocalizedPrice: String, _ locale: Locale) -> Self {
var copy = self
copy.localizedPriceString = newLocalizedPrice
copy.locale = locale

return copy
}

}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
private extension StoreProduct {

func toTestProduct() -> TestStoreProduct {
return .init(
localizedTitle: self.localizedTitle,
price: self.price,
localizedPriceString: self.localizedPriceString,
productIdentifier: self.productIdentifier,
productType: self.productType,
localizedDescription: self.localizedDescription,
subscriptionGroupIdentifier: self.subscriptionGroupIdentifier,
subscriptionPeriod: self.subscriptionPeriod,
isFamilyShareable: self.isFamilyShareable
)
}

}
Loading

0 comments on commit 44d0cb1

Please sign in to comment.