Android國際化之小語種自定義Farsi

老規矩 ,先上效果圖

這裏寫圖片描述

圖中分別展示了由應用內由中文切換到英文再到波斯語的展示。本篇博客介紹的兩個點

  • 小語種的自定義
  • 應用內無感知切換語言

一、小語種的自定義

Java Locale 的語言常量基本囊括了主流語言:

    public static final Locale CANADA = null;
    public static final Locale CANADA_FRENCH = null;
    public static final Locale CHINA = null;
    public static final Locale CHINESE = null;
    public static final Locale ENGLISH = null;
    public static final Locale FRANCE = null;
    public static final Locale FRENCH = null;
    public static final Locale GERMAN = null;
    public static final Locale GERMANY = null;
    public static final Locale ITALIAN = null;
    public static final Locale ITALY = null;
    public static final Locale JAPAN = null;
    public static final Locale JAPANESE = null;
    public static final Locale KOREA = null;
    public static final Locale KOREAN = null;
    public static final Locale PRC = null;
    public static final char PRIVATE_USE_EXTENSION = 'x';
    public static final Locale ROOT = null;
    public static final Locale SIMPLIFIED_CHINESE = null;
    public static final Locale TAIWAN = null;
    public static final Locale TRADITIONAL_CHINESE = null;
    public static final Locale UK = null;
    public static final char UNICODE_LOCALE_EXTENSION = 'u';
    public static final Locale US = null;

目前 Java8 中我們可以看到,加拿大,中文,法語,德語,日語,意大利,韓國,英美等世界主流語言常量都支持。開始我是傻眼了波斯語沒有對應的常量該如何是好?後來發現

new Locale( language, country , variant)

是可以支持自定義語言的

  • language
  • country
  • variant

language
ISO 639 alpha-2 or alpha-3 language code, or registered language subtags up to 8 alpha letters (for future enhancements). When a language has both an alpha-2 code and an alpha-3 code, the alpha-2 code must be used. You can find a full list of valid language codes in the IANA Language Subtag Registry (search for “Type: language”). The language field is case insensitive, but Locale always canonicalizes to lower case.

Well-formed language values have the form [a-zA-Z]{2,8}. Note that this is not the the full BCP47 language production, since it excludes extlang. They are not needed since modern three-letter language codes replace them.

Example: “en” (English), “ja” (Japanese), “kok” (Konkani)


country (region)
ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code. You can find a full list of valid country and region codes in the IANA Language Subtag Registry (search for “Type: region”). The country (region) field is case insensitive, but Locale always canonicalizes to upper case.

Well-formed country/region values have the form [a-zA-Z]{2} | [0-9]{3}

Example: “US” (United States), “FR” (France), “029” (Caribbean)


variant
Any arbitrary value used to indicate a variation of a Locale. Where there are two or more variant values each indicating its own semantics, these values should be ordered by importance, with most important first, separated by underscore(‘_’). The variant field is case sensitive.

Note: IETF BCP 47 places syntactic restrictions on variant subtags. Also BCP 47 subtags are strictly used to indicate additional variations that define a language or its dialects that are not covered by any combinations of language, script and region subtags. You can find a full list of valid variant codes in the IANA Language Subtag Registry (search for “Type: variant”).
However, the variant field in Locale has historically been used for any kind of variation, not just language variations. For example, some supported variants available in Java SE Runtime Environments indicate alternative cultural behaviors such as calendar type or number script. In BCP 47 this kind of information, which does not identify the language, is supported by extension subtags or private use subtags.

Well-formed variant values have the form SUBTAG ((‘_’|’-‘) SUBTAG)* where SUBTAG = [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}. (Note: BCP 47 only uses hyphen (‘-‘) as a delimiter, this is more lenient).

Example: “polyton” (Polytonic Greek), “POSIX”

這種構造方式不得不說很**, 沒有枚舉 常量 自己去網上找對應的字符也不知道對不對

最好在網上找了些參考資料以及自己 debug 調試能夠正確的切換到波斯語

private static final Locale Locale_Farsi = new Locale("FA", "fa", "");

這裏寫圖片描述

二 應用內無感知切換語言

很多語言切換比較粗暴,直接殺死進程重啓應用。或者跳轉登錄界面,上面演示圖中的效果看上去就比較平順。

    private void backToSettingActivity() {
        Intent mainActivity = new Intent(this, MainActivity.class);
        mainActivity.putExtra(MainActivity.INITIAL_TAB_INDEX, MainActivity.TAB_ME_INDEX);

        Intent settingActivity = new Intent(this, AccountSettingActivity.class);

        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
        taskStackBuilder.addNextIntent(mainActivity);
        taskStackBuilder.addNextIntent(settingActivity);
        taskStackBuilder.startActivities();
        overridePendingTransition(0, 0);
    }

核心方法做的事情是記住棧的路徑

提供一下完整代碼:

public class ConfigurationManager {
    private static boolean isInit = false;

    private ConfigurationManager() {

    }

    private static class SingletonHolder {
        static ConfigurationManager sInstance = new ConfigurationManager();
    }


    private static class SystemConfigurationChangedReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
                LangUtils.setSystemLocale(Locale.getDefault());
                LangUtils.RCLocale appLocale = LangUtils.getAppLocale(context);
                Locale systemLocale = LangUtils.getSystemLocale();
                if (!appLocale.toLocale().equals(systemLocale)) {
                    ConfigurationManager.getInstance().switchLocale(appLocale, context);
                }
            }
        }
    }

    public static ConfigurationManager getInstance() {
        return SingletonHolder.sInstance;
    }

    public static void init(Context context) {
        if (!isInit) {
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_LOCALE_CHANGED);
            context.registerReceiver(new SystemConfigurationChangedReceiver(), filter);

            //初始化時將應用語言重新設置爲之前設置的語言
            RCLocale locale = ConfigurationManager.getInstance().getAppLocale(context);
            ConfigurationManager.getInstance().switchLocale(locale, context);
            isInit = true;
        }
    }


    public void switchLocale(RCLocale locale, Context context) {
        Resources resources = context.getResources();
        Configuration config = resources.getConfiguration();
        config.locale = locale.toLocale();
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            context.getResources().updateConfiguration(config, resources.getDisplayMetrics());
        }
        LangUtils.saveLocale(context, locale);
    }


    public Context getConfigurationContext(Context context) {
        return LangUtils.getConfigurationContext(context);
    }


    public LangUtils.RCLocale getAppLocale(Context context) {
        return LangUtils.getAppLocale(context);
    }


    public Locale getSystemLocale() {
        return LangUtils.getSystemLocale();
    }
}
public class LangUtils {

    private static final Locale Locale_Farsi = new Locale("FA", "fa", "");
    private static final String LOCALE_CONF_FILE_NAME = "locale.config";
    private static final String APP_LOCALE = "seal_app_locale";
    private static Locale systemLocale = Locale.getDefault();

    public static Context getConfigurationContext(Context context) {
        Resources resources = context.getResources();
        Configuration config = new Configuration(resources.getConfiguration());
        Context configurationContext = context;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            LocaleList localeList = new LocaleList(getAppLocale(context).toLocale());
            LocaleList.setDefault(localeList);
            config.setLocales(localeList);
            configurationContext = context.createConfigurationContext(config);
        }
        return configurationContext;
    }

    public static RCLocale getAppLocale(Context context) {
        SharedPreferences sp
                = context.getSharedPreferences(LOCALE_CONF_FILE_NAME, Context.MODE_PRIVATE);
        String locale = sp.getString(APP_LOCALE, "auto");
        Log.e("language get", locale);
        return RCLocale.valueOf(locale);
    }

    public static void saveLocale(Context context, RCLocale locale) {
        SharedPreferences sp
                = context.getSharedPreferences(LOCALE_CONF_FILE_NAME, Context.MODE_PRIVATE);
        Log.e("language save", locale.value());
        sp.edit().putString(APP_LOCALE, locale.value()).commit();
    }


    public static class RCLocale {
        /**
         * 中文
         */
        public static final RCLocale LOCALE_CHINA = new RCLocale("zh");
        /**
         * 英文
         */
        public static final RCLocale LOCALE_US = new RCLocale("en");
        /**
         * 波斯
         */
        public static final RCLocale LOCALE_FARSI = new RCLocale("fa");
        /**
         * 跟隨系統
         */
        public static final RCLocale LOCALE_AUTO = new RCLocale("auto");

        private String rcLocale;

        private RCLocale(String rcLocale) {
            this.rcLocale = rcLocale;
        }

        public String value() {
            return rcLocale;
        }

        public Locale toLocale() {
            Locale locale;
            if (rcLocale.equals(LOCALE_CHINA.value())) {
                locale = Locale.CHINESE;
            } else if (rcLocale.equals(LOCALE_US.value())) {
                locale = Locale.ENGLISH;
            } else if (rcLocale.equals(LOCALE_FARSI.value())) {
                locale = Locale_Farsi;
            } else {
                locale = getSystemLocale();
            }
            return locale;
        }

        public static RCLocale valueOf(String rcLocale) {
            RCLocale locale;
            if (rcLocale.equals(LOCALE_CHINA.value())) {
                locale = LOCALE_CHINA;
            } else if (rcLocale.equals(LOCALE_US.value())) {
                locale = LOCALE_US;
            } else if (rcLocale.equals(LOCALE_FARSI.value())) {
                locale = LOCALE_FARSI;
            } else {
                locale = LOCALE_AUTO;
            }
            return locale;
        }
    }


    public static Locale getSystemLocale() {
        return systemLocale;
    }


    public static void setSystemLocale(Locale locale) {
        systemLocale = locale;
    }


}

activity:

public class LanguageActivity extends BaseActivity implements View.OnClickListener {

    private LangUtils.RCLocale selectedLocale;
    private LangUtils.RCLocale originalLocale;
    private TextView saveOptionTextView;
    private ImageView chineseCheckbox;
    private ImageView englishCheckbox;
    private ImageView farsiCheckbox;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_language);
        setTitle(R.string.language_setting);

        findViewById(R.id.ll_chinese).setOnClickListener(this);
        findViewById(R.id.ll_english).setOnClickListener(this);
        findViewById(R.id.ll_farsi).setOnClickListener(this);
        chineseCheckbox = (ImageView) findViewById(R.id.img_chinese_checkbox);
        englishCheckbox = (ImageView) findViewById(R.id.img_english_checkbox);
        farsiCheckbox = findViewById(R.id.img_farsi_checkbox);
        saveOptionTextView = findViewById(R.id.text_right);
        saveOptionTextView.setVisibility(View.VISIBLE);
        saveOptionTextView.setText(R.string.confirm);
        saveOptionTextView.setOnClickListener(this);

        originalLocale = ConfigurationManager.getInstance().getAppLocale(this);
        if (originalLocale == LangUtils.RCLocale.LOCALE_CHINA) {
            selectLocale(LangUtils.RCLocale.LOCALE_CHINA);
        } else if (originalLocale == LangUtils.RCLocale.LOCALE_US) {
            selectLocale(LangUtils.RCLocale.LOCALE_US);
        } else if (originalLocale == LangUtils.RCLocale.LOCALE_FARSI) {
            selectLocale(LangUtils.RCLocale.LOCALE_FARSI);
        }
        setSaveOptionTextViewClickable(false);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ll_chinese:
                selectLocale(LangUtils.RCLocale.LOCALE_CHINA);
                break;
            case R.id.ll_english:
                selectLocale(LangUtils.RCLocale.LOCALE_US);
                break;
            case R.id.ll_farsi:
                selectLocale(LangUtils.RCLocale.LOCALE_FARSI);
                break;
            case R.id.text_right:
                if (LangUtils.RCLocale.LOCALE_CHINA == selectedLocale) {
                    ConfigurationManager.getInstance().switchLocale(LangUtils.RCLocale.LOCALE_CHINA, this);
                } else if (LangUtils.RCLocale.LOCALE_US == selectedLocale) {
                    ConfigurationManager.getInstance().switchLocale(LangUtils.RCLocale.LOCALE_US, this);
                } else if (LangUtils.RCLocale.LOCALE_FARSI == selectedLocale) {
                    ConfigurationManager.getInstance().switchLocale(LangUtils.RCLocale.LOCALE_FARSI, this);
                }
                backToSettingActivity();
                break;
        }
    }


    private void selectLocale(LangUtils.RCLocale locale) {
        if (locale == LangUtils.RCLocale.LOCALE_CHINA) {
            farsiCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.seal_ic_checkbox_full_gray));
            englishCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.seal_ic_checkbox_full_gray));
            chineseCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.rc_ic_checkbox_full));
            selectedLocale = LangUtils.RCLocale.LOCALE_CHINA;
        } else if (locale == LangUtils.RCLocale.LOCALE_US) {
            chineseCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.seal_ic_checkbox_full_gray));
            farsiCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.seal_ic_checkbox_full_gray));
            englishCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.rc_ic_checkbox_full));
            selectedLocale = LangUtils.RCLocale.LOCALE_US;
        } else if (locale == LangUtils.RCLocale.LOCALE_FARSI) {
            chineseCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.seal_ic_checkbox_full_gray));
            englishCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.seal_ic_checkbox_full_gray));
            farsiCheckbox.setImageDrawable(getResources().getDrawable(R.drawable.rc_ic_checkbox_full));
            selectedLocale = LangUtils.RCLocale.LOCALE_FARSI;
        }
        if (selectedLocale == originalLocale) {
            setSaveOptionTextViewClickable(false);
        } else {
            setSaveOptionTextViewClickable(true);
        }
    }


    private void backToSettingActivity() {
        Intent mainActivity = new Intent(this, MainActivity.class);
        mainActivity.putExtra(MainActivity.INITIAL_TAB_INDEX, MainActivity.TAB_ME_INDEX);

        Intent settingActivity = new Intent(this, AccountSettingActivity.class);

        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
        taskStackBuilder.addNextIntent(mainActivity);
        taskStackBuilder.addNextIntent(settingActivity);
        taskStackBuilder.startActivities();
        overridePendingTransition(0, 0);
    }


    private void setSaveOptionTextViewClickable(boolean clickable) {
        if (clickable) {
            saveOptionTextView.setClickable(true);
            saveOptionTextView.setTextColor(getResources().getColor(R.color.white));
        } else {
            saveOptionTextView.setClickable(false);
            saveOptionTextView.setTextColor(getResources().getColor(R.color.group_list_gray));
        }
    }
}

以上就是全部的小語種自定義的實現方式和代碼,歡迎評論交流

參考資料

https://blog.csdn.net/chougod/article/details/52008084

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章