前言
我们在使用Android手机系统的时候经常在“设置”项里面会提供用户多种系统语言选择,比如:中文、英语…… 大家或许已经发现这些语言显示顺序都是“从左往右”;但是有一些语言是“从右往左”显示的,比如阿拉伯语、希伯来语等语言,当在这种语言环境下时,我们需要怎么来处理布局文件呢?接下来的时间我们就来讨论处理阿拉伯语等“从右往左”显示语言的问题。
布局
首先我们先讲解布局问题,在Android系统中为了支持不同语言显示,可以定义特定(阿拉伯语、希伯来语……)语言布局文件,具体如图所示:
图中layout-ar对应的就是阿拉伯语的布局文件,因此我们只需要修改该目录下的布局文件,就可以实现我们在阿拉伯语言环境中的现实效果。在Android4.2之前,我们需要对每一种“从右往左”显示的语言copy一份布局文件进行修改,如图中layout-fa layout-iw等,这样做的缺点就是会产生许多冗余布局文件。
Android4.2版本之后,Google针对阿拉伯等bidi语言(备注:bidi语言即“从右往左”书写的语言)view和文字布局文件做了重大修改,类似2D图形加速机制,可以从Activity/Application控制、Window代码控制、View资源控制共3个级别的控制。所有关于bidi语言的布局文件都可以放在layout-ldrtl目录,如图所示:
layout-ldrtl是Google专门为bidi语言预留的布局目录,所以在Android4.2版本之后,layout-fa layout-iw等目录可以直接删除,只需要在layout-ldrtl目录下定义bidi语言布局即可。
Activity/Application控制
在Manifest文件中我们可以设置android:supportsRtl属性,具体请参考如下代码:
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:supportsRtl="true" >
View控制
在layout-ldrtl目录的布局文件中设置android:layoutDirection属性,具体请参考如下代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layoutDirection="rtl" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" android:layoutDirection="rtl" /> </LinearLayout>
备注:layout-ldrtl优先级介绍,layout-ldrtl优先级要低于语言级别(layout-ar),因此如果存在layout-ar目录,会首先去查找layout-ar目录下的布局文件,因此建议删除layout-ar等bidi语言目录。layout-ldrtl优先级又高于分辨率等级,优先级归纳如下:
layout-ar(语言级别) > layout-ldrtl > layout-800*540(分辨率)
代码控制
介绍了以上两种静态的控制方式后,我们再来看看动态控制bidi语言显示方式,具体请参考如下代码:
if ("ar".equals(Locale.getDefault().getLanguage())) { getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL); }
以上就是bidi语言涉及的布局修改及配置方式,组合使用以上几种方式便可以解决我们在国际化中遇到的bidi语言问题。
HashCode
当大家阅读到这儿的时候,可能会存在疑问,Hashcode和语言会有什么关系呢?其实Hashcode问题才是最终决定我写这篇博客的目的。说到Hashcaode我们先来回忆一下Java中hashcode的作用,简单的说hashcode就是标识对象的唯一标识(备注:非严谨的说法)。最近在开发Android系统开发中遇到这样一个问题,当手机拍照后正常显示(图标显示Camera图标)应该如图1-1所示:
图1-1 图1-2
但是在Azeri和Turkish语言环境中却显示成了文件夹图标,如下图1-2所示,经过调查最终发现是以下代码在不同语言环境下Hashcode不同造成的,具体代码如下所示:
public static int getBucketId(String path) { return path.toLowerCase().hashCode(); }
按照以下方式更改后就能正常显示,具体代码如下:
public static int getBucketId(String path) { return path.toLowerCase(Locale.ENGLISH).hashCode();//使用英语字符转换 }
Android的解释信息如下:
Converts this string to lower case, using the rules of locale.
Most case mappings are unaffected by the language of a Locale. Exceptions include dotted and dotless I in Azeri and Turkish locales, and dotted and dotless I and J in Lithuanian locales. On the other hand, it isn‘t necessary to provide a Greek locale to get
correct case mapping of Greek characters: any locale will do.
大概意思就是阿塞拜疆和土耳其语言环境中使用的字符编码不一样,我们必须将字符编码设置成统一的本地编码这样Hashcode才保持一致
具体编码请参考:http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt
总结:Android语言国际化就总结这么多,希望对大家有所助力;大家如果对语言国际化有新的见解或者更好的实现方式,请在commit中评论,我们共同讨论。
Android 语言国际化