Просмотр исходного кода

Localize paywall, PDF export, and purchase error alerts.

Route StoreKit and file failures through UserFacingErrorMessage so alert bodies use the app language instead of system descriptions, and drop developer-only subscription recovery text from customer-facing UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 дней назад: 2
Родитель
Сommit
803cfa2142

+ 7 - 15
App for Indeed/Controllers/PremiumPlansWindowController.swift

@@ -1243,7 +1243,7 @@ private final class PremiumPlansViewController: NSViewController {
1243 1243
             }
1244 1244
         } catch {
1245 1245
             await MainActor.run {
1246
-                self.presentPurchaseError(error)
1246
+                self.presentPurchaseError(error, context: .purchase)
1247 1247
             }
1248 1248
         }
1249 1249
     }
@@ -1278,26 +1278,18 @@ private final class PremiumPlansViewController: NSViewController {
1278 1278
             }
1279 1279
         } catch {
1280 1280
             await MainActor.run {
1281
-                self.presentPurchaseError(error)
1281
+                self.presentPurchaseError(error, context: .restore)
1282 1282
             }
1283 1283
         }
1284 1284
     }
1285 1285
 
1286
-    private func presentPurchaseError(_ error: Error) {
1286
+    private func presentPurchaseError(
1287
+        _ error: Error,
1288
+        context: UserFacingErrorMessage.PurchaseContext
1289
+    ) {
1287 1290
         let alert = NSAlert()
1288 1291
         alert.messageText = L("Something went wrong")
1289
-        if let localized = error as? LocalizedError {
1290
-            var parts: [String] = []
1291
-            if let description = localized.errorDescription {
1292
-                parts.append(description)
1293
-            }
1294
-            if let recovery = localized.recoverySuggestion {
1295
-                parts.append(recovery)
1296
-            }
1297
-            alert.informativeText = parts.isEmpty ? error.localizedDescription : parts.joined(separator: "\n\n")
1298
-        } else {
1299
-            alert.informativeText = error.localizedDescription
1300
-        }
1292
+        alert.informativeText = UserFacingErrorMessage.purchaseFailure(error, context: context)
1301 1293
         alert.alertStyle = .warning
1302 1294
         alert.addButton(withTitle: L("OK"))
1303 1295
         if let window = view.window {

+ 144 - 11
App for Indeed/Services/UserFacingErrorMessage.swift

@@ -1,23 +1,156 @@
1 1
 import Foundation
2
+import StoreKit
2 3
 
3
-/// Maps backend and network errors to short, safe copy for the UI.
4
+/// Maps backend, StoreKit, and file errors to short, safe copy for the UI (always via `L()`).
4 5
 enum UserFacingErrorMessage {
6
+    enum PurchaseContext {
7
+        case purchase
8
+        case restore
9
+    }
10
+
5 11
     static func jobSearchFailure(_ error: Error) -> String {
12
+        let ns = error as NSError
13
+        if ns.domain == "OpenAIJobSearchService", ns.code == 1 {
14
+            return L("Job search is unavailable.")
15
+        }
16
+        if let urlError = error as? URLError, urlError.code == .cancelled {
17
+            return L("The search was cancelled. Try again when you're ready.")
18
+        }
19
+        if let message = connectivityFailure(for: error) {
20
+            return message
21
+        }
22
+        return L("Something went wrong while searching. Please try again in a moment.")
23
+    }
24
+
25
+    static func purchaseFailure(_ error: Error, context: PurchaseContext = .purchase) -> String {
26
+        if let subscription = error as? SubscriptionStoreError {
27
+            return subscription.userFacingMessage
28
+        }
29
+        if let storeKit = error as? StoreKitError {
30
+            return message(for: storeKit, context: context)
31
+        }
32
+        if let purchase = error as? Product.PurchaseError {
33
+            return message(for: purchase)
34
+        }
35
+        if let message = connectivityFailure(for: error) {
36
+            return message
37
+        }
38
+        switch context {
39
+        case .purchase:
40
+            return L("We couldn't complete your purchase. Please try again.")
41
+        case .restore:
42
+            return L("We couldn't restore your purchases. Please try again.")
43
+        }
44
+    }
45
+
46
+    static func pdfSaveFailure(_ error: Error) -> String {
47
+        if let cocoa = error as? CocoaError {
48
+            switch cocoa.code {
49
+            case .fileWriteNoPermission:
50
+                return L("We don't have permission to save to that folder. Choose another location or grant access.")
51
+            case .fileWriteVolumeReadOnly:
52
+                return L("This disk is read-only. Choose another folder to save your PDF.")
53
+            case .fileWriteOutOfSpace:
54
+                return L("The disk is full. Free up space, then try again.")
55
+            default:
56
+                break
57
+            }
58
+        }
6 59
         if let urlError = error as? URLError {
7 60
             switch urlError.code {
8
-            case .notConnectedToInternet,
9
-                 .networkConnectionLost,
10
-                 .timedOut,
11
-                 .cannotFindHost,
12
-                 .cannotConnectToHost,
13
-                 .dnsLookupFailed:
14
-                return L("We couldn't reach the server. Check your internet connection and try again.")
15
-            case .cancelled:
16
-                return L("The search was cancelled. Try again when you're ready.")
61
+            case .fileDoesNotExist, .noPermissionsToReadFile:
62
+                return L("We don't have permission to save to that folder. Choose another location or grant access.")
17 63
             default:
18 64
                 break
19 65
             }
20 66
         }
21
-        return L("Something went wrong while searching. Please try again in a moment.")
67
+        let ns = error as NSError
68
+        if ns.domain == NSCocoaErrorDomain,
69
+           ns.code == NSFileWriteOutOfSpaceError || ns.code == NSFileWriteVolumeReadOnlyError {
70
+            if ns.code == NSFileWriteOutOfSpaceError {
71
+                return L("The disk is full. Free up space, then try again.")
72
+            }
73
+            return L("This disk is read-only. Choose another folder to save your PDF.")
74
+        }
75
+        if let message = connectivityFailure(for: error) {
76
+            return message
77
+        }
78
+        return L("We couldn't save the PDF. Try again or choose a different folder.")
79
+    }
80
+
81
+    private static func connectivityFailure(for error: Error) -> String? {
82
+        if let storeKit = error as? StoreKitError,
83
+           case .networkError(let urlError) = storeKit {
84
+            return connectivityFailure(for: urlError)
85
+        }
86
+        if let urlError = error as? URLError {
87
+            return connectivityFailure(for: urlError)
88
+        }
89
+        return nil
90
+    }
91
+
92
+    private static func connectivityFailure(for urlError: URLError) -> String? {
93
+        switch urlError.code {
94
+        case .notConnectedToInternet,
95
+             .networkConnectionLost,
96
+             .timedOut,
97
+             .cannotFindHost,
98
+             .cannotConnectToHost,
99
+             .dnsLookupFailed:
100
+            return L("We couldn't reach the server. Check your internet connection and try again.")
101
+        case .cancelled:
102
+            return L("The request was cancelled. Try again when you're ready.")
103
+        default:
104
+            return nil
105
+        }
106
+    }
107
+
108
+    private static func message(for error: StoreKitError, context: PurchaseContext) -> String {
109
+        switch error {
110
+        case .userCancelled:
111
+            return L("Purchase was cancelled.")
112
+        case .networkError(let urlError):
113
+            return connectivityFailure(for: urlError)
114
+                ?? (context == .restore
115
+                    ? L("We couldn't restore your purchases. Please try again.")
116
+                    : L("We couldn't complete your purchase. Please try again."))
117
+        case .notAvailableInStorefront:
118
+            return L("This subscription isn't available in your App Store region.")
119
+        case .notEntitled:
120
+            return L("The purchase couldn't be verified. Please try again.")
121
+        case .unsupported, .unknown, .systemError:
122
+            return context == .restore
123
+                ? L("We couldn't restore your purchases. Please try again.")
124
+                : L("We couldn't complete your purchase. Please try again.")
125
+        @unknown default:
126
+            return context == .restore
127
+                ? L("We couldn't restore your purchases. Please try again.")
128
+                : L("We couldn't complete your purchase. Please try again.")
129
+        }
130
+    }
131
+
132
+    private static func message(for error: Product.PurchaseError) -> String {
133
+        switch error {
134
+        case .productUnavailable:
135
+            return L("That subscription isn’t available from the App Store right now.")
136
+        case .purchaseNotAllowed:
137
+            return L("Purchases aren't allowed on this account or device.")
138
+        case .ineligibleForOffer:
139
+            return L("This introductory offer isn't available for your account.")
140
+        case .invalidQuantity, .invalidOfferIdentifier, .invalidOfferPrice,
141
+             .invalidOfferSignature, .missingOfferParameters:
142
+            return L("We couldn't complete your purchase. Please try again.")
143
+        @unknown default:
144
+            return L("We couldn't complete your purchase. Please try again.")
145
+        }
146
+    }
147
+}
148
+
149
+private extension SubscriptionStoreError {
150
+    var userFacingMessage: String {
151
+        switch self {
152
+        case .productUnavailable:
153
+            return L("That subscription isn’t available from the App Store right now.")
154
+        }
22 155
     }
23 156
 }

+ 2 - 10
App for Indeed/Subscription/SubscriptionStore.swift

@@ -161,14 +161,6 @@ enum SubscriptionStoreError: LocalizedError {
161 161
         }
162 162
     }
163 163
 
164
-    var recoverySuggestion: String? {
165
-        switch self {
166
-        case .productUnavailable:
167
-            return """
168
-            For local testing in Xcode: Product → Scheme → Edit Scheme → Run → Options → StoreKit Configuration → choose Paywall.storekit.
169
-
170
-            For TestFlight / App Store: In App Store Connect, create auto-renewable subscriptions whose Product IDs exactly match SubscriptionProductIDs.swift (same spelling as com.hwaccount.appforindeed.pro.*), then submit them with the app version.
171
-            """
172
-        }
173
-    }
164
+    /// Developer setup notes belong in docs or console logs—not in customer-facing alerts.
165
+    var recoverySuggestion: String? { nil }
174 166
 }

+ 1 - 1
App for Indeed/Views/CVFilledPreviewPageView.swift

@@ -316,7 +316,7 @@ final class CVFilledPreviewPageView: NSView {
316 316
         do {
317 317
             try data.write(to: url, options: .atomic)
318 318
         } catch {
319
-            presentExportError(error.localizedDescription)
319
+            presentExportError(UserFacingErrorMessage.pdfSaveFailure(error))
320 320
         }
321 321
     }
322 322
 

+ 12 - 0
App for Indeed/ar.lproj/Localizable.strings

@@ -347,8 +347,20 @@
347 347
 // MARK: - الأخطاء
348 348
 "We couldn't reach the server. Check your internet connection and try again." = "لم نتمكن من الوصول إلى الخادم. تحقق من اتصالك بالإنترنت وحاول مرة أخرى.";
349 349
 "The search was cancelled. Try again when you're ready." = "تم إلغاء البحث. حاول مرة أخرى عندما تكون مستعداً.";
350
+"The request was cancelled. Try again when you're ready." = "تم إلغاء الطلب. حاول مرة أخرى عندما تكون مستعداً.";
350 351
 "Something went wrong while searching. Please try again in a moment." = "حدث خطأ ما أثناء البحث. يرجى المحاولة مرة أخرى بعد قليل.";
351 352
 "Job search is unavailable." = "البحث عن الوظائف غير متوفر.";
353
+"We couldn't complete your purchase. Please try again." = "تعذر إكمال عملية الشراء. يرجى المحاولة مرة أخرى.";
354
+"We couldn't restore your purchases. Please try again." = "تعذر استعادة مشترياتك. يرجى المحاولة مرة أخرى.";
355
+"Purchase was cancelled." = "تم إلغاء الشراء.";
356
+"This subscription isn't available in your App Store region." = "هذا الاشتراك غير متوفر في منطقة متجر التطبيقات الخاصة بك.";
357
+"Purchases aren't allowed on this account or device." = "الشراء غير مسموح به على هذا الحساب أو الجهاز.";
358
+"This introductory offer isn't available for your account." = "عرض الترحيب هذا غير متاح لحسابك.";
359
+"The purchase couldn't be verified. Please try again." = "تعذر التحقق من الشراء. يرجى المحاولة مرة أخرى.";
360
+"We couldn't save the PDF. Try again or choose a different folder." = "تعذر حفظ ملف بي دي إف. حاول مرة أخرى أو اختر مجلداً مختلفاً.";
361
+"We don't have permission to save to that folder. Choose another location or grant access." = "ليس لدينا إذن للحفظ في ذلك المجلد. اختر موقعاً آخر أو امنح الوصول.";
362
+"This disk is read-only. Choose another folder to save your PDF." = "هذا القرص للقراءة فقط. اختر مجلداً آخر لحفظ ملف بي دي إف.";
363
+"The disk is full. Free up space, then try again." = "القرص ممتلئ. حرر مساحة ثم حاول مرة أخرى.";
352 364
 
353 365
 // MARK: - التنبيهات
354 366
 "This profile will be removed from this Mac." = "سيتم إزالة هذا الملف الشخصي من جهاز ماك هذا.";

+ 12 - 0
App for Indeed/de.lproj/Localizable.strings

@@ -347,8 +347,20 @@
347 347
 // MARK: - Fehler
348 348
 "We couldn't reach the server. Check your internet connection and try again." = "Wir konnten den Server nicht erreichen. Überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut.";
349 349
 "The search was cancelled. Try again when you're ready." = "Die Suche wurde abgebrochen. Versuchen Sie es erneut, wenn Sie bereit sind.";
350
+"The request was cancelled. Try again when you're ready." = "Die Anfrage wurde abgebrochen. Versuchen Sie es erneut, wenn Sie bereit sind.";
350 351
 "Something went wrong while searching. Please try again in a moment." = "Bei der Suche ist etwas schiefgelaufen. Bitte versuchen Sie es in einem Moment erneut.";
351 352
 "Job search is unavailable." = "Jobsuche ist nicht verfügbar.";
353
+"We couldn't complete your purchase. Please try again." = "Ihr Kauf konnte nicht abgeschlossen werden. Bitte versuchen Sie es erneut.";
354
+"We couldn't restore your purchases. Please try again." = "Ihre Käufe konnten nicht wiederhergestellt werden. Bitte versuchen Sie es erneut.";
355
+"Purchase was cancelled." = "Kauf abgebrochen.";
356
+"This subscription isn't available in your App Store region." = "Dieses Abonnement ist in Ihrer App-Store-Region nicht verfügbar.";
357
+"Purchases aren't allowed on this account or device." = "Käufe sind für dieses Konto oder Gerät nicht erlaubt.";
358
+"This introductory offer isn't available for your account." = "Dieses Einführungsangebot ist für Ihr Konto nicht verfügbar.";
359
+"The purchase couldn't be verified. Please try again." = "Der Kauf konnte nicht verifiziert werden. Bitte versuchen Sie es erneut.";
360
+"We couldn't save the PDF. Try again or choose a different folder." = "PDF konnte nicht gespeichert werden. Versuchen Sie es erneut oder wählen Sie einen anderen Ordner.";
361
+"We don't have permission to save to that folder. Choose another location or grant access." = "Keine Berechtigung zum Speichern in diesem Ordner. Wählen Sie einen anderen Speicherort oder gewähren Sie Zugriff.";
362
+"This disk is read-only. Choose another folder to save your PDF." = "Dieses Laufwerk ist schreibgeschützt. Wählen Sie einen anderen Ordner für Ihr PDF.";
363
+"The disk is full. Free up space, then try again." = "Der Speicher ist voll. Schaffen Sie Speicherplatz und versuchen Sie es erneut.";
352 364
 
353 365
 // MARK: - Benachrichtigungen
354 366
 "This profile will be removed from this Mac." = "Dieses Profil wird von diesem Mac entfernt.";

+ 12 - 0
App for Indeed/en.lproj/Localizable.strings

@@ -325,8 +325,20 @@
325 325
 // MARK: - Errors
326 326
 "We couldn't reach the server. Check your internet connection and try again." = "We couldn't reach the server. Check your internet connection and try again.";
327 327
 "The search was cancelled. Try again when you're ready." = "The search was cancelled. Try again when you're ready.";
328
+"The request was cancelled. Try again when you're ready." = "The request was cancelled. Try again when you're ready.";
328 329
 "Something went wrong while searching. Please try again in a moment." = "Something went wrong while searching. Please try again in a moment.";
329 330
 "Job search is unavailable." = "Job search is unavailable.";
331
+"We couldn't complete your purchase. Please try again." = "We couldn't complete your purchase. Please try again.";
332
+"We couldn't restore your purchases. Please try again." = "We couldn't restore your purchases. Please try again.";
333
+"Purchase was cancelled." = "Purchase was cancelled.";
334
+"This subscription isn't available in your App Store region." = "This subscription isn't available in your App Store region.";
335
+"Purchases aren't allowed on this account or device." = "Purchases aren't allowed on this account or device.";
336
+"This introductory offer isn't available for your account." = "This introductory offer isn't available for your account.";
337
+"The purchase couldn't be verified. Please try again." = "The purchase couldn't be verified. Please try again.";
338
+"We couldn't save the PDF. Try again or choose a different folder." = "We couldn't save the PDF. Try again or choose a different folder.";
339
+"We don't have permission to save to that folder. Choose another location or grant access." = "We don't have permission to save to that folder. Choose another location or grant access.";
340
+"This disk is read-only. Choose another folder to save your PDF." = "This disk is read-only. Choose another folder to save your PDF.";
341
+"The disk is full. Free up space, then try again." = "The disk is full. Free up space, then try again.";
330 342
 
331 343
 // MARK: - Alerts
332 344
 "This profile will be removed from this Mac." = "This profile will be removed from this Mac.";

+ 12 - 0
App for Indeed/fr-CA.lproj/Localizable.strings

@@ -347,8 +347,20 @@
347 347
 // MARK: - Erreurs
348 348
 "We couldn't reach the server. Check your internet connection and try again." = "Nous ne pouvons pas joindre le serveur. Vérifiez votre connexion Internet et réessayez.";
349 349
 "The search was cancelled. Try again when you're ready." = "La recherche a été annulée. Réessayez quand vous êtes prêt.";
350
+"The request was cancelled. Try again when you're ready." = "La requête a été annulée. Réessayez quand vous êtes prêt.";
350 351
 "Something went wrong while searching. Please try again in a moment." = "Une erreur s'est produite lors de la recherche. Veuillez réessayer dans un instant.";
351 352
 "Job search is unavailable." = "La recherche d'emploi n'est pas disponible.";
353
+"We couldn't complete your purchase. Please try again." = "Nous n'avons pas pu finaliser votre achat. Veuillez réessayer.";
354
+"We couldn't restore your purchases. Please try again." = "Nous n'avons pas pu restaurer vos achats. Veuillez réessayer.";
355
+"Purchase was cancelled." = "Achat annulé.";
356
+"This subscription isn't available in your App Store region." = "Cet abonnement n'est pas disponible dans votre région de l'App Store.";
357
+"Purchases aren't allowed on this account or device." = "Les achats ne sont pas autorisés sur ce compte ou cet appareil.";
358
+"This introductory offer isn't available for your account." = "Cette offre d'introduction n'est pas disponible pour votre compte.";
359
+"The purchase couldn't be verified. Please try again." = "L'achat n'a pas pu être vérifié. Veuillez réessayer.";
360
+"We couldn't save the PDF. Try again or choose a different folder." = "Impossible d'enregistrer le PDF. Réessayez ou choisissez un autre dossier.";
361
+"We don't have permission to save to that folder. Choose another location or grant access." = "Nous n'avons pas l'autorisation d'enregistrer dans ce dossier. Choisissez un autre emplacement ou accordez l'accès.";
362
+"This disk is read-only. Choose another folder to save your PDF." = "Ce disque est en lecture seule. Choisissez un autre dossier pour enregistrer votre PDF.";
363
+"The disk is full. Free up space, then try again." = "Le disque est plein. Libérez de l'espace, puis réessayez.";
352 364
 
353 365
 // MARK: - Alertes
354 366
 "This profile will be removed from this Mac." = "Ce profil sera supprimé de ce Mac.";

+ 12 - 0
App for Indeed/fr.lproj/Localizable.strings

@@ -347,8 +347,20 @@
347 347
 // MARK: - Erreurs
348 348
 "We couldn't reach the server. Check your internet connection and try again." = "Nous ne pouvons pas joindre le serveur. Vérifiez votre connexion Internet et réessayez.";
349 349
 "The search was cancelled. Try again when you're ready." = "La recherche a été annulée. Réessayez quand vous êtes prêt.";
350
+"The request was cancelled. Try again when you're ready." = "La requête a été annulée. Réessayez quand vous êtes prêt.";
350 351
 "Something went wrong while searching. Please try again in a moment." = "Une erreur s'est produite lors de la recherche. Veuillez réessayer dans un instant.";
351 352
 "Job search is unavailable." = "La recherche d'emploi n'est pas disponible.";
353
+"We couldn't complete your purchase. Please try again." = "Nous n'avons pas pu finaliser votre achat. Veuillez réessayer.";
354
+"We couldn't restore your purchases. Please try again." = "Nous n'avons pas pu restaurer vos achats. Veuillez réessayer.";
355
+"Purchase was cancelled." = "Achat annulé.";
356
+"This subscription isn't available in your App Store region." = "Cet abonnement n'est pas disponible dans votre région de l'App Store.";
357
+"Purchases aren't allowed on this account or device." = "Les achats ne sont pas autorisés sur ce compte ou cet appareil.";
358
+"This introductory offer isn't available for your account." = "Cette offre d'introduction n'est pas disponible pour votre compte.";
359
+"The purchase couldn't be verified. Please try again." = "L'achat n'a pas pu être vérifié. Veuillez réessayer.";
360
+"We couldn't save the PDF. Try again or choose a different folder." = "Impossible d'enregistrer le PDF. Réessayez ou choisissez un autre dossier.";
361
+"We don't have permission to save to that folder. Choose another location or grant access." = "Nous n'avons pas l'autorisation d'enregistrer dans ce dossier. Choisissez un autre emplacement ou accordez l'accès.";
362
+"This disk is read-only. Choose another folder to save your PDF." = "Ce disque est en lecture seule. Choisissez un autre dossier pour enregistrer votre PDF.";
363
+"The disk is full. Free up space, then try again." = "Le disque est plein. Libérez de l'espace, puis réessayez.";
352 364
 
353 365
 // MARK: - Alertes
354 366
 "This profile will be removed from this Mac." = "Ce profil sera supprimé de ce Mac.";

+ 12 - 0
App for Indeed/sv.lproj/Localizable.strings

@@ -347,8 +347,20 @@
347 347
 // MARK: - Fel
348 348
 "We couldn't reach the server. Check your internet connection and try again." = "Vi kunde inte nå servern. Kontrollera din internetanslutning och försök igen.";
349 349
 "The search was cancelled. Try again when you're ready." = "Sökningen avbröts. Försök igen när du är redo.";
350
+"The request was cancelled. Try again when you're ready." = "Begäran avbröts. Försök igen när du är redo.";
350 351
 "Something went wrong while searching. Please try again in a moment." = "Något gick fel under sökningen. Försök igen om en stund.";
351 352
 "Job search is unavailable." = "Jobbsökning är inte tillgänglig.";
353
+"We couldn't complete your purchase. Please try again." = "Vi kunde inte slutföra ditt köp. Försök igen.";
354
+"We couldn't restore your purchases. Please try again." = "Vi kunde inte återställa dina köp. Försök igen.";
355
+"Purchase was cancelled." = "Köpet avbröts.";
356
+"This subscription isn't available in your App Store region." = "Den här prenumerationen är inte tillgänglig i din App Store-region.";
357
+"Purchases aren't allowed on this account or device." = "Köp är inte tillåtna på det här kontot eller enheten.";
358
+"This introductory offer isn't available for your account." = "Det här introduktionserbjudandet är inte tillgängligt för ditt konto.";
359
+"The purchase couldn't be verified. Please try again." = "Köpet kunde inte verifieras. Försök igen.";
360
+"We couldn't save the PDF. Try again or choose a different folder." = "Vi kunde inte spara PDF-filen. Försök igen eller välj en annan mapp.";
361
+"We don't have permission to save to that folder. Choose another location or grant access." = "Vi har inte behörighet att spara i den mappen. Välj en annan plats eller bevilja åtkomst.";
362
+"This disk is read-only. Choose another folder to save your PDF." = "Disken är skrivskyddad. Välj en annan mapp för din PDF.";
363
+"The disk is full. Free up space, then try again." = "Disken är full. Frigör utrymme och försök igen.";
352 364
 
353 365
 // MARK: - Aviseringar
354 366
 "This profile will be removed from this Mac." = "Den här profilen kommer att tas bort från den här Mac-datorn.";

+ 12 - 0
App for Indeed/zh-Hans.lproj/Localizable.strings

@@ -348,8 +348,20 @@
348 348
 // MARK: - 错误
349 349
 "We couldn't reach the server. Check your internet connection and try again." = "无法连接服务器。请检查您的网络连接后重试。";
350 350
 "The search was cancelled. Try again when you're ready." = "搜索已取消。准备就绪后请重试。";
351
+"The request was cancelled. Try again when you're ready." = "请求已取消。准备就绪后请重试。";
351 352
 "Something went wrong while searching. Please try again in a moment." = "搜索时出错。请稍后再试。";
352 353
 "Job search is unavailable." = "工作搜索不可用。";
354
+"We couldn't complete your purchase. Please try again." = "无法完成购买。请重试。";
355
+"We couldn't restore your purchases. Please try again." = "无法恢复购买。请重试。";
356
+"Purchase was cancelled." = "购买已取消。";
357
+"This subscription isn't available in your App Store region." = "此订阅在您的 App Store 地区不可用。";
358
+"Purchases aren't allowed on this account or device." = "此账户或设备不允许购买。";
359
+"This introductory offer isn't available for your account." = "此介绍性优惠不适用于您的账户。";
360
+"The purchase couldn't be verified. Please try again." = "无法验证购买。请重试。";
361
+"We couldn't save the PDF. Try again or choose a different folder." = "无法保存 PDF。请重试或选择其他文件夹。";
362
+"We don't have permission to save to that folder. Choose another location or grant access." = "无权保存到该文件夹。请选择其他位置或授予访问权限。";
363
+"This disk is read-only. Choose another folder to save your PDF." = "此磁盘为只读。请选择其他文件夹保存 PDF。";
364
+"The disk is full. Free up space, then try again." = "磁盘已满。请释放空间后重试。";
353 365
 
354 366
 // MARK: - 提示
355 367
 "This profile will be removed from this Mac." = "此个人资料将从这台 Mac 上移除。";

+ 12 - 0
App for Indeed/zh-Hant.lproj/Localizable.strings

@@ -347,8 +347,20 @@
347 347
 // MARK: - 錯誤
348 348
 "We couldn't reach the server. Check your internet connection and try again." = "無法連線到伺服器。請檢查您的網路連線後再試一次。";
349 349
 "The search was cancelled. Try again when you're ready." = "搜尋已取消。準備就緒後請再試一次。";
350
+"The request was cancelled. Try again when you're ready." = "請求已取消。準備就緒後請再試一次。";
350 351
 "Something went wrong while searching. Please try again in a moment." = "搜尋時發生錯誤。請稍後再試。";
351 352
 "Job search is unavailable." = "工作搜尋無法使用。";
353
+"We couldn't complete your purchase. Please try again." = "無法完成購買。請再試一次。";
354
+"We couldn't restore your purchases. Please try again." = "無法回復購買。請再試一次。";
355
+"Purchase was cancelled." = "購買已取消。";
356
+"This subscription isn't available in your App Store region." = "此訂閱在您的 App Store 地區不可用。";
357
+"Purchases aren't allowed on this account or device." = "此帳號或裝置不允許購買。";
358
+"This introductory offer isn't available for your account." = "此介紹性優惠不適用於您的帳號。";
359
+"The purchase couldn't be verified. Please try again." = "無法驗證購買。請再試一次。";
360
+"We couldn't save the PDF. Try again or choose a different folder." = "無法儲存 PDF。請再試一次或選擇其他資料夾。";
361
+"We don't have permission to save to that folder. Choose another location or grant access." = "沒有權限儲存到該資料夾。請選擇其他位置或授予存取權限。";
362
+"This disk is read-only. Choose another folder to save your PDF." = "此磁碟為唯讀。請選擇其他資料夾儲存 PDF。";
363
+"The disk is full. Free up space, then try again." = "磁碟已滿。請釋出空間後再試一次。";
352 364
 
353 365
 // MARK: - 提示
354 366
 "This profile will be removed from this Mac." = "此個人資料將從這台 Mac 上移除。";