Application Wide Locale Override

There are quite many blog posts out there on how to override the system locale in an Android application (like this or that). However they all are activity specific and to my disliking propagate the usage of Locale.setDefault(), which in my opinion should not be touched and in practice does nothing to help us achieve our goals.

As mentioned before I didn’t like the idea of having to copy the same code into all of my activities to customize the locale and wanted to do it application wide. The overriding of the Application is not a well known technique but it should be for cases like this one. Here is an example how I achieved the application wide locale overriding without altering any of my activities:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MyApplication extends Application
{
  @Override
  public void onCreate()
  {
    updateLanguage(this);
    super.onCreate();
  }

  public static void updateLanguage(Context ctx)
  {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
    String lang = prefs.getString("locale_override", "");
    updateLanguage(ctx, lang);
  }

  public static void updateLanguage(Context ctx, String lang)
  {
    Configuration cfg = new Configuration();
    if (!TextUtils.isEmpty(lang))
      cfg.locale = new Locale(lang);
    else
      cfg.locale = Locale.getDefault();

    ctx.getResources().updateConfiguration(cfg, null);
  }
}

On a little side note, the most common problem with the other locale overriding examples out there was that on Android >2.0 the locale change triggered an incorrect scaling of items. A workaround was by adjusting the android:configChanges property for each of the activities. However this ugly situation can be avoided by just passing null as the 2nd argument to the Resources.updateConfiguration() function.

Back to the application wide approach. To tell Android to use your class for the Application instance, you need to specify it in the AndroidManifest.xml like this:

1
2
3
<application android:name="com.example.MyApplication" ...>
  ...
</application>

As you can see from the code, if you want to override the locale in your application you just store the locale in the locale_override preference, if you want to use the system default locale, you unset it or just set it to an empty string.

If you want to update the locale temporarily for the duration of the application lifespan you just call the MyApplication.updateLanguage(getApplicationContext(), “en”) function with the language you want to switch to.

The main problem with this approach as with the others out there is that whenever you change the locale at runtime, the activities already created with a different locale will have UI’s with the old locale. This can be worked around in many cases, but sometimes it’s just easier to tell the user to restart the application before the changes take affect fully.

Also it is worth noting that Services get their own MyApplication instances, or at least the change of the locale doesn’t propagate the existing Services as it does for existing Activities, so whenever you need localized resources in the Service you are better off calling the updateLanguage(getApplicationContext()) before fetching the resources.