首页 > 解决方案 > 在 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"));
}

}

标签: androidlocalizationresources

解决方案


我希望你可能参观过这个。好吧,您在每个活动中必须做的一件事就是覆盖下面的方法。在 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">আমি প্রোগ্রামিং ভালবাসি। নতুন ভাষা শেখা এবং অ্যান্ড্রয়েড অ্যাপ্লিকেশন বিকাশ করা আমার এক অন্যতম অভ্যাস।&lt;/string>
<string name="menu_home">বাড়ি&lt;/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();
  }

推荐阅读