Loco for Loco

Barry Irvine
Go City Engineering
5 min readMar 8, 2023
Loco!

Every so often you come across a piece of software or tool that genuinely makes building an Android app easier. For me, Loco sits squarely in this camp. (Caveat: Although this may seem like a puff piece in places, this is not a sponsored link or anything, I just genuinely like the product!)

I’ve not really worked much with translations throughout my professional Android career. My first Android job was at a British music streaming company who had no real interest in translations. Next up was a fashion social network whose Italian origins meant that we supported Italian as well as English but this a pretty manual process with email requests for string translations etc. Then came a big UK general merchandising retailer who again, with that English exceptionalism, decided that translations weren’t needed before I finally landed at Go City where we needed to support 11 languages in our app. Clearly emailing an Excel spreadsheet around was not going to cut the mustard!

Enter Loco, a deceptively simple website where we, as developers, can create the English strings for our project, which are then translated by our translation team. You can see the translation progress of the project and which languages are still missing some translations. You can setup alerts to let you know when new translations have been updated and the translators can be alerted if there are changes or new items in the base English assets. You also add notes or context information to help the translators understand how the string asset is used in the app. You can also define roles so your French translator can’t accidentally update the Spanish assets.

Just having the notifications alone makes Loco infinitely more useful than an Excel spreadsheet but I can also import Android or iOS string files into the project, it can handle the fact that iOS has %@ for a String substitution while Android expects %s, it handles the plurals correctly for both platforms (including only having “Other” types for Japanese etc.)

One important step that we had to take as a mobile development team was to agree a common structure for our string names that worked for both the Android and the iOS teams. As a general rule, all our string asset ids look like this {screen_name}.{functional_area}_{purpose/value}. The full-stop/period isn’t supported in Android but is very useful for categorising the strings in iOS apps when using a tool such as SwiftGen.

Although we have a multi-module Android project, we also decided to put all the strings in a single module so that we didn’t have to split a single set of assets from the translators into different files. We decided to put the strings in our design module, alongside all the common Compose elements.

Where Loco really shines, is with its API. You can export the data in all sorts of formats—the most important for app development being Android string resources and iOS Localizable strings—but if your web team had similar screens they can also jump onboard with PHP language packs or whatever they use.

In fact, here at Go City, we run a shell script at the end of each sprint to populate all the Android strings. The iOS team even run their script as part of their CI (but be aware that if there are missing translations the users will see that text in the base language).

The script is written in zsh and one of the first things we need to do is associate each Loco language with the Android values directory. Looking at this now, I could just have inserted the r for the regional variations but hopefully this is easily understandable.

declare -A pairs
pairs=( en values
en-GB values-en-rGB
it values-it
fr values-fr
es values-es
de values-de
zh values-zh
ja values-ja
ko values-ko
pt values-pt
sv values-sv
da values-da
)

The script now goes to the output directory in our design module and loops through these pairs.

OUTPUT_DIR="design/src/main/res"
cd $OUTPUT_DIR
for lang dir in ${(kv)pairs}; do
mkdir -p $dir
file=$dir/strings.xml
tmp_file=$dir/strings.xml.tmp

So this might create the values-de directory if it doesn’t exist and then assigns a couple of variables file = values-de/strings.xml
and tmp_file = values-de/strings.xml.tmp

We’re going to use the temporary file so that we don’t copy any errors over the top of our existing strings files.

Within this loop we want to use Loco’s export API which we’ve defined in API_PATH at the top of our file. We’re going to do the extract in android format, we only want translated strings, we don’t want translated strings that are the same as the source (useful for British English where most of the assets are the same as the generic English), we want to order by the asset id (so that the strings are in a consistent order and it’s easy to see the delta) and we don’t want any assets that are tagged as iosonly.

We’ve also defined a TRANSFORM sed expression which we can use to convert those pesky full stops that the iOS team love so much into underscores.

API_PATH="https://localise.biz/api/export/locale/LANGUAGE.xml?format=android&status=translated,!same-as-source&order=id&filter=!iosonly"
#Matches any fullstops in the string name and replaces with an underscore
TRANSFORM="s/\(name=\"[a-z_]*\)\./\1_/g"

And here it is in use. The API_KEY variable we got from Loco for the project that we want to access, we then replace LANGUAGE in the API_PATH with our lang value, use our transform and copy that to our tmp_file

#Fail silently (so file has zero size for failure) and silence successful responses so the console isn't full of comments
curl -f -s -u $API_KEY: ${API_PATH:s/LANGUAGE/$lang} | sed -e ${TRANSFORM} > $tmp_file

The rest of our loop now looks like this. I.e. if it’s successful we move tmp_file to file.

  #If the file size is > 0
if [[ -s $tmp_file ]]; then
mv $tmp_file $file
else
echo "Extraction error for $lang"
rm $tmp_file
fi
echo -n "."
done
echo

Our script does a lot more. There are pre-checks to see if the translators have made an error (like trailing white space or accidentally translating a format function like %d) and because we support other English variants I need to forcefully mark the main file with tools:locale=”en”. You can find the full script here.

In summary, if your app supports multiple languages and you are looking for an efficient way to share the translations between your translation team and the app developers you should definitely give Loco a look.

As usual, if you enjoyed this post, I’d appreciate some claps, a follow, share or tweet and if you have any questions please don’t hesitate to post them below.

--

--

Barry Irvine
Go City Engineering

Writing elegant Android code is my passion — but with 20+ years experience in roles from programme delivery to working at the coal face, I’ve seen it all.