Fixes price formatting discrepancies on Paywalls for {{ product.price_per_[day|week|month|year] }}#2604
Conversation
{{ product.price_per_[day|week|month|year }}{{ product.price_per_[day|week|month|year] }}
| val currencyLocale by derivedStateOf { | ||
| if (storefrontCountryCode.isNullOrBlank()) { | ||
| locale | ||
| } else { | ||
| val deviceLanguageCode = locale.language.lowercase() | ||
|
|
||
| // We find all available device locales with the same country as the storefront country. | ||
| val availableStorefrontCountryLocalesByLanguage: Map<String, Locale> = | ||
| availableDeviceLocalesByCountry[storefrontCountryCode.lowercase()] | ||
| ?.associateBy { it.language.lowercase() } | ||
| ?: emptyMap() | ||
|
|
||
| // We pick the one with the same language as the device if available. If not, we just pick the | ||
| // first. If the list is empty, we build our own Locale. | ||
| val javaLocale = availableStorefrontCountryLocalesByLanguage[deviceLanguageCode] | ||
| ?: availableStorefrontCountryLocalesByLanguage.values.firstOrNull() | ||
| ?: Locale.forLanguageTag("$deviceLanguageCode-${storefrontCountryCode.uppercase()}") | ||
|
|
||
| javaLocale.toComposeLocale() | ||
| } | ||
| } |
There was a problem hiding this comment.
I remember from a past project that there are some exceptions where the locale is not just language-country, but may also contain a -variant.
I'm not sure if it's super relevant since the fallback might be good enough, but for example zh-Hans (Chinese in Simplified script) would be one of them.
There was a problem hiding this comment.
You're right! I was thinking this is good enough for a fallback, but we can do better. We're now using the entire device locale as a last resort, but only adjusting the country to the storefront one: feb641e.
📸 Snapshot Test233 modified, 427 unchanged
🛸 Powered by Emerge Tools |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2604 +/- ##
=======================================
Coverage 78.41% 78.41%
=======================================
Files 301 301
Lines 11241 11241
Branches 1561 1561
=======================================
Hits 8815 8815
Misses 1740 1740
Partials 686 686 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
I'll let someone with a bit more context on this approve the PR :) |
tonidero
left a comment
There was a problem hiding this comment.
Just a question but I think it makes sense! Many thanks for adding those tests and the fix!! Exciting to get this fixed!
| // first. If the list is empty, we build our own Locale. | ||
| val javaLocale = availableStorefrontCountryLocalesByLanguage[deviceLanguageCode] | ||
| ?: availableStorefrontCountryLocalesByLanguage.values.firstOrNull() | ||
| ?: Locale.forLanguageTag("$deviceLanguageCode-${storefrontCountryCode.uppercase()}") |
There was a problem hiding this comment.
From my tests on a kotlin playground, if the locale is wrongly formatted here it would still create the locale... what would happen in that case? Just wondering if we should add extra validation here to make sure we build a valid locale or fallback to the device locale instead...
There was a problem hiding this comment.
Good point! I changed it so we're using the device locale and only adjust the country to the storefront one: feb641e.
|
Asked Emerge for logs on the failures. |
**This is an automatic release.** ## RevenueCat SDK ### 🐞 Bugfixes * Use `Block store` to backup anonymous user ids across installations (#2595) via Toni Rico (@tonidero) ## RevenueCatUI SDK ### Paywallv2 #### 🐞 Bugfixes * Fixes price formatting discrepancies on Paywalls for `{{ product.price_per_[day|week|month|year] }}` (#2604) via JayShortway (@JayShortway) ### 🔄 Other Changes * Revert dokka 2 and gradle 9 update (#2618) via Toni Rico (@tonidero) * Introduce runtime annotations library and add stability annotations for increasing UI performances (#2608) via Jaewoong Eum (@skydoves) * Override presented offering context paywalls without offering (#2612) via Toni Rico (@tonidero) * Add APIs for hybrid SDKs to set presentedOfferingContext (#2610) via Toni Rico (@tonidero) * Bump Baseline Profiles to 1.4.0 and update profiles (#2611) via Jaewoong Eum (@skydoves) * Migrate deprecated kotlinOptions to compilerOptions (#2607) via Jaewoong Eum (@skydoves) * [AUTOMATIC][Paywalls V2] Updates paywall-preview-resources submodule (#2613) via RevenueCat Git Bot (@RCGitBot) * Migrate amazon & debugview modules to KTS (#2327) via Jaewoong Eum (@skydoves) * Update to Dokka 2.0.0 (#2609) via Toni Rico (@tonidero) * Add log when restoring purchases finds no purchases with some troubleshooting (#2599) via Toni Rico (@tonidero) Co-authored-by: revenuecat-ops <ops@revenuecat.com>
…e_per_[day|week|month|year] }}` (#2604) ## Bug We've had reports of formatting discrepancies between calculated prices (e.g. monthly price calculated from a yearly subscription) and the price that comes directly from the store (the yearly price of a yearly subscription). This store price is shown on the paywall (`{{ product.price }}`) and on the Play Billing purchase sheet. ## Cause This is caused by the fact that calculated prices use the device locale to format, and the store uses the storefront country. ## Fix The fix implemented in this PR is to use the storefront country to format all prices. The difficulty is in the fact that the storefront country is only a country, not a complete locale. It's missing a language. To solve that, we check all available device locales for the storefront country, and pick the best one.
Bug
We've had reports of formatting discrepancies between calculated prices (e.g. monthly price calculated from a yearly subscription) and the price that comes directly from the store (the yearly price of a yearly subscription). This store price is shown on the paywall (
{{ product.price }}) and on the Play Billing purchase sheet.Cause
This is caused by the fact that calculated prices use the device locale to format, and the store uses the storefront country.
Fix
The fix implemented in this PR is to use the storefront country to format all prices. The difficulty is in the fact that the storefront country is only a country, not a complete locale. It's missing a language. To solve that, we check all available device locales for the storefront country, and pick the best one.