I'm developing an app that need to support multiple languages and if the language is RTL I have to apply a custom font. For the requirement I have created my Class that extends Application
. Everything was perfect till I got Oreo version device (Before I have Marshmellow enabled device). In Oreo if we want to change the language we have to create a custom ContextWrapper
class, here problem come in.
Calligraphy
we need to Override
the attachBaseContext
method. AndOverride
the attachBaseContext
tooI tried to call super.attachBaseContext
in the Overrided
method twice One for the Calligraphy and Other for the Language code like below.
@Override
protected void attachBaseContext(Context newBase) {
// create or get your new Locale object here.
String lang = Preferences
.getSharedPreferenceString(appContext, LANGUAGE_KEY, "ar");
Context context = MyContextWrapper.wrap(newBase, lang);
super.attachBaseContext(context);
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
It give IllegalStateException as we can attach base context once.
super.attachBaseContext(context);
the language change works But Calligraphy does not. super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
Calligraphy works But Language change does not.In such case how can I make all working (Calligraphy + Multi-language). I have viewed many posts/tutorials but I'm stuck in this for three days now.
Please help me complete this. Thanks
Edit: References
Looking for a solution to be able to use custom font with Calligraphy and Change Language Functionality. Alternatively provide a way so that I may be able to change Language and Apply Font to the whole app.
Note: The solution must be compatible with API 17 to the latest 27. I'm using AppCompat
.
I have done it for oreo
In your activity:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(SLocaleHelper.onAttach(newBase)));
}
OR
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(SLocaleHelper.onAttach(newBase)));
}
In your application main class:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(SLocaleHelper.onAttach(base, "sv"));
MultiDex.install(this);
}
Locale helper Class:
package com.......;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;
import java.util.Locale;
public class SLocaleHelper {
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);
configuration.setLayoutDirection(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;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLayoutDirection(locale);
}
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
return context;
}
}
@Override
protected void attachBaseContext(Context newBase) {
ContextWrapper localeContextWrapper = LocaleManager.wrap(newBase, "en");
ContextWrapper calligraphyContextWrapper = CalligraphyContextWrapper.wrap(localeContextWrapper);
super.attachBaseContext(calligraphyContextWrapper);
}
LocaleManager.java
public class LocaleManager {
public static ContextWrapper wrap(Context context, String language) {
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
Locale newLocale = new Locale(language);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(newLocale);
LocaleList localeList = new LocaleList(newLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
context = context.createConfigurationContext(configuration);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(newLocale);
context = context.createConfigurationContext(configuration);
} else {
configuration.locale = newLocale;
res.updateConfiguration(configuration, res.getDisplayMetrics());
}
return new ContextWrapper(context);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With