Refactor alerts to use latest API (#320)
This commit is contained in:
parent
de7e574fec
commit
7198150f00
|
@ -16,6 +16,8 @@ private struct ErrorAlert: Identifiable {
|
|||
final class ErrorHandler: ObservableObject {
|
||||
static let shared = ErrorHandler()
|
||||
|
||||
@Published fileprivate var isPresented = false
|
||||
|
||||
@Published fileprivate var currentAlert: ErrorAlert?
|
||||
|
||||
func handle(_ error: Error, title: String? = nil, onDismiss: (() -> Void)? = nil) {
|
||||
|
@ -24,6 +26,7 @@ final class ErrorHandler: ObservableObject {
|
|||
message: AppError(error).localizedDescription,
|
||||
dismissAction: onDismiss
|
||||
)
|
||||
isPresented = true
|
||||
}
|
||||
|
||||
func handle(title: String, message: String, onDismiss: (() -> Void)? = nil) {
|
||||
|
@ -32,6 +35,7 @@ final class ErrorHandler: ObservableObject {
|
|||
message: message,
|
||||
dismissAction: onDismiss
|
||||
)
|
||||
isPresented = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,14 +53,18 @@ struct HandleErrorsByShowingAlertViewModifier: ViewModifier {
|
|||
// other .alert modifiers inside of content would not work anymore
|
||||
.background(
|
||||
EmptyView()
|
||||
.alert(item: $errorHandler.currentAlert) { currentAlert in
|
||||
Alert(
|
||||
title: Text(currentAlert.title ?? Unlocalized.appName),
|
||||
message: Text(currentAlert.message.withTrailingDot),
|
||||
dismissButton: .cancel(Text(L10n.Global.Strings.ok)) {
|
||||
currentAlert.dismissAction?()
|
||||
.alert(
|
||||
errorHandler.currentAlert?.title ?? Unlocalized.appName,
|
||||
isPresented: $errorHandler.isPresented,
|
||||
presenting: errorHandler.currentAlert
|
||||
) { alert in
|
||||
Button(role: .cancel) {
|
||||
alert.dismissAction?()
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.ok)
|
||||
}
|
||||
)
|
||||
} message: { alert in
|
||||
Text(alert.message.withTrailingDot)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -74,8 +74,12 @@ extension AddHostView {
|
|||
}
|
||||
}
|
||||
}
|
||||
}.alert(isPresented: $viewModel.isAskingOverwrite, content: alertOverwriteExistingProfile)
|
||||
.onAppear(perform: requestResourcePermissions)
|
||||
}.alert(
|
||||
L10n.AddProfile.Shared.title,
|
||||
isPresented: $viewModel.isAskingOverwrite,
|
||||
actions: alertOverwriteActions,
|
||||
message: alertOverwriteMessage
|
||||
).onAppear(perform: requestResourcePermissions)
|
||||
.onDisappear(perform: dropResourcePermissions)
|
||||
.navigationTitle(L10n.AddProfile.Shared.title)
|
||||
.themeSecondaryView()
|
||||
|
@ -158,15 +162,21 @@ extension AddHostView {
|
|||
url.stopAccessingSecurityScopedResource()
|
||||
}
|
||||
|
||||
private func alertOverwriteExistingProfile() -> Alert {
|
||||
Alert(
|
||||
title: Text(L10n.AddProfile.Shared.title),
|
||||
message: Text(L10n.AddProfile.Shared.Alerts.Overwrite.message),
|
||||
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) {
|
||||
@ViewBuilder
|
||||
private func alertOverwriteActions() -> some View {
|
||||
Button(role: .destructive) {
|
||||
processProfile(replacingExisting: true)
|
||||
},
|
||||
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel))
|
||||
)
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.ok)
|
||||
}
|
||||
Button(role: .cancel) {
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.cancel)
|
||||
}
|
||||
}
|
||||
|
||||
private func alertOverwriteMessage() -> some View {
|
||||
Text(L10n.AddProfile.Shared.Alerts.Overwrite.message)
|
||||
}
|
||||
|
||||
private func processProfile(replacingExisting: Bool) {
|
||||
|
|
|
@ -77,8 +77,12 @@ extension AddProviderView {
|
|||
} label: {
|
||||
themeSaveButtonLabel()
|
||||
}
|
||||
}.alert(isPresented: $viewModel.isAskingOverwrite, content: alertOverwriteExistingProfile)
|
||||
.navigationTitle(providerMetadata.fullName)
|
||||
}.alert(
|
||||
L10n.AddProfile.Shared.title,
|
||||
isPresented: $viewModel.isAskingOverwrite,
|
||||
actions: alertOverwriteActions,
|
||||
message: alertOverwriteMessage
|
||||
).navigationTitle(providerMetadata.fullName)
|
||||
}
|
||||
|
||||
private var hiddenAccountLink: some View {
|
||||
|
@ -90,15 +94,21 @@ extension AddProviderView {
|
|||
}
|
||||
}
|
||||
|
||||
private func alertOverwriteExistingProfile() -> Alert {
|
||||
return Alert(
|
||||
title: Text(L10n.AddProfile.Shared.title),
|
||||
message: Text(L10n.AddProfile.Shared.Alerts.Overwrite.message),
|
||||
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) {
|
||||
@ViewBuilder
|
||||
private func alertOverwriteActions() -> some View {
|
||||
Button(role: .destructive) {
|
||||
saveProfile(replacingExisting: true)
|
||||
},
|
||||
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel))
|
||||
)
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.ok)
|
||||
}
|
||||
Button(role: .cancel) {
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.cancel)
|
||||
}
|
||||
}
|
||||
|
||||
private func alertOverwriteMessage() -> some View {
|
||||
Text(L10n.AddProfile.Shared.Alerts.Overwrite.message)
|
||||
}
|
||||
|
||||
private func saveProfile(replacingExisting: Bool) {
|
||||
|
|
|
@ -53,6 +53,8 @@ extension DiagnosticsView {
|
|||
|
||||
@State private var isReportingIssue = false
|
||||
|
||||
@State private var isAlertPresented = false
|
||||
|
||||
@State private var alertType: AlertType?
|
||||
|
||||
private let vpnProtocol: VPNProtocolType = .openVPN
|
||||
|
@ -75,17 +77,26 @@ extension DiagnosticsView {
|
|||
issueReporterSection
|
||||
}
|
||||
}.sheet(isPresented: $isReportingIssue, content: reportIssueView)
|
||||
.alert(item: $alertType, content: presentedAlert)
|
||||
.alert(
|
||||
L10n.ReportIssue.Alert.title,
|
||||
isPresented: $isAlertPresented,
|
||||
presenting: alertType,
|
||||
actions: alertActions,
|
||||
message: alertMessage
|
||||
)
|
||||
}
|
||||
|
||||
private func presentedAlert(_ alertType: AlertType) -> Alert {
|
||||
private func alertActions(_ alertType: AlertType) -> some View {
|
||||
Button(role: .cancel) {
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.ok)
|
||||
}
|
||||
}
|
||||
|
||||
private func alertMessage(_ alertType: AlertType) -> some View {
|
||||
switch alertType {
|
||||
case .emailNotConfigured:
|
||||
return Alert(
|
||||
title: Text(L10n.ReportIssue.Alert.title),
|
||||
message: Text(L10n.Global.Messages.emailNotConfigured),
|
||||
dismissButton: .cancel(Text(L10n.Global.Strings.ok))
|
||||
)
|
||||
return Text(L10n.Global.Messages.emailNotConfigured)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +191,7 @@ extension DiagnosticsView.OpenVPNView {
|
|||
}
|
||||
guard URL.open(url) else {
|
||||
alertType = .emailNotConfigured
|
||||
isAlertPresented = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ struct DonateView: View {
|
|||
|
||||
@ObservedObject private var productManager: ProductManager
|
||||
|
||||
@State private var isAlertPresented = false
|
||||
|
||||
@State private var alertType: AlertType?
|
||||
|
||||
@State private var pendingDonationIdentifier: String?
|
||||
|
@ -57,7 +59,13 @@ struct DonateView: View {
|
|||
.disabled(pendingDonationIdentifier != nil)
|
||||
}.themeSecondaryView()
|
||||
.navigationTitle(L10n.Donate.title)
|
||||
.alert(item: $alertType, content: presentedAlert)
|
||||
.alert(
|
||||
L10n.Donate.title,
|
||||
isPresented: $isAlertPresented,
|
||||
presenting: alertType,
|
||||
actions: alertActions,
|
||||
message: alertMessage
|
||||
)
|
||||
|
||||
// reloading
|
||||
.onAppear {
|
||||
|
@ -69,14 +77,20 @@ struct DonateView: View {
|
|||
}.themeAnimation(on: productManager.isRefreshingProducts)
|
||||
}
|
||||
|
||||
private func presentedAlert(_ alertType: AlertType) -> Alert {
|
||||
private func alertActions(_ alertType: AlertType) -> some View {
|
||||
switch alertType {
|
||||
case .thankYou:
|
||||
return Alert(
|
||||
title: Text(L10n.Donate.Alerts.Purchase.Success.title),
|
||||
message: Text(L10n.Donate.Alerts.Purchase.Success.message),
|
||||
dismissButton: .cancel(Text(L10n.Global.Strings.ok))
|
||||
)
|
||||
return Button(role: .cancel) {
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func alertMessage(_ alertType: AlertType) -> some View {
|
||||
switch alertType {
|
||||
case .thankYou:
|
||||
return Text(L10n.Donate.Alerts.Purchase.Success.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,6 +138,7 @@ extension DonateView {
|
|||
case .success(let value):
|
||||
if case .done = value {
|
||||
alertType = .thankYou
|
||||
isAlertPresented = true
|
||||
} else {
|
||||
// cancelled
|
||||
}
|
||||
|
|
|
@ -30,13 +30,16 @@ extension OrganizerView {
|
|||
struct SceneView: View {
|
||||
@Environment(\.scenePhase) private var scenePhase
|
||||
|
||||
@Binding private var isAlertPresented: Bool
|
||||
|
||||
@Binding private var alertType: AlertType?
|
||||
|
||||
@Binding private var didHandleSubreddit: Bool
|
||||
|
||||
@State private var isFirstLaunch = true
|
||||
|
||||
init(alertType: Binding<AlertType?>, didHandleSubreddit: Binding<Bool>) {
|
||||
init(isAlertPresented: Binding<Bool>, alertType: Binding<AlertType?>, didHandleSubreddit: Binding<Bool>) {
|
||||
_isAlertPresented = isAlertPresented
|
||||
_alertType = alertType
|
||||
_didHandleSubreddit = didHandleSubreddit
|
||||
}
|
||||
|
@ -53,6 +56,7 @@ extension OrganizerView {
|
|||
private func onAppear() {
|
||||
guard didHandleSubreddit else {
|
||||
alertType = .subscribeReddit
|
||||
isAlertPresented = true
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ struct OrganizerView: View {
|
|||
|
||||
@State private var modalType: ModalType?
|
||||
|
||||
@State private var isAlertPresented = false
|
||||
|
||||
@State private var alertType: AlertType?
|
||||
|
||||
@State private var isHostFileImporterPresented = false
|
||||
|
@ -81,8 +83,13 @@ struct OrganizerView: View {
|
|||
}
|
||||
}
|
||||
}.sheet(item: $modalType, content: presentedModal)
|
||||
.alert(item: $alertType, content: presentedAlert)
|
||||
.fileImporter(
|
||||
.alert(
|
||||
Unlocalized.appName,
|
||||
isPresented: $isAlertPresented,
|
||||
presenting: alertType,
|
||||
actions: alertActions,
|
||||
message: alertMessage
|
||||
).fileImporter(
|
||||
isPresented: $isHostFileImporterPresented,
|
||||
allowedContentTypes: hostFileTypes,
|
||||
allowsMultipleSelection: false,
|
||||
|
@ -93,6 +100,7 @@ struct OrganizerView: View {
|
|||
|
||||
private var hiddenSceneView: some View {
|
||||
SceneView(
|
||||
isAlertPresented: $isAlertPresented,
|
||||
alertType: $alertType,
|
||||
didHandleSubreddit: $didHandleSubreddit
|
||||
)
|
||||
|
@ -133,26 +141,27 @@ extension OrganizerView {
|
|||
}
|
||||
}
|
||||
|
||||
private func presentedAlert(_ alertType: AlertType) -> Alert {
|
||||
private func alertActions(_ alertType: AlertType) -> some View {
|
||||
switch alertType {
|
||||
case .subscribeReddit:
|
||||
return Alert(
|
||||
title: Text(Unlocalized.Social.reddit),
|
||||
message: Text(L10n.Organizer.Alerts.Reddit.message),
|
||||
primaryButton: .default(Text(L10n.Organizer.Alerts.Reddit.Buttons.subscribe)) {
|
||||
return Group {
|
||||
Button(L10n.Organizer.Alerts.Reddit.Buttons.subscribe) {
|
||||
didHandleSubreddit = true
|
||||
URL.open(redditURL)
|
||||
},
|
||||
secondaryButton: .cancel(Text(L10n.Global.Alerts.Buttons.never)) {
|
||||
}
|
||||
Button(role: .cancel) {
|
||||
didHandleSubreddit = true
|
||||
}
|
||||
)
|
||||
} label: {
|
||||
Text(L10n.Global.Alerts.Buttons.never)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension OrganizerView {
|
||||
private func presentSubscribeReddit() {
|
||||
alertType = .subscribeReddit
|
||||
private func alertMessage(_ alertType: AlertType) -> some View {
|
||||
switch alertType {
|
||||
case .subscribeReddit:
|
||||
return Text(L10n.Organizer.Alerts.Reddit.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import SwiftUI
|
|||
|
||||
extension ProfileView {
|
||||
struct MainMenu: View {
|
||||
enum ActionSheetType: Int, Identifiable {
|
||||
enum AlertType: Int, Identifiable {
|
||||
case uninstallVPN
|
||||
|
||||
case deleteProfile
|
||||
|
@ -52,14 +52,14 @@ extension ProfileView {
|
|||
|
||||
@Binding private var modalType: ModalType?
|
||||
|
||||
@State private var actionSheetType: ActionSheetType?
|
||||
@State private var isAlertPresented = false
|
||||
|
||||
@State private var alertType: AlertType?
|
||||
|
||||
private let uninstallVPNTitle = L10n.Global.Strings.uninstall
|
||||
|
||||
private let deleteProfileTitle = L10n.Global.Strings.delete
|
||||
|
||||
private let cancelTitle = L10n.Global.Strings.cancel
|
||||
|
||||
init(currentProfile: ObservableProfile, modalType: Binding<ModalType?>) {
|
||||
profileManager = .shared
|
||||
vpnManager = .shared
|
||||
|
@ -70,25 +70,13 @@ extension ProfileView {
|
|||
|
||||
var body: some View {
|
||||
mainView
|
||||
.alert(item: $actionSheetType) {
|
||||
switch $0 {
|
||||
case .uninstallVPN:
|
||||
return Alert(
|
||||
title: Text(uninstallVPNTitle),
|
||||
message: Text(L10n.Profile.Alerts.UninstallVpn.message),
|
||||
primaryButton: .destructive(Text(uninstallVPNTitle), action: uninstallVPN),
|
||||
secondaryButton: .cancel(Text(cancelTitle))
|
||||
.alert(
|
||||
Text(Unlocalized.appName),
|
||||
isPresented: $isAlertPresented,
|
||||
presenting: alertType,
|
||||
actions: alertActions,
|
||||
message: alertMessage
|
||||
)
|
||||
|
||||
case .deleteProfile:
|
||||
return Alert(
|
||||
title: Text(deleteProfileTitle),
|
||||
message: Text(L10n.Organizer.Alerts.RemoveProfile.message(header.name)),
|
||||
primaryButton: .destructive(Text(deleteProfileTitle), action: removeProfile),
|
||||
secondaryButton: .cancel(Text(cancelTitle))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var mainView: some View {
|
||||
|
@ -113,9 +101,46 @@ extension ProfileView {
|
|||
}
|
||||
}
|
||||
|
||||
private func alertActions(_ alertType: AlertType) -> some View {
|
||||
switch alertType {
|
||||
case .uninstallVPN:
|
||||
return Group {
|
||||
Button(role: .destructive, action: uninstallVPN) {
|
||||
Text(uninstallVPNTitle)
|
||||
}
|
||||
Button(role: .cancel) {
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.cancel)
|
||||
}
|
||||
}
|
||||
|
||||
case .deleteProfile:
|
||||
return Group {
|
||||
Button(role: .destructive, action: removeProfile) {
|
||||
Text(deleteProfileTitle)
|
||||
}
|
||||
Button(role: .cancel) {
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.cancel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func alertMessage(_ alertType: AlertType) -> some View {
|
||||
switch alertType {
|
||||
case .uninstallVPN:
|
||||
return Text(L10n.Profile.Alerts.UninstallVpn.message)
|
||||
|
||||
case .deleteProfile:
|
||||
return Text(L10n.Organizer.Alerts.RemoveProfile.message(header.name))
|
||||
}
|
||||
}
|
||||
|
||||
private var uninstallVPNButton: some View {
|
||||
Button {
|
||||
actionSheetType = .uninstallVPN
|
||||
alertType = .uninstallVPN
|
||||
isAlertPresented = true
|
||||
} label: {
|
||||
Label(uninstallVPNTitle, systemImage: themeUninstallImage)
|
||||
}
|
||||
|
@ -123,7 +148,8 @@ extension ProfileView {
|
|||
|
||||
private var deleteProfileButton: some View {
|
||||
DestructiveButton {
|
||||
actionSheetType = .deleteProfile
|
||||
alertType = .deleteProfile
|
||||
isAlertPresented = true
|
||||
} label: {
|
||||
Label(deleteProfileTitle, systemImage: themeDeleteImage)
|
||||
}
|
||||
|
|
|
@ -59,18 +59,29 @@ extension ProfileView {
|
|||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: commitRenaming, label: themeSaveButtonLabel)
|
||||
}
|
||||
}.alert(isPresented: $isOverwritingExistingProfile, content: alertOverwriteExistingProfile)
|
||||
}.alert(
|
||||
L10n.Profile.Alerts.Rename.title,
|
||||
isPresented: $isOverwritingExistingProfile,
|
||||
actions: alertOverwriteActions,
|
||||
message: alertOverwriteMessage
|
||||
)
|
||||
}
|
||||
|
||||
private func alertOverwriteExistingProfile() -> Alert {
|
||||
Alert(
|
||||
title: Text(L10n.Profile.Alerts.Rename.title),
|
||||
message: Text(L10n.AddProfile.Shared.Alerts.Overwrite.message),
|
||||
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) {
|
||||
@ViewBuilder
|
||||
private func alertOverwriteActions() -> some View {
|
||||
Button(role: .destructive) {
|
||||
commitRenaming(force: true)
|
||||
},
|
||||
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel))
|
||||
)
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.ok)
|
||||
}
|
||||
Button(role: .cancel) {
|
||||
} label: {
|
||||
Text(L10n.Global.Strings.cancel)
|
||||
}
|
||||
}
|
||||
|
||||
private func alertOverwriteMessage() -> some View {
|
||||
Text(L10n.AddProfile.Shared.Alerts.Overwrite.message)
|
||||
}
|
||||
|
||||
private func loadCurrentName() {
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Wenn du dich erkenntlich zeigen möchtest für meine Arbeit, gibt es hier ein paar Beträge die du direkt spenden kannst.\n\nDu bezahlst pro Spende nur einmal und kannst mehrmals spenden wenn du möchtest.";
|
||||
"donate.items.loading.caption" = "Lade Spenden";
|
||||
"donate.items.purchasing.caption" = "Führe Spende durch";
|
||||
"donate.alerts.purchase.success.title" = "Danke";
|
||||
"donate.alerts.purchase.success.message" = "Das bedeutet mir viel und ich hoffe wirklich dass du die App weiterhin benutzt und unterstützt.";
|
||||
"donate.alerts.purchase.failure.message" = "Konnte Spende nicht durchführen. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Αν είστε χαρούμενη με τη δουλειά μου, εδώ είναι λίγα ποσά που μπορείτε να δώσετε αμέσως.\n\nΘα χρεωθείτε μόνο μία φορά και μπορείτε να δώσετε πολλές φορές.";
|
||||
"donate.items.loading.caption" = "Φόρτωση δωρεών";
|
||||
"donate.items.purchasing.caption" = "Εκτέλεση δωρεάς";
|
||||
"donate.alerts.purchase.success.title" = "Ευχαριστώ";
|
||||
"donate.alerts.purchase.success.message" = "Αυτό σημαίνει πολλά για μένα και πραγματικά ελπίζω να συνεχίσετε να χρησιμοποιείτε και να προωθείτε αυτήν την εφαρμογή.";
|
||||
"donate.alerts.purchase.failure.message" = "Δεν είναι δυνατή η εκτέλεση της δωρεάς. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "If you want to display gratitude for my free work, here are a couple amounts you can donate instantly.\n\nYou will only be charged once per donation, and you can donate multiple times.";
|
||||
"donate.items.loading.caption" = "Loading donations";
|
||||
"donate.items.purchasing.caption" = "Performing donation";
|
||||
"donate.alerts.purchase.success.title" = "Thank you";
|
||||
"donate.alerts.purchase.success.message" = "This means a lot to me and I really hope you keep using and promoting this app.";
|
||||
"donate.alerts.purchase.failure.message" = "Unable to perform the donation. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Si te gusta mi trabajo, aquí puedes colaborar con una donación.\n\nSólo se te cobrará una vez por donación, y puedes donar las veces que quieras.";
|
||||
"donate.items.loading.caption" = "Cargando donaciones";
|
||||
"donate.items.purchasing.caption" = "Efectuando donación";
|
||||
"donate.alerts.purchase.success.title" = "Muchas gracias";
|
||||
"donate.alerts.purchase.success.message" = "Ésto significa mucho para mí y espero sinceramente que sigas usando y promoviendo esta aplicación.";
|
||||
"donate.alerts.purchase.failure.message" = "Imposible completar la donación, por favor vuelve a intentarlo. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Si vous voulez manifester votre gratitude envers mon travail bénévole, voici certains montants pour faire un don instantanément.\n\n Vous n'allez être chargé qu'une seule fois par don et vous pouvez faire un don plus d'une fois.";
|
||||
"donate.items.loading.caption" = "Chargement des dons";
|
||||
"donate.items.purchasing.caption" = "Don en cours";
|
||||
"donate.alerts.purchase.success.title" = "Merci";
|
||||
"donate.alerts.purchase.success.message" = "Ceci signifie beaucoup pour moi et j'espère sincèrement que vous continuerez d'utiliser et de promouvoir cette app.";
|
||||
"donate.alerts.purchase.failure.message" = "Impossible de faire le don. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Se vuoi mostrare gratitudine per il mio lavoro a titolo gratuito, qui trovi varie somme da donare all'istante.\n\nLa donazione ti sarà addebitata solo una volta, e puoi effettuare più donazioni.";
|
||||
"donate.items.loading.caption" = "Caricando donazioni";
|
||||
"donate.items.purchasing.caption" = "Effettuando donazione";
|
||||
"donate.alerts.purchase.success.title" = "Grazie";
|
||||
"donate.alerts.purchase.success.message" = "Questo significa molto per me e spero vivamente che tu continui ad usare e promuovere quest'applicazione.";
|
||||
"donate.alerts.purchase.failure.message" = "Impossibile effettuare la donazione. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Als je dankbaarheid wilt tonen voor mijn gratis werk, zijn hier een paar bedragen die je direct kunt doneren.\n\nHet bedrag wordt slechts één keer per donatie in rekening gebracht en u kunt meerdere keren doneren.";
|
||||
"donate.items.loading.caption" = "Ophalen donaties";
|
||||
"donate.items.purchasing.caption" = "Doneren";
|
||||
"donate.alerts.purchase.success.title" = "Hartelijk dank";
|
||||
"donate.alerts.purchase.success.message" = "Dit betekent veel voor mij en ik hoop echt dat je deze app blijft gebruiken en promoten.";
|
||||
"donate.alerts.purchase.failure.message" = "Donatie mislukt. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Jeśli chcesz docenić moją pracę, poniżej znajdziesz kilka kwot do wyboru dotacji.\n\nTwoje konto zostanie obciążone tylko raz na jedną dotację, możesz wysłać dotację kilka razy.";
|
||||
"donate.items.loading.caption" = "Ładowanie dotacji";
|
||||
"donate.items.purchasing.caption" = "Wykonywanie dotacji";
|
||||
"donate.alerts.purchase.success.title" = "Dziękuję";
|
||||
"donate.alerts.purchase.success.message" = "To dla mnie dużo znaczy, mam nadzięję że będziesz używać aplikacji i przyczynisz się do jej rozpowrzechnienia.";
|
||||
"donate.alerts.purchase.failure.message" = "Nie można dokonać dotacji. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Se você deseja mostrar gratidão pelo meu trabalho, aqui estão alguns valores do qual você pode contribuir.\n\nVocé só será cobrado uma única vez, ou doar mais vezes caso desejar.";
|
||||
"donate.items.loading.caption" = "Carregando doações";
|
||||
"donate.items.purchasing.caption" = "Efetuando doação";
|
||||
"donate.alerts.purchase.success.title" = "Obrigado";
|
||||
"donate.alerts.purchase.success.message" = "Isso significa muito para mim! Espero que você continue usando e promovendo esse aplicativo.";
|
||||
"donate.alerts.purchase.failure.message" = "Não foi possível realizar doação. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Если Вы хотите поблагодарить мою бесплатную работу, здесь есть несколько сумм, которые Вы можете пожертвовать прямо сейчас.\n\nСумма будет списана только один раз, а Вы можете пожертвовать несколько раз.";
|
||||
"donate.items.loading.caption" = "Загружаем пожертвования";
|
||||
"donate.items.purchasing.caption" = "Исполняется";
|
||||
"donate.alerts.purchase.success.title" = "Спасибо";
|
||||
"donate.alerts.purchase.success.message" = "Это значит многое для меня, и, я надеюсь, Вы продолжить использовать и рассказывать об этом приложении.";
|
||||
"donate.alerts.purchase.failure.message" = "Не получается совершить пожертвование. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Om du vill visa tacksamhet för mitt fria arbete, här är några belopp du kan donera direkt. \n\nDu betalas endast en gång per donation, och du kan donera flera gånger. ";
|
||||
"donate.items.loading.caption" = "Laddar donationer";
|
||||
"donate.items.purchasing.caption" = "Performing donation";
|
||||
"donate.alerts.purchase.success.title" = "Tack";
|
||||
"donate.alerts.purchase.success.message" = "Detta betyder mycket för mig och jag hoppas verkligen att du fortsätter att använda och marknadsföra denna app.";
|
||||
"donate.alerts.purchase.failure.message" = "Kan inte göra donationen. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "Якщо ви бажаєте подякувати за мою безкоштовну роботу, тут є декілька сум, які ви можете пожертвувати прямо зараз.\n\nЗ вас буде стягнено плату лише один раз, але ви можете робити пожертви кілька разів.";
|
||||
"donate.items.loading.caption" = "Завантажуємо пожертвування";
|
||||
"donate.items.purchasing.caption" = "Виконується";
|
||||
"donate.alerts.purchase.success.title" = "Дякуємо";
|
||||
"donate.alerts.purchase.success.message" = "Це дуже важливо для мене, і я сподіваюся, що ви й надалі будете користуватися цією програмою та рекламувати її.";
|
||||
"donate.alerts.purchase.failure.message" = "Не вдається здійснити пожертвування. %@";
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@
|
|||
"donate.sections.one_time.footer" = "如果你想对我免费的工作表示感谢,这里是一些你可以捐助的数额。\n\n每次捐助只需要付款一次,你可以捐助多次。";
|
||||
"donate.items.loading.caption" = "加载捐助中";
|
||||
"donate.items.purchasing.caption" = "展示捐助页面中";
|
||||
"donate.alerts.purchase.success.title" = "感谢";
|
||||
"donate.alerts.purchase.success.message" = "这对于我意味着很多,希望你保持使用并使它更好。";
|
||||
"donate.alerts.purchase.failure.message" = "无法展现捐助内容。%@";
|
||||
|
||||
|
|
Loading…
Reference in New Issue