¿Cómo hacer que los errores hablen el idioma del usuario?
\n\nLos desarrolladores de Swift a menudo se enfrentan al problema: se lanza un error, pero el usuario ve algo como Error Domain=MyApp Code=42. Esto es técnicamente correcto, pero absolutamente inútil para una persona. En Stack Overflow, la pregunta "How to provide a localized description with an Error type in Swift?" ha acumulado miles de visitas, y no es casualidad.
En este artículo, analizaremos cómo convertir códigos de error secos en mensajes localizados y comprensibles. Aprenderá a usar el protocolo LocalizedError, trabajar con NSError y preparar correctamente las cadenas para diferentes idiomas. ¿Listo para hacer su aplicación más amigable? ¡Vamos allá!
¿Por qué simplemente Error no funciona?
\n\nEn Swift, el protocolo Error es un contrato mínimo. No requiere ni descripción ni localización. Cuando crea su propio error:
enum NetworkError: Error {\n case timeout\n case serverError(code: Int)\n}\n\n...solo obtiene el nombre del caso. Intente llamar a localizedDescription:
let error = NetworkError.timeout\nprint(error.localizedDescription) // "The operation couldn’t be completed. (NetworkError error 0.)"\n\nEl sistema inserta una frase estándar: poco informativa y nada elegante. Para dar al usuario un mensaje significativo, debe implementar el protocolo LocalizedError.
Conozca el protocolo LocalizedError
\n\nLocalizedError extiende Error y agrega cuatro propiedades opcionales:
- \n
errorDescription— mensaje principal para el usuario \n failureReason— causa del error (técnica) \n recoverySuggestion— qué debe hacer el usuario \n helpAnchor— enlace a la ayuda (rara vez se usa) \n
Lo más importante es errorDescription. Es lo que muestran los componentes del sistema (alertas, SwiftUI).
Implementamos un error localizado
\n\nAñadimos LocalizedError a nuestro 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 "El servidor no responde. Verifique la conexión e intente de nuevo.",\n comment: "Timeout error"\n )\n case .serverError(let code):\n let format = NSLocalizedString(\n "Error del servidor: %d. Intente más tarde.",\n comment: "Server error with code"\n )\n return String(format: format, code)\n case .noInternet:\n return NSLocalizedString(\n "No hay conexión a Internet.",\n comment: "No internet error"\n )\n }\n }\n \n var failureReason: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "Se superó el tiempo de espera de respuesta del servidor.",\n comment: "Timeout reason"\n )\n case .serverError(let code):\n return NSLocalizedString(\n "El servidor devolvió el código \\(code).",\n comment: "Server error reason"\n )\n case .noInternet:\n return NSLocalizedString(\n "No hay una conexión a Internet activa.",\n comment: "No internet reason"\n )\n }\n }\n \n var recoverySuggestion: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "Verifique el Wi-Fi o los datos móviles y vuelva a intentar la solicitud.",\n comment: "Timeout recovery"\n )\n case .serverError:\n return NSLocal