I was able to change localization programatically during runtime using the methods explained in this article. I was able to change the language of the app. + layout direction + toolbar language.
Here's My code:
build.gradle
buildTypes {
debug {
pseudoLocalesEnabled true
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.jakewharton:process-phoenix:2.0.0'
}
public class App extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocaleManager.setLocale(base));
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LocaleManager.setLocale(this);
if (Build.VERSION.SDK_INT >= 26) {
ProcessPhoenix.triggerRebirth(this); //An activity must have a category of Default in Manifest!
}
}
}
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(Build.VERSION.SDK_INT>=26) {
LocaleManager.setLocale(this);
}
startActivity(new Intent(this,MainActivity.class));
finish();
}
}
public class LocaleManager {
private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
private static final String DEFAULT_LANGUAGE = "en";
public static Context setLocale(Context c) {
return setNewLocale(c, getLanguage(c));
}
public static Context setNewLocale(Context c, String language) {
persistLanguage(c, language);
return updateResources(c, language);
}
public static String getLanguage(Context c) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(c);
return preferences.getString(SELECTED_LANGUAGE, DEFAULT_LANGUAGE);
}
public static void persistLanguage(Context c, String language) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(c);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(SELECTED_LANGUAGE, language);
editor.commit();
}
private static Context updateResources(Context context, String language) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Resources res = context.getResources();
Configuration config = new Configuration(res.getConfiguration());
if(Build.VERSION.SDK_INT >= 17) {
config.setLocale(locale);
res.updateConfiguration(config, res.getDisplayMetrics());
}
return context;
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//Change English to arabic when user clicked the button.
public void changeLanguage(View view) {
LocaleManager.persistLanguage(this ,"ar");
LocaleManager.setLocale(this);
ProcessPhoenix.triggerRebirth(this); //An activity must have a category of Default in Manifest!
The problem: This code has been working perfectly up till the point where I migrated to androidX. Now, it only works for devices with Android Oreo+. I checked a backup version before the migration to androidX and it is working perfectly. Is there something I am missing here?
Changing implementation of 'androidx.appcompat:appcompat:1.1.0'
to version 1.0.0
and keeping 'androidx.constraintlayout:constraintlayout:1.1.3'
to version 1.1.3
solves the problem.
Also, if you use implementation 'com.google.android.material:material:1.1.0'
, change it to version 1.0.0