Internacionalização orientada a protocolo
Essa postagem foi feita utilizando Xcode 9.2 e Swift 4.
Para melhor entendimento desta postagem você deve ter conhecimento sobre:
Programação orientada a protocolo :
- https://www.raywenderlich.com/148448/introducing-protocol-oriented-programming
- https://developer.apple.com/videos/play/wwdc2015/408/
Sumário
Neste post você vai aprender sobre:
- O que é internacionalização?
- Por que internacionalizar?
- Como eu posso internacionalizar?
- Como internacionalizar orientado a protocolo?
O que é internacionalização?
Quando falamos sobre internacionalização ou localização de aplicações estamos nos referindo a possibilidade de adaptar o aplicativo de acordo com o idioma e região do dispositivo do usuário.
Essa adaptação não está restrita apenas a textos, mas também abrange valores como moedas, unidades de medida, datas e imagens. Porém iremos nos limitar a internacionalização de textos do seu aplicativo.
Por que internacionalizar?
Para justificar todo o trabalho envolvido a localizar seu aplicativo para diversas línguas e culturas nós vamos precisar falar de estatísticas de fatia de mercado.
Segundo o site www.statista.com o iOS terminou o ano de 2017 com 9,68% do mercado nacional (https://www.statista.com/statistics/262167/market-share-held-by-mobile-operating-systems-in-brazil/), contando com a continentalidade do nosso país é um número bastante alto de usuários, porém há um público bem maior fora do nosso país, como podemos ver na imagem abaixo.
Temos grandes mercados utilizando o sistema da maçã e com o crescente número de aplicativos para atender as suas demandas não faz sentido o usuário baixar um aplicativo em outra língua para resolver algum problema. Então ao internacionalizar o seu aplicativo você se torna mais competitivo na guerra por downloads da App Store.
Como eu posso internacionalizar?
Existem duas maneiras de internacionalizar seus textos em uma aplicação para iOS. A primeira é através da Storyboard e de xibs e a segunda é programaticamente utilizando Localizable.strings, neste artigo vamos falar apenas da segunda.
Localizable.strings
Neste modo nós devemos criar um arquivo de String com o nome de Localizable. Criando este arquivo nós poderemos colocar uma série de itens usando notação de chave-valor(Ex: “title” = “Título”;), observe que o uso da marcação (;) é necessário para este tipo de arquivo.
Após criar esse arquivo, devemos clicar no arquivo Localizable.strings e adicionar um idioma novo no File Inspector.
Ao clicar no botão note que você irá possuir apenas o idioma base do projeto, deve-se adicionar os novos idiomas desejados. Para acrescentar uma nova lingua selecione o projeto, na secção Localizations clique em + e escolha o novo idioma. Ao fazer isso serão criadas cópias do arquivo de string, onde o trabalho de tradução será feito. Sempre seguindo o modelo “key” = “value”;.
Desta forma para usarmos essa String nós precisamos utilizar uma NSLocalizedString, o construtor recebe uma string chamada key e outra chamada comment. O parâmetro key deve ter equivalência com alguma key string do arquivo Localizable.strings, caso isso aconteça a string construída será a que for usada como valor do arquivo de strings, dependendo do idioma que o dispositivo do usuário está configurado.
Como internacionalizar orientado a protocolo?
A fim de promover reuso e aumentar a segurança na localização do aplicativo iremos utilizar uma abordagem orientada a protocolo.
Iremos trabalhar com dois protocolos, um deles para ser utilizado em conjunto com um enum e o outro em uma controller. Vamos iniciar com o protocolo criado para ser implementado por um enum, porém nada impede deste protocolo seja utilizado em outro contexto.
Pode parecer um pouco complexo, mas vamos explicar cada parte do código.
1 — Um protocolo chamado Localizable que implementa os protocolos CustomStringConvertible e RawRepresentable. Para se adequar ao primeiro é necessário declarar uma variável chamada description, esta variável será usada quando uma instância que implemente esse protocolo precise implicitamente ser convertida em uma string, por exemplo na concatenação/interpolação de strings, realizar um print da instância e em testes. No nosso caso poderemos utilizar o case do enum para realizar uma concatenação. Já o RawRepresentable é um protocolo que permite conversão de tipos para um tipo associado (associatedtype) chamado RawValue, ou seja, o tipo que implementar RawRepresentable pode ser convertido ou construído a partir de algum outro tipo.
2 — Ao fazer uma extensão do protocolo podemos definir um comportamento padrão (default implementation) para quem implementar o protocolo em questão, desta forma diminuímos a quantidade de código que temos que escrever já que todos usarão o que está definido na extensão, potencializando o reuso de código.
Caso seja necessário realizar alguma ação diferente do procedimento padrão é possível que o tipo implemente um comportamento específico para ele. Note que não foi criado nenhum valor padrão para a variável comment, logo quem implementar o protocolo Localizable terá que definir essa propriedade.
Na extensão existe uma cláusula condicional (where) para restringir a implementação padrão apenas para os casos onde o RawValue é do tipo String, ou seja, se o RawValue não obedecer essa limitação imposta através da condicional não será aplicada a implementação padrão.
3 — A declaração padrão da propriedade localizable traz a chamada da função global NSLocalizedString que explicamos no tópico anterior, a key passada é o rawValue (com r minúsculo). O rawValue é o valor convertido para o tipo do associatedtype RawValue. Quando um enum possui RawValue como String o rawValue é o case como texto, exemplo: se o case do enum for title por padrão o rawValue dele é "title".
4 — O description é a variável que será usada quando a instância do tipo que implementa o protocolo CustomStringConvertible é usado para nos dar a flexibilidade de utilizar o case diretamente na concatenação de string sem a necessidade de chamar a propriedade localizable.
ViewController
Para utilizar este método criamos uma controller modelo.
Vamos explicando os pontos:
1 — Podemos usar a String destas duas formas. A segunda forma só é possível por conta da implementação de CustomStringConvertible.
2 — Por conta do associatedtype Strings o protocolo te força a declarar algo com a mesma assinatura, desta forma podemos escrever de forma mais padronizada. Podendo cada controller ter sua própria enum com seus cases de localização. Evitando a criação de uma struct que contém todas as strings do projeto na forma de constantes estáticas, por exemplo.
Conclusão
Esta é uma abordagem diferente para fazer a internacionalização do seu aplicativo, como pontos positivos:
- Uma abordagem fortemente tipada deixando o código mais seguro evitando erro de digitações nas chaves de localização;
- Não possui code smells em relação a Strings;
- O uso de enums fornece o uso do auto-completion do Xcode.
- Cada controller possui as chaves que lhe dizem respeito, facilitando a manutenção do código;
- Podemos facilmente integrar com strings concatenadas mantendo a legibilidade do código, pois não teremos que acrescentar NSLocalizedString durante uma concatenação;
Porém nem tudo são flores e também temos pontos negativos:
- Falta de um controle de acesso eficiente, ou seja, as controllers tem acesso a enum de Strings uma das outras;
Obrigado por sua atenção, espero que as informações desse post tenham ficado claras para você.
O projeto está disponível no github: https://github.com/davicabral/protocol-oriented-localization