Implémentation de l'héritage dans les fichiers de localisation iOS





Salutations, chers hackers!



Aujourd'hui, je souhaite partager une expérience intéressante dans la résolution du problème de localisation. Sous iOS, la localisation est organisée assez commodément du point de vue d'une cible, ou de plusieurs cibles dans lesquelles les clés dans localizable.strings ne sont pas très répétées. Mais tout devient plus compliqué lorsque vous avez une douzaine de cibles, dans lesquelles plus de la moitié des clés sont répétées, mais ont en même temps des significations différentes, et il existe également un ensemble de clés uniques pour une cible particulière.



Pour ceux qui n'ont pas encore rencontré cela, j'expliquerai le problème plus en détail avec un exemple.



Disons que nous avons un grand projet dans lequel 90% du code général et 3 cibles : MyApp1 , MyApp2 , MyApp3 , qui ont un certain nombre d'écrans spécifiques, ainsi que chacun a son propre nom et ses propres textes. Par essence, une cible est une application indépendante. Chacun d'eux doit être traduit en 10 langues. Cependant, nous ne voulons PAS ajouter de clés de localisation telles que app1_localizable_key1 , app2_localizable_key1 , etc. Nous voulons que tout soit beau dans le code et localisé sur une seule ligne



NSLocalizedString(@"localizable_key1", nil)


Sans if et ifdef , de sorte que lors de l'ajout d'une nouvelle cible, nous n'ayons pas à chercher des emplacements avec NSLocalizedString dans le code d'un énorme projet et à y enregistrer de nouvelles clés. Nous voulons également que certaines des clés soient liées à des écrans cibles spécifiques, c'est-à-dire il y avait des clés app2_screen1_key , app3_screen2_key .



Vous pouvez maintenant effectuer les opérations suivantes à l'aide des outils Xcode standard:



  • Copiez la partie commune localizable.strings sur chaque cible, et nous obtiendrons 3 copies de ces fichiers.
  • Ajoutez des clés spécifiques à la cible aux localizable.strings correspondants.


Quels problèmes rencontrons-nous:



  • Il est assez coûteux d'ajouter une nouvelle clé publique à un projet. Le nombre de sièges est égal au nombre de cibles multiplié par le nombre de langues. Dans notre exemple, c'est 30 places.
  • Il y a un risque d'erreur lorsque nous avons ajouté une ligne à 1-2 cibles actuelles avec lesquelles nous travaillons activement, et un an plus tard, ils ont décidé de ressusciter une ou plusieurs cibles. Vous devrez synchroniser manuellement les localisations les unes avec les autres, ou écrire un script pour cela. Et si un peu de négligence a été montré lors de l'ajout ou de la fusion de branches, et que les clés générales sont mélangées avec des clés spécifiques, alors il y aura une vraie quête.
  • Le volume des fichiers de localisation. Ils sont tous en croissance constante, ce qui rend difficile de travailler avec eux et augmente les risques de conflit lors de la fusion de branches.


Ce que je voudrais:



  • Pour conserver toutes les clés publiques dans un fichier séparé.
  • Pour chaque cible, il y avait un fichier dans lequel seules les clés qui lui étaient spécifiques étaient stockées, ainsi que des clés générales avec des valeurs pour cette cible.


Pour notre exemple, avoir un fichier commun localizable.strings avec des chaînes



"shared_localizable_key1" = "MyApp title"
"shared_localizable_key2" = "MyApp description"
"shared_localizable_key3" = "Shared text1"
"shared_localizable_key4" = "Shared text2"


Je voudrais avoir un fichier localizable_app2.strings avec les clés



"shared_localizable_key1" = "MyApp2 another title"
"shared_localizable_key2" = "MyApp2 another description"
"app2_screen1_key" = "Profile screen title"


Ceux. organiser le principe de l'héritage dans les fichiers de localisation .



Malheureusement, Xcode n'est pas fait pour cela, j'ai donc dû réinventer mon propre "vélo", qui ne voulait pas y aller depuis longtemps car Xcode a mis ici et là un rayon dans les roues.



Nous avons un projet avec 18 cibles et 12 langues. Et ce n'est pas une blague, le projet est vraiment grand et il faut tellement de cibles là-bas. Chaque fois que nous devons ajouter une nouvelle clé publique pour la traduction, nous traitons 216 fichiers de localisation. Ça prend beaucoup de temps. Et l'ajout d'une nouvelle cible conduit au fait que vous devez y copier 12 chaînes localisables supplémentaires . En général, à un moment donné, nous avons réalisé qu'il était impossible de vivre plus comme ça et nous avons dû chercher une solution.



Je ne parlerai pas longtemps de toutes les méthodes que j'ai réussi à tester dans le processus, je vais passer directement à la solution de travail.



Donc, nous devions d'abord trouver toutes les clés partagées. Cela peut être fait à l'aide d'un script, je n'entrerai pas dans les détails, c'est une tâche assez triviale.



De plus, lorsque nous recevons un fichier de localisation commun (de base), ou plutôt 12 fichiers physiques, ainsi qu'un ensemble de fichiers pour chaque cible, nous allons sur Xcode, y ajoutons tous les fichiers. Dans le même temps, nous ne joignons de fichiers à aucune cible, c'est-à-dire le volet droit sous l'appartenance cible doit être décoché.







Nous définirons ces marques uniquement pour le fichier, qui sera le résultat du travail du script d'assemblage des fichiers.



Puis le même "vélo" commence:



  • Localization, build_localization.py.
  • Localizable. localizable.strings.
  • Localizable .






Nous en avons juste besoin pour ajouter correctement un lien vers les fichiers du projet, et pour que Xcode les reconnaisse correctement. Sinon, il ne les utilisera pas pour trouver des clés. Par exemple, si vous créez un dossier Localizable avec les fichiers localizable.strings corrects à l' intérieur et que vous l'ajoutez au projet en tant que références de dossier , peu importe ce que Xcode ne comprendra pas que nous lui avons donné des clés de localisation. Par conséquent, prenez le dossier Localizable , faites-le glisser en tant que groupe ( créer un groupe ) et décochez la case Copier les éléments si nécessaire pour l'obtenir comme l'image ci-dessous.







Supprimer le dossier Localizableet ajoutez-le aux exceptions pour la gita. Comme nous n'avons pas besoin du résultat du script dans la gita, il changera pour chaque cible et encombrera les commits.



Nous devons maintenant ajouter le script à la phase de construction. Pour ce faire, dans Build Phases, cliquez sur New Run Script Phase et écrivez notre script avec des paramètres. 




python3 ${SRCROOT}/Localization/build_localization.py -b “${SRCROOT}/BaseLocalization" -s "${SRCROOT}/Target1Localization" -d "${SRCROOT}/Localization/Localizable"


b est le dossier avec la localisation de base, s est la localisation de la cible actuelle, d est le dossier résultat.



Déplacer la nouvelle phase vers le haut, elle ne doit pas être inférieure à la phase Copier les ressources du lot . Ceux. tout d'abord, le script génère des fichiers, et ce n'est qu'ensuite qu'ils sont intégrés au bundle.







Maintenant, il est important de dire à Xcode que lors de l'exécution du script, les fichiers sont modifiés, sinon, lors de la construction, il lancera une erreur indiquant qu'il n'a pas pu trouver les fichiers. De plus, l'erreur ne se produira que sur un assemblage propre et le problème ne sera pas immédiatement clair. Dans la phase de construction, ajoutez tous les fichiers de localisation aux fichiers de sortie







Cela doit être fait pour chaque cible. Le moyen le plus simple de le faire est d'ouvrir le projet avec un éditeur de texte, car Xcode ne pourra pas copier / coller la phase entre les cibles. En conséquence, les paramètres de script -s pour chaque cible seront différents.



Désormais, à chaque build, le script prendra le fichier de localisation de base, reportera les modifications du fichier cible (ajout, écrasement des clés) et générera la localisation dans le dossier Localizable , qu'iOS utilisera pour trouver les clés.



En général, nous avons obtenu ce qui était prévu lors de la mise en œuvre du mécanisme d'héritage:



  • Les clés partagées résident dans un fichier et n'interfèrent pas avec les autres. Le temps de saisie de nouvelles clés a été réduit de 18! temps.
  • Les clés liées à une cible spécifique se trouvent dans le fichier correspondant.
  • La taille du fichier a considérablement diminué. Nous nous sommes débarrassés de l'encombrement des lignes répétitives.
  • Le processus d'ajout d'une nouvelle langue à un projet est également grandement simplifié.
  • Lors de la création d'une nouvelle cible, vous n'avez pas besoin de copier la localisation avec un tas de lignes inutiles. Créez un nouveau fichier appelé localizable.strings et ajoutez uniquement ce qui est nécessaire pour cette cible.
  • Si vous décidez de réactiver l'ancienne cible, vous n'avez rien à faire avec les lignes, tout sera extrait du fichier de base.
  • Le script n'encombre pas le git, le résultat du travail reste localement et peut être supprimé sans douleur.


→ Le script fini peut être pris ici



je ne prétends pas être un script parfait, les pull requests sont les bienvenues.



All Articles