前言
安卓应用内多语言设置其实不难,但是适配存在很多坑,我把这类问题归属为难度不大,但需要经验的那一类问题,因为适配会存在很多坑,换而言之就是要把这个功能点做好如果是第一次接触肯定会踩很多坑浪费很多时间。网上关于这方面的介绍也很多,但是很多都是几年前的文章,实际实践中发现在某些机型上或许原先起作用的方法现在不起作用了,尤其是8.0系统。所以本博客简单做个记录。
多语言实现三部曲
实现多语言一般遵循如下三个步骤
- 创建各个语言的字符串资源文件
- 在需要进行语言展示的地方使用R.string.xxx(如果是xml中文字展示直接使用@string/xxx的形式)或者getString进行文字展示,而不要直接使用某种语言展示,比如
mStatusTip.setText(R.string.tip_loading);//而不要mStatusTip.setText("正在加载,请稍后...");如果是在xml中的字符串显示android:text使用@sting/xxx,比如:
android:text="@string/login"//而不要android:text="登陆"
- 调用安卓系统提供的API进行语言切换和设置(如果需要可将当前设置进行持久化保存)
如果要让语言切换设置后马上生效,需要重启Activity。
下面按照上面三个步骤详细说明:
选中res目录,右键依次点击New->Android Resource File,如下图所示:
在弹出的New Resource File面板左侧选择Locale,文件名一般输入strings毕竟我们做的是多语言切换,文字属于字符串资源。
然后点击中间的>>按钮右侧就会出现语言和地区/国家相关的一些配置项,如图所示:
然后我们选择我们需要设置的那个国家/地区即可,选择完成之后此时res目录下就会自动为我们创建该语言的strings的资源文件,如下所示:
文件的命名形如values-xx-rXX的形式,其中xx表示语言类型,XX表示国家或者地区,比如zh-rCN这个资源文件夹zh表示中文,CN表示中国,这个命名很重要,因为当我们在使用安卓系统提供的API设置Locale变量的值的时候,可能存在我们要设置的语言或国家在该变量中不存在(通常为一些非国际知名国家,比如泰国,越南),此时我们无法通过如下方式创建Locale
Locale locale = Locale.US;//Locale内置US
而需要使用其构造函数public Locale(String language, String country) 创建Locale变量,如下所示:
Locale locale = new Locale("th","TH");
其中的th就是资源文件values-xx-rXX中的xx,TH就是XX。所以说这个命名很重要,安卓系统就是根据这个去寻找该语言对应的资源文件的字符串的内容的。
然后把默认的values/strings.xml中的内容全部复制到values-xx-rXX/strings.xml中,接着把内容中的文字翻译成对应的语言即可
为了使用多语言设置,让app内的文字根据用户语言设置类型进行展示,此时在代码或者xml界面中setText和android:text属性不能直接硬编码为某种语言,而是需要将其引用为R.string.xxx(代码中),@string/xxx(xml界面中)的形式。这样当我们调用了安卓系统提供的资源更新的API接口之后才会使用相应的values目录下的字符串语言资源。
首先创建该语言对应的Locale对象,如下是个简单示例代码:
private void setLocalLanguage(LangType langType) {
Locale locale;
switch (langType) {
case LANG_ZH_TW: {
locale = Locale.TAIWAN;
}
break;
case LANG_EN: {
locale = Locale.US;
}
break;
case LANG_JA: {
locale = Locale.JAPAN;
}
break;
case LANG_KO: {
locale = Locale.KOREA;
}
break;
case LANG_TH: {
locale = new Locale("th","TH");
}
break;
case LANG_VI: {
locale = new Locale("vi","VN");
}
break;
default:
locale = Locale.SIMPLIFIED_CHINESE;
break;
}
changeLocalLanguage(context, locale);
}
然后调用安卓系统提供的API接口进行语言设置的资源更新,如下是核心代码
private void changeLocalLanguage(Context context, Locale locale) {
Resources resources = context.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
Configuration config = resources.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//8.0及以上系统
LocaleList localeList = new LocaleList(locale);
LocaleList.setDefault(localeList);
config.setLocales(localeList);
context.createConfigurationContext(config);//对于8.0系统必须先调用该语句,否则后面的updateConfiguration不起作用
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4及以上系统
config.setLocale(locale);
} else {
config.locale = locale;
}
resources.updateConfiguration(config, dm);//所有的系统都需要调用该API
}
在实际开发中发现的坑
- 在使用Locale内置的常量创建Locale对象的时候,推荐使用国家名常量创建。因为如果使用的是语言类型创建的,在某些机型上会不起作用,比如:
locale = Locale.JAPANESE;//在某些机型上会不起作用
而使用国家名创建则不存在该问题,比如:
locale = Locale.JAPAN;
- 使用构造函数public Locale(String language, String country) 创建Locale对象的时候,传入的参数需要与资源文件名values-xx-rXX中的xx和XX保持一致
- 调用安卓系统提供的API接口进行语言设置的资源更新的时候传入的context推荐使用Activity,在实际开发过程中发现传入Application的Context在某些机型上不起作用
- 对于8.0系统必须先调用context.createConfigurationContext(config);否则后面的updateConfiguration不起作用。




文章评论