android - 在 Android 中以编程方式更改应用程序语言的问题
问题描述
我创建了设置活动,我希望用户在此活动中更改应用程序语言。我为这些语言创建了所有资源。当我转到设置活动并将语言更改为俄语时,此活动中的语言会更改,而当我返回主活动时,语言尚未更改。为了更改整个应用程序语言,我必须转到 About Activity 以应用所有这些更改。About Activity 只有一个工具栏几个 Text Views
此外,我的主活动包含带有视图寻呼机的选项卡布局,我在其中添加了两个片段。
LocaleHelper 类
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;
/**
* This class is used to change your application locale and persist this change for the next time
* that your app is going to be used.
* <p/>
* You can also change the locale of your application on the fly by using the setLocale method.
* <p/>
* Created by gunhansancar on 07/10/15.
*/
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;
}
}
//在设置活动中更改应用程序语言
listPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String selected = (String) newValue;
Log.d("Selected", selected);
if (selected.equals("0")) {
saveToPrefs("en");
LocaleHelper.setLocale(SettingsPrefActivity.this, "en");
listPreference.setSummary("English");
listPreference.setValueIndex(0);
recreate();
} else if (selected.equals("1")) {
saveToPrefs("ru");
LocaleHelper.setLocale(SettingsPrefActivity.this, "ru");
listPreference.setSummary("Russia");
listPreference.setValueIndex(1);
recreate();
} else if (selected.equals("2")) {
saveToPrefs("uz");
LocaleHelper.setLocale(SettingsPrefActivity.this, "uz");
listPreference.setSummary("Uzbek");
listPreference.setValueIndex(2);
recreate();
}
return true;
}
});
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(LocaleHelper.onAttach(newBase));
}
主活动此代码在创建更改应用程序语言之前调用
String languageCode = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("Language", "en");
if (languageCode.equals("1")) languageCode = "ru";
else if (languageCode.equals("2")) languageCode = "uz";
LocaleHelper.setLocale(TopActivity.this, languageCode);
还创建了一个扩展应用程序的单独类并添加到清单应用程序名称
公共类主页扩展应用程序{
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocaleHelper.onAttach(base,"en"));
}
}
解决方案
我希望你可能参观过这个。好吧,您在每个活动中必须做的一件事就是覆盖下面的方法。在 About Activity 中,只需输入以下代码并查看输出:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocaleHelper.onAttach(base));
}
您可以使用此示例代码以获得更好的清晰度。
设置活动应该设置当前语言。
public class SettingsActivity extends AppCompatActivity {
Spinner spinner;
Locale myLocale;
String currentLanguage = "en", currentLang;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocaleHelper.onAttach(base));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
currentLanguage = getIntent().getStringExtra(currentLang);
findViewById(R.id.nextBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent refresh = new Intent(SettingsActivity.this, ViewPagerActivity.class);
refresh.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(refresh);
}
});
spinner = findViewById(R.id.spinner);
List<String> list = new ArrayList<String>();
list.add("Select language");
list.add("English");
list.add("Bengali");
list.add("German");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
switch (position) {
case 0:
break;
case 1:
setLocale("en");
break;
case 2:
setLocale("bn");
break;
case 3:
setLocale("de");
break;
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
public void setLocale(String localeName) {
if (!localeName.equals(currentLanguage)) {
Context context = LocaleHelper.setLocale(this, localeName);
//Resources resources = context.getResources();
myLocale = new Locale(localeName);
Resources res = context.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
Intent refresh = new Intent(this, SettingsActivity.class);
refresh.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
refresh.putExtra(currentLang, localeName);
startActivity(refresh);
} else {
Toast.makeText(this, "Language already selected!", Toast.LENGTH_SHORT).show();
}
}
}
现在我想转移到其他活动,看看语言是否已更改。假设我搬到 ViewPagerActivity。
public class ViewPagerActivity extends AppCompatActivity {
@Override
public void attachBaseContext(Context context){
super.attachBaseContext(LocaleHelper.onAttach(context));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_pager);
ViewPager viewPager = findViewById(R.id.viewPager);
viewPager.setAdapter(new CustomPagerAdapter(this));
}
public enum ModelObject {
RED(R.string.menu_home, R.layout.fragment_home),
BLUE(R.string.menu_gallery, R.layout.fragment_gallery),
GREEN(R.string.menu_slideshow, R.layout.fragment_slideshow);
private int mTitleResId;
private int mLayoutResId;
ModelObject(int titleResId, int layoutResId) {
mTitleResId = titleResId;
mLayoutResId = layoutResId;
}
public int getTitleResId() {
return mTitleResId;
}
public int getLayoutResId() {
return mLayoutResId;
}
}
class CustomPagerAdapter extends PagerAdapter{
private Context mContext;
public CustomPagerAdapter(Context context) {
mContext = context;
}
@Override
public Object instantiateItem(ViewGroup collection, int position) {
ModelObject modelObject = ModelObject.values()[position];
LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup layout = (ViewGroup) inflater.inflate(modelObject.getLayoutResId(), collection, false);
collection.addView(layout);
return layout;
}
@Override
public void destroyItem(ViewGroup collection, int position, Object view) {
collection.removeView((View) view);
}
@Override
public int getCount() {
return ModelObject.values().length;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public CharSequence getPageTitle(int position) {
ModelObject customPagerEnum = ModelObject.values()[position];
return mContext.getString(customPagerEnum.getTitleResId());
}
}
}
设置活动 xml 代码:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SettingsActivity">
<Button
android:id="@+id/nextBtn"
android:text="Go to Next Activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/common_text"
android:textSize="25sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/spinner" />
</androidx.constraintlayout.widget.ConstraintLayout>
我没有将 ViewPager Activity xml 放在这里,因为那里没有什么重要的东西可以使用 1 View Pager 创建它的 xml。现在我想在 View Pager 适配器中包含的 3 个片段中显示翻译文本。我们一个接一个地看: 一、fragment_home.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.HomeFragment">
<TextView
android:id="@+id/text_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
android:text="@string/menu_home"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
第二,fragment_gallery.xml :这与上面的布局类似,但只有文本更改如下
android:text="@string/menu_gallery"
二、fragment_slideshow.xml :这与上面的布局类似,但只有文本更改如下
android:text="@string/menu_slideshow"
重要提示:只有那些字符串将显示为在字符串资源中定义的翻译文本。并且名称必须在每个语言文件夹中匹配。对于英语,strings.xml 文件看起来像
<string name="common_text">I Love Programming. Learning new language and developing android apps is one of my hubby.</string>
<string name="menu_home">Home</string>
<string name="menu_gallery">Gallery</string>
<string name="menu_slideshow">Slideshow</string>
对于孟加拉语,strings.xml 文件看起来像: 在此处标记名称都相同,否则翻译将不会显示。
<string name="common_text">আমি প্রোগ্রামিং ভালবাসি। নতুন ভাষা শেখা এবং অ্যান্ড্রয়েড অ্যাপ্লিকেশন বিকাশ করা আমার এক অন্যতম অভ্যাস।</string>
<string name="menu_home">বাড়ি</string>
<string name="menu_gallery">গ্যালারী</string>
<string name="menu_slideshow">স্লাইডশো</string>
对于德语,strings.xml 看起来像:
<string name="menu_home">Zuhause</string>
<string name="menu_gallery">Galerie</string>
<string name="menu_slideshow">Diashow</string>
<string name="common_text">Ich liebe das Programmieren. Das Erlernen einer neuen Sprache und das Entwickeln von Android-Apps ist einer meiner Ehemänner.</string>
重要提示:每当您进入设置活动时,请确保从设置活动启动的任何活动都必须有@Override public void attachBaseContext(Context context){ super.attachBaseContext(LocaleHelper.onAttach(context)); }
方法。因为这个方法是在onCreate()之前调用的。另一种情况可能是,如果您从一个活动启动设置活动,并且当您从设置活动返回到以前的活动时想要翻译,那么您必须启动以前的活动。您可以通过调用getCallingActivity().getClass()
Like 来了解哪个 Activity 启动了 Settings Activity:
@Override
public void onBackPressed(){
Intent previousActivity = new Intent(this,
getCallingActivity().getClass());
previousActivity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(previousActivity);
finish();
}
推荐阅读
- mysql - groupBy('created_at') 在 laravel eloquent 中使用子查询
- java - 想要在运行时 java 中动态传递 class.getmethod 参数
- chicken-scheme - 编译使用鸡蛋的文件
- amazon-ec2 - 无法解析 ec2 实例上的主机
- java - 如何使用 Eclipse 将数据插入 Google Cloud mysql 数据库
- templates - Golang模板从字符串数组生成值错误
- javascript - 带有 Javascript 的两列表
- javascript - jQuery没有正确地将类添加到元素
- java - 使用 shiro 的多个身份验证过滤器
- vue.js - Vue - 为什么我不能在 vuex 中显示我的 axios get 请求的结果?