Set-up the application Language in Android Preferences - android

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.

Related

Android Locale Changed but translated strings not coming in the app

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.

Changing app language in runtime

I'm trying to implement app language switch on the runtime, once the user made language changes in app preferences. I have this code in my PreferenceFragment:
public class Fragment_Preferences extends PreferenceFragment {
private SharedPreferences.OnSharedPreferenceChangeListener prefListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
Log.i("Pref changed", "Settings key changed: " + key);
if(key.equals("language_preference"))
{
String system_language = Locale.getDefault().getLanguage().toUpperCase();
String preference_language = Common_Methods.get_preference_language(getActivity());
Toast.makeText(getActivity(), "Pref changed: "+preference_language, Toast.LENGTH_SHORT).show();
Common_Methods.set_app_interface_language(getActivity(), system_language, preference_language);
}
}
};
prefs.registerOnSharedPreferenceChangeListener(prefListener);
}
}
This is my set_app_interface_language method in Common_Methods class:
public static void set_app_interface_language(Context context, String system_language, String preference_language)
{
if(!preference_language.equals(system_language))
{
Locale locale = new Locale(preference_language.toLowerCase());
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
}
}
I get the Toast message when I change language in preferences. I know that this method works since I call it also from my Fragment_Main. But the language doesn't change on the runtime - I have to exit the app and reopen it, only then I see the changes.
So how can I make the app language change on the runtime, without restarting the app? Thanks!
OK, I think I solved this problem: I call for Common_Methods.set_app_interface_language not in SharedPreferences.OnSharedPreferenceChangeListener, but rather in onRestart method of my Fragment_Main.
I also changed set_app_interface_language to return new config. And once it's returned - I pass it to onConfigurationChanged method to recreate fragment. Now, I did ran into Performing pause of activity that is not resumed... error message once my device's screen turned off. After googling a little about it, I realized that it's non-fatal exception, but I still used Handler to postpone recreate() for 1 millisecond and let the Fragment restart properly. I also set another method in my Common_Methods to check if there were any changes made to the app language and recreate the fragment only if the method returns true; I call this method in onRestart That gave the app some performance boost, since now there's no need to recreate the fragment every time the app restarts.

How to apply new Locale in Android to current screen

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

Android localization from external XML

Is it possible to translate android application at runtime using XML received from service?
If it is possible could someone please point me in right direction.
Thank you.
Warning
Everything I have read says that its not a good idea to let your app change the language because it isn't supported by the Android framework and it may cause problems.
With that being said, I have done it in my app and, while it has been a bit of a pain, it seems to be working so far. Here is how I did it in case you want to do it this way. You need a separate strings.xml file for each language. strings.xml in values folder as your default then maybe a strings.xml in say a values-es folder for Spanish strings. I have used the following code to change the configuration settings depending on a RadioButton that the user selects
final Configuration LANG_CONFIG = ChooseLocale.this.getResources().getConfiguration();
Locale newLocale = new Locale("English");
curLang = ChooseLocale.this.getLanguage();
if ((curLang.equals("English")) || (curLang.equalsIgnoreCase("Ingles")))
{
newLocale = new Locale("en_US");
}
else
{
newLocale = new Locale("es");
}
Toast.makeText(getApplicationContext(), newLangToast + " " + curLang , Toast.LENGTH_SHORT).show();
Configuration config = getBaseContext().getResources().getConfiguration();
Locale.setDefault(newLocale);
config.locale = newLocale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
SharedPreferences.Editor editor = langPref.edit();
editor.putString(LANG_PREF, curLang);
editor.commit();
With this line being the most important to update the config
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
I get the locale from my getLanguage() function which can be handled however you want. I also had to add
#Override
public void onConfigurationChanged(Configuration newConfig) {
newConfig = Globals.getUserLanguage(this);
super.onConfigurationChanged(newConfig);
to every activity that allows orientation change and add this to my onCreate() of each
final SharedPreferences langPref = getSharedPreferences (LANG_PREF, 0);
if (Globals.langConfig != null)
this.onConfigurationChanged(Globals.langConfig);
I also added android:configChanges="orientation|locale" to each activity in the manifest that allows orientation change
Android Docs on localization

getResources().getString() doesn't work after orientation has been changed

My android application is in dual language. So I have 2 res folder value and value-sw(for swahili). I am fetching string values from this file in design and also at run time. For example in layout:
android:hint="#string/Officer"
and in code:
getResources().getString(R.string.Officer);
To change the locale setting I have function which I call on onCreate() which looks like this:
public void ChangeLanguage(Context ctx,String Language){
Resources res = ctx.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration config = res.getConfiguration();
config.locale = new Locale(Language.toLowerCase());
res.updateConfiguration(config, dm);
}
All works fine. Problem comes only if I change the orientation.
For example on start up I set the language to Swahili. So everything is in Swahili. Now if I change the orientation from vertical to horizontal or vice-verse. Textbox box hint which was set in layout remains in Swahili which I expect. But getResources().getString(R.string.Officer); fetches value from the default value file, which is English.
Any suggestions?
Set android:configChanges="orientation" to your activity in AndroidManifest.xml
Doing so will cause your activity not to be destroyed and re-created when orientation is changed.
The problem with having the android:configChanges attribute, is that that disables onCreate() from being called after an orientation change. You are basically telling the app: "I know there will be orientation changes, so don't recreate the screen, I will handle it"
I would suggest calling that function of yours in the onConfigurationChanged() method. Have in mind that any views will be null at that point, so if you need them you will need to get a new reference.
I have same case as one in the question, using English and Swahili in an app.
This is how I tackled it : I created a folder called values-sw then in the folder I created a resource file named string.xml. this is where all my Swahili translations are written. I call the following method in onCreate:
public static void setLocale(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
String userLocale = sharedPreferences.getString("userlocale", null); // adapt to your need
if (userLocale != null) {
Locale locale = new Locale(userLocale);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
}
}
Dont forget to refresh your activity for changes to take effect:
finish();
startActivity(getIntent());
(I know it's pretty late for this answer I hope it helps someone out there, cheers!)

Categories

Resources