最近安卓开发遇到一个新的需求,需要支持多语言,而且还是我们五十六个大家庭中的藏语,一时间点懵了,毕竟从来没搞过多语言,一下来的还是比较小众的。后面研究了一番那个,还是大致搞出来了,这里简单写篇博客记一下。
官方文档
以前一有问题总喜欢在网上瞎找博客教程,后面发现很多写的很好的博文都是抄的官方文档,就把官方文档收藏了,有问题先看官方文档,下面是官方文档对多语言的教程:
https://developer./training/basics/supporting-devices/languages
创建资源文件
实际上官方文档写的已经非常详细了,但是我还是想说点不一样的东西。我需要弄的是属于中国区域的藏语,可是找遍网上博文列出的支持语言也没找到藏文对应的代码,差点我就使用最笨的方法自己用代码控制语言切换了,下面看我怎么做的:
这里选中 value 资源目录,创建一个资源文件,就是我们另一份语言的资源文件了
这里从下方选中 locale 移到右边去,注意 Language 里面的小字哈
我们在 Language 里面输入 Tibetan,这时候这我们的藏语就出来了,实际找也能找到,我这里只是想说明安卓支持的语言并不仅仅是网上列举的那些。
这里我创建的是 strings.xml,也就是我们的字符串资源文件
使用字符串资源文件
还记得我们在代码和布局文件总直接使用字符串的警告吗?
一般来说我们可以使用下面代码抑制警告,如果你和我一样不能接受任何一个 warning 的话
@SuppressLint("SetTextI18n")
tools:ignore="HardcodedText"
但是这些警告是提示你直接使用字符串不适合国际化,我们需要使用多语言,就不应该忽视这些警告,而是应该尽量使用字符串资源文件去加载字符串,怎么使用应该不用说了。
修改应用语言设置
配置好不同资源后,应用如果不做任何修改的话,将会跟随系统的语言,可以自己试试。但是一般在应用总提供设置功能比较好,下面是在应用总设置语言的代码:
Resources resources = context.getResources();DisplayMetrics dm = resources.getDisplayMetrics();Configuration config = resources.getConfiguration();resources.updateConfiguration(config, dm);
下面是我写的代码,可以参考,也是抄的各家博文
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)public static void setLanguage(Context context) {//读取SharedPreferences数据,默认选中第一项SharedPreferences preferences = context.getSharedPreferences("language", Context.MODE_PRIVATE);int language = preferences.getInt("language", 0);//根据读取到的数据,进行设置Resources resources = context.getResources();//注意application的context也更新,不然getString的国际化不生效DisplayMetrics displayMetrics = resources.getDisplayMetrics();Configuration configuration = resources.getConfiguration();switch (language){case 0:Locale locale;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {LocaleList localeList = LocaleList.getDefault();locale = localeList.get(localeList.size() - 1);} else {locale = Locale.getDefault();}configuration.setLocale(locale);break;case 1:configuration.setLocale( Locale.CHINESE);break;case 2:configuration.setLocale(new Locale( "bo", "rCN" , ""));break;default:break;}resources.updateConfiguration(configuration,displayMetrics);}
这里还是有东西需要注意的,使用 context 对语言进行设置是不完全的,比如你使用的是 activity 的 context 进行设置的话,在 java 代码总使用 getString 获取字符串是不生效的,需要将 application 的 context 也设置一遍:
//写在第一个界面(LoginActivity)中,在第一个界面设置了就可以if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {//设置多语言LanguageUtil.setLanguage(getContext());//注意application的context也更新,不然getString的国际化不生效LanguageUtil.setLanguage(getApplicationContext());}//注意需要写在 setContentView 前面setContentView(_aty_login);
这里注意两个都需要设置,不然多语言设置会不完全。并且 application 的 context 不能使用 application 代替,不然不会生效。
Locale的设置
注意 Locale 默认提供的区域并不多,至少从里面找不到藏语之类的,还好我们可以自己创建
Locale locale;//默认提供locale = Locale.CHINESE;//自行创建locale = new Locale( "bo", "rCN" , "");
使用 ctrl + p 很容易知道里面的参数,这里其实和我们在 Android Studio 中创建的情况差不多,前一个是语言简称,后面是国家区域,第三个我也不清楚,可以不填。
兼容设置
根据网上博客提示,好像系统版本高于 7.0 会出现问题,大概就是高于 7.0 获取的默认 Locale 是一个列表,我直接用下面代码在安卓10是没问题的,默认语言也是对的:
Locale locale;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {LocaleList localeList = LocaleList.getDefault(); locale = localeList.get(localeList.size() - 1); } else {locale = Locale.getDefault(); }
多语言的持久化
我们设置的多语言不能因为应用被杀进程就消失了,所以应该使用 SharedPreferences 储存起来,这里简单写一下储存的吧,获取的在前面有:
private void changeLanguage() {//创建单选框final AlertDialog.Builder builder = new AlertDialog.Builder(UserMoreAty.this);builder.setSingleChoiceItems(new String[]{getString(R.string.user_language_auto), getString(R.string.user_language_chianese), getString(R.string.user_language_tibetan)},getSharedPreferences("language", Context.MODE_PRIVATE).getInt("language",0),new DialogInterface.OnClickListener() {//点击单选框某一项以后public void onClick(DialogInterface dialogInterface, int i) {//将选中项存入SharedPreferences,以便重启应用后读取设置SharedPreferences preferences = getSharedPreferences("language", Context.MODE_PRIVATE);SharedPreferences.Editor editor = preferences.edit();editor.putInt("language",i);editor.apply();dialog.dismiss();//退出登录生效Intent intent = new Intent(activity, LoginActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | iIntent.FLAG_ACTIVITY_CLEAR_TASK);iactivity.startActivity(intent);}});dialog = builder.create();dialog.show();}
多语言生效问题
如上面代码设置所写,需要将 activity 栈中的页面清除,并重新开启 activity,一般来说直接让重新登陆就可以(我这设置写在登陆界面里)。
对于无感觉切换语言,我是觉得不太可能,毕竟界面已经刷新出来了,重新启动 activity 肯定会闪一下的,网上有人说下面办法可以解决闪屏问题,我没试过,可以参考:
<!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item><!--禁用窗口的预览动画--><item name="android:windowDisablePreview">true</item></style>
结语
东西不是很难,写下来发现写的有点乱,但是尽量把重要的点都写出来了,稍微总结一下:
创建不同语言的资源文件使用资源文件中的字符串编写代码和布局文件提供设置多语言的功能,储存到 SharedPreferences 中设置选定语言后清空 activity 栈,根据需要重新开启一个页面每次登录,在第一个界面读取 SharedPreferences 数据,设置选中语言
end