Search code examples
javaandroidandroid-studiolocale

Android App Locale Does Not Get Changed on App Start From Shared Preferences


My App changes the Locale from a press of a button, which works great with an Intent refresh. & once the button is pressed the Locale gets in to the Shared Preferences as well.

I have checked that the Locale is properly saved & retrieved at the start of the app with the correct values.

However, once the app is closed & started again the Locale I believe is changed & Fragment Titles are also changd but the Side Nav Menu titles stay in the default Locale which is English for me. Inside the Fragments however the Locale is properly changed.

This is the code which I've tried on onCreate(), onStart() & also have included in onResume() in the MainActivity extending AppCompatActivity.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    hideSystemUI();

    sharedPref = getPreferences(Context.MODE_PRIVATE);
    selectedLanguage = sharedPref.getString("Test.SL.LanguageName", language);
    selectedTheme = sharedPref.getString("Test.SL.ThemeName", "Light");

    if (selectedTheme.equals("Light")){
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
    } else if (selectedTheme.equals("Dark")) {
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
    }

    language = selectedLanguage;

    Log.i("selectedlang", selectedLanguage);

    if (language.equals("සිංහල")) {
        setAppLocale(this, "si");
    } else if (language.equals("English")){
        setAppLocale(this, "en");
    }

    binding = ActivityMainBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    setSupportActionBar(binding.appBarMain.toolbar);
    
    drawerLayout = binding.drawerLayout;
    NavigationView navigationView = binding.navView;
    mAppBarConfiguration = new AppBarConfiguration.Builder(
            R.id.nav_a, R.id.nav_d, R.id.nav_a, R.id.nav_settings,
            R.id.nav_about, R.id.nav_disclaimer)
            .setOpenableLayout(drawerLayout)
            .build();
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
    NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
    NavigationUI.setupWithNavController(navigationView, navController);

}

@Override
public boolean onSupportNavigateUp() {
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);

    return NavigationUI.navigateUp(navController, mAppBarConfiguration)
            || super.onSupportNavigateUp();
}

public void setAppLocale(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);
    Configuration config = context.getResources().getConfiguration();
    config.setLocale(locale);
    context.createConfigurationContext(config);
    context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        hideSystemUI();
    }
}

private void hideSystemUI() {
SYSTEM_UI_FLAG_IMMERSIVE_STICKY
        View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
    }

private void showSystemUI() {
    View decorView = getWindow().getDecorView();
    decorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}

Please let me know how I can correct whatever I'm doing wrong. Thank you very much!

Launcher Activity as Simple UX Apps mentioned but it does not seem to work still, unless again I'm doing something wrong in this particular code.

public class Launcher extends AppCompatActivity {

String language = "English";


private SharedPreferences sharedPref;
private String selectedLanguage;
private String selectedTheme;

@Override
protected void onStart() {
    super.onStart();

    sharedPref = getPreferences(Context.MODE_PRIVATE);
    selectedLanguage = sharedPref.getString("Test.SL.LanguageName", language);
    selectedTheme = sharedPref.getString("Test.SL.ThemeName", "Light");

    if (selectedTheme.equals("Light")){
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
    } else if (selectedTheme.equals("Dark")) {
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
    }

    MainActivity.language = selectedLanguage;
    language = selectedLanguage;

    Log.i("selectedlang", selectedLanguage);

    if (language.equals("සිංහල")) {
        setAppLocale(this, "si");
    } else if (language.equals("English")){
        setAppLocale(this, "en");
    }
}

public void setAppLocale(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);
    Configuration config = context.getResources().getConfiguration();
    config.setLocale(locale);
    context.createConfigurationContext(config);
    context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
    Intent refresh = new Intent(getApplicationContext(), MainActivity.class);
    startActivity(refresh);
    finish();
}
}

Solution

  • After messing with it a quite bit I couldn't figure out why only the Drawer Layout is not pulling the resources from the correct locale string file.

    So since everything works as it should with the selected locale the logical thing to do was to change the Drawer Layout item titles at onCreate in the MainActivity.

    I used a method from this post to retrieve the locale specific strings for the titles

    The code before the & after the below snippet are as is on my original question.

        drawerLayout = binding.drawerLayout;
        NavigationView navigationView = binding.navView;
    
        navigationView.getMenu().findItem(R.id.nav_a)
                .setTitle(getLocaleString(R.string.menu_a, selectedLocale));
        navigationView.getMenu().findItem(R.id.nav_d)
                .setTitle(getLocaleString(R.string.menu_d, selectedLocale));
        navigationView.getMenu().findItem(R.id.nav_ar)
                .setTitle(getLocaleString(R.string.menu_ar, selectedLocale));
        navigationView.getMenu().findItem(R.id.nav_tools)
                .setTitle(getLocaleString(R.string.menu_tools, selectedLocale));
        navigationView.getMenu().findItem(R.id.nav_settings)
                .setTitle(getLocaleString(R.string.menu_settings, selectedLocale));
        navigationView.getMenu().findItem(R.id.nav_about)
                .setTitle(getLocaleString(R.string.menu_about, selectedLocale));
        navigationView.getMenu().findItem(R.id.nav_disclaimer)
                .setTitle(getLocaleString(R.string.menu_disclaimer, selectedLocale));
    
        mAppBarConfiguration = new AppBarConfiguration.Builder(
                R.id.nav_a, R.id.nav_d, R.id.nav_ar, R.id.nav_settings,
                R.id.nav_about, R.id.nav_disclaimer)
                .setOpenableLayout(drawerLayout)
                .build();
    

    & to retrieve the strings

    public String getLocaleString(int id, String lang){
        Resources res = getResources();
        Configuration conf = res.getConfiguration();
        conf.locale = new Locale(lang);
        DisplayMetrics metrics = new DisplayMetrics();
        Resources resources = new Resources(getAssets(), metrics, conf);
        String string = resources.getString(id);
        return string;
    }
    

    If there is a better solution please do let me know!