Android 入门——App国际化之动态切换多语言小结

版权声明:本文为CrazyMo_原创,转载请在显著位置注明原文链接 https://blog.csdn.net/CrazyMo_/article/details/82151113

#引言
如果你的App是面向国际的或者是做手机ROM的,那么对于Android国际化适配应该不会陌生,今天就好好地总结下。

一、Locale和Configuration 概述

Locale对象是用于表示特定的地理,政治或文化区域。 需要Locale执行其任务的操作称为区域设置敏感,并使用Locale为用户定制信息。 例如显示数字是区域设置敏感操作 - 应根据用户原生国家,地区或文化的习惯和惯例格式化数字,再比如阿拉伯国家是从右往左布局的,这些配置信息都是由Locale决定的,当然也可以从Locale中获取对应的配置信息。而Configuration 封装了影响应用程序检索的资源的所有设备配置信息包括用户指定的配置选项(区域设置列表和缩放)以及设备配置(例如输入模式,屏幕大小和屏幕方向)等等信息。通过使用Resources.getConfiguration()方法就可以从Resources获取此对象。在Activity中还可以通过ContextThemeWrapper.getResources().getConfiguration()方法请求来获取。

二、动态切换语言

如果你查看过源码你会发现Application的第一个生命周期方法是attachBaseContext而不是onCreate方法,同样的Activity从一定程度上来说也是先调用attachBaseContext方法拿到ContextWrapper上下文封装类对象,然后根据对应的ContextWrapper进行初始化的,所以只要我们替换成我们自己的ContextWrapper就可以实现替换资源了,其实还有另另一种思路,全部使用代码进行动态设置。
##1、建立对应资源文件夹
res文件夹上右键——>New——>Android Resource Directory——>在Available qualifiers下拉列表处选择Locale——>点击“>>”——>在Language中选择要适配的语言——>再选择指定的Region——>点击OK——>再在对应的values-xx文件下——>New——>Values Resource File
在这里插入图片描述

2、自定义用于资源适配的ContextWrapper

package com.crazymo.changelanguage;

import android.content.Context;
import android.content.ContextWrapper;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import android.text.TextUtils;

import java.util.Locale;

/**
 * Auther: Crazy.Mo on 2018/4/18 14:58
 * Summary:
 */
public class LanContextWrapper extends ContextWrapper {

    public static final String LANG_HK = "hk";
    public static final String LANG_CN = "cn";
    public static final String LANG_EN = "en";

    public LanContextWrapper(Context ctx) {
        super(ctx);
    }

    public static ContextWrapper wrap(Context context) {
        Locale newLocale;
        SharedPreferences sharedPreferences=context.getSharedPreferences(MainActivity.SP_NAME, MODE_PRIVATE);
        String lanTag=sharedPreferences.getString(MainActivity.LANGUAGE, "def");
        switch (lanTag) {
            case "def"://没有手东设置过对应的语言则默认读取手机系统的语言
                String locale = Locale.getDefault().getLanguage();
                String langFlag="";
                if (TextUtils.isEmpty(locale)) {
                    langFlag=LANG_CN;
                    newLocale = Locale.CHINESE;
                } else if (locale.contains("en")) {
                    langFlag=LANG_EN;
                    newLocale = Locale.ENGLISH;
                }else if (locale.startsWith("zh")) {
                    String region=Locale.getDefault().getDisplayCountry();
                    if(region.equals("香港特別行政區")||region.equals("台灣")){
                        langFlag=LANG_HK;
                        newLocale=Locale.TRADITIONAL_CHINESE;
                    }else{
                        langFlag=LANG_CN;
                        newLocale=Locale.SIMPLIFIED_CHINESE;
                    }
                }
                else {
                    newLocale = Locale.CHINESE;
                }
                sharedPreferences.edit().putString(MainActivity.LANGUAGE, langFlag).apply();
                break;
            case LANG_EN://设置为英语
                newLocale = Locale.ENGLISH;
                break;
            case LANG_HK://设置为繁體
                newLocale = Locale.TRADITIONAL_CHINESE;
                break;
            case LANG_CN:
                newLocale=Locale.SIMPLIFIED_CHINESE;
                break;
            default://默认为汉语
                newLocale = Locale.SIMPLIFIED_CHINESE;
                break;
        }
        context = getLanContext(context, newLocale);
        return new ContextWrapper(context);
    }

    /**
     * 初始化Context
     * @param context
     * @param pNewLocale
     * @return
     */
    private static Context getLanContext(Context context, Locale pNewLocale) {
        Resources res = context.getApplicationContext().getResources();//1、获取Resources
        Configuration configuration = res.getConfiguration();//2、获取Configuration
        //3、设置Locale并初始化Context
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            configuration.setLocale(pNewLocale);
            LocaleList localeList = new LocaleList(pNewLocale);
            LocaleList.setDefault(localeList);
            configuration.setLocales(localeList);
            context = context.createConfigurationContext(configuration);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            configuration.setLocale(pNewLocale);
            context = context.createConfigurationContext(configuration);
        }
        return context;
    }


    /**
     * 获取手机设置的语言国家
     * @param context
     * @return
     */
    public static String getCountry(Context context) {
        String country;
        Resources resources = context.getApplicationContext().getResources();
        //在7.0以上和7.0一下获取国家的方式有点不一样
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            country = resources.getConfiguration().getLocales().get(0).getCountry();
        } else {
            country = resources.getConfiguration().locale.getCountry();
        }
        return country;
    }
}


3、在Activity中进行动态切换

package com.crazymo.changelanguage;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

    public static final String SP_NAME = "name";
    public static final String LANGUAGE = "language";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * 设置修改语言
     *
     * @param newBase
     */
    @Override
    protected void attachBaseContext(Context newBase) {
        Context context = LanContextWrapper.wrap(newBase);
        super.attachBaseContext(context);
    }

    public void changeChinese(View view) {
        SharedPreferences sharedPreferences=getSharedPreferences(MainActivity.SP_NAME, MODE_PRIVATE);
        sharedPreferences.edit().putString(MainActivity.LANGUAGE, LanContextWrapper.LANG_CN).apply();
        rebot();
    }

    public void changeEnglish(View view) {
        SharedPreferences sharedPreferences=getSharedPreferences(MainActivity.SP_NAME, MODE_PRIVATE);
        sharedPreferences.edit().putString(MainActivity.LANGUAGE, LanContextWrapper.LANG_EN).apply();
        rebot();
    }

    public void changeRChinese(View view) {
        SharedPreferences sharedPreferences=getSharedPreferences(MainActivity.SP_NAME, MODE_PRIVATE);
        sharedPreferences.edit().putString(MainActivity.LANGUAGE, LanContextWrapper.LANG_HK).apply();
        rebot();
    }

    private void rebot() {
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) {
            Intent intent = new Intent(this, MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            overridePendingTransition(R.anim.anim_change_lang_enter, R.anim.anim_change_lang_exit);
            finish();
        }else{
            recreate();
        }
    }

    public void toOther(View view) {
        String country=LanContextWrapper.getCountry(this);
        startActivity(new Intent(this,Main2Activity.class));
    }
}

这里写图片描述
简单源码传送门

#附录、国际化资源表示形式
Android 应用资源国际化的知识。对于资源文件的国际化,我们一般是在 Android src/main/res/ 目录下,建立对应语言文件夹,格式一般为:values-语言代号-地区代号,默认的资源是不包含语言代号和地区代号的。一般情况下,应用资源是没有做任何适配的,所以不管如何切换语言和地区设置,应用显示的资源都不会发生任何改变。配置选项包括语言代号和地区代号。表示中文和中国的配置选项是 zh-rCN(zh表示中文,CN表示中国)。表示英文和美国的配置选项是 en-rUS(en表示英文,US表示美国)。同一语言代号可以有多个地区代号,用 r 表示区分。

国家/区域 对应values文件夹
中文(中国) values-zh-rCN
中文(台湾) values-zh-rTW
中文(香港) values-zh-rHK
维吾尔文(中国) values-ug-rCN
英语(美国) values-en-rUS
英语(英国) values-en-rGB
英文(澳大利亚) values-en-rAU
英文(加拿大) values-en-rCA
英文(爱尔兰) values-en-rIE
英文(印度) values-en-rIN
英文(新西兰) values-en-rNZ
英文(新加坡) values-en-rSG
英文(南非) values-en-rZA
阿拉伯文(埃及) values-ar-rEG
阿拉伯文(以色列) values-ar-rIL
保加利亚文: values-bg-rBG
加泰罗尼亚文 values-ca-rES
捷克文 values-cs-rCZ
丹麦文 values-da-rDK
德文(奥地利) values-de-rAT
德文(瑞士) values-de-rCH
德文(德国) values-de-rDE
德文(列支敦士登) values-de-rLI
希腊文 values-el-rGR
西班牙文(西班牙) values-es-rES
西班牙文(美国) values-es-rUS
芬兰文(芬兰) values-fi-rFI
法文(比利时) values-fr-rBE
法文(加拿大) values-fr-rCA
法文(瑞士) values-fr-rCH
法文(法国) values-fr-rFR
希伯来文 values-iw-rIL
印地文 values-hi-rIN
克罗里亚文 values-hr-rHR
匈牙利文 values-hu-rHU
印度尼西亚文 values-in-rID
意大利文(瑞士) values-it-rCH
意大利文(意大利) values-it-rIT
日文 values-ja-rJP
韩文 values-ko-rKR
立陶宛文 valueslt-rLT
拉脱维亚文 values-lv-rLV
挪威博克马尔文 values-nb-rNO
荷兰文(比利时) values-nl-BE
荷兰文(荷兰) values-nl-rNL
波兰文 values-pl-rPL
葡萄牙文(巴西) values-pt-rBR
葡萄牙文(葡萄牙) values-pt-rPT
罗马尼亚文 values-ro-rRO
俄文 values-ru-rRU
斯洛伐克文 values-sk-rSK
斯洛文尼亚文 values-sl-rSI
塞尔维亚文 values-sr-rRS
瑞典文 values-sv-rSE
泰文 values-th-rTH
塔加洛语 values-tl-rPH
土耳其文 values–r-rTR
乌克兰文 values-uk-rUA
越南文 values-vi-rVN

猜你喜欢

转载自blog.csdn.net/CrazyMo_/article/details/82151113