I have implemented an option to select GUI language in my app, but I can't make it refresh the screen when a new language is selected.
The selection is made through a ListPreference so there are 2 problems :
1. Refresh the Preference page in which the language is selected.
2. When the app starts, I set the Locale on the onCreate() of the MainActivity but the MainActivity layout is never getting updated with the new selected Locale. (all other screens are updated so the set code is good).
Here is the code for setting the new Locale :
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
String langKey = ctx.getString(R.string.shared_options_select_language_key);
String langDefault = ctx.getString(R.string.shared_options_select_language_default_value);
String appLanguage = preferences.getString(langKey, langDefault);
Locale locale = null;
if (appLanguage.equals(langDefault)) {
locale = new Locale(Resources.getSystem().getConfiguration().locale.getLanguage());
} else {
String[] languageInfo = appLanguage.split("_");
if (languageInfo.length > 1) {
locale = new Locale(languageInfo[0], languageInfo[1]);
} else {
locale = new Locale(appLanguage);
}
}
if (appLanguage.contains(currentLang)) {
return false;
}
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
act.getBaseContext().getResources().updateConfiguration(config, act.getBaseContext().getResources().getDisplayMetrics());
Thank you
Try to refresh the MainActivity after selecting the new Locale
use this to reload the main activity or any activity
public void refrehs_me()
{
Intent intent = getIntent();
finish();
startActivity(intent);
}
Edit : As I can get from your explanation above you save the new locale selected in a shared preference.
Make a new boolean key in the shared preference called (locale_changed) - when a user select a new locale set this key to (TURE) and on the onCreate after setting the new locale check for this key if (TRUE) set it to (FALSE) and reload the activity.
on the second go it will not loop as the key remains (FALSE) until a user change the locale preference again.
The answer would be to position the call to setLocale right before setting the screen content :
setLocale();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Related
Following is the Application code of my Android app:
public class MyApplication extends Application
{
private Locale locale = null;
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
if (locale != null)
{
newConfig.locale = locale;
Locale.setDefault(locale);
getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
}
}
#Override
public void onCreate()
{
super.onCreate();
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
Configuration config = getBaseContext().getResources().getConfiguration();
String lang = settings.getString(getString(R.string.pref_language), "");
if (! "".equals(lang) && ! config.locale.getLanguage().equals(lang))
{
locale = new Locale(lang);
Log.i("Locale" , lang);
Locale.setDefault(locale);
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
}
}
}
I have got to change the value of settings.getString(getString(R.string.pref_language), ""); from the Settings Activity of my app.
The problem is none of the strings (which have a translation) and are accessed using getString() method, are showing the translated text.
EDIT1 : I am using Android 8.0
In android 8, the behavior of the Locales changed, now every Activity context will take its locale, i.e if you in Activity1 and changed the locale for Activity1, then Activity2 will remain on the default locale.
The solution is to change the locale for every Activity and your issue will be fixed.
When you are using getString(R.string.pref_language) the call will return the string from the language matching Locale.getDefault() as long as a translation is provided.
If a translation is not provided it will return the default language, that is the language your using in the values/strings.xml file.
All translated values are in values-xx folders, where xx is the 2 letter ISO code for the language.
I've create an activity to change the locale of the application to load resources of the selected language and I restart the application,moreover I'm keeping an integer value as the app state using sharedpreferences,after setting the locale via the following code,the next time that I open the application the mentioned state does not have the correct value!!!!But,when I remove the language setting there isn't any problem with the state of the application!
myLocale = new Locale(lang);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
/*
* Intent refresh = new Intent(this, AndroidLocalizeActivity.class);
* startActivity(refresh); finish();
*/
PrefManager _p = new PrefManager(getApplicationContext(), PrefConfigNames.LANGUAGE_APP_CONFIG);
_p.setStringValue(GeneralPrefKeyNames.LANGUAGE, lang);
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
setResult(RESULT_OK, null);
finish();
I cannot get what happens to sharedpreferences(I've used open source securepreferences (CodeProject article)in this app)
here!!!
Thanks in advance
Edit#1
PrefManager.java
public class PrefManager {
private SecurePreferences _securePreferences = null;
public PrefManager(Context context, String PrefName)
{
_securePreferences = new SecurePreferences(context, PrefName);
}
public void setStringValue(String key, String value)
{
_securePreferences.edit().putString(key, value).commit();
}
}
Edit#2
Something which is so weird is that the state of the application stored in the sharedprefs has the correct value when I debug or run the application from eclipse (debug or run as an android application)!!!but when I rerun it on the phone it has the default value!!!Please help me solve this issue!
Edit#3
I found out that there was a problem with relaunching the application using the following lines,is there another way to relaunch the app without any problem???Or even a better way (to update the language without relaunching the app)?
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
I've tried the following link to achieve the second mentioned approach
Changing locale: Force activity to reload resources?
,but it is not being raised after the following line
res.updateConfiguration(conf, dm);
Thanks in advance
I finally got the solution,in the onPause method I save the currently saved language in the sharedprefs and after changing the locale in the setting activity and returning to the previous activity in the onResume method I compare the newly saved lang with the value kept in the onPause,and if these two are not equal I call recreate method.
#Override
protected void onResume()
{
super.onResume();
SharedPreferences _sPreferences = getSharedPreferences(PrefConfigNames.LANGUAGE_APP_CONFIG,
Context.MODE_PRIVATE);
String resumeLang = _sPreferences.getString(GeneralPrefKeyNames.LANGUAGE, "En");
if (!currentLang.equals(resumeLang))
recreate();
};
#Override
protected void onPause()
{
SharedPreferences _sPreferences = getSharedPreferences(PrefConfigNames.LANGUAGE_APP_CONFIG,
Context.MODE_PRIVATE);
currentLang = _sPreferences.getString(GeneralPrefKeyNames.LANGUAGE, "En");
super.onPause();
};
You should commit() the values
I am currently work with changing language in the app. My app structure is tab host + fragment I have successfully change the locale but it is quite strange.
That means after I run the change locale code , it does not change the view immediately but only when I go to another tab. I think this is due to I need to reload the view, but are there any way to implment this without kill and restart the activity?
Because there is some goolge analytic code, the entry number will be increase if the user start activity again? Are there standard way to reload view? thanks
The change locale function is in one of the tabhost fragment, I have to refresh the view in tabhost (main activity), and the current fragment .
public OnClickListener setChangeLangListener(final String lang) {
OnClickListener changeLangListener = new OnClickListener() {
#Override
public void onClick(View arg0) {
Configuration config = new Configuration(getResources()
.getConfiguration());
if (lang.equals("en")) {
config.locale = Locale.ENGLISH;
chi.setTextColor(oldColor);
eng.setTextColor(getActivity().getResources().getColor(android.R.color.white));
} else {
config.locale = Locale.TRADITIONAL_CHINESE;
eng.setTextColor(oldColor);
chi.setTextColor(getActivity().getResources().getColor(android.R.color.white));
}
getResources().updateConfiguration(config,
getResources().getDisplayMetrics());
}
};
return changeLangListener;
}
eng.setOnClickListener(setChangeLangListener("en"));
chi.setOnClickListener(setChangeLangListener("zh"));
Allright add this to your manifest
android:configChanges="locale"
and override onConfigurationChanged() in your activity
#Override
public void onConfigurationChanged(Configuration newConfig) {
// refresh your views here
super.onConfigurationChanged(newConfig);
}
go here for more info.
Hope it helps. :)
Have you tried calling setContentView. Eg.:
String languageToLoad = "fr"; // your language
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
activity.setContentView(R.layout.your_layout);
I would like the application language to be set according to the user preferences but up till now it doesn't work how I would like it to.
I have set the default values: strings.xml and also values-es with a strings.xml inside in spanish. I have a menu option which brings the user to a Preference activity where he can amon gother things chose the language.
So here are some extracts of the code:
public class Preference extends PreferenceActivity implements
OnSharedPreferenceChangeListener {
......
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
...}
//(......)
//and here I have the listener so when the language pref changes value the locale gets changed.
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
if (key.equals("listPref2")) {
String idioma = sharedPreferences.getString("listPref2", "catala");
if ("castella".equals(idioma)) {
idioma = "es_ES";
Locale locale = new Locale(idioma);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getApplicationContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
}
}
}
So when I change the language it works but then when I come back later or restart the emulator the language gets back to default locale the en_US and the app language gets changed back to default again. What can I do to sort that out?
I know I can get this preference (which I can access to from all my activities) and then each time set up the locale but I find it a bit heavy isn't there a way to do it in a more elegant way?
What I would like to do is if the user sets up the language so when he comes back 2 days later he doesn't have to change the language again.
Any ideas?
OK it may help someone. I have added the folowing to the main activity manifest:
android:configChanges="locale"
Then when the user choses the preferences I have put a confirm button and then this button brings you to main activity that is why the lnagages gets reset.
I have a static class where I have this code to change the locale:
public static void updateLanguage(Context context, String idioma) {
if (!"".equals(idioma)) {
if ("castella".equals(idioma)) {
idioma = "es_ES";
} else if ("catala".equals(idioma)) {
idioma = "ca_ES";
}
Locale locale = new Locale(idioma);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
context.getResources().updateConfiguration(config, null);
}
}
end at every activity I have like 20 of them I call this method before:
setContentView(R.layout.list_event);
With these methods when I rotate the screen the activities don't change the language
here is a link to a blog that helped me:
http://adrianvintu.com/blogengine/post/Force-Locale-on-Android.aspx
I would think that you need to be setting the locale in the MainActivity onCreate method. The same way you are setting it when the onSharedPreferenceChanged method.
So I have a language setting in my application. When the language is switched, I would like all the textviews etc to change language immediately. Currently I just change the locale in the configuration, so the language has changed when the user restarts the activity.
An ugly solution to my problem would be to make each textview load the new resources each time the language is changed. Is there a better solution? Perhaps a neat way to discretely restart the activity? Or maybe just force reload of the resources?
In your AndroidManifest.xml, add this attribute to your Activity
android:configChanges="locale"
In your activity override onConfigurationChanged()
#Override
public void onConfigurationChanged(Configuration newConfig) {
// refresh your views here
super.onConfigurationChanged(newConfig);
}
https://developer.android.com/guide/topics/manifest/activity-element.html#config
I think the question is switching language in runtime for the app and displaying localized messages in UI. android:configChanges="locale" calls onConfigurationChanged if the system locale is changed (in setting of your device) while the app is running, and not if you change locale in the code for your app, which I guess is what you want to accomplish. That's why it's not refreshing.
Here is the method I use during every activity onCreate() or onResume() depending on my needs (if my activity will be resuming after user changed language settings or will always be created with language already set):
From there I just refresh the view manually or from onConfigurationChanged() which get called after this method finishes.
public static void changeLocale(Activity activity, String language)
{
final Resources res = activity.getResources();
final Configuration conf = res.getConfiguration();
if (language == null || language.length() == 0)
{
conf.locale = Locale.getDefault();
}
else
{
final int idx = language.indexOf('-');
if (idx != -1)
{
final String[] split = language.split("-");
conf.locale = new Locale(split[0], split[1].substring(1));
}
else
{
conf.locale = new Locale(language);
}
}
res.updateConfiguration(conf, null);
}
I'm not sure why this isn't picked up by onConfigurationChanged().
Hey, sandis, do you mean the method onConfigurationChanged() doesn't called in your activity when you changed the language? I met the same problem. The problem maybe this: when we change the language, the activity goes to onDestroy()(you can try this), so there is nobody to call onConfigurationChanged(). When we launch the activity again, the onCreate() is called, not the onConfigurationChanged(). There maybe something different in locale change and orientation change.
public void settingLocale(Context context, String language) {
Locale locale;
Configuration config = new Configuration();
if(language.equals(LANGUAGE_ENGLISH)) {
locale = new Locale("en");
Locale.setDefault(locale);
config.locale = locale;
}else if(language.equals(LANGUAGE_ARABIC)){
locale = new Locale("hi");
Locale.setDefault(locale);
config.locale = locale;
}
context.getResources().updateConfiguration(config, null);
// Here again set the text on view to reflect locale change
// and it will pick resource from new locale
tv1.setText(R.string.one); //tv1 is textview in my activity
}
Assuming you're changing the language through something like
private void updateLocale(#NonNull final Context context,
#NonNull final Locale newLocale) {
final Resources resources = context.getResources();
final DisplayMetrics displayMetrics = resources.getDisplayMetrics();
final Configuration configuration = resources.getConfiguration();
configuration.locale = newLocale;
resources.updateConfiguration(configuration, displayMetrics);
Locale.setDefault(newLocale);
}
You'll need to call Activity.recreate() in all currently open activities, which is what would happen if the user changed the system language while you were not subscribing to android:configChanges="locale".