Переглянути джерело

Fix localized purchase failure messages instead of showing raw StoreKit English.

Route StoreKit errors through a dedicated localized purchase message across all locales so purchase and restore alerts stay fully translated.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 місяць тому
батько
коміт
617a6a6020

+ 48 - 5
meetings_app/Localization/Error+Localization.swift

@@ -1,4 +1,5 @@
 import Foundation
+import StoreKit
 
 extension Error {
     /// User-facing text for alerts and labels, respecting Settings → Language.
@@ -6,6 +7,13 @@ extension Error {
         if let localizedError = self as? LocalizedError,
            let description = localizedError.errorDescription,
            description.isEmpty == false {
+            let fromAppBundle = description.localized
+            if fromAppBundle != description {
+                return fromAppBundle
+            }
+            if Self.isFrameworkLocalizedError(self) {
+                return Self.genericUserFacingMessage
+            }
             return description
         }
 
@@ -17,14 +25,14 @@ extension Error {
             if fromAppBundle != description {
                 return fromAppBundle
             }
-            if Self.isSystemLocalizedDomain(nsError.domain) {
-                return "An issue occurred. Please try again.".localized
+            if Self.isFrameworkLocalizedError(self) {
+                return Self.genericUserFacingMessage
             }
             return description
         }
 
-        if Self.isSystemLocalizedDomain(nsError.domain) {
-            return "An issue occurred. Please try again.".localized
+        if Self.isFrameworkLocalizedError(self) {
+            return Self.genericUserFacingMessage
         }
 
         let systemDescription = localizedDescription
@@ -32,7 +40,42 @@ extension Error {
             return systemDescription
         }
 
-        return "An issue occurred. Please try again.".localized
+        return Self.genericUserFacingMessage
+    }
+
+    /// Localized purchase/restore failure copy that never surfaces raw StoreKit or system English.
+    var localizedPurchaseFailureMessage: String {
+        if Self.isFrameworkLocalizedError(self) {
+            return Self.purchaseFailureMessage
+        }
+
+        let message = localizedUserFacingMessage
+        let nsError = self as NSError
+        if message == nsError.localizedDescription
+            || message == (self as? LocalizedError)?.errorDescription {
+            return Self.purchaseFailureMessage
+        }
+        return message
+    }
+
+    private static var genericUserFacingMessage: String {
+        "An issue occurred. Please try again.".localized
+    }
+
+    private static var purchaseFailureMessage: String {
+        "Your purchase could not be completed. Please try again.".localized
+    }
+
+    private static func isFrameworkLocalizedError(_ error: Error) -> Bool {
+        if error is StoreKitError {
+            return true
+        }
+
+        let nsError = error as NSError
+        if isSystemLocalizedDomain(nsError.domain) {
+            return true
+        }
+        return nsError.domain.contains("StoreKit")
     }
 
     private static func isSystemLocalizedDomain(_ domain: String) -> Bool {

+ 5 - 5
meetings_app/ViewController.swift

@@ -124,7 +124,7 @@ private final class StoreKitCoordinator {
             lastProductLoadError = nil
         } catch {
             productsByID = [:]
-            lastProductLoadError = error.localizedUserFacingMessage
+            lastProductLoadError = error.localizedPurchaseFailureMessage
         }
     }
 
@@ -164,8 +164,8 @@ private final class StoreKitCoordinator {
         guard let product = productsByID[productID] else {
             await refreshProducts()
             guard let refreshed = productsByID[productID] else {
-                if let lastProductLoadError, !lastProductLoadError.isEmpty {
-                    return .failed("Unable to load products: %@".localized(with: lastProductLoadError))
+                if lastProductLoadError != nil {
+                    return .failed("Unable to load this product. Check your StoreKit configuration and product IDs.".localized)
                 }
                 let loadedIDs = productsByID.keys.sorted().joined(separator: ", ")
                 let debugIDs = loadedIDs.isEmpty ? "none".localized : loadedIDs
@@ -186,7 +186,7 @@ private final class StoreKitCoordinator {
             }
             return "No previous premium purchase was found for this Apple ID.".localized
         } catch {
-            return "Restore failed: %@".localized(with: error.localizedUserFacingMessage)
+            return "Restore failed: %@".localized(with: error.localizedPurchaseFailureMessage)
         }
     }
 
@@ -209,7 +209,7 @@ private final class StoreKitCoordinator {
                 return .failed("Unknown purchase state.".localized)
             }
         } catch {
-            return .failed(error.localizedUserFacingMessage)
+            return .failed(error.localizedPurchaseFailureMessage)
         }
     }
 

+ 1 - 0
meetings_app/ar.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "تم شراؤه بالفعل";
 "This plan is already active on your Apple ID." = "هذه الخطة نشطة بالفعل على معرف آبل الخاص بك.";
 "Purchase Failed" = "فشلت عملية الشراء";
+"Your purchase could not be completed. Please try again." = "تعذر إكمال عملية الشراء. يرجى المحاولة مرة أخرى.";
 "Restore Purchases" = "استعادة المشتريات";
 "Purchases restored successfully." = "تمت استعادة المشتريات بنجاح.";
 "No previous premium purchase was found for this Apple ID." = "لم يتم العثور على عملية شراء مميزة سابقة لمعرف آبل هذا.";

+ 1 - 0
meetings_app/de.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Bereits gekauft";
 "This plan is already active on your Apple ID." = "Dieser Plan ist bereits auf Ihrer Apple-ID aktiv.";
 "Purchase Failed" = "Kauf fehlgeschlagen";
+"Your purchase could not be completed. Please try again." = "Ihr Kauf konnte nicht abgeschlossen werden. Bitte versuchen Sie es erneut.";
 "Restore Purchases" = "Käufe wiederherstellen";
 "Purchases restored successfully." = "Käufe erfolgreich wiederhergestellt.";
 "No previous premium purchase was found for this Apple ID." = "Für diese Apple-ID wurde kein vorheriger Premium-Kauf gefunden.";

+ 1 - 0
meetings_app/el.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Έχει ήδη αγοραστεί";
 "This plan is already active on your Apple ID." = "Αυτό το πρόγραμμα είναι ήδη ενεργό στο Apple ID σας.";
 "Purchase Failed" = "Αποτυχία αγοράς";
+"Your purchase could not be completed. Please try again." = "Η αγορά δεν μπόρεσε να ολοκληρωθεί. Παρακαλώ δοκιμάστε ξανά.";
 "Restore Purchases" = "Επαναφορά αγορών";
 "Purchases restored successfully." = "Οι αγορές επαναφέρθηκαν με επιτυχία.";
 "No previous premium purchase was found for this Apple ID." = "Δεν βρέθηκε προηγούμενη αγορά premium για αυτό το Apple ID.";

+ 1 - 0
meetings_app/en.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Already Purchased";
 "This plan is already active on your Apple ID." = "This plan is already active on your Apple ID.";
 "Purchase Failed" = "Purchase Failed";
+"Your purchase could not be completed. Please try again." = "Your purchase could not be completed. Please try again.";
 "Restore Purchases" = "Restore Purchases";
 "Purchases restored successfully." = "Purchases restored successfully.";
 "No previous premium purchase was found for this Apple ID." = "No previous premium purchase was found for this Apple ID.";

+ 1 - 0
meetings_app/es-ES.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Ya comprado";
 "This plan is already active on your Apple ID." = "Este plan ya está activo en tu ID de Apple.";
 "Purchase Failed" = "Compra fallida";
+"Your purchase could not be completed. Please try again." = "No se pudo completar tu compra. Inténtalo de nuevo.";
 "Restore Purchases" = "Restaurar compras";
 "Purchases restored successfully." = "Compras restauradas correctamente.";
 "No previous premium purchase was found for this Apple ID." = "No se encontró ninguna compra prémium anterior para este ID de Apple.";

+ 1 - 0
meetings_app/es-MX.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Ya comprado";
 "This plan is already active on your Apple ID." = "Este plan ya está activo en tu ID de Apple.";
 "Purchase Failed" = "Compra fallida";
+"Your purchase could not be completed. Please try again." = "No se pudo completar tu compra. Inténtalo de nuevo.";
 "Restore Purchases" = "Restaurar compras";
 "Purchases restored successfully." = "Compras restauradas correctamente.";
 "No previous premium purchase was found for this Apple ID." = "No se encontró ninguna compra Premium anterior para este ID de Apple.";

+ 1 - 0
meetings_app/fi.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Jo ostettu";
 "This plan is already active on your Apple ID." = "Tämä paketti on jo aktiivinen Apple ID:lläsi.";
 "Purchase Failed" = "Ostos epäonnistui";
+"Your purchase could not be completed. Please try again." = "Ostosta ei voitu suorittaa loppuun. Yritä uudelleen.";
 "Restore Purchases" = "Palauta ostokset";
 "Purchases restored successfully." = "Ostokset palautettu onnistuneesti.";
 "No previous premium purchase was found for this Apple ID." = "Tälle Apple ID:lle ei löytynyt aikaisempaa Premium-ostosta.";

+ 1 - 0
meetings_app/fr-CA.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Déjà acheté";
 "This plan is already active on your Apple ID." = "Ce forfait est déjà actif sur votre Apple ID.";
 "Purchase Failed" = "Échec de l'achat";
+"Your purchase could not be completed. Please try again." = "Votre achat n'a pas pu être finalisé. Veuillez réessayer.";
 "Restore Purchases" = "Restaurer les achats";
 "Purchases restored successfully." = "Achats restaurés avec succès.";
 "No previous premium purchase was found for this Apple ID." = "Aucun achat Premium antérieur n'a été trouvé pour cet Apple ID.";

+ 1 - 0
meetings_app/fr.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Déjà acheté";
 "This plan is already active on your Apple ID." = "Ce plan est déjà actif sur votre Apple ID.";
 "Purchase Failed" = "Échec de l'achat";
+"Your purchase could not be completed. Please try again." = "Votre achat n'a pas pu être finalisé. Veuillez réessayer.";
 "Restore Purchases" = "Restaurer les achats";
 "Purchases restored successfully." = "Achats restaurés avec succès.";
 "No previous premium purchase was found for this Apple ID." = "Aucun achat Premium antérieur n'a été trouvé pour cet Apple ID.";

+ 1 - 0
meetings_app/he.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "כבר נרכש";
 "This plan is already active on your Apple ID." = "תוכנית זו כבר פעילה במזהה אפל שלך.";
 "Purchase Failed" = "הרכישה נכשלה";
+"Your purchase could not be completed. Please try again." = "לא ניתן היה להשלים את הרכישה. אנא נסה שוב.";
 "Restore Purchases" = "שחזר רכישות";
 "Purchases restored successfully." = "הרכישות שוחזרו בהצלחה.";
 "No previous premium purchase was found for this Apple ID." = "לא נמצאה רכישת Premium קודמת עבור מזהה אפל זה.";

+ 1 - 0
meetings_app/it.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Già acquistato";
 "This plan is already active on your Apple ID." = "Questo piano è già attivo sul tuo ID Apple.";
 "Purchase Failed" = "Acquisto fallito";
+"Your purchase could not be completed. Please try again." = "L'acquisto non è stato completato. Riprova.";
 "Restore Purchases" = "Ripristina acquisti";
 "Purchases restored successfully." = "Acquisti ripristinati con successo.";
 "No previous premium purchase was found for this Apple ID." = "Nessun acquisto premium precedente trovato per questo ID Apple.";

+ 1 - 0
meetings_app/ko.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "이미 구매함";
 "This plan is already active on your Apple ID." = "이 플랜은 이미 애플 ID에 활성화되어 있습니다.";
 "Purchase Failed" = "구매 실패";
+"Your purchase could not be completed. Please try again." = "구매를 완료할 수 없습니다. 다시 시도하세요.";
 "Restore Purchases" = "구매 복원";
 "Purchases restored successfully." = "구매가 성공적으로 복원되었습니다.";
 "No previous premium purchase was found for this Apple ID." = "이 애플 ID에 대한 이전 프리미엄 구매 내역이 없습니다.";

+ 1 - 0
meetings_app/nb.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Allerede kjøpt";
 "This plan is already active on your Apple ID." = "Denne planen er allerede aktiv på Eple-ID-en din.";
 "Purchase Failed" = "Kjøp mislyktes";
+"Your purchase could not be completed. Please try again." = "Kjøpet kunne ikke fullføres. Prøv igjen.";
 "Restore Purchases" = "Gjenopprett kjøp";
 "Purchases restored successfully." = "Kjøp gjenopprettet.";
 "No previous premium purchase was found for this Apple ID." = "Ingen tidligere premium-kjøp ble funnet for denne Eple-ID-en.";

+ 1 - 0
meetings_app/nl.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Al gekocht";
 "This plan is already active on your Apple ID." = "Dit abonnement is al actief op uw Apple ID.";
 "Purchase Failed" = "Aankoop mislukt";
+"Your purchase could not be completed. Please try again." = "Je aankoop kon niet worden voltooid. Probeer het opnieuw.";
 "Restore Purchases" = "Aankopen herstellen";
 "Purchases restored successfully." = "Aankopen succesvol hersteld.";
 "No previous premium purchase was found for this Apple ID." = "Er is geen eerdere premium-aankoop gevonden voor dit Apple ID.";

+ 1 - 0
meetings_app/pl.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Już zakupiono";
 "This plan is already active on your Apple ID." = "Ten plan jest już aktywny na Twoim ID Jabłka.";
 "Purchase Failed" = "Zakup nieudany";
+"Your purchase could not be completed. Please try again." = "Zakup nie mógł zostać zakończony. Spróbuj ponownie.";
 "Restore Purchases" = "Przywróć zakupy";
 "Purchases restored successfully." = "Pomyślnie przywrócono zakupy.";
 "No previous premium purchase was found for this Apple ID." = "Nie znaleziono poprzedniego zakupu premium dla tego ID Jabłka.";

+ 1 - 0
meetings_app/pt-BR.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Já comprado";
 "This plan is already active on your Apple ID." = "Este plano já está ativo no seu ID Apple.";
 "Purchase Failed" = "Falha na compra";
+"Your purchase could not be completed. Please try again." = "Não foi possível concluir sua compra. Tente novamente.";
 "Restore Purchases" = "Restaurar compras";
 "Purchases restored successfully." = "Compras restauradas com sucesso.";
 "No previous premium purchase was found for this Apple ID." = "Nenhuma compra Premium anterior foi encontrada para este ID Apple.";

+ 1 - 0
meetings_app/ru.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Уже куплено";
 "This plan is already active on your Apple ID." = "Этот план уже активен для вашего идентификатора Apple.";
 "Purchase Failed" = "Ошибка покупки";
+"Your purchase could not be completed. Please try again." = "Не удалось завершить покупку. Пожалуйста, попробуйте снова.";
 "Restore Purchases" = "Восстановить покупки";
 "Purchases restored successfully." = "Покупки успешно восстановлены.";
 "No previous premium purchase was found for this Apple ID." = "Для этого идентификатора Apple не найдено предыдущих покупок Премиум.";

+ 1 - 0
meetings_app/sv.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Redan köpt";
 "This plan is already active on your Apple ID." = "Denna plan är redan aktiv på ditt Apple-ID.";
 "Purchase Failed" = "Köp misslyckades";
+"Your purchase could not be completed. Please try again." = "Ditt köp kunde inte slutföras. Försök igen.";
 "Restore Purchases" = "Återställ köp";
 "Purchases restored successfully." = "Köp återställda framgångsrikt.";
 "No previous premium purchase was found for this Apple ID." = "Inget tidigare Premium-köp hittades för detta Apple-ID.";

+ 1 - 0
meetings_app/uk.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Вже придбано";
 "This plan is already active on your Apple ID." = "Цей план уже активний для вашого ідентифікатора Епл.";
 "Purchase Failed" = "Помилка покупки";
+"Your purchase could not be completed. Please try again." = "Не вдалося завершити покупку. Спробуйте знову.";
 "Restore Purchases" = "Відновити покупки";
 "Purchases restored successfully." = "Покупки успішно відновлено.";
 "No previous premium purchase was found for this Apple ID." = "Попередніх покупок Преміум для цього ідентифікатора Епл не знайдено.";

+ 1 - 0
meetings_app/vi.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "Đã mua";
 "This plan is already active on your Apple ID." = "Gói này đã hoạt động trên Apple ID của bạn.";
 "Purchase Failed" = "Mua hàng thất bại";
+"Your purchase could not be completed. Please try again." = "Không thể hoàn tất giao dịch mua. Vui lòng thử lại.";
 "Restore Purchases" = "Khôi phục mua hàng";
 "Purchases restored successfully." = "Đã khôi phục mua hàng thành công.";
 "No previous premium purchase was found for this Apple ID." = "Không tìm thấy giao dịch mua Premium trước đó cho Apple ID này.";

+ 1 - 0
meetings_app/zh-Hans.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "已购买";
 "This plan is already active on your Apple ID." = "此计划已在您的苹果账号上激活。";
 "Purchase Failed" = "购买失败";
+"Your purchase could not be completed. Please try again." = "无法完成购买。请重试。";
 "Restore Purchases" = "恢复购买";
 "Purchases restored successfully." = "购买恢复成功。";
 "No previous premium purchase was found for this Apple ID." = "未找到此苹果账号之前的任何高级版购买记录。";

+ 1 - 0
meetings_app/zh-Hant.lproj/Localizable.strings

@@ -279,6 +279,7 @@
 "Already Purchased" = "已購買";
 "This plan is already active on your Apple ID." = "此方案已在您的蘋果帳號上啟用。";
 "Purchase Failed" = "購買失敗";
+"Your purchase could not be completed. Please try again." = "無法完成購買。請重試。";
 "Restore Purchases" = "回復購買";
 "Purchases restored successfully." = "購買回復成功。";
 "No previous premium purchase was found for this Apple ID." = "未找到此蘋果帳號之前的任何進階版購買記錄。";