Conversion By Translation - Changing Your Android App Language At Runtime

Idan Atsmon
Oct 28 · 4 min read
credit: https://www.freepik.com/free-vector/human-alien-speaking-different-languages-backgroun_2857857.htm

You have an awesome app with lots of cool features, one of which is multi-language support for your users. Everything works great but your Product Manager wants to improve conversion by prompting users to choose the app’s language on the first launch as part of the onboarding process.
With a couple of years of Android experience under your belt, you're thinking,
“How hard can it be?”

Well…

The Problem

On Android, there is no official support, documentation or API to change an entire app’s language at runtime. When a user opens an app, the resource framework automatically selects the resources that best match the device language settings. In Google Maps, for example, you can not change the street names on the map without changing the entire device language.

Prerequisite

In order to change an app’s language (or Locale in Android terms), we need to be familiar with 2 different mechanisms that will help us achieve our goal:

Configuration Class

This class describes all device configuration information that can impact the resources the application retrieves. This includes user-specified configuration options (locale list and scaling)

Basically, this is the class that Android is gettings its Locale information from.
Overriding this class with the Locale that represents the user’s selected language will change the folder Android is looking for its resources (e.g strings.xml).

Locale.setDefault() Method

Gets the current value of the default locale for this instance of the Java Virtual Machine.

The Default Locale is usually used when using operations like formatting text, parsing numbers or handling dates. So it is important to override it, otherwise, an app may be displayed in the correct language but things like dates and currency will be broken.

The Solution

From API 17 and above, the preferred way to override a Configuration is by wrapping the currently used Context in a new Context using the method below:

We can combine all the actions we need to take into a single function:

This method should be called inside the attachBaseContext() method in the Application class and in each Activity.

As far as the Android system implementation goes, we are done!
(or so I thought? more on that later)

an example showcasing runtime locale changing

A few things you should do in order to achieve this:

  • The selected language should be persisted in Room/SharedPreferences/etc in order to retrieve it later (CreateLocaleFromSavedLanguage() method in the snippet above)
  • Optional: Load fresh data from the server based on the selected language, like translated strings or specific business logic directed to the selected language users
  • Reflect the language change by rebuilding your UI in a nice and clean way

A Game of Cat & माउस्

The feature is done and you confidently mark it as ready for QA testing. 💪
As the days pass, bug tickets pile up, each with a different scenario that made the app look like it is partially translated to the selected language and partially using the device language.

Below are 2 example scenarios, there are probably more weird cases, so keep that in mind if you decide to go on this road.

#1: System Language Change

If the user changes the device’s main language while your app is in the background, your app Locale will be overridden by the Android system to reflect the new system language.

The fix, in this case, is to override the onConfigurationChanged() method in the Application class and override the Locale using the updateConfiguration() method found in Resource class.

#2: WebView

If your app is using WebView in order to display web pages (yeah I hate it too) then you will notice strange behavior every time a WebView is used.
After each WebView creation, the Application Locale gets overridden with the system Locale which messed up the translations. 🤔

The reason behind this is starting with Android N, the Chrome app will be used to render any/all Webviews in third-party Android apps. Because Chrome is an Android app in itself, running in its own sandboxed process, it will not be bound to the Locale set by your app. Instead, Chrome will revert to the primary device Locale.
Source: https://stackoverflow.com/a/40675539/5516215

The fix, in this case, is again to override the Locale after a WebView is created using the technique we wrote above. One way of doing this is by using a custom WebView:

Hopefully, this issue should be resolved in Android 10, where the Chrome app will no longer be the WebView provider.
Source: https://www.xda-developers.com/google-chrome-no-longer-webview-provider-android-10/

Conclusion

After a few iterations, everything looks good. The Product Manager is happy, your users are happy and even you feel quite pleased with implementing a feature that is not officially supported. 👏
With that said, future Android versions can change how this solution affects your app and even introduce new edge cases that require special care, it is up to you to decide if the investment is worthwhile.

Idan Atsmon

Written by

Android Developer @IronSource

ironSource Tech Blog

At ironSource, developers build the company, not just the code. This is a blog written by our amazing engineers on the problems solved, projects initiated, and innovations pioneered at ironSource.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade