Accesibilidad y localización
Una app de nivel dios funciona para todos y en todos los idiomas. VoiceOver, Dynamic Type y catálogos de strings: hazla accesible y global casi gratis.
La diferencia entre una app buena y una excelente muchas veces no se ve: es que una persona ciega puede usarla con VoiceOver, que el texto crece para quien lo necesita, y que se siente nativa en cinco idiomas. SwiftUI te da mucho de esto gratis; el resto, con poco esfuerzo.
- Accesibilidad básica: labels, hints y traits.
- Dynamic Type: texto que se adapta.
- Localizar tu app a varios idiomas.
- Catálogos de strings modernos.
Accesibilidad: SwiftUI ayuda de serie
SwiftUI genera información de accesibilidad automáticamente: un Button("Guardar") ya lo lee VoiceOver. Pero cuando usas iconos o vistas personalizadas, ayúdale con contexto:
Image(systemName: "trash")
.accessibilityLabel("Eliminar") // qué es
.accessibilityHint("Borra la tarea seleccionada") // qué hace
// agrupar elementos como uno solo para VoiceOver
VStack {
Text("Total"); Text("42 €")
}
.accessibilityElement(children: .combine) // se lee "Total, 42 euros"
Es fácil pensar en la accesibilidad como un “por si acaso”, pero millones de personas dependen de VoiceOver, del texto grande y del alto contraste para usar su teléfono. Una app inaccesible sencillamente no existe para ellas. Y lo mejor: SwiftUI hace el 80% del trabajo solo, así que el esfuerzo de cubrir el 20% restante —etiquetar tus iconos, agrupar lo que va junto— es mínimo comparado con el impacto. Probar tu app con VoiceOver activado una vez te abre los ojos a cómo la vive otra gente. Hazlo.
Dynamic Type: texto que respira
Usa los estilos de fuente semánticos (.body, .headline, .title) en vez de tamaños fijos, y tu texto escalará con la preferencia del usuario:
Text("Título").font(.title) // ✅ escala con Dynamic Type
Text("Cuerpo").font(.body)
// Text("X").font(.system(size: 14)) // ❌ tamaño fijo, no se adapta
Alguien con baja visión que sube el tamaño del texto del sistema verá tu app crecer con él, sin que hagas nada más.
Localización: una app, muchos idiomas
Todo texto literal en SwiftUI es, por defecto, una LocalizedStringKey. Eso significa que ya está listo para traducirse:
Text("Bienvenido") // esto ya es una clave localizable
Catálogos de strings
En Xcode moderno, añades un String Catalog (.xcstrings): Xcode recopila automáticamente todos los textos de tu app y te da una tabla para traducir cada uno a cada idioma, con seguimiento de qué falta:
Recolección automática
Xcode extrae todos los Text("…") de tu código al catálogo. No mantienes listas a mano.
Un idioma por columna
Añades idiomas y rellenas las traducciones en una tabla, con estado (pendiente, hecho, revisar).
Plurales y variantes
Maneja “1 mensaje” vs “3 mensajes” correctamente en cada idioma, con sus reglas.
Retrofit de localización a una app terminada es doloroso: textos concatenados a mano, formatos de fecha y número cableados, capturas de pantalla que hay que rehacer. Si desde el inicio usas Text con literales (ya localizables), formateas fechas y números con las APIs del sistema (.formatted()), y evitas construir frases pegando trozos, cuando quieras añadir un idioma será casi solo rellenar el catálogo. La localización barata empieza con buenos hábitos, no con una fase final.
- Añade
.accessibilityLabela un botón de solo icono. - Agrupa un par de textos con
.accessibilityElement(children: .combine). - Activa VoiceOver en el simulador y navega tu app con él.
- Usa fuentes semánticas (
.body,.title) y sube el Dynamic Type para ver el texto crecer. - Añade un String Catalog y una segunda lengua a un proyecto de prueba.