Android跨语言字符串资源报错:非位置格式指定多替换项的最优解决方案咨询
Android跨语言字符串资源报错:非位置格式指定多替换项的最优解决方案咨询
Hey,碰到这个编译报错确实挺闹心的,我结合自己做Android本地化踩过的坑,给你把这两个方案的适用场景、还有你担心的问题都讲明白:
先搞懂两个方案的适用场景
1. 改成位置格式化符(%1$s、%2$s)—— 优先推荐给需要动态替换变量的场景
如果你的字符串确实需要动态替换多个变量(比如例子里的“From: %s (%s)”,要填发件人名称和邮箱),那必须改成带位置标记的格式,而且所有语言的对应字符串都要同步修改。
- 为什么要这么做?因为不同语言的语序逻辑天差地别,比如有的语言会把括号里的信息前置,用位置标记后,翻译人员可以自由调整字符串的语序结构,同时保证变量对应正确的内容,本地化的灵活性高太多了。
- 举个例子:原英文写成
<string name="forward_body_prefix_from">From: %1$s (%2$s)</string>,翻译成韩语可能调整为<string name="forward_body_prefix_from">%2$s - %1$s 님으로부터</string>,这样用户看到的内容符合韩语的阅读习惯,变量也不会串位。
2. 添加formatted="false"属性—— 仅适合纯文本包含%s等符号的场景
如果你的字符串里的%s根本不是用来动态替换的(比如要显示一段代码示例、正则表达式,或者只是文本里的固定占位符),那直接给<string>标签加这个属性就行:
<string name="code_snippet" formatted="false">示例代码:String pattern = "user_%s";
- 踩坑提醒:加了这个属性后,系统会把所有
%开头的符号当成普通文本显示,如果你之后再想用这个字符串做动态替换,肯定会失效,所以一定要确认这个字符串不需要格式化再用。
关于复数和本地化排序的那些坑
复数的注意事项
如果用位置格式化符搭配复数资源,只要保证每个复数分支里的位置标记和主逻辑的变量对应一致就没问题。比如:
<plurals name="message_count"> <item quantity="one">你有 %1$d 条来自 %2$s 的新消息</item> <item quantity="other">你有 %1$d 条来自 %2$s 的新消息</item> </plurals>
这里%1$d对应消息数量,%2$s对应发件人,不管复数形式怎么变,位置标记对应正确就不会出错。千万不要在复数分支里乱改位置标记的序号,不然会出现变量串位的问题。
本地化排序的坑
这其实就是为什么我们优先推荐位置格式化符的核心原因!如果不用位置标记,直接用%s,不同语言翻译后变量顺序会完全混乱。比如原英文是“%s shared %s photos with you”,翻译成阿拉伯语可能会变成“%2$s صور مشاركة من %1$s معك”(直译:%2$s 照片 来自 %1$s 与你),这时候如果不用位置标记,就会出现“照片数量 shared 发件人 photos with you”这种完全不通的内容。
额外的小坑
- 不要混用两种方案:如果有的字符串改了位置标记,有的加了
formatted="false",后期维护的时候很容易搞混,最好在团队里统一规范。 - 搭配Compose使用要注意:如果用
stringResource调用带位置标记的字符串,要按顺序传参数;如果调用加了formatted="false"的字符串,就别传格式化参数,不然会显示异常。
内容来源于stack exchange
相关产品推荐
相关产品推荐

