Search code examples
androidstringinternationalizationlocale

Android app chooses default language regardless language preference order config in settings


Starting with Android 7.0 (API level 24) user is able to set preferred languages on his device (source: LocaleList API). My problem is that my app does not respect this setting - it does not take the second language into account.

In Settings -> languages I have chosen my language preferences as:

 1. Polish (preferred)
 2. French

In Android app I have two languages supported (en as default, and fr):

values/strings.xml (English as default)
values-fr/strings.xml (French)

With this config, App is starting in English (which is default) while on my list of language preferences there is French (which is supported in my app, and should be used).

Why Android chooses English in this case? How to fix that?

Note: French language is set properly when I choose FR language as preferred in settings

EN strings.xml file sample:

  <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE resources [<!ENTITY applicationName "app\'s name">]>
<resources>
  <string name="application_name">&applicationName;</string>
  <string name="dialog_ok">OK</string>
  ...
</resources>

FR strings.xml file sample:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE resources [<!ENTITY applicationName "french name">]>
<resources>
  <string name="application_name">&applicationName;</string>
  <string name="dialog_ok">Oui</string>
  ...
</resources>

Solution

  • The solution is to add resConfigs in the android.defaultConfig of the app/build.gradle to contain your exact locale list (what you have in your app):

    android {
      defaultConfig {
        resConfigs "nb", "nn", "in", "iw", "fr", ...
      }
    }
    

    See the slides for the "Android Internationalization" tutorial at http://www.unicodeconference.org/presentations/ (direct link: http://www.unicodeconference.org/presentations/TS1T3-Nita-Pournader.pdf)

    Also https://gist.github.com/amake/0ac7724681ac1c178c6f95a5b09f03ce


    The explanation: the fallback through the locale list happens at start time, not when loading the strings.

    Most applications these days use some kind of support libraries. The Google support libraries are localized in about 80 languages, and the resources from the libraries are merged into your application.

    At load time the system checks for localized resources in the order in the list, finds some "traces" of Polish from the support libraries, and decides that your application is translated into Polish.

    So it decides that in fact you have Polish, sets the default locale to Polish (so you get dates, times, etc. formatted for Polish). But when it tries to load the strings there is nothing to be found, the and loads the strings from the default folder (in values), which are English.

    By using resConfigs you are telling the resource compiler to only include the locales you want in the apk. So it will drop the few Polish strings from the support libraries. Now the loader will check, there are no Polish strings, goes to French, and all is good.

    This not only solves your problem, but also results in a (slightly) smaller apk.