0

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();
}
}

2 Answers2

0

Create another activity as the launcher activity.

Then declare the new launcher activity in your manifest like this:

<activity android:name="com.sux.alarmclocknew.LauncherActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

Put the code where you set the locale in your new LauncherActivity. After you set the locale, launch MainAcitivty from LauncherActivity.

Simple UX Apps
  • 611
  • 2
  • 10
  • 20
  • I have done this but now the result is so that even the Fragment titles don't change. I have included the code for the Launcher Activity in the original question. – Jay Gunawardena Jul 12 '21 at 14:30
  • @JayGunawardena I will go through your update tomorrow, Till then, try to use the onCreate method instead onStart in the launcher activity. Also, place a log inside setAppLocale(this, "si"); to see that it really gets there. – Simple UX Apps Jul 12 '21 at 15:22
  • I have actually placed a log inside & it does go in there & saves it & when it's loaded the Log at onStart (or onCreate) logs the proper selected language. Actually I was trying out both onStart & onCreate & the code seems to work better on onCreate. If it's placed onStart it doesn't change the Fragment titles also. Thank you very much btw! – Jay Gunawardena Jul 12 '21 at 18:57
  • @JayGunawardena so, did Putting the code in onCreate solved the issue and you can set the locale now? – Simple UX Apps Jul 13 '21 at 04:17
  • actually no, it did not help, it was giving me the same exact result as before. The locale gets changed but the Drawer Layout still pulled the strings from the default locale strings file. So I did find a solution though, please check my answer below :) – Jay Gunawardena Jul 13 '21 at 04:49
0

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!