Android(安卓)入门——App国际化之动态切换多语言小结
#引言
如果你的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 |
更多相关文章
- 戒骄戒躁
- 关于Android(安卓)app 国际化 中英文翻译的细节处理
- 2020Android又凉了?来看看Android的发展-谈一下当下最合适的架构
- android 7.0 兼容多语言切换总结
- 《Java和Android开发实战详解》——1.5节习题
- 如何在Android中使用汇编语言
- Android中的软件安全和逆向分析[一]—apk反编译破解以及java汇编
- Android(安卓)TTS 初体验
- android多国语言与国际化