My Android Application is Multilanguage. When the user changing app Language, the app saves it in SharedPreferences to make changes permanent (set locale when the app opens).
The way I change language:
public static void changeInterfaceLanguage(Activity activity, #Language String lang) {
Resources res = activity.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
Locale currentLocale = getCurrentLocale(activity);
final Locale newLocale = new Locale(lang);
if (!currentLocale.equals(newLocale)) {
SettingsPrefsEdit.putString(activity, SettingCons.INTERFACE_LANGUAGE, lang);
conf.setLocale(newLocale);
res.updateConfiguration(conf, dm);
activity.recreate();
}
The way I restore Locale when the app opens:
#Override protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String lang = SettingsPrefsGet.getString(activity, SettingCons.INTERFACE_LANGUAGE,
SettingCons.LANG_ENGLISH);
Locale locale = new Locale(lang);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
activity.getResources()
.updateConfiguration(config, activity.getResources().getDisplayMetrics());
...
}
Also, Admob Native Ads is implemented in this App.
The problem is this:
After destroying app and reopen it, exactly when my code calls any method from Admob library, the app language (Locale) is changing to English, and after that, every new screen of the app is in English.
Some of the methods that cause this problem:
MobileAds.initialize(this)
AdLoader.Builder adLoader = ...
adLoader.build().loadAd(new AdRequest.Builder().build());
Useful notes:
SharedPreferences doesn't get change when this problem occurs.
There is only one Activity in the app. All pages are implemented as Fragment (50+ pages)
After changing app language, everything is fine until app getting destroyed
I'm using Firebase version of Admob:
implementation 'com.google.firebase:firebase-ads:19.6.0'
What I've tried:
When I disable all calls to Admob methods, the problem disappears.
I moved locale update code block to MainApplication. But the problem exists yet.
I re-implemented Language change operation with this library, but didn't resolve:
https://github.com/YarikSOffice/lingver
Related
I have two different strings.xml for multi-language app. Where can I set that I want to use English strings.xml file independent of phone locale language always but use Chinese language only in case when on splash screen we have chosen it?
To support language setting in your application you need to change current configuration and restart activity to reload all resources. You can change current configuration like this:
void changeLanguage(Context context, String language) {
final Locale locale = new Locale(language);
Locale.setDefault(locale);
final Resources res = context.getResources();
final Configuration config = new Configuration(res.getConfiguration());
config.setLocale(locale);
res.updateConfiguration(config, res.getDisplayMetrics());
}
And then don't forget to recreate your activity activity.recreate(); or reload your resources manually.
Also you need to set your locale on every process start. You can do it in application onCreate:
public void YourApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
changeLanguage(this, getLanguageSettingsFromPreferences());
}
}
I'm trying to change the language of the application according to the user's input. I tried using this code to change the language of the application and it's working pretty fine.
public void setLocale(String lang) {
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(MainActivity.this, MainActivity.class);
startActivity(refresh);
}
But the problem is that app has to restart/refresh in order to reload the resources.
Is this the correct approach to set the language of the app programmatically?
Is there any other way to change the language without refreshing the app?
Try with recreate() on your activity. This approach was successful in my case. If you are on Fragment, then use getActivity().recreate();
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.APP_STATE.SAVED_LOCALE, localeString);
editor.apply();
getActivity().recreate();
Override following method of your activity:
#Override
protected void attachBaseContext(Context newBase) {
SharedPreferences prefs = newBase.getSharedPreferences(Constants.APP_STATE.STATE_SHARED_PREFERENCES, MODE_PRIVATE);
String localeString = prefs.getString(Constants.APP_STATE.SAVED_LOCALE, Constants.DEFAULTS.DEFAULT_LOCALE);
Locale myLocale = new Locale(localeString);
Locale.setDefault(myLocale);
Configuration config = newBase.getResources().getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
config.setLocale(myLocale);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N){
Context newContext = newBase.createConfigurationContext(config);
super.attachBaseContext(newContext);
return;
}
} else {
config.locale = myLocale;
}
super.attachBaseContext(newBase);
getResources().updateConfiguration(config, getResources().getDisplayMetrics());
When user set wanted locale, what you want to do is to save it into some string in SharedPreferences and call recreate() of activity. This will then call attachBaseContext(Context context) and in this method proper locale will be set to configuration, then new context will be created with this configuration. After that, new context will be sent to super class which will update application context and proper locale will be shown.
It is also good because locale is automatically set when starting app next time.
Change locale is a Configuration which leads your acitivity restart. There are many other things have the same effect like orientation , keyboardHidden. Take care of your activity's states.
If restarting your activity requires that you recover large sets of
data, re-establish a network connection, or perform other intensive
operations, then a full restart due to a configuration change might be
a slow user experience. Also, it might not be possible for you to
completely restore your activity state with the Bundle that the system
saves for you with the onSaveInstanceState() callback—it is not
designed to carry large objects (such as bitmaps) and the data within
it must be serialized then deserialized, which can consume a lot of
memory and make the configuration change slow. In such a situation,
you can alleviate the burden of reinitializing part of your activity
by retaining a Fragment when your activity is restarted due to a
configuration change. This fragment can contain references to stateful
objects that you want to retain.
Not the best-practice, but you can handle it
<activity android:name=".MyActivity"
android:configChanges="locale"
android:label="#string/app_name">
Then in your Activity
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Do your stuff here
}
Remember to take care of your state. Using setRetainFragment(true) is a good approach. Read this
Yes your code is correct and if you want without refreshing the application
then In Your Application class you need to call this in onCreate() method
String languageSelected = "en";//selected language
Locale myLocale = new Locale(languageSelected);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
getActivity().onConfigurationChanged(conf);//Call this method
You need to perform this particular language to be selected on Application class.
I am developing an app which supports two languages. There is one ToggleButton to change language.I am using following code to change locale and all works fine.
Resources res = viewDashBoardScreen.getResources(
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.locale = new Locale("es".toLowerCase());
res.updateConfiguration(conf, dm);
Question: How to refresh whole app after language change ?
Currently I am restarting that activity in which language is changed. It works fine but is it good practice ? Or is there any other way to apply language change in app.
Any help would be greatly appreciated..Thanks.
i thing you can call this function whn togal button change it's working for me
private void setLocale(String localeCode){
AppLog.logString(TAG+"set location function: "+localeCode);
locale = new Locale(localeCode);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
getApplicationContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
UserDetail.this.getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
onCreate(null);
}
on toggel buttong change call function this way :
setLocale("en-us");// pass languen in whicy u want to translate
setLocale("ar",savedInstanceStat);
I'm having a problem where if I open my android app and then go into the system settings to change the language and then open the app again, some strings in the app won't be translated unless the app is force quit and relaunched. Any idea why this happens? I don't have android:configChanges set to "locale" anywhere in my AndroidManifest, so doesn't this mean all activities should be restarted on their own?
I also had this issue.I used the code below which was posted in some StackOverflow answer and then it changed the language without refreshing the activity
public void setLocale(String lang) {
myLocale = new Locale(lang);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
onConfigurationChanged(conf);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
// refresh your views here
lblLang.setText(R.string.langselection);
super.onConfigurationChanged(newConfig);
}
I hope it would help you.......
Finally figured out the problem. The strings that weren't being translated were being populated within a static class. So because this class was only being instantiated once, the strings weren't getting re-populated again with the proper translations.
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".