Android的應用多語言開發


2020-02-02

關鍵字:自動切換語言、高版本下應用內多語言切換


 

在 Android 應用開發中,最簡單的多語言實現就是直接在 res 目錄下將你需要的不同語言的資源以 values-xx 子目錄的形式存放。

 

例如,res 目錄下默認只有一個 values 目錄,這個目錄下存放的資源就是應用默認使用的資源,包括文字、色彩值、尺寸、樣式等等等等。

 

如果你默認目錄下使用的是中文,現在想要增加一個英文,則只需要自行創建多一個目錄,以名稱 values-en 命名即可。然后將 values 目錄下的資源文件翻譯好后拷貝過去即可。

 

這種情況下應用選擇的語言環境是跟着 Android 系統走的,即系統的顯示語言是什么它就讀取哪個目錄下的資源。當我們的應用中沒有與系統對應的資源時,就使用默認的 values 目錄下的資源。

 

想象一下,這種可以將不同語言分目錄保管,並自動加載的機制是不是可以讓我們的應用更容易做到“全球化”?

 

舉個例子來說就是,我們不說文字,這個太膚淺。假如你正在開發的一款應用,它的其中一個頁面的基本色調是天藍色。而偏偏有一個民族的人非常忌諱天藍色,他們更喜歡大紅色。那我們有這套機制解決起這個問題來豈不易哉。代碼完全不用改,只需要准備兩套基本色調配置表即可。這種機制真是太妙了。

 

言歸正傳。世界上不同語言種族這么多,我們很難記得住每個國家地區的對應縮寫是什么。那我們要如何來創建這個 values-xx 目錄呢?

 

如果你是使用 Android Studio 來開發應用的,那這個就不難。只需要按照如下步驟操作即可由 Android Studio 自動幫你創建對應目錄:

 

 

 

當然,其實也完全可以手動創建目錄與資源文件,如果你知道它的對應縮寫的話。

 

而 Android Studio 中也有很方便的多語言資源編輯工具,可以讓開發者很方便地以對照式來編輯不同語言的資源。其操作步驟如下圖所示:

 

 

 

以上是跟隨 Android 系統來切換顯示語言的情況。但有些應用可能還需要能夠擺脫操作系統的設置,自行選擇顯示語言。這該怎么辦呢?

 

其實也不難。只需要在上述步驟的基礎之上,再在應用啟動時自行設置一下顯示語言就可以了。

 

為了全局統一,一般是在自定義的 Application 類的初始化中來設置。

 

這里簡單說一下筆者的一個比較簡單的解決方案。

 

因為是應用自行控制語言選項,因為應用需要自行保存當前選擇的顯示語言。筆者采用的是 SharedPreferences 來保存。

 

從 SharedPreferences 中讀取出要顯示的語言以后,再通過如下代碼設置即可:

        Configuration conf = context.getResources().getConfiguration();
        conf.locale = isThai ? new Locale(LOCALE_THAI) : Locale.SIMPLIFIED_CHINESE;
        context.getResources().updateConfiguration(conf, context.getResources().getDisplayMetrics());

上述代碼已將關鍵的一行以加粗標紅表示出來了。需要注意的是,Locale 類默認提供的語言並不全面。如果恰巧你需要的語言各類它沒有默認提供,正如筆者上面所需要的泰語言一樣,那就需要你自行實例化一個 Locale 對象。實例化時直接將對應語言的縮寫作為參數傳入即可。如筆者上面的實例化泰語言時,它的寫法就是:new Locale("th");。

 

如此即可。

 

對了,這種方式似乎是針對較低版本的 Android 系統的,這段代碼筆者最高在 Android7.0 上運行通過過。其它更高版本的系統似乎還有另外一種寫法,那種寫法筆者沒有去研究過,就不貼出來了,僅在此提一下。

 

 

最后,筆者不得不提一下應用多語言顯示與 AppCompact 主題之間的沖突。

 

這個沖突當初可是困擾了筆者一整天。

 

具體現象就是在正確設置好 values-xx 資源目錄以后,發現應用怎么都不能切換至對應語言風格去顯示。無論是用跟隨系統顯示語言的方式還是手動指定顯示語言的方式。

 

當時筆者真是各種加打印,各種百度谷歌都找不到原因。

 

在幾近絕望的時候偶然發現在另外一個 Activity 中能夠將語言給切換過來。(注:筆者開發的是一款需要登錄的應用,且這個應用有免密登錄功能。筆者先前保存過登錄信息,因此應用每次打開都只顯示一個固定的界面。)

 

唯獨那個主 Activity 的語言死活不能切換。

 

有了這個對照,至少證明了筆者的資源配置沒有錯,甚至也可以證明手動切換顯示語言的代碼也沒有錯。

 

那就只能在這兩個 Activity 中找差異了。

 

經過對比,筆者最終發現是因為這兩個 Activity 所使用的主題樣式,就是 style 不同而導致另一個 Activity 不能切換顯示語言的。

 

這個不能讓應用切換顯示語言的主題就是 AppCompact 主題:

 <style name="App_Compact_Theme" parent="Theme.AppCompat.Light.NoActionBar"/>

 

筆者的主 Activity 使用到了 Fragment,因此最開始繼承了 AppCompactActivity 類,而這個 AppCompactActivity 類又要求其主題必須是 AppCompact 的主題。至於為什么這個主題會不能切換顯示語言,筆者倒是沒有去深究,也覺得沒有必要。

 

最終筆者將主 Activity 的父類換成 FragmentActivity,再將 style 更換成 <style name="Normal_theme" parent="android:Theme.Light.NoTitleBar"/> 以后成功地解決了問題。

 

以上就是筆者關於Android應用多語言開發的心得與筆記。

 

 

關於Android8.0及以上版本系統下的應用內多語言切換

在Android8.0及以后的版本系統下,上述的語言切換功能將失效。原因是Android自那以后改變了系統語言控制架構。

 

因此,我們的軟件中關於顯示語言功能需要針對高低版本做兩套兼容代碼。

 

因絕大多數情況下僅Activity需要展示UI,所以這里僅針對Activity來講解。

 

首先,我們要將應用內所有的Activity的Context實例做個自定義,即在每個Activity實例化之初給它一個已經指定了顯示語言種類的Context實例。

 

怎么做呢,給我們的Activity重寫 attachBaseContext() 方法:

    @Override
    protected void attachBaseContext(Context newBase) {
        if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1){
            super.attachBaseContext(getSelfContext());
        }else {
            super.attachBaseContext(newBase);
        }
    }

這里有個小坑要注意的,在這個方法剛執行時,其參數中的 newBase 將是 null。因為Activity生命周期中調用這個方法就是為了獲得Context實例的,此時它當然還沒有任何可以使用的Context對象的了。

 

其次,根據自己的業務邏輯,准備相應的 Context 實例給到上面的方法,即上面 getSelfContext() 方法的實現:

    public Context getSelfContext(Context ctx){
        if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
            Configuration conf = getApplicationContext().getResources().getConfiguration();
            LocaleList ll = new LocaleList(isThai ? new Locale(LOCALE_THAI) : Locale.SIMPLIFIED_CHINESE);
            conf.setLocales(ll);

            return new ContextWrapper(getApplicationContext().createConfigurationContext(conf));
        }

        return ctx;
    }

 

如此,便可。

 


參考博客: https://www.jianshu.com/p/32ff13db1f0d

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM