Locale Software Suite

My application supports 3 (soon 4) languages. Since several locales are quite similar, I would like to give the user the opportunity to change the language in my application, for example, an Italian person may prefer Spanish in English.

Is there a way for the user to choose among the locales available for the application, and then change which language is used? I see no problem in setting the locale for each action, since it is a simple task to execute in the base class.

+114
android locale user-defined
Feb 13 '11 at 17:51
source share
11 answers

For people who are still looking for this answer, since configuration.locale deprecated in API 24, now you can use:

 configuration.setLocale(locale); 

Bear in mind that minSkdVersion for this method is API 17.

Full code example:

 @SuppressWarnings("deprecation") private void setLocale(Locale locale){ SharedPrefUtils.saveLocale(locale); // optional - Helper method to save the selected language to SharedPreferences in case you might need to attach to activity context (you will need to code this) Resources resources = getResources(); Configuration configuration = resources.getConfiguration(); DisplayMetrics displayMetrics = resources.getDisplayMetrics(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){ configuration.setLocale(locale); } else{ configuration.locale=locale; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ getApplicationContext().createConfigurationContext(configuration); } else { resources.updateConfiguration(configuration,displayMetrics); } } 

Do not forget that if you change the locale with the Activity running, you will need to restart it for the changes to take effect.

EDIT May 11, 2018

Starting with the @CookieMonster post, you may have trouble saving the locale change in higher versions of the API. If so, add the following code to the base action to update the locale of the context each time the action is created:

 @Override protected void attachBaseContext(Context base) { super.attachBaseContext(updateBaseContextLocale(base)); } private Context updateBaseContextLocale(Context context) { String language = SharedPrefUtils.getSavedLanguage(); // Helper method to get saved language from SharedPreferences Locale locale = new Locale(language); Locale.setDefault(locale); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return updateResourcesLocale(context, locale); } return updateResourcesLocaleLegacy(context, locale); } @TargetApi(Build.VERSION_CODES.N) private Context updateResourcesLocale(Context context, Locale locale) { Configuration configuration = context.getResources().getConfiguration(); configuration.setLocale(locale); return context.createConfigurationContext(configuration); } @SuppressWarnings("deprecation") private Context updateResourcesLocaleLegacy(Context context, Locale locale) { Resources resources = context.getResources(); Configuration configuration = resources.getConfiguration(); configuration.locale = locale; resources.updateConfiguration(configuration, resources.getDisplayMetrics()); return context; } 

If you use this, remember to save the language in SharedPreferences when you set the locale using setLocate(locale)

+79
Feb 16 '17 at 9:34 on
source share

Hope this help (in onResume):

 Locale locale = new Locale("ru"); Locale.setDefault(locale); Configuration config = getBaseContext().getResources().getConfiguration(); config.locale = locale; getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics()); 
+175
Feb 13 '11 at 19:54
source share

I have a problem with language programming software using devices that have Android N and higher . For me, the solution wrote this code in my base activity:

(if you do not have a basic action, then you must make these changes in all your actions)

 @Override protected void attachBaseContext(Context base) { super.attachBaseContext(updateBaseContextLocale(base)); } private Context updateBaseContextLocale(Context context) { String language = SharedPref.getInstance().getSavedLanguage(); Locale locale = new Locale(language); Locale.setDefault(locale); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return updateResourcesLocale(context, locale); } return updateResourcesLocaleLegacy(context, locale); } @TargetApi(Build.VERSION_CODES.N) private Context updateResourcesLocale(Context context, Locale locale) { Configuration configuration = context.getResources().getConfiguration(); configuration.setLocale(locale); return context.createConfigurationContext(configuration); } @SuppressWarnings("deprecation") private Context updateResourcesLocaleLegacy(Context context, Locale locale) { Resources resources = context.getResources(); Configuration configuration = resources.getConfiguration(); configuration.locale = locale; resources.updateConfiguration(configuration, resources.getDisplayMetrics()); return context; } 

note that it’s not enough to call here

 createConfigurationContext(configuration) 

you also need to get the context returned by this method, and then set this context in the attachBaseContext method.

+15
Jun 15 '17 at 15:10
source share

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; /** * Manages setting of the app locale. */ 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, ""); } /** * Set the app locale to the one specified by the given String. * * @param context * @param localeSpec a locale specification as used for Android resources (NOTE: does not * support country and variant codes so far); the special string "system" sets * the locale to the locale specified in system settings * @return */ 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 { //noinspection deprecation locale = Resources.getSystem().getConfiguration().locale; } } else { locale = new Locale(localeSpec); } Locale.setDefault(locale); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return updateResources(context, locale); } else { return updateResourcesLegacy(context, locale); } } @TargetApi(Build.VERSION_CODES.N) private static Context updateResources(Context context, Locale locale) { Configuration configuration = context.getResources().getConfiguration(); configuration.setLocale(locale); configuration.setLayoutDirection(locale); return context.createConfigurationContext(configuration); } @SuppressWarnings("deprecation") private static Context updateResourcesLegacy(Context context, Locale locale) { Resources resources = context.getResources(); Configuration configuration = resources.getConfiguration(); configuration.locale = locale; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { configuration.setLayoutDirection(locale); } resources.updateConfiguration(configuration, resources.getDisplayMetrics()); return context; } } 

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; /** * Fragment containing the app main settings. */ public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String KEY_PREF_LANGUAGE = "pref_key_language"; public SettingsFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_settings, container, false); return view; } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { switch (key) { case KEY_PREF_LANGUAGE: LocaleHelper.setLocale(getContext(), PreferenceManager.getDefaultSharedPreferences(getContext()).getString(key, "")); getActivity().recreate(); // necessary here because this Activity is currently running and thus a recreate() in onResume() would be too late break; } } @Override public void onResume() { super.onResume(); // documentation requires that a reference to the listener is kept as long as it may be called, which is the case as it can only be called from this Fragment getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); } @Override public void onPause() { super.onPause(); getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); } } 

Create a locales.xml resource which lists all locales with available translations as follows ( list of locale codes ):

 <!-- Lists available locales used for setting the locale manually. For now only language codes (locale codes without country and variant) are supported. Has to be in sync with "settings_language_values" in strings.xml (the entries must correspond). --> <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> <!-- system setting --> <item>@string/default_locale</item> <!-- default locale --> <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> <!-- NOTE: Has to correspond to array "locales" in locales.xml (elements in same orderwith) --> <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; /** * {@link AppCompatActivity} with main menu in the action bar. Automatically recreates * the activity when the locale has changed. */ 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.
+15
Nov 10 '17 at 13:07 on
source share
 @SuppressWarnings("deprecation") public static void forceLocale(Context context, String localeCode) { String localeCodeLowerCase = localeCode.toLowerCase(); Resources resources = context.getApplicationContext().getResources(); Configuration overrideConfiguration = resources.getConfiguration(); Locale overrideLocale = new Locale(localeCodeLowerCase); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { overrideConfiguration.setLocale(overrideLocale); } else { overrideConfiguration.locale = overrideLocale; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { context.getApplicationContext().createConfigurationContext(overrideConfiguration); } else { resources.updateConfiguration(overrideConfiguration, null); } } 

Just use this helper method to force a specific locale.

UDPATE 22 AUG 2017. It is better to use this approach .

+14
Mar 27 '17 at 13:25
source share

Add a helper class with the following method:

 public class LanguageHelper { public static final void setAppLocale(String language, Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { Resources resources = activity.getResources(); Configuration configuration = resources.getConfiguration(); configuration.setLocale(new Locale(language)); activity.getApplicationContext().createConfigurationContext(configuration); } else { Locale locale = new Locale(language); Locale.setDefault(locale); Configuration config = activity.getResources().getConfiguration(); config.locale = locale; activity.getResources().updateConfiguration(config, activity.getResources().getDisplayMetrics()); } } } 

And name it in your launch activity, for example MainActivity.java :

 public void onCreate(Bundle savedInstanceState) { ... LanguageHelper.setAppLocale("fa", this); ... } 
+4
Aug 03 '17 at 8:13 on
source share

simple and easy

 Locale locale = new Locale("en", "US"); Resources res = getResources(); DisplayMetrics dm = res.getDisplayMetrics(); Configuration conf = res.getConfiguration(); conf.locale = locale; res.updateConfiguration(conf, dm); 

where "en" is the language code, and "US" is the country code.

+1
Mar 23 '17 at 4:47 on
source share
  /** * Requests the system to update the list of system locales. * Note that the system looks halted for a while during the Locale migration, * so the caller need to take care of it. */ public static void updateLocales(LocaleList locales) { try { final IActivityManager am = ActivityManager.getService(); final Configuration config = am.getConfiguration(); config.setLocales(locales); config.userSetLocale = true; am.updatePersistentConfiguration(config); } catch (RemoteException e) { // Intentionally left blank } } 
+1
May 09 '18 at 10:07
source share

Valid from API16 to API28. Just put this method somewhere:

  Context newContext = context; Locale locale = new Locale(languageCode); Locale.setDefault(locale); Resources resources = context.getResources(); Configuration config = new Configuration(resources.getConfiguration()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { config.setLocale(locale); newContext = context.createConfigurationContext(config); } else { config.locale = locale; resources.updateConfiguration(config, resources.getDisplayMetrics()); } return newContext; } 

Paste this code into all your actions using:

  @Override protected void attachBaseContext(Context base) { super.attachBaseContext(localeUpdateResources(base, "<-- language code -->")); } 

or call localeUpdateResources for fragments, adapters, etc., where you need a new context.

Credits: Yaroslav Berezansky

0
May 18 '19 at 14:00
source share

Add a new values ​​folder as shown below. enter image description here

values-ru for Russia, and values-bonds for the Uzbek language. You must install the languages. add this code to your actvitiy class

  String languageToLoad = "uz"; // your language Locale locale = new Locale(languageToLoad); Locale.setDefault(locale); Configuration config = new Configuration(); config.locale = locale; getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics()); 
-one
Jul 11 '17 at 7:50
source share

Put this code in your activity

  if (id==R.id.uz) { LocaleHelper.setLocale(MainActivity.this, mLanguageCode); //It is required to recreate the activity to reflect the change in UI. recreate(); return true; } if (id == R.id.ru) { LocaleHelper.setLocale(MainActivity.this, mLanguageCode); //It is required to recreate the activity to reflect the change in UI. recreate(); } 
-one
Jul 19 '18 at 19:30
source share



All Articles