Android应用内切换语言

添加多语言文件

在不同的 value文件夹下(例如value 、value-en、values-zh-rCN、values-zh-rTW、value-th 文件夹)添加不同语言的 string.xml

对于Android 7.0及以下版本

Android 7.0及以前版本,Configuration中的语言相当于是App的全局设置:

/**
 * @param context
 * @param newLanguage 想要切换的语言类型 比如 "en" ,"zh"
 */
@SuppressWarnings("deprecation")
public static void changeAppLanguage(Context context, String newLanguage) {
    if (TextUtils.isEmpty(newLanguage)) {
        return;
    }

    Resources resources = context.getResources();
    Configuration configuration = resources.getConfiguration();

    // app locale
    //获取想要切换的语言类型
    Locale locale = getLocaleByLanguage(newLanguage);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        configuration.setLocale(locale);
    } else {
        configuration.locale = locale;
    }

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

然后在继承Application的类中调用更换语言的方法即可:

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        //对于7.0以下,需要在Application创建的时候进行语言切换
        onLanguageChange();
    }

    /**
     * Handling Configuration Changes
     * @param newConfig newConfig
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        onLanguageChange();
    }

    private void onLanguageChange() {
        String language = SpUtil.getInstance(this).getString(SpUtil.LANGUAGE); //读取App配置
        if (TextUtils.isEmpty(language)) {
            language = SettingUtil.getLanguage();
        }
        LanguageUtils.changeAppLanguage(this, language);
    }
}

经过上面的操作就可以在7.0以下实现应用内切换语言

对于Android 7.0及以上版本

Android 7.0及之后版本,使用了LocaleListConfiguration中的语言设置可能获取的不同,而是生效于各自的Context。这会导致:Android 7.0使用旧的方式,有些Activity可能会显示为手机的系统语言

Android 7.0优化了对多语言的支持,废弃了updateConfiguration()方法,替代方法:createConfigurationContext(),而返回的是Context。也就是语言需要植入到Context中,每个Context都植入一遍

(1)定义一个BaseActivity,重写attachBaseContext方法,在此方法里进行语言切换

public class BaseActivity extends AppCompatActivity {

    /**
     * 此方法先于 onCreate()方法执行
     * @param newBase
     */
    @Override
    protected void attachBaseContext(Context newBase) {
        //获取我们存储的语言环境 比如 "en","zh"等等
        String language = SpUtil.getInstance(App.getContext()).getString(SpUtil.LANGUAGE);
        //attach 对应语言环境下的context
        super.attachBaseContext(LanguageUtils.attachBaseContext(newBase, language));
    }
}

(2)LanguageUtils中的attachBaseContext()方法

public static Context attachBaseContext(Context context, String language) {
    Log.d(TAG, "attachBaseContext: "+Build.VERSION.SDK_INT);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResources(context, language);
    } else {
        return context;
    }
}

@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, String language) {
    Resources resources = context.getResources();
    Locale locale = LanguageUtils.getLocaleByLanguage(language);

    Configuration configuration = resources.getConfiguration();
    configuration.setLocale(locale);
    configuration.setLocales(new LocaleList(locale));
    return context.createConfigurationContext(configuration);
}

attachBaseContext()方法中,我们判断一下,如果当前api大于24,那么就调用updateResources()方法更新context

定义好BaseActivity以后,我们只需要让所有的Activity都继承这个基类即可

手动切换语言

定义一个ChangeLanguageActivity

public void onClick(View view) {
    String language = null;
    switch (view.getId()) {
        case R.id.btn_chinese:
            //切换为简体中文
            language = LanguageType.CHINESE.getLanguage();
            break;
        case R.id.btn_english:
            //切换为英语
            language = LanguageType.ENGLISH.getLanguage();
            break;
        case R.id.btn_thailand:
            //切换为泰语
            language = LanguageType.THAILAND.getLanguage();
            break;
        default:
            break;
    }
    changeLanguage(language);
}

private void changeLanguage(String language) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
        LanguageUtils.changeAppLanguage(getApplicationContext(), language);
    } else {
        LanguageUtils.changeAppLanguage(this, newLanguage);
    }
    SpUtil.getInstance(this).putString(SpUtil.LANGUAGE, language);

    recreate();
    ActivityUtil.getInstance().recreateAllOtherActivity(this);
}

如果控件尺寸固定,当切换语言的时候,文字长短发生变化如何解决?

可以使用google提供的新特性来解决:Autosizing TextViews

代码封装

(1)创建工具类

public class AppLanguageUtils {

    public static HashMap<String, Locale> mAllLanguages = new HashMap<String, Locale>(8) {{
        put(Constants.ENGLISH, Locale.ENGLISH);
        put(Constants.CHINESE, Locale.SIMPLIFIED_CHINESE);
        put(Constants.SIMPLIFIED_CHINESE, Locale.SIMPLIFIED_CHINESE);
        put(Constants.TRADITIONAL_CHINESE, Locale.TRADITIONAL_CHINESE);
        put(Constants.FRANCE, Locale.FRANCE);
        put(Constants.GERMAN, Locale.GERMANY);
        put(Constants.HINDI, new Locale(Constants.HINDI, "IN"));
        put(Constants.ITALIAN, Locale.ITALY);
    }};

    @SuppressWarnings("deprecation")
    public static void changeAppLanguage(Context context, String newLanguage) {
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();

        // app locale
        Locale locale = getLocaleByLanguage(newLanguage);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLocale(locale);
        } else {
            configuration.locale = locale;
        }

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

    private static boolean isSupportLanguage(String language) {
        return mAllLanguages.containsKey(language);
    }

    public static String getSupportLanguage(String language) {
        if (isSupportLanguage(language)) {
            return language;
        }

        if (null == language) {//为空则表示首次安装或未选择过语言,获取系统默认语言
            Locale locale = Locale.getDefault();
            for (String key : mAllLanguages.keySet()) {
                if (TextUtils.equals(mAllLanguages.get(key).getLanguage(), locale.getLanguage())) {
                    return locale.getLanguage();
                }
            }
        }
        return Constants.ENGLISH;
    }

    /**
     * 获取指定语言的locale信息,如果指定语言不存在{@link #mAllLanguages},返回本机语言,如果本机语言不是语言集合中的一种{@link #mAllLanguages},返回英语
     *
     * @param language language
     * @return
     */
    public static Locale getLocaleByLanguage(String language) {
        if (isSupportLanguage(language)) {
            return mAllLanguages.get(language);
        } else {
            Locale locale = Locale.getDefault();
            for (String key : mAllLanguages.keySet()) {
                if (TextUtils.equals(mAllLanguages.get(key).getLanguage(), locale.getLanguage())) {
                    return locale;
                }
            }
        }
        return Locale.ENGLISH;
    }

    public static Context attachBaseContext(Context context, String language) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        } else {
            return context;
        }
    }

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Resources resources = context.getResources();
        Locale locale = AppLanguageUtils.getLocaleByLanguage(language);

        Configuration configuration = resources.getConfiguration();
        configuration.setLocale(locale);
        configuration.setLocales(new LocaleList(locale));
        return context.createConfigurationContext(configuration);
    }

}

(2)在继承Application的类中重写attachBaseContext()方法等操作

public class AppApplication extends Application {
    private static Context sContext;
    private String language;

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(AppLanguageUtils.attachBaseContext(base, getAppLanguage(base)));
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sContext = this;
        spu = new SharedPreferencesUtil(getApplicationContext());
        language = spu.getString("language");
        onLanguageChange();
    }

    public static Context getContext() {
        return sContext;
    }

    /**
     * Handling Configuration Changes
     * @param newConfig newConfig
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        onLanguageChange();
    }

    private void onLanguageChange() {
        //AppLanguageUtils.changeAppLanguage(this, AppLanguageUtils.getSupportLanguage(getAppLanguage(this)));
        AppLanguageUtils.changeAppLanguage(this, AppLanguageUtils.getSupportLanguage(language));
    }

    private String getAppLanguage(Context context) {
        String appLang = PreferenceManager.getDefaultSharedPreferences(context)
                .getString("language", Constants.ENGLISH);
        return appLang ;
    }
}

(3)在需要切换语言的SetLanguageActivity中设置切换方法

private void onChangeAppLanguage(String newLanguage) {
    spu.putString("language", newLanguage);
    AppLanguageUtils.changeAppLanguage(this, newLanguage);
    AppLanguageUtils.changeAppLanguage(App.getContext(), newLanguage);
    this.recreate();
}

(4)跳转到SetLanguageActivity的原界面语言需要刷新

//携参跳转
startActivityForResult(new Intent(OriginActivity.this, SetLanguageActivity.class), CHANGE_LANGUAGE_REQUEST_CODE);
//切换后返回刷新
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
     if (requestCode == CHANGE_LANGUAGE_REQUEST_CODE) {
        recreate();
    }
}

参考:https://yanlu.me/android-7-0-app-language-switch/

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/18/switch-languages-within-android-applications/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Android应用内切换语言
添加多语言文件 在不同的 value文件夹下(例如value 、value-en、values-zh-rCN、values-zh-rTW、value-th 文件夹)添加不同语言的 string.xml 对于Android 7.……
<<上一篇
下一篇>>
文章目录
关闭
目 录