Since there is no answer for the current way to solve this problem, I am trying to give instructions for a complete solution. Please comment if something is missing or can be done better.
Home Information
Firstly, there are some libraries that want to solve the problem, but they are all outdated or some functions are missing:
Further, I think that writing a library cannot be a good / easy way to solve this problem, because there is nothing to do, and what needs to be done is to change the existing code than to use something completely untied. Therefore, I made the following instructions, which should be complete.
My solution is mainly based on https://github.com/gunhansancar/ChangeLanguageExample (as has already been associated with localhost ). This is the best code I've found targeting. Some notes:
- If necessary, it provides various options for changing the locale for Android N (and above) and below
- It uses the
updateViews() method in each Activity to manually update all rows after changing the locale (using the usual getString(id) ), which is not required in the approach shown below - It only supports languages, not full locales (which also include regions (countries) and option codes)
I changed it a bit, dividing the part that is stored in the selected locale (how one could do it separately, as suggested below).
Decision
The solution consists of the following two steps:
- Constantly change the language used by the application
- Make the application use a custom set of locales without restarting
Step 1: change the language
Use the LocaleHelper class based on gunhansancar LocaleHelper :
- Add
ListPreference to PreferenceFragment with available languages ββ(must be supported when languages ββneed to be added later)
import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import android.preference.PreferenceManager; import java.util.Locale; import mypackage.SettingsFragment; public class LocaleHelper { public static Context onAttach(Context context) { String locale = getPersistedLocale(context); return setLocale(context, locale); } public static String getPersistedLocale(Context context) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); return preferences.getString(SettingsFragment.KEY_PREF_LANGUAGE, ""); } public static Context setLocale(Context context, String localeSpec) { Locale locale; if (localeSpec.equals("system")) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { locale = Resources.getSystem().getConfiguration().getLocales().get(0); } else {
Create a SettingsFragment as follows:
import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import mypackage.LocaleHelper; import mypackage.R; public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String KEY_PREF_LANGUAGE = "pref_key_language"; public SettingsFragment() {
Create a locales.xml resource which lists all locales with available translations as follows ( list of locale codes ):
<resources> <string name="system_locale" translatable="false">system</string> <string name="default_locale" translatable="false"></string> <string-array name="locales"> <item>@string/system_locale</item> <item>@string/default_locale</item> <item>de</item> </string-array> </resources>
On your PreferenceScreen you can use the following section so that the user can select the available languages:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="@string/preferences_category_general"> <ListPreference android:key="pref_key_language" android:title="@string/preferences_language" android:dialogTitle="@string/preferences_language" android:entries="@array/settings_language_values" android:entryValues="@array/locales" android:defaultValue="@string/system_locale" android:summary="%s"> </ListPreference> </PreferenceCategory> </PreferenceScreen>
which uses the following lines from strings.xml :
<string name="preferences_category_general">General</string> <string name="preferences_language">Language</string> <string-array name="settings_language_values"> <item>Default (System setting)</item> <item>English</item> <item>German</item> </string-array>
Step 2. Make the application using a custom language.
Now configure each action to use a custom set of locales. The easiest way to achieve this is to have a common base class for all actions with the following code (where the important code is in attachBaseContext(Context base) and onResume() ):
import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import mypackage.LocaleHelper; import mypackage.R; public class MenuAppCompatActivity extends AppCompatActivity { private String initialLocale; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); initialLocale = LocaleHelper.getPersistedLocale(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_settings: Intent intent = new Intent(this, SettingsActivity.class); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(LocaleHelper.onAttach(base)); } @Override protected void onResume() { super.onResume(); if (initialLocale != null && !initialLocale.equals(LocaleHelper.getPersistedLocale(this))) { recreate(); } } }
What is he doing
- Override
attachBaseContext(Context base) to use the locale previously saved with LocaleHelper - Detect a change in locale and recreate the action to update its lines.
Notes to this decision
Playing an activity does not update the ActionBar (as already noted here: https://github.com/gunhansancar/ChangeLanguageExample/issues/1 ).
- This can be achieved simply by using
setTitle(R.string.mytitle) in onCreate() for each activity.
It allows the user to select the default locale for the system, as well as the standard application locale (which can be called, in this case, "English").
fr-rCA only language codes are supported, fr-rCA (countries) and variant codes (e.g. fr-rCA ). To support the full specifications of the language , a parser similar to that used in the Android Languages ββlibrary (which supports the region, but not the option codes) can be used.
- If someone found or wrote a good parser, add a comment so that I can include it in the solution.