是否有可能在使用Android资源的同时以编程方式改变应用程序的语言?
如果不是,是否可以用特定的语言请求资源?
我想让用户改变应用程序的语言从应用程序。
是否有可能在使用Android资源的同时以编程方式改变应用程序的语言?
如果不是,是否可以用特定的语言请求资源?
我想让用户改变应用程序的语言从应用程序。
当前回答
是时候更新了。
首先,弃用列表和它被弃用的API:
配置。locale (API 17) updateConfiguration(配置,displaymetrics) (API 17)
最近没有问题的答案是正确的是新方法的使用。
createconfigationcontext是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呢?
您需要在没有TargetApi注释的情况下使用updateConfiguration创建另一个方法。
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;
}
This code works by having one method that makes calls to the appropriate method based on what API. This is something I have done with a lot of different deprecated calls (including Html.fromHtml). You have one method that takes in the arguments needed, which then splits it into one of two (or three or more) methods and returns the appropriate result based on API level. It is flexible as you do't have to check multiple times, the "entry" method does it for you. The entry-method here is setLanguage
使用前请仔细阅读
您需要使用获取资源时返回的Context。为什么?我在这里看到了其他使用createconfigationcontext而不使用它返回的上下文的答案。为了让它这样工作,必须调用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,你仍然需要使用活动上下文来显示对话框或toast。为此,您可以使用一个活动的实例(如果您在外部)
最后,在活动上使用rebuild()来刷新内容。快捷方式可以不用创建意图刷新。
其他回答
我也面临着同样的问题。在GitHub上,我找到了Android-LocalizationActivity库。
这个库使得在运行时更改应用程序的语言变得非常简单,如下面的代码示例所示。包含下面示例代码的示例项目和更多信息可以在github页面上找到。
LocalizationActivity扩展了AppCompatActivity,所以你也可以在使用Fragments时使用它。
public class MainActivity extends LocalizationActivity implements View.OnClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
findViewById(R.id.btn_th).setOnClickListener(this);
findViewById(R.id.btn_en).setOnClickListener(this);
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btn_en) {
setLanguage("en");
} else if (id == R.id.btn_th) {
setLanguage("th");
}
}
}
添加LocaleHelper类
public class LocaleHelper{
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;
}
}
在活动或片段中
Context context = LocaleHelper.setLocale(this, App.getSharedPre().getLanguage());
Resource resources = context.getResources();
现在在每个文本上设置文本
TextView tv = findViewById(R.id.tv);
tv.setText(resources.getString(R.string.tv));
在运行每个Activity时,必须对attachBaseContext函数进行这些更改。
public Context createConfiguration(Context context, String lan) {
Locale locale = new Locale(lan);
Configuration configuration = new Configuration(context.getResources().getConfiguration());
configuration.setLocale(locale);
return context.createConfigurationContext(configuration);
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(createConfiguration(newBase, "en"/*LANGUAGE_SELECTED*/)));
}
同样,对于您所在的活动,在更改语言后,调用函数recrere ();
您可以要求用户在第一个屏幕中选择语言并将其保存在SharedPreferences中
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
editor.putString("lang", "si");
editor.apply();
recreate();
然后你可以在应用程序中的每个Activity中使用它。这里我设置了英语和僧伽罗语。
@Override
protected void attachBaseContext(Context base) {
SharedPreferences prefs = base.getSharedPreferences("uinfo", MODE_PRIVATE);
String restoredText = prefs.getString("lang", "No name defined");
if (restoredText.equals("si")){
super.attachBaseContext(LocaleHelper.localeUpdateResources(base, "si"));
}else{
super.attachBaseContext(LocaleHelper.localeUpdateResources(base, "en"));
}
}
这是你的localUpdateResources方法。把它放在LocalHelper类中
public class LocaleHelper {
public static Context localeUpdateResources(Context context, String languageCode) {
Context newContext = context;
Locale locale = new Locale(languageCode);
Locale.setDefault(locale);
Resources resources = context.getResources();
Configuration config = new Configuration(resources.getConfiguration());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
config.setLocale(locale);
newContext = context.createConfigurationContext(config);
} else {
config.locale = locale;
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
return newContext;
}
}
对每应用语言偏好的支持刚刚添加到API 33 (Android 13,提拉米苏目前在开发者预览版)。
要改变应用程序的语言环境,只需从LocaleManager调用setApplicationLocales:
// Set app locale to pt-BR (Portuguese, Brazil)
getSystemService(LocaleManager::class.java)
.applicationLocales = LocaleList(Locale.forLanguageTag("pt-BR"))
详见https://developer.android.com/about/versions/13/features/app-languages#api-impl
我已经写了一篇关于这个功能的文章https://proandroiddev.com/exploring-the-new-android-13-per-app-language-preferences-8d99b971b578