Android通過代碼實現多語言切換

前言

最近接手一個Android項目,需要實現對維吾爾族語的支持。雖然做了這么久的android開發,只做過多語言支持,但做應用內部多語言支持還是第一次,而且還是對維吾爾語的支持。所以,又是一次面向搜索引擎編程。

面向搜索編程

如果我們搜索“android 多語言切換”,我相信得到大部分的答案是千篇一律的,連文章都長的一樣:

Locale locale = new Locale("zh");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());

以上代碼應該說沒什么大問題,畢竟確實可以工作,可以實現需求。但是,作為一個強迫癥患者,我實際受不了有2處劃線的地方,也就是說上面代碼中有2處被廢棄了(沒錯,API 25被廢棄的):

 config.locale = locale;
 getBaseContext().getResources().updateConfiguration(config, 
 getBaseContext().getResources().getDisplayMetrics());

看到有2處被廢棄了,必須進去看看啊。

/**
     * Current user preference for the locale, corresponding to
     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
     * resource qualifier.
     *
     * @deprecated Do not set or read this directly. Use {@link #getLocales()} and
     * {@link #setLocales(LocaleList)}. If only the primary locale is needed,
     * <code>getLocales().get(0)</code> is now the preferred accessor.
     */
    @Deprecated public Locale locale;

很顯然我們找到了替代方法:

config.setLocales(LocaleList);
config.setLocale(locale);

很好,沒問題。繼續查看下一個:

    /**
     * Store the newly updated configuration.
     *
     * @deprecated See {@link android.content.Context#createConfigurationContext(Configuration)}.
     */
    @Deprecated
    public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
        updateConfiguration(config, metrics, null);
    }

很簡單嘛,代替方法也找到了哦。于是就這么寫了下去:

    Locale locale = new Locale("ug");
    final Resources res = getResources();
    final Configuration config = res.getConfiguration();
    config.setLocale(locale); // getLocale() should return a Locale
    createConfigurationContext(config);

完全不好用!怎么寫就是不好用。再仔細一看,文檔上說createConfigurationContext(config)會返回一個新的Context,然而對新Context如何處理只字未提。又是一番面向搜索編程,終于找到了正確姿勢:

    @Override
    protected void attachBaseContext(Context newBase) {
        Locale locale = new Locale("ug");
        final Resources res = newBase.getResources();
        final Configuration config = res.getConfiguration();
        config.setLocale(locale); // getLocale() should return a Locale
        final Context newContext = newBase.createConfigurationContext(config);
        super.attachBaseContext(newContext);
    }

我們的Activity應該重寫這個方法。然后當Activity被創建的時候,新的Context將被應用。需要注意的,如果你想讓當前Activity生效,你需要調用recreate()

當然啦,我們也可以寫個工具類:

public class ConfigurationWrapper {
    private ConfigurationWrapper() {
    }

    public static Context wrapConfiguration(@NonNull final Context context, @NonNull final Configuration config) {
        return context.createConfigurationContext(config);
    }
 
    
    public static Context wrapLocale(@NonNull final Context context,@NonNull final Locale locale) {
        final Resources res = context.getResources();
        final Configuration config = res.getConfiguration();
        config.setLocale(locale);
        return wrapConfiguration(context, config);
    }
}

然后你就可以這樣使用。如果你想更改configuration,就可以用wrapConfiguration

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(ConfigurationWrapper.wrapLocale(newContext, getLocale()));
}

關于Locale

實現多語言切換用到了Locale。Locale里很多常見國家和地區以及語言,如果我們做常見的語言,可以直接調用系統的,比如Locale.CHINESE。但是這次做的維吾爾語的適配,略我坑一下。
首先,維吾爾語的英文名字叫Uyghur。Locale里并沒有,也可能是我找的不對。
其次,Uyghur是阿拉伯系的。嗯,沒錯,有個詞叫RTL,會出現神奇的東西。
最后,AndroidStudio的values里面是有Uyghur選項的。并且有相對應選項,其中就包括中國,我猜這就是維吾爾語。所以就建了一個,全名是:values-ug-rCN
問題是,我最開始直接這樣寫的:

 Locale locale = new Locale("ug-rCN");

好吧,是我太天真,不好用。機智的我看了看Locale的構造方法。后來猜了一個結論

ug代表語種,rCN代表國家和地區。比如說同樣都是中文zh,但分了很多國家和地區,如中國,臺灣,香港以及新家坡等

所以下面的寫法才是正確姿勢:

Locale locale = new Locale("ug", Locale.CHINA.getCountry());

結束

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容