structContentView:View{varbody:someView{letcolors=[Color.red,Color.yellow,Color.blue,Color.green,Color.orange,Color.black,Color.pink,Color.purple]letcolumns=[GridItem(.flexible()),GridItem(.flexible()),]returnScrollView{LazyVGrid(columns:columns){ForEach(colors,id:\.self){colorinZStack{Rectangle().fill(color).padding().frame(height:200)CutOutText(text:"This is a demo")}}}}}}
This approach could be applied to images, views, etc.
One thing I really enjoy about my current company is how we leverage the power of GitHub actions to run many different tasks in our workflows: from linting and formatting, to creating releases or deploy apps to App Store Connect.
Is quite impressive the amount of actions that the community put up together in the GitHub Marketplace.
I wanted to therefore leverage this technology in a smaller scale: the build and deployment of this Jekyll blog.
The idea would be that on every new push to the master branch, Jekyll should build the site and upload it to my hosting site via FTP. This can achieved surprisingly easily using the Build and the FTP Deploy actions.
The resulting workflow is quite straightforward:
on:push:branches:-masterjobs:build:name:Build & Deployruns-on:ubuntu-lateststeps:-name:Checkoutuses:actions/checkout@v2-name:Builduses:jerryjvl/jekyll-build-action@v1-name:Deployuses:SamKirkland/FTP-Deploy-Action@2.0.0env:FTP_SERVER:$FTP_USERNAME:$FTP_PASSWORD:$LOCAL_DIR:_siteREMOTE_DIR:moraleda.infoARGS:--delete --transfer-all# --delete arg will delete files on the server if you've deleted them in git
It is important to notice that, since jobs run in isolation, both steps should run in the same job in order to share the environment, otherwise we would need to pass the output of build to the deploy step.
Bonus track
I also added a different workflow to run on pull requests in order to check the spelling of Markdown files (which contain most of the blog content):
Localization is an often overlooked problem. We start a project, we know that we only have to support one language and we approach our string-handling based on that requirement. When the time comes to support a second language, the project grew so much that adapting to that second language causes pain and frustration.
Doing it right from the beginning
iOS and Xcode support localized strings in a rudimentary-but-pragmatic way: we can define a Localizable.strings file, and localize that file in n languages. For each language we will have a key-value file that will contain all our strings:
For accessing these strings all we need to do is to use NSLocalizedString(key, comment: "") and pass the key we are interested in. Eg. NSLocalizedString("ok_button_title", comment: "")
This is going to work nicely and, if we were to launch the app in German or Spanish, the system will know which strings to use.
Getting they keys under control
The main drawback of that approach is that keys are strings and if they start going around, that could be prone to error.
This can be easily solved as well. Let’s define a new type called Strings which will contain all our keys:
Now all we need to do to use a string in a UILabel, for example, is to call:
label.text=Strings.mainTitle.localized
Bringing it to the next level: extracting the strings
Keeping strings and wordings up to date is usually a burden for developers. Designers would produce a mockup which some wordings than then the product manager will need to check/update. The developer is usually left with the task of making sure that these wordings are in sync. If a project is run in several platforms (iOS, Android, web…), keeping the wordings up to date and synchronized can get out of control easily.
A wiser approach would be to move these strings out of the project and place them in a centralized tool that every platform could access. You could build such a service or you can use a commercial solution. For the sake of this tutorial I’m going to use POEditor: an online tool which allows you define terms and their translations and provides an API to access that information.
Setting up the project
This step is very straight-forward: we create a project, we add new entries (called terms in POEditor) and provide the translations. That’s all it is.
POEditor
Automatizing the fetching of the strings
The underlying idea is that, on every build, we want to fetch the latest strings, generating our Strings enum automatically (listing all available keys), and download the translations in the different supported languages.
To do so I’m using Python, hacking my way into it (please, don’t judge my Python knowledge: I know nothing about nothing).
The script does two main things: first, it fetches all the terms listed in the project. With that we create our Strings class (we are also taking care of the case conversion from snake to camel case).
The second step is to download the files containing the translations.
This script is run during the build phase:
Build Phases
Conclusion
This can be easily improved, but with a couple of neat tricks we were able to create a setup where developers don’t really need to worry about strings anymore. A PM or marketing person could go into that tool and update these strings and the app will pick-up on the changes during the next build.
The tool also supports other formats for the export file (JSON, Android XML, etc.), so this script could be easily adapted to your project/platform requirements.
My daughter Lola, as any other toddler I suppose, loves screens. She gets hypnotized by any square that throws light. My wife and I have been pretty consequent about her exposure to screens: we don’t watch TV if she is around, we limit our own screen time, etc. Yet there is one last screen my daughter is enjoying: my Apple Watch.
You have decided that you want to become a developer. Good. There is a huge demand and salaries are high. But what does it take to succeed at this job?