Robert P
Robert P

Reputation: 9793

Android - Defining the default locale

I am developing a bilingual android application, which supports german and italian.
At the moment i have a values-it with italian strings and a values with the german strings. This works well, unless you are using german and italian on your device. In this case, the application is always in italian, following this calculation:

User Setting: de_DE, it_IT
App Resources: default(en), it

Try de_DE -> fail
Try de -> fail
Try it_IT -> fail
Try it -> Success

This is probably because the default is implicitly treated as values-en, while in my case it is actually values-de.

Is there a way to tell android, that my applications default locale is de instead of en?

Upvotes: 3

Views: 3163

Answers (2)

Denis
Denis

Reputation: 653

20210715 this seems to work for me. Focus on the statement that identifies the locale and recognize that context must be provided

///this function was called from a FRAGMENT and works fine .
////  dateLong = TimeConvert.tcConvertDateToLong(..........,requireContext()
fun tcConvertDateToLong(
        yyyy: Int, MM: Int, dd: Int, HH: Int, mm: Int,context: Context
): Long {
    val mTag64="TimeConvert_tcConvertDateToLong"
    val date:String
    date=yyyy.toString() + "." + MM.toString() + "."+ dd.toString() +" "+ HH.toString() + ":" + mm.toString()
    ////////////-------------------------------------------------------------
    val locale = getLocales(context.getResources().getConfiguration()).get(0)
    //////////-------------------------------------------------------------
    val df = SimpleDateFormat("yyyy.MM.dd HH:mm",locale)
    return try {
        df.parse(date)!!.time
    }  catch (  e: ParseException){
        java.lang.System.currentTimeMillis()
    }
}

Upvotes: 0

a.toraby
a.toraby

Reputation: 3391

I don't know if there are any other options or not, one way is to do it programmatically. According to Ricardo's great solution, I've created the following class to change the default Local:

public class LocaleHelper {

public static Context onAttach(Context context) {
    String lang = Locale.getDefault().getLanguage();
    if(lang.equals("it") || lang.equals("de"))
        return context;
    String locale = "de";
    return setLocale(context, locale);
}

private static Context setLocale(Context context, String localeSpec) {
    Locale locale;
    if (localeSpec.equals("system")) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            locale = Resources.getSystem().getConfiguration().getLocales().get(0);
        } else {
            locale = Resources.getSystem().getConfiguration().locale;
        }
    } else {
        locale = new Locale(localeSpec);
    }
    Locale.setDefault(locale);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResources(context, locale);
    } else {
        return updateResourcesLegacy(context, locale);
    }
}

@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, Locale locale) {
    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);
    configuration.setLayoutDirection(locale);

    return context.createConfigurationContext(configuration);
}

@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, Locale 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;
}
}

You should use that on your Activity class:

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

If you are using uk.co.chrisjenx.calligraphy to change fonts, you should do as follows:

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

Update

Using this outstanding post I managed to find the provided languages automatically. So you no further have to hard code it, de or other provided translations whenever you add a new one to the resources.

public class LocaleHelper {

public static Context onAttach(Activity context) {
    Set<String> providedLangs = getProvidedLanguages(context);
    String lang = Locale.getDefault().getLanguage();
    if(providedLangs.contains(lang))
        return context;
    String locale = "de";
    return setLocale(context, locale);
}

private static Set<String> getProvidedLanguages(Activity activity){
    DisplayMetrics metrics = new DisplayMetrics();
    activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
    Resources r = activity.getResources();
    Configuration c = r.getConfiguration();
    String[] loc = r.getAssets().getLocales();
    Set<String> providedLangs = new HashSet<String>();
    for (int i = 0; i < loc.length; i++) {
        Timber.e("LOCALE: " +  i + ": " + loc[i]);

        c.locale = new Locale(loc[i]);
        Resources res = new Resources(activity.getAssets(), metrics, c);
        String s1 = res.getString(R.string.app_name);
        c.locale = new Locale("");
        Resources res2 = new Resources(activity.getAssets(), metrics, c);
        String s2 = res2.getString(R.string.app_name);

        if(!s1.equals(s2)){
            if(!providedLangs.contains(loc[i]))
                providedLangs.add(loc[i]);
        }
    }

    return providedLangs;
}

private static Context setLocale(Context context, String localeSpec) {
    Locale locale;
    if (localeSpec.equals("system")) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            locale = Resources.getSystem().getConfiguration().getLocales().get(0);
        } else {
            locale = Resources.getSystem().getConfiguration().locale;
        }
    } else {
        locale = new Locale(localeSpec);
    }
    Locale.setDefault(locale);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResources(context, locale);
    } else {
        return updateResourcesLegacy(context, locale);
    }
}

@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, Locale locale) {
    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);
    configuration.setLayoutDirection(locale);

    return context.createConfigurationContext(configuration);
}

@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, Locale 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;
}
}

Upvotes: 3

Related Questions