Время для обновления.
Прежде всего, устаревший список с API, в котором он объявлен устаревшим:
configuration.locale
(API 17)
updateConfiguration(configuration, displaymetrics)
(API 17)
То, на что не отвечал ни один вопрос в последнее время, стало правильным, так это использование нового метода .
createConfigurationContext - это новый метод для updateConfiguration.
Некоторые использовали его автономно, как это:
Configuration overrideConfiguration = ctx.getResources().getConfiguration();
Locale locale = new Locale("en_US");
overrideConfiguration.setLocale(locale);
createConfigurationContext(overrideConfiguration);
... но это не работает. Зачем? Метод возвращает контекст, который затем используется для обработки переводов Strings.xml и других локализованных ресурсов (изображений, макетов и т. Д.).
Правильное использование выглядит так:
Configuration overrideConfiguration = ctx.getResources().getConfiguration();
Locale locale = new Locale("en_US");
overrideConfiguration.setLocale(locale);
//the configuration can be used for other stuff as well
Context context = createConfigurationContext(overrideConfiguration);
Resources resources = context.getResources();
Если вы только что скопировали это в свою IDE, вы можете увидеть предупреждение о том, что API требует, чтобы вы настроили таргетинг на API 17 или выше. Это можно обойти, поместив его в метод и добавив аннотацию @TargetApi(17)
Но подождите. А как насчет старых API?
Вам необходимо создать другой метод с использованием updateConfiguration без аннотации TargetApi.
Resources res = YourApplication.getInstance().getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.locale = new Locale("th");
res.updateConfiguration(conf, dm);
Вам не нужно возвращать контекст здесь.
Теперь управлять ими может быть сложно. В API 17+ вам нужен созданный контекст (или ресурсы из созданного контекста), чтобы получить соответствующие ресурсы на основе локализации. Как вы справляетесь с этим?
Ну, вот как я это делаю:
/**
* Full locale list: https://stackoverflow.com/questions/7973023/what-is-the-list-of-supported-languages-locales-on-android
* @param lang language code (e.g. en_US)
* @return the context
* PLEASE READ: This method can be changed for usage outside an Activity. Simply add a COntext to the arguments
*/
public Context setLanguage(String lang/*, Context c*/){
Context c = AndroidLauncher.this;//remove if the context argument is passed. This is a utility line, can be removed totally by replacing calls to c with the activity (if argument Context isn't passed)
int API = Build.VERSION.SDK_INT;
if(API >= 17){
return setLanguage17(lang, c);
}else{
return setLanguageLegacy(lang, c);
}
}
/**
* Set language for API 17
* @param lang
* @param c
* @return
*/
@TargetApi(17)
public Context setLanguage17(String lang, Context c){
Configuration overrideConfiguration = c.getResources().getConfiguration();
Locale locale = new Locale(lang);
Locale.setDefault(locale);
overrideConfiguration.setLocale(locale);
//the configuration can be used for other stuff as well
Context context = createConfigurationContext(overrideConfiguration);//"local variable is redundant" if the below line is uncommented, it is needed
//Resources resources = context.getResources();//If you want to pass the resources instead of a Context, uncomment this line and put it somewhere useful
return context;
}
public Context setLanguageLegacy(String lang, Context c){
Resources res = c.getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();//Utility line
android.content.res.Configuration conf = res.getConfiguration();
conf.locale = new Locale(lang);//setLocale requires API 17+ - just like createConfigurationContext
Locale.setDefault(conf.locale);
res.updateConfiguration(conf, dm);
//Using this method you don't need to modify the Context itself. Setting it at the start of the app is enough. As you
//target both API's though, you want to return the context as you have no clue what is called. Now you can use the Context
//supplied for both things
return c;
}
Этот код работает, имея один метод, который выполняет вызовы соответствующего метода в зависимости от того, какой API. Это то, что я сделал с множеством различных устаревших вызовов (в том числе Html.fromHtml). У вас есть один метод, который принимает необходимые аргументы, который затем разбивает его на один из двух (или трех или более) методов и возвращает соответствующий результат на основе уровня API. Он гибкий, так как вам не нужно проверять несколько раз, метод "entry" сделает это за вас. Метод ввода здесь setLanguage
ПОЖАЛУЙСТА, ПРОЧИТАЙТЕ ЭТО ПЕРЕД ИСПОЛЬЗОВАНИЕМ ЭТОГО
Вам необходимо использовать возвращаемый контекст при получении ресурсов. Зачем? Я видел другие ответы, которые используют createConfigurationContext и не используют возвращаемый контекст. Чтобы заставить его работать так, необходимо вызвать updateConfiguration. Что не рекомендуется. Используйте контекст, возвращаемый методом, для получения ресурсов.
Пример использования :
Конструктор или где-то похожий:
ctx = getLanguage(lang);//lang is loaded or generated. How you get the String lang is not something this answer handles (nor will handle in the future)
И затем, везде, где вы хотите получить ресурсы, которые вы делаете:
String fromResources = ctx.getString(R.string.helloworld);
Использование любого другого контекста (теоретически) сломает это.
AFAIK, вы все равно должны использовать контекст активности, чтобы показывать диалоги или тосты. для этого вы можете использовать экземпляр действия (если вы находитесь снаружи)
И, наконец, используйте recreate()
в действии, чтобы обновить содержимое. Ярлык, чтобы не создавать намерения для обновления.