Can't change the language of my application perfectly

Viewed 563

I'm a newbie to the Android Studio, and I am stuck in a language changing problem. I hope my application enables us to change its language by pressing the "Save" button on the settings dialog, after we change the language at the spinner. For example, if I choose "English", the application's language must turn into English, even though the phone's language is something else. To make this work, I searched the Internet, and imported LocalHelper class, which had help me change the language of the MainActivity with the Button. Here is the Code:

package com.example.evolutionarytree;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button searchButton;
    Button lifeTreeButton;
    Button settingsButton;
    TextView experiment;

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Context context = ElephasMaximus.this;
        searchButton = findViewById(R.id.search);
        lifeTreeButton = findViewById(R.id.lifeTree);
        settingsButton = findViewById(R.id.settings);
        experiment = findViewById(R.id.experiment);


        searchButton.setOnClickListener(this);
        lifeTreeButton.setOnClickListener(this);
        settingsButton.setOnClickListener(this);

    }


    @Override
    public void onClick(View v) {
        if (v == searchButton) {

        }
        else if (v == lifeTreeButton) {
            Intent intent = new Intent(this, ElephasMaximus.class);
            startActivity(intent);
        }
        else if (v == settingsButton) {
            SettingDialog settingDialog = new SettingDialog(this);
            settingDialog.setDialogListener(new SettingDialog.CustomDialogListener() {
                @Override
                public void onPositiveClicked(String language) {
                    //Change Application level locale
                    LocaleHelper.setLocale(MainActivity.this, language);

                    //It is required to recreate the activity to reflect the change in UI.
                    recreate();

                    experiment.setText(language);
                }

                @Override
                public void onNegativeClicked() {

                }
            });
            settingDialog.show();

            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);

            Window window = settingDialog.getWindow();

            int x = (int)(size.x * 0.8f);
            int y = (int)(size.y * 0.4f);

            window.setLayout(x, y);

        }
    }
}

That was the MainActivity. Next is LocaleHelper:

package com.example.evolutionarytree;

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);
        Locale.setDefault(locale);

        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);

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

Final one is the dialog's code:

package com.example.evolutionarytree;

public class SettingDialog extends Dialog implements View.OnClickListener {

    Button saveButton;
    ImageButton closeButton;
    Button sendButton;
    Context context;
    Spinner languageSpinner;

    CustomDialogListener customDialogListener;

    public SettingDialog(@NonNull Context context) {
        super(context);
        this.context = context;
    }

    interface CustomDialogListener{
        void onPositiveClicked(String language);
        void onNegativeClicked();
    }

    public void setDialogListener(CustomDialogListener customDialogListener){
        this.customDialogListener = customDialogListener;
    }

    Resources res = getContext().getResources();
    String[] languageArray= res.getStringArray(R.array.language);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.setting_dialog);

        saveButton = findViewById(R.id.savebutton);
        closeButton = findViewById(R.id.closebutton);
        sendButton = findViewById(R.id.sendbutton);

        languageSpinner = findViewById(R.id.languageSpinner);


        ArrayAdapter arrayAdapter = ArrayAdapter.createFromResource(getContext(),
                R.array.language, android.R.layout.simple_spinner_item);
        arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        languageSpinner.setAdapter(arrayAdapter);


        saveButton.setOnClickListener(this);
        closeButton.setOnClickListener(this);
        sendButton.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.savebutton:
                if(languageSpinner.getSelectedItem().toString().equals(languageArray[0])) {
                    String languageString = "ko";
                    customDialogListener.onPositiveClicked(languageString);
                }
                else if (languageSpinner.getSelectedItem().toString().equals(languageArray[1])) {
                    String languageString = "en";
                    customDialogListener.onPositiveClicked(languageString);
                }

                dismiss();
                break;
            case R.id.closebutton:
                cancel();
                break;

            case R.id.sendbutton:
                Intent email = new Intent(Intent.ACTION_SEND);
                email.setType("plain/Text");
                String[] address = {"My Email. HaHaHa"};
                email.putExtra(Intent.EXTRA_EMAIL, address);
                email.putExtra(Intent.EXTRA_SUBJECT, R.string.bug);
                context.startActivity(email);

        }
    }
}

Now, the problem is that I can change the MainActivity's language, thanks to the LocaleHelper. But other activity's language doesn't change. How can I fix this problem? What I want is by pressing the "Save" button on the dialog, the whole application's language changes into the language that I've picked from the spinner.

2 Answers

After changing locale, do restart activity

fun restartActivity(){
        startActivity(Intent(this@your_activity, your_activity::class.java)
                .also {
                    it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                    it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)                  
                })
        finish()
        finishAffinity()

    }

In the activity that you are changing the language, call recreate() right after the change is done! If there are other activities that are going to be started later, just

@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
    }

is enough since they are not created yet.

If your current activity is created from the main activity then you need to recreated main. For that you should call recreate() in onResume() and make sure you only call it once by some check i.e LocaleHelper.languageIsChanged, otherwise it will be an infinite loop.

Related