From 335d0b25fa3e2ddc9bbd257bdbb5e4d774412759 Mon Sep 17 00:00:00 2001 From: Josh Holtz Date: Mon, 19 Aug 2024 13:50:41 -0500 Subject: [PATCH] [Paywalls] Add default locale (#1809) ### Motivation Support new `default_locale` property in paywall data ### Description If localization for preferred language isn't found, use the default locale before falling back to the first locale. #### Demo https://github.com/user-attachments/assets/fae5bfb1-d22b-4d69-a944-ff3311c47ee5 --------- Co-authored-by: Toni Rico --- .../revenuecat/paywallstester/Constants.kt | 2 +- .../purchases/paywalls/PaywallData.kt | 27 +++++++++++++- .../purchases/paywalls/PaywallDataTest.kt | 10 +++++ ...lt-locale-with-missing_current_locale.json | 37 +++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 purchases/src/test/resources/paywalldata-default-locale-with-missing_current_locale.json diff --git a/examples/paywall-tester/src/main/java/com/revenuecat/paywallstester/Constants.kt b/examples/paywall-tester/src/main/java/com/revenuecat/paywallstester/Constants.kt index be25fce951..93c21b87c6 100644 --- a/examples/paywall-tester/src/main/java/com/revenuecat/paywallstester/Constants.kt +++ b/examples/paywall-tester/src/main/java/com/revenuecat/paywallstester/Constants.kt @@ -1,5 +1,5 @@ package com.revenuecat.paywallstester object Constants { - const val GOOGLE_API_KEY = "goog_uArAGtKQJeuXMWoSNXCAZBzTepD" + const val GOOGLE_API_KEY = "API_KEY" } diff --git a/purchases/src/main/kotlin/com/revenuecat/purchases/paywalls/PaywallData.kt b/purchases/src/main/kotlin/com/revenuecat/purchases/paywalls/PaywallData.kt index 0babe39d2b..5fc8294405 100644 --- a/purchases/src/main/kotlin/com/revenuecat/purchases/paywalls/PaywallData.kt +++ b/purchases/src/main/kotlin/com/revenuecat/purchases/paywalls/PaywallData.kt @@ -49,6 +49,11 @@ data class PaywallData( @SerialName("zero_decimal_place_countries") @Serializable(with = GoogleListSerializer::class) val zeroDecimalPlaceCountries: List = emptyList(), + + /** + * The default locale to be used on a paywall if the preferred languages aren't found. + */ + @SerialName("default_locale") val defaultLocale: String? = null, ) { /** @@ -61,6 +66,7 @@ data class PaywallData( } @VisibleForTesting + @Suppress("ReturnCount") fun localizedConfiguration(locales: List): Pair { for (locale in locales) { val localeToCheck = locale.convertToCorrectlyFormattedLocale() @@ -69,6 +75,15 @@ data class PaywallData( } } + // Try finding default local + defaultLocale?.let { defaultLocale -> + localization.entries.firstOrNull { localization -> + localization.key.toLocale() == defaultLocale.toLocale() + }?.let { localization -> + return (localization.key.toLocale() to localization.value) + } + } + // Fallback to first localization localization.entries.first().let { localization -> return (localization.key.toLocale() to localization.value) @@ -92,6 +107,7 @@ data class PaywallData( return tieredConfigForLocales(locales = getDefaultLocales()) } + @Suppress("ReturnCount") private fun tieredConfigForLocales(locales: List): Pair> { for (locale in locales) { val localeToCheck = locale.convertToCorrectlyFormattedLocale() @@ -100,9 +116,18 @@ data class PaywallData( } } + // Try finding default locale + defaultLocale?.let { defaultLocale -> + localizationByTier.entries.firstOrNull { localization -> + localization.key.toLocale() == defaultLocale.toLocale() + }?.let { localization -> + return (localization.key.toLocale() to localization.value) + } + } + // Fallback to first localization val first = localizationByTier.entries.first() - return Pair(first.key.toLocale(), first.value) + return (first.key.toLocale() to first.value) } @VisibleForTesting diff --git a/purchases/src/test/java/com/revenuecat/purchases/paywalls/PaywallDataTest.kt b/purchases/src/test/java/com/revenuecat/purchases/paywalls/PaywallDataTest.kt index 1ea15b88d4..9901e9fa69 100644 --- a/purchases/src/test/java/com/revenuecat/purchases/paywalls/PaywallDataTest.kt +++ b/purchases/src/test/java/com/revenuecat/purchases/paywalls/PaywallDataTest.kt @@ -16,6 +16,7 @@ import java.util.* private const val PAYWALLDATA_SAMPLE1 = "paywalldata-sample1.json" private const val PAYWALLDATA_CHINESE = "paywalldata-chinese.json" private const val PAYWALLDATA_MISSING_CURRENT_LOCALE = "paywalldata-missing_current_locale.json" +private const val PAYWALLDATA_DEFAULT_LOCALE_WITH_MISSING_CURRENT_LOCALE = "paywalldata-default-locale-with-missing_current_locale.json" private const val PAYWALLDATA_EMPTY_IMAGES = "paywalldata-empty-images.json" @RunWith(AndroidJUnit4::class) @@ -149,6 +150,15 @@ class PaywallDataTest { assertThat(localization.title).isEqualTo("Tienda") } + @Test + fun `if current locale is missing it loads default locale`() { + val paywall: PaywallData = decode(PAYWALLDATA_DEFAULT_LOCALE_WITH_MISSING_CURRENT_LOCALE) + + val localization = paywall.localizedConfiguration.second + assertThat(localization.callToAction).isEqualTo("Kup") + assertThat(localization.title).isEqualTo("Sklep") + } + @Test fun `localized configuration finds locale with different region`() { val paywall: PaywallData = decode(PAYWALLDATA_SAMPLE1) diff --git a/purchases/src/test/resources/paywalldata-default-locale-with-missing_current_locale.json b/purchases/src/test/resources/paywalldata-default-locale-with-missing_current_locale.json new file mode 100644 index 0000000000..8765431eb9 --- /dev/null +++ b/purchases/src/test/resources/paywalldata-default-locale-with-missing_current_locale.json @@ -0,0 +1,37 @@ +{ + "template_name": "1", + "localized_strings": { + "es_ES": { + "title": "Tienda", + "subtitle": "Descripción", + "call_to_action": "Comprar", + "call_to_action_with_intro_offer": "Comprar", + "offer_details": "{{ sub_price_per_month }} cada mes", + "offer_details_with_intro_offer": "Comienza tu prueba de {{ sub_offer_duration }}, y después {{ sub_price_per_month }} cada mes" + }, + "pl_PL": { + "title": "Sklep", + "subtitle": "Opis", + "call_to_action": "Kup", + "call_to_action_with_intro_offer": "Kup", + "offer_details": "{{ sub_price_per_month }} co miesiąc", + "offer_details_with_intro_offer": "Rozpocznij swój {{ sub_offer_duration }} okres próbny, a następnie {{ sub_price_per_month }} co miesiąc" + } + }, + "config": { + "packages": ["$rc_monthly", "$rc_annual"], + "images_webp": {}, + "colors": { + "light": { + "background": "#FFFFFF", + "text_1": "#FFFFFF", + "call_to_action_background": "#FFFFFF", + "call_to_action_foreground": "#FFFFFF", + "accent_1": "#FFFFFF" + }, + "dark": null + } + }, + "asset_base_url": "https://rc-paywalls.s3.amazonaws.com", + "default_locale": "pl_PL" +}