The concept of a “developer-facing language” on Android

Stefan M.
5 min readMay 24, 2023
AI generated image for the prompt “developer facing language”

The Android localization matching system is quite handy. You can define your “default strings” in a directory named values, and all translated strings can be moved to a folder named values-[LANG_ISO_CODE]. For example, the translations for Germany would go into values-de, while translations for Spain would go into values-es.

To keep things simple in this blog, I will leave out the fact that this “ISO-CODE” does not have to include only the language, but could also include the country. For example, Switzerland has several languages. To support their different languages you can use the ISO-CODES de_CH, fr_CH, it_CH.

Android will automatically load and display the correct strings (from the correct resource directory) based on your phone’s language settings. Starting with Android 13, you can even set a language for a specific app. But that is another story 😉.

However, if the phone language is set to a language that is not supported by the app, Android will load the strings from the default (values) directory.

So far, in all the projects I have worked on, the default directory has contained “English” translations.

But this could be a problem, right?
No, not because we use English as a fallback, which is actually desired since English is “the global language”, but because of something else.

We Android developers put the strings we see in our mockups or UI designs (from our UI team) into the default (values) directory. But since both teams are not native English speakers (and writers), we may use the wrong words, phrases, or make grammatical mistakes.

Now, if a user is using our app in a language that we do not natively support, they would see the default language. Including all the mistakes that might have it.

This is unacceptable to us at ioki. We have once defined that we want to ship high-quality software. This includes the default translations that were used in phones that use a language we don’t fully support yet.

How to solve this problem?

We all make mistakes, for sure. Even if English would be our native language, mistakes (bugs) happen. Eventually, they will be found by someone, fixed (in the default values directory), and shipped in the next release. So what is the problem?, I hear you screaming.

The problem with this approach is that we (Android developers) don’t want to maintain these translations. Like any developer, we want to solve problems. Replacing a wrong string in our code base is definitely not the work we want to do. Especially when we can’t verify that it really “fixes” the wrong translations. As non-native English speakers, we can’t tell if the new phrasing is more correct or more accurate.

So we need another solution for that. A solution, that doesn’t “bother” us developers when a mistake was found in one of our supported languages.

What if we supported English natively, and at release build time, copy those English translations into the release sourceSet
Would that solve our problem? Yes, it would! 🎉

More details, please!

Imagine we support German, Spanish, and English natively, we would have the following structure in our Android app:

- main/**/values/
- main/**/values-de/
- main/**/values-es/
- main/**/values-en/

If we introduce a developer-facing language and build a release type, we copy the values-en directory — which contains the well-translated English strings — into the release sourceSet. Finish with the following structure before packaging the APK (or Bundle):

- main/**/values/
- main/**/values-de/
- main/**/values-es/
- main/**/values-en/
- release/**/values/

Since the Android build tool will always pick the most concrete requested sourceSet, it will pick the release/**/values as the default directory and leave out the main/**/values directory (assuming that the same resources ids are available in release/**/values).

That’s it. Now we have well-translated English strings as our fallback language. The developer-facing language in main/**/values will never be visible to our app users.

Concerns and problems with this solution

This solution doesn’t solve the problem of developers getting poked in case an English translation is wrong, does it?

If you use one of the available localization tools out there, you don’t have to fix translations in code anymore. For example, you could use Phrase or Lokalise to move the translations out of your code base. Any member of your (translation) team can change the translations and fix mistakes. In your release process, you download the translations from the translation tool of your choice and place them in the correct directories (the latter is done automatically by most tools I’m aware of).

In practice, this means that your code base will have only a single directory containing your developer-facing language:

main/**/values

But before building the app release, you download the strings to end up with the structure I already showed above:

- main/**/values/
- main/**/values-de/
- main/**/values-es/
- main/**/values-en/
- release/**/values/

No developer will ever be annoyed by someone because of a translation mistake. Everyone in your company can fix the mistakes with the appropriate tool. We (Android developers) just have to make sure that we download it at release time. Done ✅.

Like everything else, this solution has its problems.

One problem is that user-facing language mistakes are hidden from developers. For example, the German language is known to have words that are longer than in other languages. When developing, you might forget to add some view constraints and end up with something like this:

Another problem is that your build releases are no longer reproducible. Since changes in the translation tool can happen at any time, and you don’t check them in source control, it could (probably) happen that the version x.y.z of your app has different translations today than it did a few weeks ago.

We have been using the developer-facing language practice for three years now, and we are all very happy with it. Developers don’t have to worry about translation errors, they just maintain their developer language, while product owners, UI team members, and product managers can make translation changes on the fly, knowing that their changes will be shipped in the next release.

What about you and your team? Have you ever heard of or thought about a solution like this? Do you do anything similar? Or are translations not an issue in your organization? Let me know, I’m curious. 🙂

--

--