|
package com.davidmedenjak.babel; |
|
|
|
import android.annotation.TargetApi; |
|
import android.content.Context; |
|
import android.content.res.Configuration; |
|
import android.content.res.Resources; |
|
import android.os.Build; |
|
import android.os.LocaleList; |
|
import android.support.annotation.NonNull; |
|
import android.support.v4.os.LocaleListCompat; |
|
import android.util.DisplayMetrics; |
|
|
|
import java.util.Locale; |
|
|
|
/** |
|
* Helps apply the correct locale in case of the default locale ({@code res/values}) being used. |
|
*/ |
|
public class BabelFish { |
|
|
|
/** |
|
* Verify that the current locale is supported by this app, otherwise override the locale with the apps default. |
|
* <p> |
|
* Call this in {@code attachBaseContext} of your Application, Activity, and potentially Service. |
|
* |
|
* @param base the context to wrap |
|
* @param defaultLanguage the default language used for `res/values` |
|
* @param supportedLanguages the supported languages of your app, as BCP 47 language tags |
|
* @return a context with resources that map to the apps supported languages |
|
* @see android.app.Application#attachBaseContext(Context) |
|
* @see android.app.Activity#attachBaseContext(Context) |
|
* @see android.app.Service#attachBaseContext(Context) |
|
*/ |
|
public static Context translate( |
|
@NonNull Context base, |
|
@NonNull String defaultLanguage, |
|
String[] supportedLanguages |
|
) { |
|
final Configuration configuration = base.getResources().getConfiguration(); |
|
final Locale currentUserLocale = getCurrentUserLocale(configuration); |
|
|
|
final Locale defaultLocale = new Locale(defaultLanguage); |
|
if (isUserLocaleSupported(defaultLocale, supportedLanguages, currentUserLocale)) { |
|
// if our app supports one of the users language it will be selected |
|
// since we don't have to override anything, lets just return the context |
|
return base; |
|
} |
|
return overrideLocales(base, configuration, defaultLocale); |
|
} |
|
|
|
private static Context overrideLocales(@NonNull Context base, Configuration configuration, Locale defaultLocale) { |
|
final Configuration overrideConfiguration = overrideLocale(configuration, defaultLocale); |
|
|
|
// e.g. DateUtils up to ? uses Resources.getSystem() to format some of their texts. |
|
// to prevent a mix of different locales we override this as well |
|
final DisplayMetrics displayMetrics = base.getResources().getDisplayMetrics(); |
|
//noinspection deprecation |
|
Resources.getSystem().updateConfiguration(overrideConfiguration, displayMetrics); |
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { |
|
return base.createConfigurationContext(overrideConfiguration); |
|
} else { |
|
//noinspection deprecation |
|
base.getResources().updateConfiguration(overrideConfiguration, displayMetrics); |
|
return base; |
|
} |
|
} |
|
|
|
private static boolean isUserLocaleSupported(Locale defaultLanguage, String[] supportedLanguages, Locale currentUserLocale) { |
|
if (currentUserLocale.equals(defaultLanguage)) { |
|
return true; |
|
} |
|
// we have to include `defaultLanguage` since the support library will always assume |
|
// that the locale matches when there is only one entry |
|
final Locale match = LocaleListCompat.create(currentUserLocale, defaultLanguage) |
|
.getFirstMatch(supportedLanguages); |
|
|
|
return match != null && (!match.equals(defaultLanguage)); |
|
} |
|
|
|
private static Locale getCurrentUserLocale(Configuration configuration) { |
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { |
|
return configuration.getLocales().get(0); |
|
} else { |
|
//noinspection deprecation |
|
return configuration.locale; |
|
} |
|
} |
|
|
|
private static Configuration overrideLocale(Configuration configuration, Locale defaultLocale) { |
|
final Configuration overrideConfiguration = new Configuration(); |
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { |
|
overrideLocaleN(defaultLocale, overrideConfiguration, configuration.getLocales()); |
|
} else { |
|
overrideLocaleCompat(defaultLocale, overrideConfiguration); |
|
} |
|
return overrideConfiguration; |
|
} |
|
|
|
@TargetApi(Build.VERSION_CODES.N) |
|
private static void overrideLocaleN(Locale defaultLocale, Configuration overrideConfiguration, LocaleList userLocales) { |
|
final LocaleList adaptedLocales = copyLocalesWithDefault(defaultLocale, userLocales); |
|
LocaleList.setDefault(adaptedLocales); |
|
overrideConfiguration.setLocales(adaptedLocales); |
|
} |
|
|
|
@NonNull |
|
@TargetApi(Build.VERSION_CODES.N) |
|
private static LocaleList copyLocalesWithDefault(Locale defaultLocale, LocaleList userLocales) { |
|
final Locale[] locales = new Locale[userLocales.size() + 1]; |
|
|
|
locales[0] = defaultLocale; |
|
for (int i = 1; i < locales.length; i++) { |
|
locales[i] = userLocales.get(i - 1); |
|
} |
|
|
|
return new LocaleList(locales); |
|
} |
|
|
|
private static void overrideLocaleCompat(Locale defaultLocale, Configuration overrideConfiguration) { |
|
Locale.setDefault(defaultLocale); |
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { |
|
overrideConfiguration.setLocale(defaultLocale); |
|
} else { |
|
overrideConfiguration.locale = defaultLocale; |
|
} |
|
} |
|
} |