Android中的string资源占位符及Plurals string
Android支持以占位符的方式,定义字符串。
例如,在xml中定义:
.........%s crimes .........
在使用该字符串时,可以在运行时动态替换占位符号,例如:
.............//crimeCount将出现在上面字符中%s的位置String subtitle = getString(R.string.subtitle_format, "" + crimeCount);.............
然后,不同的语言对数量的语法规定有不同的规则。
例如一棵树是one tree, 两颗树是two trees。
为了解决后缀的问题,Android引入了plurals 这种资源,其xml定义类似于:
<!--定义到资源文件即可 --><plurals name="subtitle_plural"> <item quantity="one">%s crimeitem> <item quantity="other">%s crimesitem>plurals>
在代码中的使用规则如下:
..............int crimeCount = crimeLab.getCrimes().size();//第一参数为resId,第二个参数为数量,第三个为替换占位符的字符String subtitle = getResources().getQuantityString( R.plurals.subtitle_plural, crimeCount, crimeCount);..............
不过plurals的使用,受到系统当前语言(本地化)的限制。
例如,当终端的首选语言为英文时,上面的代码可以很好的工作:
但当系统语言切换为中文时,就会出现问题:
可以看出plurals失效了,为什么会出现这种情况?
为了解释这个问题,只能看看Android源码是如何实现的。
我们从Android 7.0中Resource.java的代码入手:
@NonNullpublic String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs) throws NotFoundException { //容易看出,先根据quantity决定要使用的字符串 String raw = getQuantityText(id, quantity).toString(); //再进行占位符的替换工作 return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw, formatArgs);}@NonNullpublic CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { //依赖于ResourceImpl的实现 return mResourcesImpl.getQuantityText(id, quantity);}
跟进ResourceImpl中的getQuantityText函数:
CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { //得到规则 PluralRules rule = getPluralRule(); //rule.select根据规则,得到quantity对应的QuanitiyCode,即"zero"、"one"、"other"等 //之后再根据QuanitiyCode,的到具体的资源文件 CharSequence res = mAssets.getResourceBagText(id, attrForQuantityCode(rule.select(quantity))); if (res != null) { return res; } //rule没能找到对应的QuanitiyCode时,就用"other"字段的定义 res = mAssets.getResourceBagText(id, ID_OTHER); if (res != null) { return res; } //上面寻找资源文件出问题,就抛出异常 throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id) + " quantity=" + quantity + " item=" + rule.select(quantity));}
这里我们首先看一下getPluralRule函数:
private PluralRules getPluralRule() { synchronized (sSync) { if (mPluralRule == null) { //单例模式,且和本地化有关,以Locales的第一个配置来初始化规则 mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); } return mPluralRule; }}
PluralRules的select函数对应的底层实现,在此不作深研究,不同的Locales应该有不同的实现。
在此看看attrForQuantityCode:
private static int attrForQuantityCode(String quantityCode) { switch (quantityCode) { case PluralRules.KEYWORD_ZERO: return 0x01000005; case PluralRules.KEYWORD_ONE: return 0x01000006; case PluralRules.KEYWORD_TWO: return 0x01000007; case PluralRules.KEYWORD_FEW: return 0x01000008; case PluralRules.KEYWORD_MANY: return 0x01000009; default: return ID_OTHER; }}
从上面的代码可以看出,PluralRules的select函数的作用,就是将quantity映射成PluralRules定义的Keyword。
然后attrForQuantityCode将Keyword转化成资源文件能识别的标志。
现在回到我们之前的问题,为什么终端语言为中文时,Plurals string失效?
原因是attrForQuantityCode的结果一直是ID_OTHER,即中文对应PluralRules无法有效将Quantity转化为正确的Keyword。
当然,Google的这种设计并不是Bug,毕竟中文语言环境下,App的显示就应该是中文,本来就没有这种需求。
更多相关文章
- android 日期控件对话框
- android自定义View-垂直滚动的TextView
- Android(安卓)中文API(86)――ResourceCursorAdapter
- android如何使用自定义JNI接口,以及NDK工具的环境搭建与使用。
- listview(1、BaseAdapter)
- Android麦克风录音带音量大小动态显示的圆形自定义View
- UI控件--自定义SeekBar样式
- Android(安卓)中文API (91) —— GestureDetector
- 彻底解决Android(安卓)studio中文乱码问题