¡Atención! Este sitio utiliza cookies.
Si no cambias la configuración de tu navegador, aceptas su uso.

Otra forma de lidiar con los localizables en Swift

Tengo la costumbre —e imagino que tú también— de guardar los números mágicos y las cadenas de texto en constantes, de partida con el fin de evitar equívocos y comprender mejor el código. Sin embargo, a la hora de tratar con las cadenas de texto que se traducen automágicamente en pantalla, no solemos ser tan estrictos. Llamamos a la macro NSLocalizedString con la clave correspondiente, y confiamos en que, si nadie ha tocado los archivos .strings del proyecto, nos devuelva la cadena traducida.

Ahora bien, cuando se renombra una clave o se modifica un texto, no es fácil seguir el rastro de sus cambios por toda la aplicación, básicamente porque estas cadenas están ‘sueltas’ por todas partes.

Como en todo artículo técnico, la solución está al final del todo. De nada.

Dado que no vamos a librarnos de momento de los archivos .strings ni de la macro NSLocalizedString, pensé “qué menos que centralizar en alguna parte toda esta locura”. No solo es que un pequeño cambio me diera mucho trabajo —soy vago—, es que además me es muy poco intuitivo recuperar las cadenas correctas si no es accediendo a los dichosos .strings, organizándolos por prefijos, etc; así que, ¿por qué no crear un único punto de acceso a ellas? Tuve en cuenta que estos archivos no debían ser considerados parte del código de mi proyecto, que están al mismo nivel que una base de datos, las imágenes, y demás recursos de los que no debería ser dependiente.

Partiendo de una base de cadenas extensa, la primera ocurrencia que tuve fue la de crear una clase ‘Strings’ con constantes a todas ellas, de forma que, por lo menos, las cadenas de texto estuvieran en un único sitio y mis clases pasasen a utilizar únicamente las variables dentro ella.

Bien, mucho mejor, pero seguía teniendo ocurrencias de NSLocalizedString por todas partes, así que lo suyo fue crear un método que envolviese a esta macro, con el fin de controlar mejor cómo la clase Strings manejase las traducciones (y evitar que volviera a utilizarla).

De modo que en los controladores de vista comenzaba a quedar un código tal que así:

Algo mejor, la verdad, pero empezaba a aflorarme una pregunta: “¿y si tengo un porrón de strings de estos?, ¿no preferiría meterlos en tablas para evitar prefijarlos?”.

Vale, el nombre de la tabla podría ir en una constante, sí, pero estamos de acuerdo en que esto empieza ya a tener un olor bastante feo con constantes de strings, de tablas…

¿Y cómo replicar las tablas de los .strings en el código? “Sôstáchupao”, dije.

¡Enums!

Me propuse que el código debía tener esta pinta, o no valdría la pena ni que lo intentase.

De esta forma, todas las cadenas quedarían ‘atrapadas’ dentro de la clase Strings, ¡y ya podía separar las diferentes tablas a modo de ‘espacios de nombre’ gracias a los enum!

Solo para asegurarme de que fuera fácil saber a qué tabla hacían referencia estos enum (y para que no quedasen olvidados), creé un protocolo (Localizable) sobre cada uno que les obligase a buscarse las habichuelas: su ‘rawValue’ sería la cadena a traducir y a través de la variable ‘localized’ (la del protocolo) llamarían internamente —cada uno— al método ‘localized()’ en la extensión de ’String’, en donde especificarían, como poco, la tabla de la que había que sacar la cadena traducida.

Resultado

Y uno de los archivos .strings del que hemos estado recuperando cadenas todo el tiempo.

Esta es la solución más limpia a la que he conseguido llegar. Estoy totalmente abierto a críticas o mejoras con el fin de alcanzar una forma más sencilla y más mantenible, así que no dejéis de aporrear el teclado en los comentarios.

Rafa Barberá se animó a desarrollar un playground con algunas muy buenas ideas en su GitHub.

Y por último, una mención especial a Erik Erice y a Diego Freniche, que son los grandes culpables de que haya escrito esto.

Escrito por Miguel Hernández Jaso

Autor del blog. Desarrollador especializado en iOS.

Una respuesta a “Otra forma de lidiar con los localizables en Swift”

  1. protocol Localizable {

    var rawValue: String { get }
    var localized: String { get }

    }

    extension Localizable {
    var localized: String {
    return NSLocalizedString(self.rawValue, comment: “”)
    }
    }

    Así no tienes que implementar el var localized en cada enum 🙂

    Muy chulo el articulo

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Mi Gobierno me obliga a decirle que utilizo 'cookies' en mi página. Si continúa navegando, quiere decir que está conforme con ello.