Android的应用多语言开发
<p>2020-02-02</p><p>关键字:自动切换语言、高版本下应用内多语言切换</p>
<hr>
<p> </p>
<p>在 Android 应用开发中,最简单的多语言实现就是直接在 res 目录下将你需要的不同语言的资源以 values-xx 子目录的形式存放。</p>
<p> </p>
<p>例如,res 目录下默认只有一个 values 目录,这个目录下存放的资源就是应用默认使用的资源,包括文字、色彩值、尺寸、样式等等等等。</p>
<p> </p>
<p>如果你默认目录下使用的是中文,现在想要增加一个英文,则只需要自行创建多一个目录,以名称 values-en 命名即可。然后将 values 目录下的资源文件翻译好后拷贝过去即可。</p>
<p> </p>
<p>这种情况下应用选择的语言环境是跟着 Android 系统走的,即系统的显示语言是什么它就读取哪个目录下的资源。当我们的应用中没有与系统对应的资源时,就使用默认的 values 目录下的资源。</p>
<p> </p>
<p>想象一下,这种可以将不同语言分目录保管,并自动加载的机制是不是可以让我们的应用更容易做到“全球化”?</p>
<p> </p>
<p>举个例子来说就是,我们不说文字,这个太肤浅。假如你正在开发的一款应用,它的其中一个页面的基本色调是天蓝色。而偏偏有一个民族的人非常忌讳天蓝色,他们更喜欢大红色。那我们有这套机制解决起这个问题来岂不易哉。代码完全不用改,只需要准备两套基本色调配置表即可。这种机制真是太妙了。</p>
<p> </p>
<p>言归正传。世界上不同语言种族这么多,我们很难记得住每个国家地区的对应缩写是什么。那我们要如何来创建这个 values-xx 目录呢?</p>
<p> </p>
<p>如果你是使用 Android Studio 来开发应用的,那这个就不难。只需要按照如下步骤操作即可由 Android Studio 自动帮你创建对应目录:</p>
<p style="text-align: center"><img src="https://img2018.cnblogs.com/i-beta/1146198/202002/1146198-20200202201907068-895205622.png"></p>
<p> </p>
<p style="text-align: center"><img src="https://img2018.cnblogs.com/i-beta/1146198/202002/1146198-20200202202003743-1167552028.png"></p>
<p style="text-align: center"><img src="https://img2018.cnblogs.com/i-beta/1146198/202002/1146198-20200202202028261-1797111805.png"></p>
<p> </p>
<p> </p>
<p>当然,其实也完全可以手动创建目录与资源文件,如果你知道它的对应缩写的话。</p>
<p> </p>
<p>而 Android Studio 中也有很方便的多语言资源编辑工具,可以让开发者很方便地以对照式来编辑不同语言的资源。其操作步骤如下图所示:</p>
<p style="text-align: center"><img src="https://img2018.cnblogs.com/i-beta/1146198/202002/1146198-20200202202443752-1615922948.png"></p>
<p> </p>
<p style="text-align: center"><img src="https://img2018.cnblogs.com/i-beta/1146198/202002/1146198-20200202202505976-901462730.png"></p>
<p> </p>
<p> </p>
<p>以上是跟随 Android 系统来切换显示语言的情况。但有些应用可能还需要能够摆脱操作系统的设置,自行选择显示语言。这该怎么办呢?</p>
<p> </p>
<p>其实也不难。只需要<strong>在上述步骤的基础之上</strong>,再在应用启动时自行设置一下显示语言就可以了。</p>
<p> </p>
<p>为了全局统一,一般是在自定义的 Application 类的初始化中来设置。</p>
<p> </p>
<p>这里简单说一下笔者的一个比较简单的解决方案。</p>
<p> </p>
<p>因为是应用自行控制语言选项,因为应用需要自行保存当前选择的显示语言。笔者采用的是 SharedPreferences 来保存。</p>
<p> </p>
<p>从 SharedPreferences 中读取出要显示的语言以后,再通过如下代码设置即可:</p>
<div class="cnblogs_code">
<pre> Configuration conf =<span style="color: rgba(0, 0, 0, 1)"> context.getResources().getConfiguration();
<span style="color: rgba(255, 0, 0, 1)"><strong>conf.locale </strong></span></span><span style="color: rgba(255, 0, 0, 1)"><strong>= isThai ? new</strong></span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(255, 0, 0, 1)"><strong> Locale(LOCALE_THAI) : Locale.SIMPLIFIED_CHINESE;</strong></span>
context.getResources().updateConfiguration(conf, context.getResources().getDisplayMetrics());</span></pre>
</div>
<p>上述代码已将关键的一行以加粗标红表示出来了。需要注意的是,Locale 类默认提供的语言并不全面。如果恰巧你需要的语言各类它没有默认提供,正如笔者上面所需要的泰语言一样,那就需要你自行实例化一个 Locale 对象。实例化时直接将对应语言的缩写作为参数传入即可。如笔者上面的实例化泰语言时,它的写法就是:new Locale("th");。</p>
<p> </p>
<p>如此即可。</p>
<p> </p>
<p>对了,这种方式似乎是针对较低版本的 Android 系统的,这段代码笔者最高在 Android7.0 上运行通过过。其它更高版本的系统似乎还有另外一种写法,那种写法笔者没有去研究过,就不贴出来了,仅在此提一下。</p>
<p> </p>
<p> </p>
<p>最后,笔者不得不提一下应用多语言显示与 AppCompact 主题之间的冲突。</p>
<p> </p>
<p>这个冲突当初可是困扰了笔者一整天。</p>
<p> </p>
<p>具体现象就是在正确设置好 values-xx 资源目录以后,发现应用怎么都不能切换至对应语言风格去显示。无论是用跟随系统显示语言的方式还是手动指定显示语言的方式。</p>
<p> </p>
<p>当时笔者真是各种加打印,各种百度谷歌都找不到原因。</p>
<p> </p>
<p>在几近绝望的时候偶然发现在另外一个 Activity 中能够将语言给切换过来。(注:笔者开发的是一款需要登录的应用,且这个应用有免密登录功能。笔者先前保存过登录信息,因此应用每次打开都只显示一个固定的界面。)</p>
<p> </p>
<p>唯独那个主 Activity 的语言死活不能切换。</p>
<p> </p>
<p>有了这个对照,至少证明了笔者的资源配置没有错,甚至也可以证明手动切换显示语言的代码也没有错。</p>
<p> </p>
<p>那就只能在这两个 Activity 中找差异了。</p>
<p> </p>
<p>经过对比,笔者最终发现是因为这两个 Activity 所使用的主题样式,就是 style 不同而导致另一个 Activity 不能切换显示语言的。</p>
<p> </p>
<p>这个不能让应用切换显示语言的主题就是 AppCompact 主题:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">style </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="App_Compact_Theme"</span><span style="color: rgba(255, 0, 0, 1)"> parent</span><span style="color: rgba(0, 0, 255, 1)">="Theme.AppCompat.Light.NoActionBar"</span><span style="color: rgba(0, 0, 255, 1)">/></span></pre>
</div>
<p> </p>
<p>笔者的主 Activity 使用到了 Fragment,因此最开始继承了 AppCompactActivity 类,而这个 AppCompactActivity 类又要求其主题必须是 AppCompact 的主题。至于为什么这个主题会不能切换显示语言,笔者倒是没有去深究,也觉得没有必要。</p>
<p> </p>
<p>最终笔者将主 Activity 的父类换成 FragmentActivity,再将 style 更换成 <style name="Normal_theme" parent="android:Theme.Light.NoTitleBar"/> 以后成功地解决了问题。</p>
<p> </p>
<p>以上就是笔者关于Android应用多语言开发的心得与笔记。</p>
<p> </p>
<p> </p>
<h1>关于Android8.0及以上版本系统下的应用内多语言切换</h1>
<p>在Android8.0及以后的版本系统下,上述的语言切换功能将失效。原因是Android自那以后改变了系统语言控制架构。</p>
<p> </p>
<p>因此,我们的软件中关于显示语言功能需要针对高低版本做两套兼容代码。</p>
<p> </p>
<p>因绝大多数情况下仅Activity需要展示UI,所以这里仅针对Activity来讲解。</p>
<p> </p>
<p>首先,我们要将应用内所有的Activity的Context实例做个自定义,即在每个Activity实例化之初给它一个已经指定了显示语言种类的Context实例。</p>
<p> </p>
<p>怎么做呢,给我们的Activity重写 attachBaseContext() 方法:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> @Override
</span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> attachBaseContext(Context newBase) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(Build.VERSION.SDK_INT ><span style="color: rgba(0, 0, 0, 1)"> Build.VERSION_CODES.N_MR1){
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.attachBaseContext(getSelfContext());
}</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.attachBaseContext(newBase);
}
}</span></pre>
</div>
<p>这里有个小坑要注意的,在这个方法刚执行时,其参数中的 newBase 将是 null。因为Activity生命周期中调用这个方法就是为了获得Context实例的,此时它当然还没有任何可以使用的Context对象的了。</p>
<p> </p>
<p>其次,根据自己的业务逻辑,准备相应的 Context 实例给到上面的方法,即上面 getSelfContext() 方法的实现:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Context getSelfContext(Context ctx){
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(Build.VERSION.SDK_INT ><span style="color: rgba(0, 0, 0, 1)"> Build.VERSION_CODES.N_MR1) {
Configuration conf </span>=<span style="color: rgba(0, 0, 0, 1)"> getApplicationContext().getResources().getConfiguration();
LocaleList ll </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> LocaleList(isThai ? <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Locale(LOCALE_THAI) : Locale.SIMPLIFIED_CHINESE);
conf.setLocales(ll);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ContextWrapper(getApplicationContext().createConfigurationContext(conf));
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ctx;
}</span></pre>
</div>
<p> </p>
<p>如此,便可。</p>
<p> </p>
<hr>
<p>参考博客: https://www.jianshu.com/p/32ff13db1f0d</p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
+++<br><br>
来源:https://www.cnblogs.com/chorm590/p/12229889.html
頁:
[1]