Android國際化(多語言)實現(xiàn),支持8.0+

前言

最近因為項目中使用了國際化卒蘸,所以正好研究了下實現(xiàn)方法雌隅;
首先說下項目需求:

  • 可以隨著系統(tǒng)切換語言而切換語言,不支持的語言顯示默認(rèn)
  • 用戶可以選擇語言缸沃,且不會隨著系統(tǒng)切換語言或者應(yīng)用重啟而還原

雖然需求還是很簡單的恰起,但是實現(xiàn)起來還是遇到了不少的麻煩,首先看下效果圖:


效果圖

老規(guī)矩

項目源碼

實現(xiàn)思路

  • 在application 的 attachBaseContext設(shè)置當(dāng)前設(shè)置的語言Local
  • 在application 的onConfigurationChanged(改變系統(tǒng)語言時會調(diào)用到)設(shè)置當(dāng)前的語言Local
  • 在 Activity 的attachBaseContext設(shè)置當(dāng)前設(shè)置的語言Local趾牧,所以一般這里是創(chuàng)建BaseActivity來方便統(tǒng)一改變
  • 在 service 的attachBaseContext設(shè)置當(dāng)前設(shè)置的語言Local

實現(xiàn)代碼

有了思路實現(xiàn)起來就很清晰了检盼,

  • 第一步肯定是創(chuàng)建對應(yīng)語言的string.xml,在demo中我只實現(xiàn)了:中文簡體,中文繁體翘单,和英文三個語言


    image.png
  • 因為這個我們要保存用戶的選擇語言吨枉,所以這里創(chuàng)建個 SharedPreferences的單例:
public class SPUtil {

    private final String SP_NAME = "language_setting";
    private final String TAG_LANGUAGE = "language_select";
    private static volatile SPUtil instance;

    private final SharedPreferences mSharedPreferences;

    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 static SPUtil getInstance(Context context) {
        if (instance == null) {
            synchronized (SPUtil.class) {
                if (instance == null) {
                    instance = new SPUtil(context);
                }
            }
        }
        return instance;
    }
}

創(chuàng)建管理語言的Util

  • 創(chuàng)建根據(jù)用戶設(shè)置獲取對應(yīng)的 Local方法:
/**
     * 獲取選擇的語言設(shè)置
     *
     * @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;
        }
    }

 /**
     * 獲取系統(tǒng)的locale
     *
     * @return Locale對象
     */
    public static Locale getSystemLocale(Context context) {
        Locale locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            locale = LocaleList.getDefault().get(0);
        } else {
            locale = Locale.getDefault();
        }
        return locale;
    }
  • 創(chuàng)建改變Local方法
public static Context setLocal(Context context) {
        return updateResources(context, getSetLanguageLocale(context));
    }

    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;
    }
  • 在相應(yīng)地方調(diào)用
#Application
 @Override
    protected void attachBaseContext(Context base) {
       super.attachBaseContext(LocalManageUtil.setLocal(base));
    }

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LocalManageUtil.setLocal(context);
    }
#BaseActivity
@Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(LocalManageUtil.setLocal(newBase));
    }
#service
@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocalManageUtil.setLocal(base));
    }
  • 切換語言
private void selectLanguage(int select) {
        LocalManageUtil.saveSelectLanguage(this, select);
        //重啟APP到主頁面
        MainActivity.reStart(this);
    }

搞定,


image.png

沒錯就是這么簡單哄芜。


image.png

但是總有你想不到的事

我們都會在代碼中調(diào)用context.getResource().getString()這句代碼看起來沒什么問題貌亭,但是你這個context要是用的是applicationContext那么問題就來了。你會發(fā)現(xiàn)當(dāng)你切換語言后用這樣方式設(shè)置的string沒有改變属提,所以我們需要改動我們的代碼。
解決方法就是美尸,在切換語言后把application的updateConfiguration也要更新了冤议,方法如下:

 /**
     * 設(shè)置語言類型
     */
    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);
    }
  • 但是當(dāng)你調(diào)用這個代碼后你獲取到的系統(tǒng)選擇語言就是你設(shè)置的語言,這不準(zhǔn)確呀师坎,那怎么辦呢恕酸?很簡單,我們把真實的系統(tǒng)語言保存下來就行了胯陋。
  • 我們在SharedPreferences單例中添加系統(tǒng)Local變量:
    /**
     * 用來保存系統(tǒng)語言
     */
    private Locale systemCurrentLocal = Locale.ENGLISH;

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


    public Locale getSystemCurrentLocal() {
        return systemCurrentLocal;
    }
  • 然后在 application的attachBaseContextonConfigurationChanged獲取真實的系統(tǒng)Local并保存

  • 最后改變下我們原來獲取系統(tǒng)Local的方法:

    /**
     * 獲取系統(tǒng)的locale
     *
     * @return Locale對象
     */
    public static Locale getSystemLocale(Context context) {
        return SPUtil.getInstance(context).getSystemCurrentLocal();
    }

這樣就真的完成了蕊温,具體的代碼可見項目源碼這里袱箱,
若您覺得對您有幫助,您的贊是我最大的動力

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末义矛,一起剝皮案震驚了整個濱河市发笔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凉翻,老刑警劉巖了讨,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異制轰,居然都是意外死亡前计,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門垃杖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來男杈,“玉大人,你說我怎么就攤上這事调俘×姘簦” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵脉漏,是天一觀的道長苞冯。 經(jīng)常有香客問我,道長侧巨,這世上最難降的妖魔是什么舅锄? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮司忱,結(jié)果婚禮上皇忿,老公的妹妹穿的比我還像新娘。我一直安慰自己坦仍,他們只是感情好鳍烁,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著繁扎,像睡著了一般幔荒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梳玫,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天爹梁,我揣著相機(jī)與錄音,去河邊找鬼提澎。 笑死姚垃,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盼忌。 我是一名探鬼主播积糯,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼掂墓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了看成?” 一聲冷哼從身側(cè)響起君编,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎川慌,沒想到半個月后啦粹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡窘游,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了跳纳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忍饰。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖寺庄,靈堂內(nèi)的尸體忽然破棺而出艾蓝,到底是詐尸還是另有隱情,我是刑警寧澤斗塘,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布赢织,位于F島的核電站,受9級特大地震影響馍盟,放射性物質(zhì)發(fā)生泄漏于置。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一贞岭、第九天 我趴在偏房一處隱蔽的房頂上張望八毯。 院中可真熱鬧,春花似錦瞄桨、人聲如沸话速。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泊交。三九已至,卻和暖如春柱查,著一層夾襖步出監(jiān)牢的瞬間廓俭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工物赶, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留白指,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓酵紫,卻偏偏與公主長得像告嘲,于是被迫代替她去往敵國和親错维。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理橄唬,服務(wù)發(fā)現(xiàn)赋焕,斷路器,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • 《ilua》速成開發(fā)手冊3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 1...
    葉染柒丶閱讀 10,729評論 0 11
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,111評論 25 707
  • ¥開啟¥ 【iAPP實現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程仰楚,因...
    小菜c閱讀 6,409評論 0 17
  • 正月十五僧界,往年都在家的日子侨嘀,我,想你了捂襟。 我已經(jīng)很久都沒有想你了咬腕,但是今晚卻抵擋不住回憶的翻涌,思念十年前你的笑臉...
    不魚的貓閱讀 277評論 1 0