Translating mobile apps, automate all the things!

Georgios Metaxakis
Making Plum 🛠️
7 min readDec 2, 2021

Plum, the ultimate money management app, started life as a Facebook messenger chatbot when it was launched in the UK, almost 5 years ago. Since then, Plum has grown into a leading finance app, currently available in 4 countries (UK, Ireland, France, Spain), and with ambitious plans to expand into more European markets over the coming months.

One of the biggest challenges for a digital product when moving into new territories is the translation of content. So, we’re going to share our experience in setting up the translation process (for both Android and iOS apps)… plus, we’ll lift the lid on a small piece of code that helped us to automate “all the things”!

Does it really need a process?

When the translation project came knocking at our backlog, we needed to decide who was going to translate the mobile products and how they were going to do it. We decided to use employees as in-house translators and settled on Phrase as our translation tool of choice.

We needed to translate content across both clients (iOS and Android), plus email comms and our website landing pages. And because our systems were built with scalability in mind, they contain no hard-coded content.

Both mobile clients had their translation files in place ( strings.xml for Android and Localizable.strings and Localizable.stringsdict for iOS), so we could translate those, right?

Actually, not!

Our mobile products are live, so their content changes in every sprint, with fresh features and new screens/copy being added across two different projects, on Android and iOS.

Because humans are prone to error and even a single misaligned phrase might lead to confusion for the end-user, we knew we had to create an automated process to help us ship translation-ready features, faster and more accurately.

The process!

After discussing with the product and design teams, we agreed the following process:

  1. Design the feature and confirm the untranslated copy
  2. Start development of the feature
  3. Upload the copy to the translation platform and translate
  4. Verify the validity of the translated copy
  5. Merge the translated copy back into the codebase

Implementing the process

While the basic plan above seems simple enough, we faced certain challenges when trying to implement the steps of the process one-by-one:

1. Design the feature and confirm the untranslated copy

The feature designs we work with normally contain a draft version of the actual copy text that is to be used, rather than mockups with e.g. Latin placeholders.

So, when creating a new feature, the Product Manager and Designer will decide on the content and the feature language, plus check that the content is appropriate from a Compliance perspective.

2. Start development of the feature

Once the copy text has been validated, the implementation of the feature starts, and Mobile Engineers need to start with the translations first!

This means that they need to add the new text content into string values in the strings.xml for Android and Localizable.strings and Localizable.stringsdictfor iOS files (note: a top tip for iOS is to store the Localizable.strings file as UTF-8, for easier review of changes in Github).

We follow a specific key-naming convention in our strings for easier group/search between contents. Each content has a key-name, key-value:

{feature}{ContentDescription}{CTA (or not)}

We use only one key for the whole sentence (adding placeholders where we need to add content programmatically), and we never edit an old key (we create a new one instead because our process covers the automated addition of new keys).

After the development process of the feature Mobile Engineers create a Pull Request integrating the new text content into their codebases.

3. Upload the copy to the translation platform and translate

After the PRs (Pull Requests) in the Android and iOS Github projects are merged, the strings are automatically uploaded to Phrase for translation and Translators get emailed to notify them of requirements.

To achieve this, we created a Github action that automatically pushes keys to our translation tool. When a PR gets merged, a Github Action workflow starts to do the following:

  • Git — checkout the latest develop branch
  • Download phrase-cli client for the Linux that the workflow will run on
  • Use phrase-clito push changes (based on .phrase.yml) of the project
  • Use phrase-cli and the Phrase-API uploads to get the tag and the count of the last keys that got uploaded
    (A little more complex for iOS here as we push 2 files instead of 1, and we had to get the count and the tag of 2 different uploaded files, to decide the next steps.)
  • Delete all unmentioned keys (to clean up all old keys)
  • If no keys got pushed the Github Action will finish
  • If keys got pushed the Github Action will follow up with those
  • Use phrase-cliand Phrase API jobs to create a job for all the keys that have the tag from the last upload
  • Parse response to save Job id
  • Use phrase-cliand Phrase API job_locales to set a translation locale(for all the locales that we want to support) for the Job
  • Use phrase-cliand Phrase API jobs to start the job
phrase_push_create_job.yml

4. Notify team that the translation process started

An integration of the translation tool with the team communication tool is needed, in order to notify everyone about the new content that is ready to get translated and all the product team members can get notified about the new content and its translation status in a#translationschannel we created.

In our case, while there is an integration of Phrase & Slack, the events are very limited to only 4 but not the ones that we needed. We wanted to have notifications for everything that happens in Phrase, so we used a webhook to connect Phrase & Slack and we specified the events that we thought are useful for us to get updates.

So, each client project has a Phrase - Webhook integration with the events: keys:update, keys:delete , keys:batch_delete, comments:create, jobs:start, jobs:complete, jobs:locale:complete

5. Notify team of any comments from our translators.

For each comment that our Translators leave in Phrase while translating, a message is posted in the#translationschannel, so that the people involved in the process (Product managers, Designers, Engineers, Marketing team) can get notified about and respond accordingly if needed.

6. Notify team that the translation process ended.

In the same manner, the team needs to get notified that the translation has been concluded. In our case, when the Translators finish translating the new content in Phrase, a new message is sent to the #translations channel.

7. Marketing team verifies the translations.

The Marketing team needs to verify that the translation result is the expected and mark the translation process as completed. So, when Translators complete their translation, the Marketing team marks the Job as complete.

8. CI creates automatically a PR to add the newly translated files in the codebase.

After the translation process has been marked as completed, we wanted to go one step further and introduce and automatic way where our translations are going to be merged back again into the codebases.

We wanted, whenever a translation Job is marked as complete in Phrase, a Pull Request to be created in our projects in GitHub.

However the connection between Phrase & Github Action Workflow wasn’t possible without any “middle-worker”.

So, we created a custom webhook in Pipedream, and when it gets triggered by Phrase event jobs:complete creates a HTTP POST in our Github Action Workflow that runs the following in the container:

  • Checkout latest code develop branch
  • Download phrase-cli client for the Linux that the workflow will run on
  • Use phrase-cli to pull changes (based on .phrase.yml) of the project
  • Create a Pull Request with the changes
phrase_pull.yml

Then a PR will be created automatically in Android/iOS codebases including the new files that contain the translated content. The PRs need to be approved and merged by the Mobile Engineers, and then the feature is translated and ready to be released!

Future improvements

Setting a process like this, as well as automating as much as possible, has not been easy up until now and more challenges are stored for us in the future!

There is a list of improvements that we are planning for the future, to help us achieve the best result based on our efforts, for instance, the modification of the process for multi-modular projects, or the translations of already existing keys of the project.

However, we believe that the setup that we have created now has already helped us save precious development time, avoid translation errors and of course frustration between the teams and individuals that take part in the creation of the product!

--

--