// // SubscriptionLocale.swift // StoreKit2Manager // // Created by xiaopin on 2025/12/6. // import Foundation import StoreKit /// 订阅产品国际化工具类 public struct SubscriptionLocale { /// 将 StoreKit 的周期单位转换为标准单位 /// - Parameter period: 订阅周期 /// - Returns: 标准单位字符串:day, week, month, year public static func getUnit(from period: Product.SubscriptionPeriod?) -> String { guard let period = period else { return "day" } let unit = period.unit let numberOfUnits = period.value switch unit { case .day: if numberOfUnits >= 365 { return "year" } else if numberOfUnits >= 30 { return "month" } else if numberOfUnits >= 7 { return "week" } return "day" case .week: if numberOfUnits >= 52 { return "year" } else if numberOfUnits >= 4 { return "month" } return "week" case .month: if numberOfUnits >= 12 { return "year" } return "month" case .year: return "year" @unknown default: if numberOfUnits >= 365 { return "year" } else if numberOfUnits >= 30 { return "month" } else if numberOfUnits >= 7 { return "week" } return "day" } } /// 获取本地化的单位文本 /// - Parameters: /// - languageCode: 语言代码 /// - numberOfPeriods: 周期数量 /// - unit: 单位(day, week, month, year) /// - Returns: 本地化的单位文本 private static func getLocalizedUnit(languageCode: String, numberOfPeriods: Int, unit: String) -> String { switch languageCode { case "ar": switch unit { case "day": return numberOfPeriods == 1 ? "يوم" : "أيام" case "week": return numberOfPeriods == 1 ? "أسبوع" : "أسابيع" case "month": return numberOfPeriods == 1 ? "شهر" : "أشهر" case "year": return numberOfPeriods == 1 ? "سنة" : "سنوات" default: return numberOfPeriods == 1 ? "يوم" : "أيام" } case "de": switch unit { case "day": return "Täg" case "week": return "Wochen" case "month": return "Monat" case "year": return "Jahr" default: return "Täg" } case "en": switch unit { case "day": return numberOfPeriods == 1 ? "day" : "days" case "week": return numberOfPeriods == 1 ? "week" : "weeks" case "month": return numberOfPeriods == 1 ? "month" : "months" case "year": return numberOfPeriods == 1 ? "year" : "years" default: return numberOfPeriods == 1 ? "day" : "days" } case "es": switch unit { case "day": return numberOfPeriods == 1 ? "día" : "días" case "week": return numberOfPeriods == 1 ? "semana" : "semanas" case "month": return numberOfPeriods == 1 ? "mes" : "meses" case "year": return numberOfPeriods == 1 ? "año" : "años" default: return numberOfPeriods == 1 ? "día" : "días" } case "fil": switch unit { case "day": return "araw" case "week": return "linggo" case "month": return "buwan" case "year": return "taon" default: return "araw" } case "fr": switch unit { case "day": return numberOfPeriods == 1 ? "jour" : "jours" case "week": return numberOfPeriods == 1 ? "semaine" : "semaines" case "month": return numberOfPeriods == 1 ? "mois" : "mois" case "year": return numberOfPeriods == 1 ? "an" : "ans" default: return numberOfPeriods == 1 ? "jour" : "jours" } case "id": switch unit { case "day": return "hari" case "week": return "minggu" case "month": return "bulan" case "year": return "tahun" default: return "hari" } case "it": switch unit { case "day": return numberOfPeriods == 1 ? "giorno" : "giorni" case "week": return numberOfPeriods == 1 ? "settimana" : "settimane" case "month": return numberOfPeriods == 1 ? "mese" : "mesi" case "year": return numberOfPeriods == 1 ? "anno" : "anni" default: return numberOfPeriods == 1 ? "giorno" : "giorni" } case "ja": switch unit { case "day": return "日間" case "week": return "週間" case "month": return "ヶ月" case "year": return "年間" default: return "日間" } case "ko": switch unit { case "day": return "일" case "week": return "주" case "month": return "개월" case "year": return "년" default: return "일" } case "pl": switch unit { case "day": return numberOfPeriods == 1 ? "dzień" : "dni" case "week": return numberOfPeriods == 1 ? "tydzień" : "tygodni" case "month": return numberOfPeriods == 1 ? "miesiąc" : "miesięcy" case "year": return numberOfPeriods == 1 ? "rok" : "lat" default: return numberOfPeriods == 1 ? "dzień" : "dni" } case "pt": switch unit { case "day": return numberOfPeriods == 1 ? "dia" : "dias" case "week": return numberOfPeriods == 1 ? "semana" : "semanas" case "month": return numberOfPeriods == 1 ? "mês" : "meses" case "year": return numberOfPeriods == 1 ? "ano" : "anos" default: return numberOfPeriods == 1 ? "dia" : "dias" } case "ru": switch unit { case "day": return numberOfPeriods == 1 ? "день" : "дней" case "week": return numberOfPeriods == 1 ? "неделя" : "недель" case "month": return numberOfPeriods == 1 ? "месяц" : "месяцев" case "year": return numberOfPeriods == 1 ? "год" : "лет" default: return numberOfPeriods == 1 ? "день" : "дней" } case "th": switch unit { case "day": return "วัน" case "week": return "สัปดาห์" case "month": return "เดือน" case "year": return "ปี" default: return "วัน" } case "tr": switch unit { case "day": return "gün" case "week": return "hafta" case "month": return "ay" case "year": return "yıl" default: return "gün" } case "uk": switch unit { case "day": return numberOfPeriods == 1 ? "день" : "днів" case "week": return numberOfPeriods == 1 ? "тиждень" : "тижнів" case "month": return numberOfPeriods == 1 ? "місяць" : "місяців" case "year": return numberOfPeriods == 1 ? "рік" : "років" default: return numberOfPeriods == 1 ? "день" : "днів" } case "vi": switch unit { case "day": return "ngày" case "week": return "tuần" case "month": return "tháng" case "year": return "năm" default: return "ngày" } case "zh_Hans": switch unit { case "day": return "天" case "week": return "周" case "month": return "月" case "year": return "年" default: return "天" } case "zh_Hant": switch unit { case "day": return "天" case "week": return "周" case "month": return "月" case "year": return "年" default: return "天" } default: switch unit { case "day": return numberOfPeriods == 1 ? "day" : "days" case "week": return numberOfPeriods == 1 ? "week" : "weeks" case "month": return numberOfPeriods == 1 ? "month" : "months" case "year": return numberOfPeriods == 1 ? "year" : "years" default: return numberOfPeriods == 1 ? "day" : "days" } } } /// 从 Product 的 displayPrice 中提取货币符号 /// 通过从 displayPrice 中移除价格数字部分来获取货币符号 /// - Parameter product: Product 对象 /// - Returns: 货币符号字符串 public static func getCurrencySymbol(from product: Product) -> String { let displayPrice = product.displayPrice let priceDecimal = product.price let priceDouble = NSDecimalNumber(decimal: priceDecimal).doubleValue // 生成多种可能的价格格式字符串 var pricePatterns: [String] = [] // 1. 标准格式 "9.99" pricePatterns.append(String(format: "%.2f", priceDouble)) // 2. 整数格式(如果价格是整数) if priceDouble.truncatingRemainder(dividingBy: 1) == 0 { pricePatterns.append(String(format: "%.0f", priceDouble)) } // 3. 一位小数格式 "9.9"(如果最后一位是0) let priceString = String(format: "%.2f", priceDouble) if priceString.hasSuffix("0") { pricePatterns.append(String(format: "%.1f", priceDouble)) } // 4. 本地化格式(可能包含千位分隔符,如 "1,234.56" 或 "1.234,56") let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.maximumFractionDigits = 2 if let localizedPrice = formatter.string(from: NSNumber(value: priceDouble)) { pricePatterns.append(localizedPrice) } // 5. 本地化整数格式 if priceDouble.truncatingRemainder(dividingBy: 1) == 0 { formatter.maximumFractionDigits = 0 if let localizedPrice = formatter.string(from: NSNumber(value: priceDouble)) { pricePatterns.append(localizedPrice) } } // 从 displayPrice 中移除所有可能的价格格式 var cleanedPrice = displayPrice for pattern in pricePatterns { // 移除价格(处理前后可能有空格的情况) cleanedPrice = cleanedPrice.replacingOccurrences(of: " \(pattern) ", with: " ") cleanedPrice = cleanedPrice.replacingOccurrences(of: "\(pattern) ", with: " ") cleanedPrice = cleanedPrice.replacingOccurrences(of: " \(pattern)", with: " ") cleanedPrice = cleanedPrice.replacingOccurrences(of: pattern, with: "") } // 进一步清理:移除所有数字、小数点、逗号 cleanedPrice = cleanedPrice.replacingOccurrences(of: #"\d"#, with: "", options: .regularExpression) cleanedPrice = cleanedPrice.replacingOccurrences(of: #"[.,]"#, with: "", options: .regularExpression) // 清理多余的空格 cleanedPrice = cleanedPrice.trimmingCharacters(in: .whitespaces) cleanedPrice = cleanedPrice.replacingOccurrences(of: #"\s+"#, with: " ", options: .regularExpression) cleanedPrice = cleanedPrice.trimmingCharacters(in: .whitespaces) // 如果提取成功且不为空,返回货币符号 if !cleanedPrice.isEmpty { return cleanedPrice } // 后备方案:使用 Locale.current.currencySymbol return Locale.current.currencySymbol ?? "$" } // MARK: - 按钮文案 /// 获取订阅按钮文案 /// - Parameters: /// - type: 按钮类型 /// - languageCode: 语言代码 /// - Returns: 本地化的按钮文案 public static func subscriptionButtonText(type: SubscriptionButtonType, languageCode: String) -> String { switch languageCode { case "ar": switch type { case .standard: return "اشترك" case .freeTrial: return "جرّب مجانًا" case .payUpFront: return "ادفع الآن" case .payAsYouGo: return "ادفع حسب الاستخدام" case .lifetime: return "اشتر مدى الحياة" } case "de": switch type { case .standard: return "Abonnieren" case .freeTrial: return "Kostenlos testen" case .payUpFront: return "Jetzt bezahlen" case .payAsYouGo: return "Bezahlen nach Nutzung" case .lifetime: return "Lebenslang kaufen" } case "en": switch type { case .standard: return "Subscribe" case .freeTrial: return "Start Free Trial" case .payUpFront: return "Prepay Now" case .payAsYouGo: return "Pay As You Go" case .lifetime: return "Buy Lifetime" } case "es": switch type { case .standard: return "Suscribirse" case .freeTrial: return "Prueba gratis" case .payUpFront: return "Pagar ahora" case .payAsYouGo: return "Pagar por uso" case .lifetime: return "Comprar de por vida" } case "fil": switch type { case .standard: return "Mag-subscribe" case .freeTrial: return "Subukan nang libre" case .payUpFront: return "Magbayad ngayon" case .payAsYouGo: return "Magbayad ayon sa paggamit" case .lifetime: return "Bilhin ang panghabang-buhay" } case "fr": switch type { case .standard: return "S'abonner" case .freeTrial: return "Essai gratuit" case .payUpFront: return "Payer maintenant" case .payAsYouGo: return "Payer à l'usage" case .lifetime: return "Acheter à vie" } case "id": switch type { case .standard: return "Berlangganan" case .freeTrial: return "Coba gratis" case .payUpFront: return "Bayar sekarang" case .payAsYouGo: return "Bayar sesuai pemakaian" case .lifetime: return "Beli seumur hidup" } case "it": switch type { case .standard: return "Abbonati" case .freeTrial: return "Prova gratuita" case .payUpFront: return "Paga ora" case .payAsYouGo: return "Paga a consumo" case .lifetime: return "Acquista a vita" } case "ja": switch type { case .standard: return "購読する" case .freeTrial: return "無料トライアル開始" case .payUpFront: return "今すぐ支払う" case .payAsYouGo: return "使った分だけ支払う" case .lifetime: return "生涯購入" } case "ko": switch type { case .standard: return "구독하기" case .freeTrial: return "무료 체험 시작" case .payUpFront: return "지금 결제" case .payAsYouGo: return "사용한 만큼 결제" case .lifetime: return "평생 구매" } case "pl": switch type { case .standard: return "Subskrybuj" case .freeTrial: return "Wypróbuj za darmo" case .payUpFront: return "Zapłać teraz" case .payAsYouGo: return "Płać zgodnie z użyciem" case .lifetime: return "Kup na całe życie" } case "pt": switch type { case .standard: return "Assinar" case .freeTrial: return "Teste grátis" case .payUpFront: return "Pagar agora" case .payAsYouGo: return "Pagar conforme o uso" case .lifetime: return "Comprar vitalício" } case "ru": switch type { case .standard: return "Подписаться" case .freeTrial: return "Попробовать бесплатно" case .payUpFront: return "Оплатить сейчас" case .payAsYouGo: return "Оплата по мере использования" case .lifetime: return "Купить навсегда" } case "th": switch type { case .standard: return "สมัครสมาชิก" case .freeTrial: return "ทดลองใช้ฟรี" case .payUpFront: return "ชำระตอนนี้" case .payAsYouGo: return "จ่ายตามการใช้งาน" case .lifetime: return "ซื้อตลอดชีพ" } case "tr": switch type { case .standard: return "Abone ol" case .freeTrial: return "Ücretsiz dene" case .payUpFront: return "Şimdi öde" case .payAsYouGo: return "Kullandıkça öde" case .lifetime: return "Yaşam boyu satın al" } case "uk": switch type { case .standard: return "Підписатися" case .freeTrial: return "Спробувати безкоштовно" case .payUpFront: return "Оплатити зараз" case .payAsYouGo: return "Оплата за мірою використання" case .lifetime: return "Купити назавжди" } case "vi": switch type { case .standard: return "Đăng ký" case .freeTrial: return "Dùng thử miễn phí" case .payUpFront: return "Thanh toán ngay" case .payAsYouGo: return "Trả theo nhu cầu" case .lifetime: return "Mua trọn đời" } case "zh_Hans": switch type { case .standard: return "订阅" case .freeTrial: return "开始免费试用" case .payUpFront: return "立即支付" case .payAsYouGo: return "按需付费" case .lifetime: return "购买终身" } case "zh_Hant": switch type { case .standard: return "訂閱" case .freeTrial: return "開始免費試用" case .payUpFront: return "立即支付" case .payAsYouGo: return "按需付費" case .lifetime: return "購買終身" } default: // 默认返回英语 switch type { case .standard: return "Subscribe" case .freeTrial: return "Start Free Trial" case .payUpFront: return "Prepay Now" case .payAsYouGo: return "Pay As You Go" case .lifetime: return "Buy Lifetime" } } } // MARK: - 订阅标题 /// 获取订阅标题 /// - Parameters: /// - periodType: 持续时间类型(week, month, year, lifetime) /// - languageCode: 语言代码 /// - isShort: 是否使用简短版本 /// - Returns: 本地化的标题 public static func subscriptionTitle(periodType: SubscriptionPeriodType, languageCode: String, isShort: Bool = false) -> String { switch languageCode { case "ar": switch periodType { case .week: return isShort ? "أسبوعي" : "اشتراك أسبوعي" case .month: return isShort ? "شهري" : "اشتراك شهري" case .year: return isShort ? "سنوي" : "اشتراك سنوي" case .lifetime: return isShort ? "مدى الحياة" : "اشتراك مدى الحياة" } case "de": switch periodType { case .week: return isShort ? "Woche" : "Wöchentliches Abo" case .month: return isShort ? "Monat" : "Monatliches Abo" case .year: return isShort ? "Jahr" : "Jährliches Abo" case .lifetime: return isShort ? "Lebenslang" : "Lebenslanges Abo" } case "en": switch periodType { case .week: return isShort ? "Weekly" : "Weekly Subscription" case .month: return isShort ? "Monthly" : "Monthly Subscription" case .year: return isShort ? "Yearly" : "Annual Subscription" case .lifetime: return isShort ? "Lifetime" : "Lifetime Membership" } case "es": switch periodType { case .week: return isShort ? "Semanal" : "Suscripción semanal" case .month: return isShort ? "Mensual" : "Suscripción mensual" case .year: return isShort ? "Anual" : "Suscripción anual" case .lifetime: return isShort ? "De por vida" : "Suscripción de por vida" } case "fil": switch periodType { case .week: return isShort ? "Lingguhan" : "Lingguhang Subscription" case .month: return isShort ? "Buwanang" : "Buwanang Subscription" case .year: return isShort ? "Taunan" : "Taunang Subscription" case .lifetime: return isShort ? "Panghabang-buhay" : "Panghabang-buhay na Subscription" } case "fr": switch periodType { case .week: return isShort ? "Hebdo" : "Abonnement hebdomadaire" case .month: return isShort ? "Mensuel" : "Abonnement mensuel" case .year: return isShort ? "Annuel" : "Abonnement annuel" case .lifetime: return isShort ? "À vie" : "Abonnement à vie" } case "id": switch periodType { case .week: return isShort ? "Mingguan" : "Langganan mingguan" case .month: return isShort ? "Bulanan" : "Langganan bulanan" case .year: return isShort ? "Tahunan" : "Langganan tahunan" case .lifetime: return isShort ? "Seumur hidup" : "Langganan seumur hidup" } case "it": switch periodType { case .week: return isShort ? "Sett." : "Abbonamento settimanale" case .month: return isShort ? "Mese" : "Abbonamento mensile" case .year: return isShort ? "Anno" : "Abbonamento annuale" case .lifetime: return isShort ? "A vita" : "Abbonamento a vita" } case "ja": switch periodType { case .week: return isShort ? "週額" : "週額プラン" case .month: return isShort ? "月額" : "月額プラン" case .year: return isShort ? "年額" : "年額プラン" case .lifetime: return isShort ? "生涯" : "生涯プラン" } case "ko": switch periodType { case .week: return isShort ? "주간" : "주간 구독" case .month: return isShort ? "월간" : "월간 구독" case .year: return isShort ? "연간" : "연간 구독" case .lifetime: return isShort ? "평생" : "평생 회원권" } case "pl": switch periodType { case .week: return isShort ? "Tyg." : "Subskrypcja tygodniowa" case .month: return isShort ? "Mies." : "Subskrypcja miesięczna" case .year: return isShort ? "Rocznie" : "Subskrypcja roczna" case .lifetime: return isShort ? "Dożywotnia" : "Subskrypcja dożywotnia" } case "pt": switch periodType { case .week: return isShort ? "Semanal" : "Assinatura semanal" case .month: return isShort ? "Mensal" : "Assinatura mensal" case .year: return isShort ? "Anual" : "Assinatura anual" case .lifetime: return isShort ? "Vitalício" : "Assinatura vitalícia" } case "ru": switch periodType { case .week: return isShort ? "Неделя" : "Еженедельная подписка" case .month: return isShort ? "Месяц" : "Ежемесячная подписка" case .year: return isShort ? "Год" : "Годовая подписка" case .lifetime: return isShort ? "Навсегда" : "Пожизненная подписка" } case "th": switch periodType { case .week: return isShort ? "รายสัปดาห์" : "สมัครสมาชิกแบบรายสัปดาห์" case .month: return isShort ? "รายเดือน" : "สมัครสมาชิกแบบรายเดือน" case .year: return isShort ? "รายปี" : "สมัครสมาชิกแบบรายปี" case .lifetime: return isShort ? "ตลอดชีพ" : "สมาชิกตลอดชีพ" } case "tr": switch periodType { case .week: return isShort ? "Haftalık" : "Haftalık abonelik" case .month: return isShort ? "Aylık" : "Aylık abonelik" case .year: return isShort ? "Yıllık" : "Yıllık abonelik" case .lifetime: return isShort ? "Ömür boyu" : "Ömür boyu abonelik" } case "uk": switch periodType { case .week: return isShort ? "Тиж." : "Тижнева підписка" case .month: return isShort ? "Міс." : "Місячна підписка" case .year: return isShort ? "Рік" : "Річна підписка" case .lifetime: return isShort ? "Довічна" : "Довічна підписка" } case "vi": switch periodType { case .week: return isShort ? "Tuần" : "Gói thuê bao hàng tuần" case .month: return isShort ? "Tháng" : "Gói thuê bao hàng tháng" case .year: return isShort ? "Năm" : "Gói thuê bao hàng năm" case .lifetime: return isShort ? "Trọn đời" : "Gói trọn đời" } case "zh_Hans": switch periodType { case .week: return isShort ? "周会员" : "每周会员" case .month: return isShort ? "月会员" : "每月会员" case .year: return isShort ? "年会员" : "年度会员" case .lifetime: return isShort ? "终身会员" : "终身会员" } case "zh_Hant": switch periodType { case .week: return isShort ? "週會員" : "每週會員" case .month: return isShort ? "月會員" : "每月會員" case .year: return isShort ? "年會員" : "年度會員" case .lifetime: return isShort ? "終身會員" : "終身會員" } default: // 默认返回英语 switch periodType { case .week: return isShort ? "Weekly" : "Weekly Subscription" case .month: return isShort ? "Monthly" : "Monthly Subscription" case .year: return isShort ? "Yearly" : "Annual Subscription" case .lifetime: return isShort ? "Lifetime" : "Lifetime Membership" } } } // MARK: - 订阅副标题 /// 获取订阅类型描述词 /// - Parameters: /// - periodType: 持续时间类型 /// - languageCode: 语言代码 /// - Returns: 描述词(如:灵活选择、性价比之选、最优惠) private static func defaultSubDescWord(periodType: SubscriptionPeriodType, languageCode: String) -> String { switch languageCode { case "ar": switch periodType { case .week: return "مرونة" case .month: return "قيمة ممتازة" case .year: return "الأكثر توفيراً" case .lifetime: return "اشتراك دائم بدون تجديد" } case "de": switch periodType { case .week: return "Flexibilität" case .month: return "Bester Wert" case .year: return "Meist gespart" case .lifetime: return "Einmalig zahlen, dauerhaft nutzen" } case "en": switch periodType { case .week: return "Flexible" case .month: return "Best Value" case .year: return "Most Popular" case .lifetime: return "Pay once, own forever" } case "es": switch periodType { case .week: return "Flexible" case .month: return "Mejor Valor" case .year: return "Más Popular" case .lifetime: return "Paga una vez, disfruta siempre" } case "fil": switch periodType { case .week: return "Nakakalag" case .month: return "Pinakamahusay na Halaga" case .year: return "Pinakasikat" case .lifetime: return "Isang beses lang, habambuhay na" } case "fr": switch periodType { case .week: return "Flexible" case .month: return "Meilleur Rapport" case .year: return "Plus Populaire" case .lifetime: return "Achetez une fois, profitez à vie" } case "id": switch periodType { case .week: return "Fleksibel" case .month: return "Nilai Terbaik" case .year: return "Paling Populer" case .lifetime: return "Bayar sekali, pakai selamanya" } case "it": switch periodType { case .week: return "Flessibile" case .month: return "Miglior Valore" case .year: return "Più Popolare" case .lifetime: return "Paga una volta, usa per sempre" } case "ja": switch periodType { case .week: return "柔軟性" case .month: return "お得" case .year: return "人気" case .lifetime: return "一度の支払いで永久利用" } case "ko": switch periodType { case .week: return "유연함" case .month: return "최고 가치" case .year: return "인기" case .lifetime: return "한 번 결제로 평생 이용" } case "pl": switch periodType { case .week: return "Elastyczność" case .month: return "Najlepsza Wartość" case .year: return "Najpopularniejsze" case .lifetime: return "Zapłać raz, korzystaj zawsze" } case "pt": switch periodType { case .week: return "Flexível" case .month: return "Melhor Valor" case .year: return "Mais Popular" case .lifetime: return "Pague uma vez, use para sempre" } case "ru": switch periodType { case .week: return "Гибкость" case .month: return "Лучшая Цена" case .year: return "Популярный" case .lifetime: return "Оплати один раз, используй всегда" } case "th": switch periodType { case .week: return "ยืดหยุ่น" case .month: return "คุ้มค่าที่สุด" case .year: return "ยอดนิยม" case .lifetime: return "จ่ายครั้งเดียว ใช้ได้ตลอดชีพ" } case "tr": switch periodType { case .week: return "Esnek" case .month: return "En İyi Değer" case .year: return "En Popüler" case .lifetime: return "Bir kez öde, sürekli kullan" } case "uk": switch periodType { case .week: return "Гнучкість" case .month: return "Найкраща Ціна" case .year: return "Популярний" case .lifetime: return "Сплати один раз, використовуй завжди" } case "vi": switch periodType { case .week: return "Linh hoạt" case .month: return "Giá trị tốt nhất" case .year: return "Phổ biến nhất" case .lifetime: return "Thanh toán một lần, sử dụng mãi mãi" } case "zh_Hans": switch periodType { case .week: return "灵活选择" case .month: return "性价比之选" case .year: return "最优惠" case .lifetime: return "一次购买,终身访问" } case "zh_Hant": switch periodType { case .week: return "靈活選擇" case .month: return "性價比之選" case .year: return "最優惠" case .lifetime: return "一次購買,終生訪問" } default: switch periodType { case .week: return "Flexible" case .month: return "Best Value" case .year: return "Most Popular" case .lifetime: return "Pay once, own forever" } } } /// 获取订阅副标题 /// - Parameters: /// - product: 产品对象 /// - periodType: 持续时间类型 /// - languageCode: 语言代码 /// - Returns: 本地化的副标题 public static func defaultSubtitle(product: Product, periodType: SubscriptionPeriodType, languageCode: String) -> String { let priceDouble = NSDecimalNumber(decimal: product.price).doubleValue let priceString = String(format: "%.2f", priceDouble) let currencySymbol = getCurrencySymbol(from: product) var productUnit = periodType.rawValue if let subscription = product.subscription { productUnit = getLocalizedUnit(languageCode: languageCode, numberOfPeriods: 1, unit: getUnit(from: subscription.subscriptionPeriod)) } // 原价订阅描述:灵活选择、性价比之选、最优惠 let description = defaultSubDescWord(periodType: periodType, languageCode: languageCode) if periodType == .lifetime { // 终身会员只返回描述 return description } else if periodType == .week { return description + "," + buildDefaultSubtitle(languageCode: languageCode, price: priceString, currencySymbol: currencySymbol, productUnit: productUnit) } else if periodType == .month { return description + "," + buildMonthlySubtitle(languageCode: languageCode, price: priceString, currencySymbol: currencySymbol) } else if periodType == .year { return description + "," + buildYearlySubtitle(languageCode: languageCode, price: priceString, currencySymbol: currencySymbol) } return buildDefaultSubtitle(languageCode: languageCode, price: priceString, currencySymbol: currencySymbol, productUnit: productUnit) } /// 获取介绍性优惠副标题 /// - Parameters: /// - product: 产品对象 /// - languageCode: 语言代码 /// - Returns: 本地化的介绍性优惠副标题 public static func introductoryOfferSubtitle(product: Product, languageCode: String) async -> String { guard let subscription = product.subscription, let introductoryOffer = subscription.introductoryOffer else { return "" } let priceDouble = NSDecimalNumber(decimal: product.price).doubleValue let priceString = String(format: "%.2f", priceDouble) let currencySymbol = getCurrencySymbol(from: product) //print("introductoryOfferSubtitle:priceString \(priceString) currencySymbol: \(currencySymbol)") // 获取产品单位 let productUnit = getUnit(from: subscription.subscriptionPeriod) let localizedUnit = getLocalizedUnit(languageCode: languageCode, numberOfPeriods: 1, unit: productUnit) // 获取介绍性优惠价格 let introPrice = introductoryOffer.price let introPriceDouble = NSDecimalNumber(decimal: introPrice).doubleValue let introPriceString = String(format: "%.2f", introPriceDouble) switch introductoryOffer.paymentMode { case .payAsYouGo: // 按需付费:显示折扣价格 let numberOfPeriods = introductoryOffer.periodCount return buildPayAsYouGoText( languageCode: languageCode, introPrice: introPriceString, currencySymbol: currencySymbol, productUnit: localizedUnit, numberOfPeriods: numberOfPeriods ) case .payUpFront: // 预付:显示节省金额和折扣价格 return buildPayUpFrontText( languageCode: languageCode, introPrice: introPriceString, originalPrice: priceString, currencySymbol: currencySymbol, productUnit: localizedUnit ) case .freeTrial: // 免费试用:显示试用期和后续价格 let trialPeriod = introductoryOffer.period let numberOfPeriods = trialPeriod.value let trialUnit = getUnit(from: trialPeriod) let trialLocalizedUnit = getLocalizedUnit(languageCode: languageCode, numberOfPeriods: numberOfPeriods, unit: trialUnit) return buildFreeTrialText( languageCode: languageCode, numberOfPeriods: numberOfPeriods, trialPeriodUnit: trialLocalizedUnit, productUnit: localizedUnit, price: priceString, currencySymbol: currencySymbol ) default: return "" } } /// 获取促销优惠副标题 /// - Parameters: /// - product: 产品对象 /// - languageCode: 语言代码 /// - Returns: 本地化的促销优惠副标题 public static func promotionalOfferSubtitle(product: Product, languageCode: String) async -> String { guard let subscription = product.subscription, let promotionalOffer = subscription.promotionalOffers.first else { return "" } let priceDouble = NSDecimalNumber(decimal: product.price).doubleValue let priceString = String(format: "%.2f", priceDouble) let currencySymbol = getCurrencySymbol(from: product) // 获取产品单位 let productUnit = getUnit(from: subscription.subscriptionPeriod) let localizedUnit = getLocalizedUnit(languageCode: languageCode, numberOfPeriods: 1, unit: productUnit) // 获取促销优惠价格 let discountPrice = promotionalOffer.price let discountPriceDouble = NSDecimalNumber(decimal: discountPrice).doubleValue let discountPriceString = String(format: "%.2f", discountPriceDouble) switch promotionalOffer.paymentMode { case .payAsYouGo: // 按需付费:显示折扣价格 let numberOfPeriods = promotionalOffer.periodCount return buildPayAsYouGoText( languageCode: languageCode, introPrice: discountPriceString, currencySymbol: currencySymbol, productUnit: localizedUnit, numberOfPeriods: numberOfPeriods ) case .payUpFront: // 预付:显示节省金额和折扣价格 return buildPayUpFrontText( languageCode: languageCode, introPrice: discountPriceString, originalPrice: priceString, currencySymbol: currencySymbol, productUnit: localizedUnit ) case .freeTrial: // 免费试用:显示试用期和后续价格 let trialPeriod = promotionalOffer.period let numberOfPeriods = trialPeriod.value let trialUnit = getUnit(from: trialPeriod) let trialLocalizedUnit = getLocalizedUnit(languageCode: languageCode, numberOfPeriods: numberOfPeriods, unit: trialUnit) return buildFreeTrialText( languageCode: languageCode, numberOfPeriods: numberOfPeriods, trialPeriodUnit: trialLocalizedUnit, productUnit: localizedUnit, price: priceString, currencySymbol: currencySymbol ) default: return "" } } // MARK: - 价格格式化辅助方法 /// 构建默认价格显示 /// - Parameters: /// - languageCode: 语言代码 /// - price: 价格字符串 /// - currencySymbol: 货币符号 /// - productUnit: 产品单位(本地化) /// - Returns: 格式化的价格字符串 private static func buildDefaultSubtitle(languageCode: String, price: String, currencySymbol: String, productUnit: String) -> String { switch languageCode { case "ar", "de", "en", "es", "fil", "fr", "id", "it", "ja", "ko", "pl", "pt", "ru", "th", "tr", "uk", "vi": return "\(currencySymbol)\(price)/\(productUnit)" case "zh_Hans": return "每\(productUnit)\(currencySymbol)\(price)元" case "zh_Hant": return "每\(productUnit)\(currencySymbol)\(price)" default: return "\(currencySymbol)\(price)/\(productUnit)" } } /// 构建月订阅价格显示 - 突出性价比 /// - Parameters: /// - languageCode: 语言代码 /// - price: 价格字符串 /// - currencySymbol: 货币符号 /// - Returns: 格式化的价格字符串 private static func buildMonthlySubtitle(languageCode: String, price: String, currencySymbol: String) -> String { let monthlyPrice = Double(price) ?? 0 let weeklyPrice = monthlyPrice / 4.33 let weeklyPriceString = String(format: "%.2f", weeklyPrice) switch languageCode { case "ar": return "\(currencySymbol)\(price)/شهر · ~\(currencySymbol)\(weeklyPriceString)/أسبوع" case "de": return "\(currencySymbol)\(price)/Monat · ~\(currencySymbol)\(weeklyPriceString)/Woche" case "en": return "\(currencySymbol)\(price)/month · ~\(currencySymbol)\(weeklyPriceString)/week" case "es": return "\(currencySymbol)\(price)/mes · ~\(currencySymbol)\(weeklyPriceString)/semana" case "fil": return "\(currencySymbol)\(price)/buwan · ~\(currencySymbol)\(weeklyPriceString)/linggo" case "fr": return "\(currencySymbol)\(price)/mois · ~\(currencySymbol)\(weeklyPriceString)/semaine" case "id": return "\(currencySymbol)\(price)/bulan · ~\(currencySymbol)\(weeklyPriceString)/minggu" case "it": return "\(currencySymbol)\(price)/mese · ~\(currencySymbol)\(weeklyPriceString)/settimana" case "ja": return "\(currencySymbol)\(price)/月 · 約\(currencySymbol)\(weeklyPriceString)/週" case "ko": return "\(currencySymbol)\(price)/월 · 약\(currencySymbol)\(weeklyPriceString)/주" case "pl": return "\(currencySymbol)\(price)/miesiąc · ~\(currencySymbol)\(weeklyPriceString)/tydzień" case "pt": return "\(currencySymbol)\(price)/mês · ~\(currencySymbol)\(weeklyPriceString)/semana" case "ru": return "\(currencySymbol)\(price)/мес · ~\(currencySymbol)\(weeklyPriceString)/нед" case "th": return "\(currencySymbol)\(price)/เดือน · ~\(currencySymbol)\(weeklyPriceString)/สัปดาห์" case "tr": return "\(currencySymbol)\(price)/ay · ~\(currencySymbol)\(weeklyPriceString)/hafta" case "uk": return "\(currencySymbol)\(price)/міс · ~\(currencySymbol)\(weeklyPriceString)/тиж" case "vi": return "\(currencySymbol)\(price)/tháng · ~\(currencySymbol)\(weeklyPriceString)/tuần" case "zh_Hans": return "每月\(currencySymbol)\(price)元 · 约\(currencySymbol)\(weeklyPriceString)元/周" case "zh_Hant": return "每月\(currencySymbol)\(price) · 約\(currencySymbol)\(weeklyPriceString)/周" default: return "\(currencySymbol)\(price)/month · ~\(currencySymbol)\(weeklyPriceString)/week" } } /// 构建年订阅价格显示 - 突出最大优惠 /// - Parameters: /// - languageCode: 语言代码 /// - price: 价格字符串 /// - currencySymbol: 货币符号 /// - Returns: 格式化的价格字符串 private static func buildYearlySubtitle(languageCode: String, price: String, currencySymbol: String) -> String { let yearlyPrice = Double(price) ?? 0 let weeklyPrice = yearlyPrice / 52 let weeklyPriceString = String(format: "%.2f", weeklyPrice) switch languageCode { case "ar": return "\(currencySymbol)\(price)/سنة · فقط \(currencySymbol)\(weeklyPriceString)/أسبوع" case "de": return "\(currencySymbol)\(price)/Jahr · nur \(currencySymbol)\(weeklyPriceString)/Woche" case "en": return "\(currencySymbol)\(price)/year · only \(currencySymbol)\(weeklyPriceString)/week" case "es": return "\(currencySymbol)\(price)/año · solo \(currencySymbol)\(weeklyPriceString)/semana" case "fil": return "\(currencySymbol)\(price)/taon · \(currencySymbol)\(weeklyPriceString)/linggo lang" case "fr": return "\(currencySymbol)\(price)/an · seulement \(currencySymbol)\(weeklyPriceString)/semaine" case "id": return "\(currencySymbol)\(price)/tahun · hanya \(currencySymbol)\(weeklyPriceString)/minggu" case "it": return "\(currencySymbol)\(price)/anno · solo \(currencySymbol)\(weeklyPriceString)/settimana" case "ja": return "\(currencySymbol)\(price)/年 · わずか\(currencySymbol)\(weeklyPriceString)/週" case "ko": return "\(currencySymbol)\(price)/년 · 단\(currencySymbol)\(weeklyPriceString)/주" case "pl": return "\(currencySymbol)\(price)/rok · tylko \(currencySymbol)\(weeklyPriceString)/tydzień" case "pt": return "\(currencySymbol)\(price)/ano · apenas \(currencySymbol)\(weeklyPriceString)/semana" case "ru": return "\(currencySymbol)\(price)/год · всего \(currencySymbol)\(weeklyPriceString)/нед" case "th": return "\(currencySymbol)\(price)/ปี · เพียง \(currencySymbol)\(weeklyPriceString)/สัปดาห์" case "tr": return "\(currencySymbol)\(price)/yıl · sadece \(currencySymbol)\(weeklyPriceString)/hafta" case "uk": return "\(currencySymbol)\(price)/рік · ~\(currencySymbol)\(weeklyPriceString)/тиж" case "vi": return "\(currencySymbol)\(price)/năm · chỉ \(currencySymbol)\(weeklyPriceString)/tuần" case "zh_Hans": return "每年\(currencySymbol)\(price)元 · 仅\(currencySymbol)\(weeklyPriceString)元/周" case "zh_Hant": return "每年\(currencySymbol)\(price) · 僅\(currencySymbol)\(weeklyPriceString)/周" default: return "\(currencySymbol)\(price)/year · only \(currencySymbol)\(weeklyPriceString)/week" } } // MARK: - 优惠相关副标题 /// 构建按需付费文本 /// - Parameters: /// - languageCode: 语言代码 /// - introPrice: 优惠价格字符串 /// - currencySymbol: 货币符号 /// - productUnit: 产品单位(本地化) /// - numberOfPeriods: 周期数量 /// - Returns: 格式化的按需付费文本 private static func buildPayAsYouGoText(languageCode: String, introPrice: String, currencySymbol: String, productUnit: String, numberOfPeriods: Int) -> String { switch languageCode { case "ar": if numberOfPeriods == 1 { return "عرض خاص: \(currencySymbol)\(introPrice)/\(productUnit) (الأسبوع الأول)" } else { return "عرض خاص: \(currencySymbol)\(introPrice)/\(productUnit) (الأسبوعين الأولين)" } case "de": if numberOfPeriods == 1 { return "Sonderangebot: \(currencySymbol)\(introPrice)/\(productUnit) (erste Woche)" } else { return "Sonderangebot: \(currencySymbol)\(introPrice)/\(productUnit) (erste \(numberOfPeriods) Wochen)" } case "en": if numberOfPeriods == 1 { return "Special offer: \(currencySymbol)\(introPrice)/\(productUnit) (first \(productUnit))" } else { return "Special offer: \(currencySymbol)\(introPrice)/\(productUnit) (first \(numberOfPeriods) \(productUnit)s)" } case "es": if numberOfPeriods == 1 { return "Oferta especial: \(currencySymbol)\(introPrice)/\(productUnit) (primer \(productUnit))" } else { return "Oferta especial: \(currencySymbol)\(introPrice)/\(productUnit) (primeros \(numberOfPeriods) \(productUnit)s)" } case "fil": if numberOfPeriods == 1 { return "Espesyal na alok: \(currencySymbol)\(introPrice)/\(productUnit) (unang \(productUnit))" } else { return "Espesyal na alok: \(currencySymbol)\(introPrice)/\(productUnit) (unang \(numberOfPeriods) \(productUnit)s)" } case "fr": if numberOfPeriods == 1 { return "Offre spéciale: \(currencySymbol)\(introPrice)/\(productUnit) (premier \(productUnit))" } else { return "Offre spéciale: \(currencySymbol)\(introPrice)/\(productUnit) (premiers \(numberOfPeriods) \(productUnit)s)" } case "id": if numberOfPeriods == 1 { return "Penawaran khusus: \(currencySymbol)\(introPrice)/\(productUnit) (\(productUnit) pertama)" } else { return "Penawaran khusus: \(currencySymbol)\(introPrice)/\(productUnit) (\(numberOfPeriods) \(productUnit) pertama)" } case "it": if numberOfPeriods == 1 { return "Offerta speciale: \(currencySymbol)\(introPrice)/\(productUnit) (primo \(productUnit))" } else { return "Offerta speciale: \(currencySymbol)\(introPrice)/\(productUnit) (primi \(numberOfPeriods) \(productUnit)s)" } case "ja": if numberOfPeriods == 1 { return "特別価格: \(currencySymbol)\(introPrice)/\(productUnit) (初回\(productUnit))" } else { return "特別価格: \(currencySymbol)\(introPrice)/\(productUnit) (初回\(numberOfPeriods)\(productUnit))" } case "ko": if numberOfPeriods == 1 { return "특별 할인: \(currencySymbol)\(introPrice)/\(productUnit) (첫 \(productUnit))" } else { return "특별 할인: \(currencySymbol)\(introPrice)/\(productUnit) (첫 \(numberOfPeriods)\(productUnit))" } case "pl": if numberOfPeriods == 1 { return "Oferta specjalna: \(currencySymbol)\(introPrice)/\(productUnit) (pierwszy \(productUnit))" } else { return "Oferta specjalna: \(currencySymbol)\(introPrice)/\(productUnit) (pierwsze \(numberOfPeriods) \(productUnit)s)" } case "pt": if numberOfPeriods == 1 { return "Oferta especial: \(currencySymbol)\(introPrice)/\(productUnit) (primeiro \(productUnit))" } else { return "Oferta especial: \(currencySymbol)\(introPrice)/\(productUnit) (primeiros \(numberOfPeriods) \(productUnit)s)" } case "ru": if numberOfPeriods == 1 { return "Специальное предложение: \(currencySymbol)\(introPrice)/\(productUnit) (первый \(productUnit))" } else { return "Специальное предложение: \(currencySymbol)\(introPrice)/\(productUnit) (первые \(numberOfPeriods) \(productUnit)s)" } case "th": if numberOfPeriods == 1 { return "ข้อเสนอพิเศษ: \(currencySymbol)\(introPrice)/\(productUnit) (\(productUnit)แรก)" } else { return "ข้อเสนอพิเศษ: \(currencySymbol)\(introPrice)/\(productUnit) (\(numberOfPeriods) \(productUnit)แรก)" } case "tr": if numberOfPeriods == 1 { return "Özel teklif: \(currencySymbol)\(introPrice)/\(productUnit) (ilk \(productUnit))" } else { return "Özel teklif: \(currencySymbol)\(introPrice)/\(productUnit) (ilk \(numberOfPeriods) \(productUnit))" } case "uk": if numberOfPeriods == 1 { return "Спеціальна пропозиція: \(currencySymbol)\(introPrice)/\(productUnit) (перший \(productUnit))" } else { return "Спеціальна пропозиція: \(currencySymbol)\(introPrice)/\(productUnit) (перші \(numberOfPeriods) \(productUnit)s)" } case "vi": if numberOfPeriods == 1 { return "Ưu đãi đặc biệt: \(currencySymbol)\(introPrice)/\(productUnit) (\(productUnit) đầu tiên)" } else { return "Ưu đãi đặc biệt: \(currencySymbol)\(introPrice)/\(productUnit) (\(numberOfPeriods) \(productUnit) đầu tiên)" } case "zh_Hans": if numberOfPeriods == 1 { return "限时优惠: 每\(productUnit)\(currencySymbol)\(introPrice)元(首\(productUnit))" } else { return "限时优惠: 每\(productUnit)\(currencySymbol)\(introPrice)元(前\(numberOfPeriods)\(productUnit))" } case "zh_Hant": if numberOfPeriods == 1 { return "限時優惠: 每\(productUnit)\(currencySymbol)\(introPrice)(首\(productUnit))" } else { return "限時優惠: 每\(productUnit)\(currencySymbol)\(introPrice)(前\(numberOfPeriods)\(productUnit))" } default: if numberOfPeriods == 1 { return "Special offer: \(currencySymbol)\(introPrice)/\(productUnit) (first \(productUnit))" } else { return "Special offer: \(currencySymbol)\(introPrice)/\(productUnit) (first \(numberOfPeriods) \(productUnit)s)" } } } /// 构建预付文本 /// - Parameters: /// - languageCode: 语言代码 /// - introPrice: 优惠价格字符串 /// - originalPrice: 原价字符串 /// - currencySymbol: 货币符号 /// - productUnit: 产品单位(本地化) /// - Returns: 格式化的预付文本 private static func buildPayUpFrontText(languageCode: String, introPrice: String, originalPrice: String, currencySymbol: String, productUnit: String) -> String { // 计算折扣百分比 let original = Double(originalPrice) ?? 0 let discounted = Double(introPrice) ?? 0 let discountPercent = original > 0 ? Int(((original - discounted) / original * 100).rounded()) : 0 switch languageCode { case "ar": return "وفر \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "de": return "Spare \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "en": return "Save \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "es": return "Ahorra \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "fil": return "Makatipid ng \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "fr": return "Économisez \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "id": return "Hemat \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "it": return "Risparmia \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "ja": return "\(discountPercent)%OFF: \(currencySymbol)\(introPrice)/\(productUnit)" case "ko": return "\(discountPercent)% 할인: \(currencySymbol)\(introPrice)/\(productUnit)" case "pl": return "Zaoszczędź \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "pt": return "Economize \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "ru": return "Экономия \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "th": return "ประหยัด \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "tr": return "%\(discountPercent) tasarruf: \(currencySymbol)\(introPrice)/\(productUnit)" case "uk": return "Економія \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "vi": return "Tiết kiệm \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" case "zh_Hans": return "节省\(discountPercent)%: 每\(productUnit)\(currencySymbol)\(introPrice)元" case "zh_Hant": return "節省\(discountPercent)%: 每\(productUnit)\(currencySymbol)\(introPrice)" default: return "Save \(discountPercent)%: \(currencySymbol)\(introPrice)/\(productUnit)" } } /// 构建免费试用文本 /// - Parameters: /// - languageCode: 语言代码 /// - numberOfPeriods: 试用周期数量 /// - trialPeriodUnit: 试用周期单位(本地化) /// - productUnit: 产品单位(本地化) /// - price: 后续价格字符串 /// - currencySymbol: 货币符号 /// - Returns: 格式化的免费试用文本 private static func buildFreeTrialText(languageCode: String, numberOfPeriods: Int, trialPeriodUnit: String, productUnit: String, price: String, currencySymbol: String) -> String { switch languageCode { case "ar": return "تجربة مجانية \(numberOfPeriods) \(trialPeriodUnit)، ثم \(currencySymbol)\(price)/\(productUnit)" case "de": return "\(numberOfPeriods)-\(trialPeriodUnit)ige kostenlose Testphase, dann \(currencySymbol)\(price)/\(productUnit)" case "en": return "Free trial \(numberOfPeriods) \(trialPeriodUnit), then \(currencySymbol)\(price)/\(productUnit)" case "es": return "Prueba gratuita \(numberOfPeriods) \(trialPeriodUnit), luego \(currencySymbol)\(price)/\(productUnit)" case "fil": return "Libreng pagsubok \(numberOfPeriods) \(trialPeriodUnit), pagkatapos \(currencySymbol)\(price)/\(productUnit)" case "fr": return "Essai gratuit \(numberOfPeriods) \(trialPeriodUnit), puis \(currencySymbol)\(price)/\(productUnit)" case "id": return "Coba gratis \(numberOfPeriods) \(trialPeriodUnit), lalu \(currencySymbol)\(price)/\(productUnit)" case "it": return "Prova gratuita \(numberOfPeriods) \(trialPeriodUnit), poi \(currencySymbol)\(price)/\(productUnit)" case "ja": return "\(numberOfPeriods)\(trialPeriodUnit)無料トライアル、その後\(currencySymbol)\(price)/\(productUnit)" case "ko": return "\(numberOfPeriods)\(trialPeriodUnit) 무료 체험, 이후 \(currencySymbol)\(price)/\(productUnit)" case "pl": return "Bezpłatny okres próbny \(numberOfPeriods) \(trialPeriodUnit), następnie \(currencySymbol)\(price)/\(productUnit)" case "pt": return "Teste gratuito \(numberOfPeriods) \(trialPeriodUnit), depois \(currencySymbol)\(price)/\(productUnit)" case "ru": return "Бесплатная пробная версия \(numberOfPeriods) \(trialPeriodUnit), затем \(currencySymbol)\(price)/\(productUnit)" case "th": return "ทดลองใช้ฟรี \(numberOfPeriods) \(trialPeriodUnit) จากนั้น \(currencySymbol)\(price)/\(productUnit)" case "tr": return "\(numberOfPeriods) \(trialPeriodUnit) ücretsiz deneme, sonrasında \(currencySymbol)\(price)/\(productUnit)" case "uk": return "Безкоштовна пробна версія \(numberOfPeriods) \(trialPeriodUnit), потім \(currencySymbol)\(price)/\(productUnit)" case "vi": return "Dùng thử miễn phí \(numberOfPeriods) \(trialPeriodUnit), sau đó \(currencySymbol)\(price)/\(productUnit)" case "zh_Hans": return "免费试用 \(numberOfPeriods) \(trialPeriodUnit),然后每\(productUnit)\(currencySymbol)\(price)元" case "zh_Hant": return "免費試用 \(numberOfPeriods) \(trialPeriodUnit),然後每\(productUnit)\(currencySymbol)\(price)" default: return "Free trial \(numberOfPeriods) \(trialPeriodUnit), then \(currencySymbol)\(price)/\(productUnit)" } } }