最近安卓开发遇到一个新的需求,需要支持多语言,而且还是我们五十六个大家庭中的藏语,一时间点懵了,毕竟从来没搞过多语言,一下来的还是比较小众的。后面研究了一番那个,还是大致搞出来了,这里简单写篇博客记一下。

官方文档

以前一有问题总喜欢在网上瞎找博客教程,后面发现很多写的很好的博文都是抄的官方文档,就把官方文档收藏了,有问题先看官方文档,下面是官方文档对多语言的教程:

https://developer.android.google.cn/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(R.layout.com_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>


结语

东西不是很难,写下来发现写的有点乱,但是尽量把重要的点都写出来了,稍微总结一下:

  1. 创建不同语言的资源文件
  2. 使用资源文件中的字符串编写代码和布局文件
  3. 提供设置多语言的功能,储存到 SharedPreferences 中
  4. 设置选定语言后清空 activity 栈,根据需要重新开启一个页面
  5. 每次登录,在第一个界面读取 SharedPreferences 数据,设置选中语言

end

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐