كيف تجعل الأخطاء تتحدث بلغة المستخدم؟
\n\nغالبًا ما يواجه مطورو Swift مشكلة: تم إلقاء خطأ، لكن المستخدم يرى شيئًا مثل Error Domain=MyApp Code=42. هذا صحيح من الناحية الفنية، لكنه عديم الفائدة تمامًا للبشر. على Stack Overflow، جمع سؤال "How to provide a localized description with an Error type in Swift?" آلاف المشاهدات - وليس بدون سبب.
في هذه المقالة، سنشرح كيفية تحويل رموز الأخطاء الجافة إلى رسائل مترجمة ومفهومة. ستتعلم كيفية استخدام بروتوكول LocalizedError، والعمل مع NSError، وإعداد السلاسل النصية بشكل صحيح للغات مختلفة. هل أنت مستعد لجعل تطبيقك أكثر ودية؟ هيا بنا!
لماذا لا يعمل Error فقط؟
\n\nفي Swift، بروتوكول Error هو عقد أدنى. لا يتطلب وصفًا ولا ترجمة. عندما تنشئ خطأك الخاص:
enum NetworkError: Error {\n case timeout\n case serverError(code: Int)\n}\n\n...ستحصل فقط على اسم الحالة. جرب استدعاء localizedDescription:
let error = NetworkError.timeout\nprint(error.localizedDescription) // "The operation couldn’t be completed. (NetworkError error 0.)"\n\nيقوم النظام بإدراج عبارة افتراضية - غير مفيدة وقبيحة. لإعطاء المستخدم رسالة ذات معنى، تحتاج إلى تنفيذ بروتوكول LocalizedError.
تعرف على: بروتوكول LocalizedError
\n\nLocalizedError يوسع Error ويضيف أربع خصائص اختيارية:
- \n
errorDescription- الرسالة الرئيسية للمستخدم \n failureReason- سبب الخطأ (تقني) \n recoverySuggestion- ما يجب على المستخدم فعله \n helpAnchor- رابط للمساعدة (نادر الاستخدام) \n
الأهم هو errorDescription. هذا ما تعرضه مكونات النظام (التنبيهات، SwiftUI).
تنفيذ خطأ مترجم
\n\nدعنا نضيف LocalizedError إلى NetworkError الخاص بنا:
enum NetworkError: LocalizedError {\n case timeout\n case serverError(code: Int)\n case noInternet\n \n var errorDescription: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "الخادم لا يستجيب. تحقق من الاتصال وحاول مرة أخرى.",\n comment: "Timeout error"\n )\n case .serverError(let code):\n let format = NSLocalizedString(\n "خطأ في الخادم: %d. حاول لاحقًا.",\n comment: "Server error with code"\n )\n return String(format: format, code)\n case .noInternet:\n return NSLocalizedString(\n "لا يوجد اتصال بالإنترنت.",\n comment: "No internet error"\n )\n }\n }\n \n var failureReason: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "تم تجاوز مهلة انتظار الرد من الخادم.",\n comment: "Timeout reason"\n )\n case .serverError(let code):\n return NSLocalizedString(\n "الخادم أعاد الكود \\(code).",\n comment: "Server error reason"\n )\n case .noInternet:\n return NSLocalizedString(\n "لا يوجد اتصال إنترنت نشط.",\n comment: "No internet reason"\n )\n }\n }\n \n var recoverySuggestion: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "تحقق من Wi-Fi أو بيانات الجوال وأعد الطلب.",\n comment: "Timeout recovery"\n )\n case .serverError:\n return NSLocalized