Android国际化多语言切换

Posted 自由渴望

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android国际化多语言切换相关的知识,希望对你有一定的参考价值。

关于App国际化,之前有讲到国际化资源、字符换、布局相关,想要了解的猛戳用力抱一下APP国际化。借着本次重构多语言想跟大家聊一下多语言切换,多语言切换对于一款国际化App来讲是重中之重,并非难事,但是若要做好也是一件不容易的事情。

问题

  1. android N版本适配问题
  2. AndroidX不同版本兼容问题
  3. 一些界面局部适配突然失效
  4. 切换系统导航,更改深色模式导致多语言无法适配
  5. 系统授权弹窗导致ApplicationContext中的Local被还原
  6. 切换语言,系统通知栏显示未翻译,重启后正常
  7. Service服务中Toast不适配
  8. 系统Local.getDefault()之伤,如何正确获取系统当前语言
  9. WebView第一次加载多语言不适配
  10. 系统广播中的获取context中的Local信息显示异常

上面我随手列出了项目中常见遇到的问题,有一些是随着Android版本升级而未做出相应兼容性调整造成的,有一些则是局部失效寻找原因所得。我们先了解下应用中一般多语言切换适配的方案,从中会提到这些问题相应的解决方案。

Andorid 13 语言偏好设置

最近Android 13发布了,讲多语言切换之前,我们先了解一下这个新平台多语言新特性。Android 13 在手机设置页面中新增了一个集中设置应用语言的选项,用于设置各个应用语言首选语言,如果你的应用存在多语言,谷歌强烈建议在设置中进行多语言切换,这样就无须在应用中去做多语言选择切换的功能,页面由设置中的应用语言界面统一管理,具体使用如下:

1. 如何让应用app显示在设置中的应用语言中

  • 创建一个名为 res/xml/locales_config.xml 的文件,并指定您的应用的语言,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
   <locale android:name="ja"/>
   <locale android:name="fr"/>
   <locale android:name="en"/>
</locale-config>
  • 在清单中,添加一行指向这个新文件的代码:
<manifest
    ...
    <application
        ...
        android:localeConfig="@xml/locales_config">
    </application>
</manifest>

2. 如何处理设置中的语言偏好

对于具有或想要使用应用内语言选择器的应用,请使用这些新 API(而非自定义应用逻辑)来处理相关设置和获取用户对应用的首选语言设置。

// 如需设置用户的首选语言,您需要让用户在语言选择器中选择语言区域,然后在系统中设置该值
LocaleListCompat appLocale = LocaleListCompat.forLanguageTags("xx-YY");
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale);
  • 使用 Android 框架 API 来实现
// 1. Inside an activity, in-app language picker gets an input locale "xx-YY"
// 2. App calls the API to set its locale
mContext.getSystemService(LocaleManager.class).setApplicationLocales(newLocaleList(Locale.forLanguageTag("xx-YY")));
// 3. The system updates the locale and restarts the app, including any configuration updates
// 4. The app is now displayed in "xx-YY" language
  • 获取用户当前的首选语言
// 1. App calls the API to get the preferred locale
LocaleList currentAppLocales =
    mContext.getSystemService(LocaleManager.class).getApplicationLocales();
// 2. App uses the returned LocaleList to display languages to the user

举个栗子,手机系统如果是中文,设置界面中的应用语言如果首选英文,app如果已启动,那么需要自己监听 onConfigurationChanged来切换应用内部语言,如果未启动,第一次启动时候需要先去读取设置中的语言然后设置给当前应用。亦或是如果你的应用保留了内部切换语言的方案,那么语言切换是也应该调用以上API把当前语言刷到系统设置应用语言中,以保持同步。

讲完Andorid 13 多语言新特性,想要了解更多猛戳,我们继续回到本文的重点,应用内多语言切换如何去做适配。

多语言适配整体部分

1. Application的适配

我们为什么要适配Application,原因很简单,对于多语言来讲,我们其实最关心的是切换语言后,界面或者Toast等等显示是否已经翻译成所选择的语言,但是一般我们项目中都会直接或者间接用到ApplicationContext,比如Application中一些三方控件的初始化,还有一些项目中封装的工具类,为了方便全局一次行初始化,有可能甚至用到单例模式,当我们用到ApplicationContxt去getString(@StringRes int id),在切换语言后,如果不重启整个应用或者刷新ApplicaitonContext的local,那么肯定是无效的。
我们在启动APP时候,应该对Application中的context进行当前应用语言Local适配。

@Override
protected void attachBaseContext(Context newBase) 
    super.attachBaseContext(LanguageUtil.attachBaseContext(newBase));

当我们做了系统的配置更改,比如说切换了系统导航或者说更改了深色模式,那么我们一般的处理是也是要对Application作出处理。

@Override
public void onConfigurationChanged(Configuration newConfig) 
    super.onConfigurationChanged(newConfig);
    // 系统资源配置发生更改,例如主题模式,需要重新刷新多语言
    LanguageUtil.attachBaseContext(this);

如果项目中有用到ApplicationContext去getString(@StringRes int id)实现加载的提示语,那么如果只是单纯的重启界面则无法让当前的提示语跟随当前切换的语言,所以我们要么重启整个应用,要么对ApplicationContext中的Local也作出相应的更新方可,这里有一点问题,虽然Android N之后updateConfiguration是过时方法,官方给出使用createConfigurationContext代替,但是更新ApplicationContext的Local发现无效使用老版本updateConfiguration正常。

Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale locale = getLanguageLocale(newLanguage);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
    // apply locale
    configuration.setLocales(new LocaleList(locale));
 else 
    configuration.setLocale(locale);

DisplayMetrics dm = resources.getDisplayMetrics();
resources.updateConfiguration(configuration, dm);

如果你发现你的应用广播通知栏适配无效,那就是context中的Local在切换语言是并未及时更新Local,这里调试一下便知,如果是Applicaiton注册的广播,那么多半情况下是没有更新ApplicationContext的Local所导致的。

2. Service适配

如果你的Service有用到Toast提示或者UI相关的东西,你必须要对Service也进行适配,这时候Service中也需要重写attachBaseContext进行语言适配,否则语言适配也是无效的。

@Override
protected void attachBaseContext(Context newBase) 
    super.attachBaseContext(LanguageUtil.getNewLocalContext(newBase));

3. Activity适配

Activity是我们最主要的适配的界面,正常的情况下我们直接在基类BaseActivity中去处理即可,但是值得注意的一点是如果我们使用的是Androidx而非support库,那么不同的版本适配有点区别,这也是官方组件的问题.记得一些第三方界面如果不是继承我们的BaseActivity需要单独处理即可。

@Override
protected void attachBaseContext(Context newBase) 
    if(isSupportMultiLanguage())
        // 多语言适配
        super.attachBaseContext(LanguageUtil.getNewLocalContext(newBase));
    else 
        super.attachBaseContext(newBase);
    

多语言适配基本步骤大概就是如此了,下面看一下适配的细节问题。

适配部分细节

1. Andorid N 适配

Android N开始,由于系统的API变更,updateConfiguration已经被沦为过时的方法。但是有一点需要大家注意,网上几乎全部的判断都是有问题的,API已经明确说明是在API25过时的,不等价于Build.VERSION_CODES.N,所以你的项目用对了嘛,详情可参考下图。

还有一点Android N之后,手机系统的语言配置选项已经不是单选了,改为一个列表了,具体可以参考手机设置中的语言和输入法,所以setLocal(@Nullable Locale loc)方法建议不要再使用了,我相信很多人还在用,正确的用法应该是setLocals(@Nullable LocaleList locales),需要传递一个集合。

public static Context attachBaseContext(Context context) 
    String language = LanguageSp.getLanguage(context);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) 
        return createConfigurationContext(context, language);
     else 
        return updateConfiguration(context, language);
    

// 注意此处不是Build.VERSION_CODES.N
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
private static Context createConfigurationContext(Context context, String language) 
    Resources resources = context.getResources();
    Configuration configuration = resources.getConfiguration();
    Locale locale = getLanguageLocale(language);
    Log.d(TAG, "current Language locale = " + locale);
    LocaleList localeList = new LocaleList(locale);
    // 注意此处setLocales
    configuration.setLocales(localeList);
    return context.createConfigurationContext(configuration);

private static Context updateConfiguration(Context context, String language) 
    Resources resources = context.getResources();
    Configuration configuration = resources.getConfiguration();
    Locale locale = getLanguageLocale(language);
    Log.e(TAG, "updateLocalApiLow==== " + locale.getLanguage());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
        // apply locale 注意此处是setLocales
        configuration.setLocales(new LocaleList(locale));
     else 
        // updateConfiguration
        configuration.locale = locale;
        DisplayMetrics dm = resources.getDisplayMetrics();
        resources.updateConfiguration(configuration, dm);
    
    return context;

2. 关于AndroidX版本兼容问题

当你的应用使用的是androidx.appcompat:appcompat:1.1.0时,BaseActivity中需要实现下面方法。

@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration) 
    // 兼容androidX在部分手机切换语言失败问题
    if (overrideConfiguration != null) 
        int uiMode = overrideConfiguration.uiMode;
        overrideConfiguration.setTo(getBaseContext().getResources().getConfiguration());
        overrideConfiguration.uiMode = uiMode;
    
    super.applyOverrideConfiguration(overrideConfiguration);

当你的应用使用的是androidx.appcompat:appcompat:1.2.0及以上时,BaseActivity中需要实现下面方法。

@Override
protected void attachBaseContext(Context newBase) 
    if (isSupportMultiLanguage()) 
        String language = LanguageSp.getLanguage(newBase);
        Context context = LanguageUtil.attachBaseContext(newBase, language);
        final Configuration configuration = context.getResources().getConfiguration();
        final ContextThemeWrapper wrappedContext = new ContextThemeWrapper(context,
            R.style.Theme_AppCompat_Empty) 
            @Override
            public void applyOverrideConfiguration(Configuration overrideConfiguration) 
                if (overrideConfiguration != null) 
                    overrideConfiguration.setTo(configuration);
                
                super.applyOverrideConfiguration(overrideConfiguration);
            
        ;
        super.attachBaseContext(wrappedContext);
     else 
        super.attachBaseContext(newBase);
    

3. 系统授权弹框导致Local失效

我们惊奇的发现,当我们首次进入APP选择语言后,当首页检查系统权限弹框的时候,Local被莫名其妙的重置了,我在想,可能因为google授权弹框他有自己的多语言翻译,所以不会采取我们的,所以把ApplicationContext中的Local给重置了,所以当我们点击允许或者仅在使用此应用时允许后需要再次把Application中的Local修改掉。

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) 
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    // 更新Application中的local
    LanguageUtil.updateApplicationLocale(AppApplication.getAppContext(),LanguageSp.getLanguage(mContext))

4. 如何真正的获取系统语言

我们有可能会存在这个场景,当我们的APP不跟随系统语言的时候,使用的APP内部语言,我们去检测系统语言的时候如何去判断,是不是很多人在此跌倒了,无论是Local.getDefault()还是LocalList.get(0)始终获取的语言是错误的,应该通过以下渠道获取当前的系统语言。

// 第一种方式
if (Build.VERSION.SDK_INT  >= Build.VERSION_CODES.N) 
return Resources.getSystem().getConfiguration().getLocales().get(0).getLanguage();//解决了获取系统默认错误的问题
 else 
return Locale.getDefault().getLanguage();

// 第二种方式(推荐)
return ConfigurationCompat.getLocales(Resources.getSystem().getConfiguration()).get(0).getLanguage();

5. 关于WebView适配

在原来的低版本切换语言中,我们会发现WebView第一次加载时,适配是无效的,再次加载则正常适配,所以网上也有了一道方案如下:

@Override public void onCreate(Bundle savedInstanceState)  
// TODO 解决含有webView控件导致切换语言失效 
~~new WebView(this).destroy(); ~~
super.onCreate(savedInstanceState); 

这套方案目前不在推荐,直接去替换attatchBaseContext()中的context则可,经过测试是完全正常的。

工具类

以下则是多语言操作的工具类,现在提供出来,需要的朋友可以自行进行改造。

/**
 * @author : le.hu
 * e-mail : 暂无
 * time   : 2021/11/26/16:08
 * desc   : 多语言适配方案,适配各种版本,核心未替换上下文Context中的Local
 */
public class LanguageUtil 

    private static final String TAG = "LanguageUtil";

    /**
     * 默认支持的语言,英语、法语、阿拉伯语
     */
    private static HashMap<String, Locale> supportLanguage = new HashMap<String, Locale>(4) 
        put(Language.ENGLISH, Locale.ENGLISH);
        put(Language.FRANCE, Locale.FRANCE);
        put(Language.ARABIC, new Locale("ar", "", ""));
    ;

    /**
     * 应用多语言切换,重写BaseActivity中的attachBaseContext即可
     * 采用本地SP存储的语言
     *
     * @param context 上下文
     * @return context
     */
    public static Context attachBaseContext(Context context) 
        String language = LanguageSp.getLanguage(context);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) 
            return createConfigurationContext(context, language);
         else 
            return updateConfiguration(context, language);
        
    

    /**
     * 应用多语言切换,重写BaseActivity中的attachBaseContext即可
     *
     * @param context  上下文
     * @param language 语言
     * @return context
     */
    public static Context attachBaseContext(Context context, String language) 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) 
            return createConfigurationContext(context, language);
         else 
            return updateConfiguration(context, language);
        
    

    /**
     * 获取Local,根据language
     *
     * @param language 语言
     * @return Locale
     */
    private static Locale getLanguageLocale(String language) 
        if (supportLanguage.containsKey(language)) 
            return supportLanguage.get(language);
         else 
            Locale systemLocal = getSystemLocal();
            for (String languageKey : supportLanguage.keySet()) 
                if (TextUtils.equals(supportLanguage.get(languageKey).getLanguage(), systemLocal.getLanguage())) 
                    return systemLocal;
                
            
        
        return Locale.ENGLISH;
    

    /**
     * 获取当前的Local,默认英语
     *
     * @param context context
     * @return Locale
     */
    public static Locale getCurrentLocale(Context context) 
        String language = LanguageSp.getLanguage(context);
        if (supportLanguage.containsKey(language)) 
            return supportLanguage.get(language);
         else 
            Locale systemLocal = getSystemLocal();
            for (String languageKey : supportLanguage.keySet()) 
                if (TextUtils.equals(supportLanguage.get(languageKey).getLanguage(), systemLocal.getLanguage())) 
                    return systemLocal;
                
            
        
        return Locale.ENGLISH;
    

    /**
     * 获取系统的Local
     *
     * @return Locale
     */
    private static Locale getSystemLocal() 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
            return Resources.getSystem().getConfiguration().getLocales().get(0);
         else 
            return Locale.getDefault();
        
    

    /**
     * Android 7.1 以下通过 updateConfiguration
     *
     * @param context  context
     * @param language 语言
     * @return Context
     */
    private static Context updateConfiguration(Context context, String language) 
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        Locale locale = getLanguageLocale(language);
        Log.e(TAG, "updateLocalApiLow==== " + locale.getLanguage());
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
            // apply locale
            configuration.setLocales(new LocaleList(locale));
         else 
            // updateConfiguration
            configuration.locale = locale;
            DisplayMetrics dm = resources.getDisplayMetrics();
            resources.updateConfiguration(configuration, dm);
        
        return context;
    

    /**
     * Android 7.1以上通过createConfigurationContext
     * N增加了通过config.setLocales去修改多语言
     *
     * @param context  上下文
     * @param language 语言
     * @return context
     */
    @RequiresApi(api = Build.VERSION_CODES.N_MR1)
    private static Context createConfigurationContext(Context context, String language) 
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        Locale locale = getLanguageLocale(language);
        Log.d(TAG, "current Language locale = " + locale);
        LocaleList localeList = new LocaleList(locale);
        configuration.setLocales(localeList);
        return context.createConfigurationContext(configuration);
    

    /**
     * 切换语言
     *
     * @param language 语言
     * @param activity 当前界面
     * @param cls      跳转的界面
     */
    public static void switchLanguage(String language, Activity activity, Class<?> cls) 
        LanguageSp.setLanguage(activity, language);
        Intent intent = new Intent(activity, cls);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        activity.startActivity(intent);
        activity.finish();
    

    /**
     * 切换语言,携带传递数据
     *
     * @param language 语言
     * @param activity 当前界面
     * @param cls      跳转的界面
     */
    public static void switchLanguage(String language, Activity activity, Class<?> cls, Bundle bundle) 
        LanguageSp.setLanguage(activity, language);
        Intent intent = new Intent(activity, cls);
        if (bundle != null) 
            intent.putExtras(bundle);
        
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        activity.startActivity(intent);
        activity.finish();
    

    /**
     * 获取新语言的 Context,修复了androidx.appCompact 1.2.0的问题
     *
     * @param newBase newBase
     * @return Context
     */
    public static Context getNewLocalContext(Context newBase) 
        try 
            // 多语言适配
            Context context = LanguageUtil.attachBaseContext(newBase);
            // 兼容appcompat 1.2.0后切换语言失效问题
            final Configuration configuration = context.getResources().getConfiguration();
            return new ContextThemeWrapper(context, R.style.Theme_AppCompat_Empty) 
                @Override
                public void applyOverrideConfiguration(Configuration overrideConfiguration) 
                    if (overrideConfiguration != null) 
                        overrideConfiguration.setTo(configuration);
                    
                    super.applyOverrideConfiguration(overrideConfiguration);
                
            ;
         catch (Exception e) 
            e.printStackTrace();
        
        return newBase;
    

    /**
     *  更新Application的Resource local,应用不重启的情况才调用,因为部分会用到application中的context
     *  切记不能走新api createConfigurationContext,亲测
     * @param context context
     * @param newLanguage newLanguage
     */
    public static void updateApplicationLocale(Context context, String newLanguage) 
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        Locale locale = getLanguageLocale(newLanguage);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
            // apply locale
            configuration.setLocales(new LocaleList(locale));
         else 
            configuration.setLocale(locale);
        
        DisplayMetrics dm = resources.getDisplayMetrics();
        resources.updateConfiguration(configuration, dm);
    

Android 产品研发-->实现国际化(多语言)

简介

最近工作中突然要求要项目进行国际化,之前没遇到过。但是也很简单呀,只需要把添加一个相应语言的的 strings.xml 的资源文件就好了,不是吗?这样只要切换系统语言就能切换 app 的文字语言了。

效果图

实现

1. 创建对应语言的 string.xml 简体中文,繁体和 English 三个语言。

2. MultiLanguage.java

/**
 * Created on 2021/11/10 17:02
 *
 * @author Gong Youqiang
 */
public class MultiLanguage 
    private static LanguageListener languageLocalListener;

    public static void init(LanguageListener listener) 
        languageLocalListener = listener;
    

    public static Context setLocal(Context context) 
        return updateResources(context, getSetLanguageLocale(context));
    


    /**
     * 设置语言类型
     */
    public static void setApplicationLanguage(Context context) 
        Resources resources = context.getApplicationContext().getResources();
        DisplayMetrics dm = resources.getDisplayMetrics();
        Configuration config = resources.getConfiguration();
        Locale locale = getSetLanguageLocale(context);
        config.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
            LocaleList localeList = new LocaleList(locale);
            LocaleList.setDefault(localeList);
            config.setLocales(localeList);
            context.getApplicationContext().createConfigurationContext(config);
            Locale.setDefault(locale);
        
        resources.updateConfiguration(config, dm);
    


    /**
     * @param context
     */
    public static void onConfigurationChanged(Context context) 
        setLocal(context);
        setApplicationLanguage(context);
    


    /**
     * 获取选择的语言
     *
     * @param context
     * @return
     */
    private static Locale getSetLanguageLocale(Context context) 
        if (languageLocalListener != null) 
            return languageLocalListener.getSetLanguageLocale(context);
        
        return Locale.ENGLISH;
    

    /**
     * 更新语言设置
     *
     * @param context
     * @param locale
     * @return
     */
    private static Context updateResources(Context context, Locale locale) 
        Locale.setDefault(locale);

        Resources res = context.getResources();
        Configuration config = new Configuration(res.getConfiguration());
        if (Build.VERSION.SDK_INT >= 17) 
            config.setLocale(locale);
            context = context.createConfigurationContext(config);
         else 
            config.locale = locale;
            res.updateConfiguration(config, res.getDisplayMetrics());
        
        return context;
    

    /**
     * 获取系统语言
     * @param newConfig
     * @return
     */
    public static Locale getSystemLocal(Configuration newConfig) 
        Locale locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
            locale = newConfig.getLocales().get(0);
         else 
            locale = newConfig.locale;
        
        return locale;
    

    /**
     * 获取系统语言
     * @param context
     * @return
     */
    public static Locale getSystemLocal(Context context) 
        Locale locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
            locale = LocaleList.getDefault().get(0);
         else 
            locale = Locale.getDefault();
        
        return locale;
    

3. SPUtil.java

/**
 * Created on 2021/11/10 17:04
 *
 * @author Gong Youqiang
 */
public class SPUtil 
    private final String SP_NAME = "language_setting";
    private final String TAG_LANGUAGE = "language_select";
    private final String TAG_SYSTEM_LANGUAGE = "system_language";
    private static volatile SPUtil instance;

    private final SharedPreferences mSharedPreferences;

    private Locale systemCurrentLocal = Locale.ENGLISH;


    public SPUtil(Context context) 
        mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
    


    public void saveLanguage(int select) 
        SharedPreferences.Editor edit = mSharedPreferences.edit();
        edit.putInt(TAG_LANGUAGE, select);
        edit.commit();
    

    public int getSelectLanguage() 
        return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
    


    public Locale getSystemCurrentLocal() 
        return systemCurrentLocal;
    

    public void setSystemCurrentLocal(Locale local) 
        systemCurrentLocal = local;
    

    public static SPUtil getInstance(Context context) 
        if (instance == null) 
            synchronized (SPUtil.class) 
                if (instance == null) 
                    instance = new SPUtil(context);
                
            
        
        return instance;
    

4. LanguageUtils.java

/**
 * Created on 2021/11/10 16:50
 *
 * @author Gong Youqiang
 */
public class LanguageUtils 
    private static final String TAG = "LocalManageUtil";

    /**
     * 获取系统的locale
     *
     * @return Locale对象
     */
    public static Locale getSystemLocale(Context context) 
        return SPUtil.getInstance(context).getSystemCurrentLocal();
    

    public static String getSelectLanguage(Context context) 
        switch (SPUtil.getInstance(context).getSelectLanguage()) 
            case 0:
                return context.getString(R.string.language_auto);
            case 1:
                return context.getString(R.string.language_cn);
            case 2:
                return context.getString(R.string.language_traditional);
            case 3:
            default:
                return context.getString(R.string.language_en);
        
    

    /**
     * 获取选择的语言设置
     *
     * @param context
     * @return
     */
    public static Locale getSetLanguageLocale(Context context) 

        switch (SPUtil.getInstance(context).getSelectLanguage()) 
            case 0:
                return getSystemLocale(context);
            case 1:
                return Locale.CHINA;
            case 2:
                return Locale.TAIWAN;
            case 3:
            default:
                return Locale.ENGLISH;
        
    


    public static void saveSystemCurrentLanguage(Context context) 
        SPUtil.getInstance(context).setSystemCurrentLocal(MultiLanguage.getSystemLocal(context));
    

    /**
     * 保存系统语言
     * @param context
     * @param newConfig
     */
    public static void saveSystemCurrentLanguage(Context context, Configuration newConfig) 

        SPUtil.getInstance(context).setSystemCurrentLocal(MultiLanguage.getSystemLocal(newConfig));
    

    public static void saveSelectLanguage(Context context, int select) 
        SPUtil.getInstance(context).saveLanguage(select);
        MultiLanguage.setApplicationLanguage(context);
    

5. LanguageListener.java

/**
 * Created on 2021/11/10 16:49
 *
 * @author Gong Youqiang
 */
public interface LanguageListener 
    /**
     * 获取选择设置语言
     *
     * @param context
     * @return
     */
    Locale getSetLanguageLocale(Context context);

  1. LauncherApp.java
/**
 * Created on 2021/11/10 17:01
 *
 * @author Gong Youqiang
 */
public class LauncherApp extends Application 
    @Override
    protected void attachBaseContext(Context base) 
        //第一次进入app时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了)
        LanguageUtils.saveSystemCurrentLanguage(base);
        super.attachBaseContext(MultiLanguage.setLocal(base));
    

    @Override
    public void onConfigurationChanged(Configuration newConfig) 
        super.onConfigurationChanged(newConfig);
        //用户在系统设置页面切换语言时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了)
        LanguageUtils.saveSystemCurrentLanguage(getApplicationContext(), newConfig);
        MultiLanguage.onConfigurationChanged(getApplicationContext());
    

    @Override
    public void onCreate() 
        super.onCreate();
        MultiLanguage.init(new LanguageListener() 
            @Override
            public Locale getSetLanguageLocale(Context context) 
                //返回自己本地保存选择的语言设置
                return LanguageUtils.getSetLanguageLocale(context);
            
        );
        MultiLanguage.setApplicationLanguage(this);
    

7. 布局文件

<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=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

若觉得对您有帮助,您的赞是我最大的动力!

在线转换工具:中文转繁体

以上是关于Android国际化多语言切换的主要内容,如果未能解决你的问题,请参考以下文章

Android:应用多语言切换,国际化实现

Android 产品研发-->实现国际化(多语言)

Android 实现应用内语言切换(包括不重启应用方式)

Android国际化之多语言(配置及应用内设置)✈️

Android 内多语言切换实现

android国家化(多语言版本APP)