(EDIT)
I used a solution for locale change to change the language of my app and it is not working in oreo. It's working perfectly on my samsung S4, but not on my S9.
So I am doing the locale change like this:
public void initAppLanguages(Context context, String lang){
PreferenceUtil.setSelectedLanguageId(lang);
LocaleUtils.setLocale(context, lang );
MyApplication.reouvrir=1;
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
this.finishAffinity();
finish();
startActivity(i);
}
My LocaleUtils class:
public class LocaleUtils {
@Retention(RetentionPolicy.SOURCE)
@StringDef({ENGLISH, FRENCH, SPANISH})
public @interface LocaleDef {
String[] SUPPORTED_LOCALES = {ENGLISH, FRENCH, SPANISH};
}
public static final String ENGLISH = "en";
public static final String FRENCH = "fr";
public static final String SPANISH = "es";
public static void initialize(Context context) {
setLocale(context, ENGLISH);
}
public static void initialize(Context context, @LocaleDef String defaultLanguage) {
setLocale(context, defaultLanguage);
}
public static boolean setLocale(Context context, @LocaleDef String language) {
return updateResources(context, language);
}
private static boolean updateResources(Context context, String language) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
context.createConfigurationContext(configuration);
configuration.locale = locale;
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
return true;
}
}
My PreferenceUtil class:
public class PreferenceUtil {
private static SharedPreferences getDefaultSharedPreference(Context context) {
if (PreferenceManager.getDefaultSharedPreferences(MyApplication.getInstance().getApplicationContext()) != null)
return PreferenceManager.getDefaultSharedPreferences(MyApplication.getInstance().getApplicationContext());
else
return null;
}
public static void setSelectedLanguageId(String id){
final SharedPreferences prefs = getDefaultSharedPreference(MyApplication.getInstance().getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putString("app_language_id", id);
editor.apply();
}
public static String getSelectedLanguageId(){
return getDefaultSharedPreference(MyApplication.getInstance().getApplicationContext())
.getString("app_language_id", "en");
}
}
And the locale change in the child activities like this:
MyApplication.initAppLanguage(mContext);
What am I doing wrong? Why is it not working in Oreo?
Follow the steps below:
Note: I assume that you created different string file in values folder for different english, spanish and french. (i.e strings.xml file in each values-en, values-es, values-fr folder in res directory)
Add this file: LocaleHelper.java
package com.test;
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.os.LocaleList;
import android.preference.PreferenceManager;
import java.util.Locale;
public class LocaleHelper {
private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
public static Context onAttach(Context context) {
String lang = getPersistedData(context, Locale.getDefault().getLanguage());
return setLocale(context, lang);
}
public static Context onAttach(Context context, String defaultLanguage) {
String lang = getPersistedData(context, defaultLanguage);
return setLocale(context, lang);
}
public static String getLanguage(Context context) {
return getPersistedData(context, Locale.getDefault().getLanguage());
}
public static Context setLocale(Context context, String language) {
persist(context, language);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return updateResources(context, language);
}
return updateResourcesLegacy(context, language);
}
private static String getPersistedData(Context context, String defaultLanguage) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
}
private static void persist(Context context, String language) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(SELECTED_LANGUAGE, language);
editor.apply();
}
@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, String language) {
Locale locale = new Locale(language);
Configuration configuration = context.getResources().getConfiguration();
LocaleList localeList = new LocaleList(locale);
localeList.setDefault(localeList);
configuration.setLocales(localeList);
return context.createConfigurationContext(configuration);
}
@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, String language) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
configuration.locale = locale;
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
return context;
}
}
Add file: LanguageUtil.java
package com.test;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.util.Log;
import java.util.Locale;
public class LanguageUtil {
public static void changeLanguageType(Context context, Locale localelanguage) {
Log.i("=======", "context = " + context);
Resources resources = context.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
Configuration config = resources.getConfiguration();
// Application user selects language
// reference https://developer.android.com/reference/android/content/res/Configuration.html
if (VersionUtils.isAfter24()) {
config.setLocale(localelanguage);
} else {
config.locale = localelanguage;
resources.updateConfiguration(config, dm);
}
}
public static Locale getLanguageType(Context context) {
Log.i("=======", "context = " + context);
Resources resources = context.getResources();
Configuration config = resources.getConfiguration();
// Application user selects language
if (VersionUtils.isAfter24()) {
return config.getLocales().get(0);
} else {
return config.locale;
}
}
}
Add file: MyContextWrapper.java
package com.test;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import java.util.Locale;
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
@TargetApi(Build.VERSION_CODES.N)
public static ContextWrapper wrap(Context context, Locale newLocale) {
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
if (VersionUtils.isAfter24()) {
configuration.setLocale(newLocale);
LocaleList localeList = new LocaleList(newLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
context = context.createConfigurationContext(configuration);
} else if (VersionUtils.isAfter17()) {
configuration.setLocale(newLocale);
context = context.createConfigurationContext(configuration);
} else {
configuration.locale = newLocale;
res.updateConfiguration(configuration, res.getDisplayMetrics());
}
return new ContextWrapper(context);
}
}
Add file: VersionUtils.java
package com.test;
import android.os.Build;
import android.support.annotation.RequiresApi;
public final class VersionUtils {
@RequiresApi(Build.VERSION_CODES.N_MR1)
public static boolean isAfter25() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1;
}
@RequiresApi(Build.VERSION_CODES.N)
public static boolean isAfter24() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
}
public static boolean isAfter23() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
public static boolean isAfter22() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1;
}
public static boolean isAfter21() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
public static boolean isAfter20() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH;
}
public static boolean isAfter19() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
}
public static boolean isAfter18() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
}
public static boolean isAfter17() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
}
public static boolean isAfter16() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
}
public static boolean isAfter14() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
}
public static boolean isAfter13() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2;
}
public static boolean isAfter11() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
public static boolean isAfter9() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
}
public static boolean isAfter8() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
}
public static boolean isAfter5() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR;
}
}
Now Create Prefs file: Prefs.kt (This is Kotlin class file)
Note: You can use your own preference creation and retrivation code.
package com.test
import android.content.Context
import android.content.SharedPreferences
import android.content.SharedPreferences.Editor
class Prefs private constructor(private val context: Context) {
private val prefranceName = "testPrefs"
companion object {
private fun getPrefs(context: Context): SharedPreferences {
return context.getSharedPreferences(context.packageName, 0)
}
fun clearDefaultShared(key: String, context: Context) {
val e = getPrefs(context).edit()
e.remove(key)
e.apply()
}
fun setString(key: String, sunDefult: String, context: Context) {
val e = getPrefs(context).edit()
e.putString(key, sunDefult)
e.apply()
}
fun getString(key: String, sunDefult: String, context: Context): String? {
return getPrefs(context).getString(key, sunDefult)
}
fun clearAll(context: Context) {
val editor = getPrefs(context).edit()
editor.clear()
editor.commit()
}
}
}
Now create one class TestApp which extends the Application class.
This will use to save the last selected language you want to apply when app restarts.
Note: don't forget to add this app class name "TestApp" to AndroidManifest.xml in tag.
Add file: TestApp.kt
package com.test
import android.app.Application
import com.test.LanguageUtil
import com.test.Prefs
import java.util.*
class TestApp : Application() {
override fun onCreate() {
super.onCreate()
dbAdapter = DBAdapter(applicationContext)
dbAdapter.openDataBase()
// Set Language Because Local will not be saved every time the app restarts after it is completely logged out
var languageType = Prefs.getString("languageType", "en", this@TestApp).toString()
if (languageType == "fr") {
LanguageUtil.changeLanguageType(this, Locale.FRENCH)
} else if (languageType == "es") {
LanguageUtil.changeLanguageType(this, Locale("es",""))
} else {
LanguageUtil.changeLanguageType(this, Locale.ENGLISH)
}
}
}
Now in each activity, add the code below to apply the changed language.
This is Kotlin code:
override fun attachBaseContext(newBase: Context) {
var languageType = Prefs.getString("languageType", "en", newBase).toString()
super.attachBaseContext(MyContextWrapper.wrap(newBase, Locale(languageType, "")))
}
When you select the different language, use this code:
LanguageUtil.changeLanguageType(this@MainActivity, Locale.ENGLISH) // for englsih
LanguageUtil.changeLanguageType(this@MainActivity, Locale("es","")) // for spanish
LanguageUtil.changeLanguageType(this@MainActivity, Locale.FRENCH)// for french
and after also store it in sharedpreference.
Remember: If you change language in current Activity and you will not see the language change in that, because you need to restart activity to see the changes but activity opened after this current activity you will see the changes.
If you call recreate() in the same activity, it will blink the screen, so do not use the recreate() function.
I have one solution (not proper solution but I can say it is patch and it is worked perfect).
For displaying changes in current activity you need to create all the english, spanish and french string in default strings.xml and set it runtime in current activity when the user selects a different language.
Start your activity after set the new locale. That worked for me.
private void restartActivity() {
Intent intent = getIntent();
finish();
startActivity(intent);
}
You can see the full answer here