Comment faire parler les erreurs dans la langue de l'utilisateur ?
\n\nLes développeurs Swift sont souvent confrontés à un problème : une erreur est levée, mais l'utilisateur voit quelque chose comme Error Domain=MyApp Code=42. C'est techniquement correct, mais totalement inutile pour un humain. Sur Stack Overflow, la question "How to provide a localized description with an Error type in Swift?" a recueilli des milliers de vues — et ce n'est pas pour rien.
Dans cet article, nous allons voir comment transformer des codes d'erreur arides en messages localisés et compréhensibles. Vous apprendrez à utiliser le protocole LocalizedError, à travailler avec NSError et à préparer correctement les chaînes pour différentes langues. Prêt à rendre votre application plus conviviale ? C'est parti !
Pourquoi un simple Error ne fonctionne-t-il pas ?
\n\nEn Swift, le protocole Error est un contrat minimal. Il n'exige ni description, ni localisation. Lorsque vous créez votre propre erreur :
enum NetworkError: Error {\n case timeout\n case serverError(code: Int)\n}\n\n...vous obtenez uniquement le nom du cas. Essayez d'appeler localizedDescription :
let error = NetworkError.timeout\nprint(error.localizedDescription) // "The operation couldn’t be completed. (NetworkError error 0.)"\n\nLe système insère une phrase standard — peu informative et peu élégante. Pour donner à l'utilisateur un message pertinent, vous devez implémenter le protocole LocalizedError.
Faites connaissance : le protocole LocalizedError
\n\nLocalizedError étend Error et ajoute quatre propriétés optionnelles :
- \n
errorDescription— le message principal pour l'utilisateur \n failureReason— la cause de l'erreur (technique) \n recoverySuggestion— ce que l'utilisateur doit faire \n helpAnchor— un lien vers l'aide (rarement utilisé) \n
Le plus important est errorDescription. C'est lui qui est affiché par les composants système (alertes, SwiftUI).
Implémentons une erreur localisée
\n\nAjoutons LocalizedError à notre 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 "Le serveur ne répond pas. Vérifiez votre connexion et réessayez.",\n comment: "Timeout error"\n )\n case .serverError(let code):\n let format = NSLocalizedString(\n "Erreur serveur : %d. Réessayez plus tard.",\n comment: "Server error with code"\n )\n return String(format: format, code)\n case .noInternet:\n return NSLocalizedString(\n "Pas de connexion Internet.",\n comment: "No internet error"\n )\n }\n }\n \n var failureReason: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "Le délai d'attente de la réponse du serveur a été dépassé.",\n comment: "Timeout reason"\n )\n case .serverError(let code):\n return NSLocalizedString(\n "Le serveur a renvoyé le code \\(code).",\n comment: "Server error reason"\n )\n case .noInternet:\n return NSLocalizedString(\n "Aucune connexion Internet active.",\n comment: "No internet reason"\n )\n }\n }\n \n var recoverySuggestion: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "Vérifiez votre Wi-Fi ou vos données mobiles et réitérez la requête.",\n comment: "Timeout recovery"\n )\n case .serverError:\n return NSLocalized