安卓修改大师智改工坊 · 多语言精修专题

经典版补全多语言:values 目录、默认语言与缺项检查

切到英文后,首页还夹着中文;按钮文字被截成两行;明明是同一个应用,繁体界面却有几处空白。多语言问题很少是“翻译得不好”,更多是资源目录、默认语言和缺项没有被系统整理。本文用修改大师经典版走一遍手工补全流程:反编译、盘点 values 目录、补 strings.xml、查缺项、回编、装机验收。

了解修改大师经典版

只需说话,就能让应用变成你想要的样子。这句品牌口号描述的是智改工坊的方向;经典版走的是手工精修路线,下面每一步都由你亲手确认。

先还原一个很常见的验收现场:把手机系统语言切成英文,打开自家应用,启动器里的名字是英文,首页标题却还是中文;点进设置,按钮被截成“Settin…”;再点错误提示,弹出一段空白。开发者第一反应往往是“翻译没做完”,于是把 strings.xml 又翻了一遍,问题依旧。因为多语言的呈现由三套东西共同决定:资源目录里的键值、默认语言的回退、以及那些根本没进资源文件的硬编码文字。

翻译只解决第一套。默认语言决定“找不到翻译时拿什么顶上去”,硬编码决定“有些文字永远不跟着语言变”。这三件事任何一件没处理,界面就会露出破绽。本文按“先认清目录、再做清单、再补内容、最后查缺项”的顺序展开,每一步都说明在经典版里做什么、看到什么、怎么判断做对了。

修改大师经典版是 Windows 上的手动精修工具,安装包约 13.74 MB,环境要求 ASP.Net 4.5 以上、JDK 1.8 以上。它的工作方式是手动反编译,然后把 smali 和资源工程摊开给你改,适合汉化、功能增强这类需要逐处确认的任务;也支持导出 Android Studio 工程,方便后续继续维护。它不追求“一句话改完”,追求的是每一步可控、结果可复现。补多语言恰好属于这种工作:键名、占位符、目录限定符,任何一处马虎都会在真机上被放大。

合规边界先讲清楚。本文只讨论自有版权或已经获得授权的应用,例如自己公司开发的内部工具、自己团队运营的展示类应用、客户书面授权你维护的产品。请勿用于破解他人付费应用、去除授权校验或绕过安全机制,也不要拿去修改来源不明的商业软件。多语言补全本质上是对自己资产的整理,不是绕过别人的规则。

读法建议:第一次做多语言,从第一节顺着往下走,先建目录认知,再做清单,最后才动手改 XML;已经有多语言工程、只是缺项的读者,可以直接看第四节和第七节,前者讲 strings.xml 的硬规则,后者讲缺项检查。文中出现的键名、目录名和脚本都做过去标识处理,替换成你自己的项目即可。

可以用一个仓库的比喻理解整件事:默认的 values 目录是总仓,values-en、values-zh-rTW 是分仓。顾客走到分仓,先看分仓有没有货;没有就回总仓取。总仓缺货,分仓再满也会露馅;分仓有货但标签写错,顾客拿到的就是错的东西。多语言补全,就是把总仓和分仓的货架都对齐。

多语言资源目录与翻译清单的桌面

图 1:多语言不是一份翻译表,而是默认语言、分语言目录与回退规则共同组成的资源体系。

多语言缺项的三个来源:默认语言、限定符与硬编码

第一个来源是默认语言不完整。Android 的资源回退规则很直接:系统按当前语言去找最匹配的目录,找不到某个键,就回到没有限定符的 values 目录取。默认目录里缺一个键,英文用户看到的可能是空白,也可能是上一次编译残留的旧值,还可能是运行时异常。很多人只检查 values-en 是否翻全,却忘了 values 本身才是最后的兜底。

第二个来源是限定符不匹配。目录名不是随便写的,values-en 表示英语,values-en-rUS 表示美式英语,values-zh-rCN 表示简体中文,values-zh-rTW 表示繁体中文。系统在 en-GB 环境下,会优先找 en-GB,再找 en,最后回默认;如果你只建了 values-en-rUS,en-GB 设备就可能直接回默认。限定符越具体,覆盖范围越窄,写错一个地区码,整批用户都吃不到翻译。

第三个来源是硬编码。有些文字写在布局的 android:text 里,有些写在 smali 的 const-string 里,有些干脆画在图片上。资源文件翻得再全,这些文字也不会变。它们是多语言验收里最隐蔽的一类:开发者切了语言,看到大部分界面正常,就以为完成了;测试人员点进一个不常去的页面,才发现那里整页都是默认语言。

除了这三类,还有一组“结构型”资源容易被漏:string-array 的每一项、plurals 的单复数分类、带占位符的格式化文本、菜单项和无障碍描述。它们不在 strings.xml 的普通条目里,翻译工具按行导出时经常被跳过。补多语言时要把它们单独列出来,不能只盯着普通字符串。

界面现象 常见根因 先查哪里
大部分英文,个别位置仍是中文 该键在 values-en 缺失,回退到默认中文 键集合对比,先看 values 与 values-en 的差集
整个页面都不翻译 文字硬编码在布局或 smali 里 全工程搜索原文字符串,检查 layout 与 smali
只有部分机型生效 目录限定符与设备语言不完全匹配 核对 values-en 与 values-en-rUS 的覆盖范围
按钮文字被截断 译文比原文长,布局宽度固定 真机截图,逐屏检查按钮与标签
列表项少了一行或错位 string-array 条目数与代码索引不一致 对比默认与翻译目录的 item 数量
格式化文本运行时崩溃 占位符被翻译改动或丢失 提取所有百分号占位符逐条比对

这张表可以直接拿去当排查顺序。先判断“是缺键还是硬编码”,再判断“是目录不匹配还是布局问题”,最后才看翻译质量。顺序反了,就会陷入反复改译文却始终有一个角落不对的循环。多语言是资源工程,不是文字工作,先把结构对齐,再谈措辞。

还有一个容易忽略的细节:应用名也可能有多语言版本。启动器标签来自 AndroidManifest 里的 android:label,它通常指向一个字符串资源;如果这个资源在 values-en 里没有对应项,桌面上的名字就不会跟着变。很多“应用名改不全”的问题,根子不在图标,而在 label 的多语言资源。补语言时把应用名、关于页名称、分享面板名称一起列进清单,能省掉后面一轮返工。

理解了三个来源,接下来的动作就有了方向:先把反编译出来的 values 目录认清,知道哪个是总仓、哪个是分仓,再决定往哪里补。下一节从工程结构开始,把目录和文件逐个对上号。

反编译之后先认清 values 目录:总仓、分仓与限定符

在修改大师经典版里导入 APK,执行反编译,完成后会得到一个可以展开的工程目录。先不要急着打开 strings.xml,先在资源目录里停一分钟,看清有哪些 values 开头的文件夹。它们通常长这样:values、values-en、values-zh-rCN、values-zh-rTW,有的项目还会带 values-night、values-sw600dp、values-v21。名字相近,含义完全不同。

values 没有限定符,是默认资源目录,也是所有回退的终点。values-en 是英语,values-zh-rCN 是简体中文,values-zh-rTW 是繁体中文。values-night 不是语言,是深色模式;values-sw600dp 不是语言,是最小宽度限定符;values-v21 是 API 等级。把 night 或 sw600dp 当成语言目录去翻译,是新手常犯的错误,结果就是“翻了半天,切语言没变化”。

一个 values 目录里通常不止 strings.xml。还可能有 arrays.xml、plurals.xml、colors.xml、dimens.xml、bools.xml、integers.xml。真正需要翻译的是字符串类资源:strings.xml 里的 string、arrays.xml 里的 string-array、plurals.xml 里的 plurals。colors、dimens、bools、integers 一般不需要按语言复制,除非某些地区有特殊的尺寸或开关需求。把不需要翻译的文件也复制一份,会让后续维护变得混乱。

目录或文件 含义 补多语言时怎么处理
values/ 默认资源,无语言限定符 保持键完整,作为回退底
values-en/ 英语资源 补全键值,保留占位符
values-zh-rCN/ 简体中文资源 与默认中文对照,避免重复维护
values-zh-rTW/ 繁体中文资源 注意用词差异,不要只做简繁转换
values-night/ 深色模式资源 不是语言目录,不要整份复制翻译
values-sw600dp/ 平板宽度限定符 按设备形态处理,与语言分开
strings.xml 普通字符串 主要翻译对象,保留键名
arrays.xml 字符串数组 逐项翻译,保持条目数量
plurals.xml 复数形式 按语言保留对应分类,不能删项

目录名有两种写法:旧式限定符和 BCP 47 标签。旧式写法是 values-zh-rCN、values-en-rUS,经典工程里很常见;新式写法是 values-b+zh+Hans+CN、values-b+en+US,aapt2 支持。两种写法在不同工具链版本下的兼容性不完全一样。原则是:工程里原来用哪种,就继续用哪种;新增语言时先看相邻目录的命名风格,不要一半旧式一半新式。混用不是一定会报错,但会让资源匹配和后续维护都变得难查。

还有一个小文件值得看一眼:public.xml。反编译工程里它会列出资源类型、名称和 ID。补语言时不需要改 ID,但可以用它确认某个字符串是否真的被编译进包、类型是不是 string。比如你改了一个叫 app_name 的键,public.xml 里却找不到它,说明它可能不是资源,而是硬编码在别处。这个核对能避免“改了 XML 却没生效”的困惑。

资源目录树与多语言文件夹

图 2:先分清语言目录与夜间、尺寸等限定符目录,再决定翻译范围。

默认目录和分语言目录的关系,建议用“总仓必须全、分仓可以少”来记。分仓允许只放一部分键,缺的会自动回退到总仓;总仓不允许缺键,因为它是最后一层。很多项目反过来做:默认目录只放中文常用文案,英文目录放得很全。结果英文系统下看着正常,中文系统下某些页面反而空白。补语言之前,先用脚本或人工把默认目录的键集合确认一遍。

如果你在默认目录里看到 values-zh-rCN 和 values 内容几乎一样,不要急着删。先确认默认语言到底是什么:有的项目默认就是简体中文,values-zh-rCN 是历史遗留;有的项目默认是英文,values-zh-rCN 才是中文入口。判断方法很简单:把设备语言切成一个没有对应目录的语言,看界面显示什么。显示中文,默认就是中文;显示英文,默认就是英文。这个结论决定了后面往哪个目录补。

目录认清之后,下一步不是马上翻译,而是做清单。没有清单就动手,翻到一半会发现同一个词有三种译法、同一个键在两个文件里重复、某些页面根本找不到对应资源。清单的作用是把“翻译”变成“有边界的工程任务”。

先做语言清单:键名、场景、优先级与术语表

语言清单不是给翻译公司看的表格,而是给你自己看的施工图。它至少要有五列:键名、默认文案、目标语言文案、出现场景、备注。出现场景这一列最容易被省,却最有用。“保存”这个词,在按钮上是 Save,在提示里可能是 Saved,在菜单里可能是 Save changes;没有场景,翻译只能猜。备注列用来记占位符、长度限制、是否允许换行。

生成清单最稳的方式是从工程里导出键集合,而不是从翻译平台反推。修改大师经典版支持导出 Android Studio 工程,导出后可以用 Android Studio 的 Translations Editor 查看所有键和语言列;如果不想开 IDE,也可以用一段很小的脚本,把 values 和 values-en 的 strings.xml 解析成键集合,做差集。两种方式都比“打开文件用眼睛找”可靠。

import sys
import xml.etree.ElementTree as ET

def load_keys(path):
    root = ET.parse(path).getroot()
    return {node.get("name") for node in root if node.get("name")}

base = load_keys(sys.argv[1])
target = load_keys(sys.argv[2])
print("missing:", sorted(base - target))
print("extra:", sorted(target - base))

把这段脚本保存成 check_keys.py,放在工程目录外,运行时传入两个 strings.xml 的路径即可。它只做一件事:比较键集合。missing 是目标语言缺的键,extra 是目标语言多出来的键。extra 不一定是错误,可能是历史遗留,也可能是某个版本独有的资源,但至少说明两份文件不同步。先把这个差集清零,再谈翻译质量。

清单要分优先级。第一优先级是启动器名称、启动页文案、首页标题、底部导航、主要按钮、登录注册、支付相关提示。第二优先级是设置页、关于页、帮助中心、错误提示、空状态。第三优先级是活动页、运营弹窗、免责声明、隐私政策入口。第四优先级是极少出现的调试文案和内部提示。优先级不是永远不变,按你的用户路径调整;但一定要有,否则翻译资源会平均用力,最重要的页面反而最后才验收。

优先级 范围 验收方式
P0 应用名、启动页、首页、登录、支付主流程 每种语言各走一遍主流程
P1 设置、关于、帮助、错误提示、空状态 逐屏截图对照
P2 活动页、运营弹窗、免责声明 按运营档期抽查
P3 调试文案、内部提示、低频页面 键集合检查即可

术语表要单独建。应用名、品牌名、功能名、按钮动词、错误码说明,各定一个译法,后面所有页面都照这个来。比如“订单”在电商里可能是 Order,在团购里可能是 Group order,在门店巡检里可能是 Task。同一个中文词在不同产品里的英文对应不同,术语表要按产品语境定,不是按词典定。术语表不需要长,一页纸就够,但要在开工前定,避免翻到一半改口径。

清单还要记录“不翻译”的项。品牌名、产品代号、日志标签、接口路径、占位符里的变量名、某些第三方 SDK 的回调文案,这些应该标成不翻译。Android 资源里可以用 translatable="false" 标记,翻译工具会跳过。把不该翻的翻了,轻则界面别扭,重则代码里按字符串比较的逻辑失效。清单里有一列“是否翻译”,比事后补救有效。

多语言术语表与优先级清单

图 3:先定场景和术语,再开始翻译,能减少大量来回改稿。

最后,给源工程做一次快照。把反编译后的整个工程目录复制一份,命名带上日期和版本,例如 project-20261021-baseline。后面所有修改都在工作副本里做,快照不动。多语言补全往往会改十几个文件,一旦发现某个页面被改坏,可以拿快照对照,也可以整体回退。手工精修最怕“改到一半忘了原来是什么样”,快照是最便宜的回滚手段。

清单、术语表、快照三样齐了,才可以打开 strings.xml。下一节讲补字符串的六条硬规则,每条都对应一种真实会踩的坑。

补 strings.xml 的六条硬规则:键名、占位符、转义与长度

第一条规则:只改文字,不改键名。name 属性是代码引用资源的唯一入口,改一个字母,代码里对应的 R.string.xxx 就找不到。翻译人员最容易犯这个错:看到键名是英文单词,顺手把它“翻译”了。正确做法是把键名锁死,翻译只动标签之间的文本。批量替换时尤其要小心,搜索替换范围只限文本节点,不要全文件替换。

第二条规则:占位符原样保留。常见形式有 %1$s、%2$d、%f、%1$.2f,带序号的是位置参数,不带序号的是顺序参数。翻译时可以调整位置参数的出现顺序,但不能改变类型和数量。比如原文是“%1$s 共 %2$d 件”,英文可以写成“%2$d items in %1$s”,两个占位符都在,类型也对。把 %d 写成 %s,编译不一定报错,运行时可能直接崩溃。占位符检查要单独做,不能靠肉眼扫一遍。

第三条规则:XML 特殊字符要转义。& 要写成 &,小于号要写成 <,大于号写成 >,单引号在部分情况下要写成 \',双引号写成 "。如果整段文字里有大量标签或特殊符号,可以用 CDATA 包起来,但 CDATA 里的内容不会被转义,写错一个结束标记就会导致解析失败。补完一批字符串,先用 XML 解析器跑一遍,比等回编报错再找要快。

第四条规则:空格和换行要显式处理。XML 会折叠连续空白,字符串首尾的空格容易被吃掉;需要保留时用 \u0020 或  。换行用 ,不要直接在 XML 里敲回车,除非你确实想要一个换行节点。按钮文字前后的空格、单位与数字之间的空格,在中文里不明显,在英文里会影响排版。翻译时把这些细节写进备注,验收时逐屏看。

第五条规则:该不翻译的标清楚。品牌名、产品名、URL、邮箱、日志标签、调试开关名,加 translatable="false"。有些字符串是代码用来比较的,比如某个状态值 "success",翻译后逻辑就断了。判断方法:看这个字符串是否只用于显示。只用于显示,可以翻译;参与比较、拼接、请求参数,一律不翻译。拿不准时,先在工程里搜索这个键的引用位置,再决定。

第六条规则:控制长度,但不要为了短而丢信息。英文通常比中文长,德文、俄文更长。按钮、标签、底部导航这些固定宽度的位置,译文要优先保证不截断;标题、说明文可以换行。遇到实在放不下的情况,宁可改布局的宽度或字号,也不要把关键词删掉。删掉一个动词,用户可能就看不懂这个按钮是干什么的。

<string name="order_summary">%1$s · 共 %2$d 件</string>
<string name="order_summary">%1$s · %2$d items</string>

<string name="brand_name" translatable="false">Qinghe</string>
<string name="share_hint">分享给好友长按可保存图片</string>

上面两组示例,第一组展示了占位符顺序不变、只改文字的写法;第二组展示了不翻译标记和换行写法。实际工程里,键名可能更短,文案可能更长,但规则一样。改完一个文件,不要立刻回编,先用解析器验证 XML 是否合法。很多回编错误其实是少了一个闭合标签或一个引号,提前验证能省一轮等待。

错误写法 问题 正确写法
把 name="app_name" 改成 name="应用名" 代码引用失效,资源找不到 键名不动,只改标签内文字
%1$s 改成 %s 位置参数丢失,多参数时错位 保留序号与类型,允许调整顺序
& 直接写在文本里 XML 解析失败,回编报错 写成 &amp;,或整段用 CDATA
把状态值 "success" 翻译成 "成功" 代码比较失败,逻辑异常 标记 translatable="false"
按钮译文过长,硬塞进固定宽度 文字截断,用户看不懂 精简译文或调整布局宽度
字符串资源文件与占位符校对

图 4:键名不动、占位符不动、该不翻译的标记清楚,是补字符串的三条底线。

手工改 XML 时,建议一次只处理一个页面或一个功能模块,改完立刻做键集合和占位符检查,再进入下一个模块。不要一口气改完几百条再回编,那样一旦报错,很难判断是哪一批引入的。经典版的手工路线本来就不追求快,追求的是每一批改动都能解释清楚。分批改、分批验,最后合并回编,返工最少。

普通字符串只是大头,真正容易被漏的是数组、复数和格式化文本。下一节把这三类资源单独拆开,给出可照抄的写法。

数组、复数与格式化文本:最容易被漏的三类资源

string-array 常见于下拉选项、筛选条件、星期、月份、帮助条目。翻译时有两个硬要求:条目数量保持一致,条目顺序保持一致。代码里通常用下标取值,数组少一项,后面全部错位;顺序换了,界面上的“周一”可能对应到“周三”。翻译人员看到数组,最好连同上一次出现的界面截图一起给,避免把“选项顺序”当成可以自由调整的排版。

<string-array name="week_days">
    <item>周一</item>
    <item>周二</item>
    <item>周三</item>
</string-array>

<string-array name="week_days">
    <item>Monday</item>
    <item>Tuesday</item>
    <item>Wednesday</item>
</string-array>

plurals 比数组更复杂,因为它按语言区分单复数分类。英语通常有 one 和 other,中文只有 other,俄语、阿拉伯语有更多分类。补语言时不要删掉目标语言需要的分类,也不要把所有分类都写成同一句话。中文翻译成英文时,如果只保留 other,英文的“1 item”会变成“1 items”。正确做法是按目标语言的语法习惯写 one 和 other,并把数量占位符放进每个分类里。

<plurals name="cart_count">
    <item quantity="one">%d item</item>
    <item quantity="other">%d items</item>
</plurals>

格式化文本是第三类。它看起来像普通字符串,实际带有类型和位置约束。除了 %1$s、%2$d,还可能看到 %1$.2f、%1$tY-%1$tm-%1$td 这类格式。翻译时最容易出问题的是把 % 当成普通符号,或者把 %1$s 和 %2$s 的顺序调换后忘了检查类型。一个实用做法:用正则把所有占位符提取出来,和默认语言逐条比对,数量、类型、序号三者一致才算通过。

还有一类藏在字符串里的富文本。比如“点击 <b>同意</b> 继续”,资源里带 HTML 标签,代码里用 Html.fromHtml 渲染。翻译时标签要保留,标签内的文字可以翻,标签属性不要动。把 <b> 翻成 <粗体>,运行时不会加粗,用户看到的是一串尖括号。遇到带标签的字符串,先在真机上确认渲染效果,再决定是否需要调整标签。

菜单项、无障碍描述、Toast 文案也属于资源,却常被清单漏掉。菜单项通常在 menu 目录的 XML 里,android:title 指向字符串资源;无障碍描述在布局里是 android:contentDescription,读屏软件会读它。补多语言时,把这些资源按页面列出来,和可见文字一起翻译。一个应用如果视觉上全英文,读屏却读出中文,体验会很割裂。

资源类型 检查点 失败后的表现
string-array 条目数量、顺序、空项 选项错位、列表少一行
plurals one/other 等分类是否齐全 单复数不自然,或运行时找不到资源
格式化字符串 占位符数量、类型、序号 崩溃、数字错位、格式异常
富文本字符串 HTML 标签是否完整 标签被当文字显示
菜单与无障碍 title、contentDescription 是否覆盖 菜单夹杂旧语言,读屏不连贯
复数与数组资源的校对界面

图 5:数组看数量和顺序,复数看分类,格式化文本看占位符,三类资源三种检查法。

这三类资源补完,strings.xml 才算真正完整。接下来要处理默认语言与回退策略,这是决定“最终界面到底显示哪种语言”的总开关。很多项目翻译都做了,却因为默认目录和语言目录的关系没理清,仍然在真机上出现混合语言。下一节专门讲这个总开关。

提醒一句:补资源时不要顺手改布局和业务代码。多语言补全应该是一次边界清晰的改动,只动资源文件;布局适配、字号调整、硬编码替换,另开一轮。两类改动混在一起,回编报错时很难判断是哪一类引起的,回滚也不干净。

默认语言怎么定:values 放什么、回退怎么发生

默认语言不是“开发者习惯的语言”,而是资源回退的底座。它的选择只取决于两件事:产品的主要用户是谁,以及团队希望缺翻译时看到什么。主要用户在国内,默认放简体中文最自然;主要用户在海外,默认放英文更合理。默认语言一旦定下来,就不要因为某次翻译方便而换,换来换去会让所有分语言的缺项都变得难以判断。

常见的两种结构,第一种是默认中文加 values-en:values 放完整简体中文,values-en 放英语。英语用户进来,先读 values-en;某个键没翻,回退到 values 的中文。第二种是默认英文加 values-zh-rCN:values 放完整英文,values-zh-rCN 放简体中文。中文用户进来,先读 values-zh-rCN;缺键时回退到英文。两种结构都成立,关键是默认目录必须完整,分语言目录可以暂时有缺项。

不推荐的结构是默认中文、values-zh-rCN 又放一份几乎相同的中文。这样做不会立刻报错,但会出现两个维护入口:改默认目录忘了改 zh-rCN,中文用户看到的是旧文案;改 zh-rCN 忘了改默认,其他语言回退时又拿到旧值。除非你有明确的历史原因,否则保留一份中文即可。判断当前项目属于哪种结构,用前面说的“切到无对应目录的语言看显示”方法,一次就能确认。

地区限定符的选择要按用户分布来。只写 values-zh,覆盖所有中文用户,但简体用户和繁体用户看到的是同一套字;写 values-zh-rCN 和 values-zh-rTW,可以分别给简中和繁体,但香港、澳门用户可能落到哪个目录,要看系统返回的语言标签。英语也是同理:values-en 覆盖大多数英语地区,values-en-rGB 和 values-en-rUS 用于处理拼写差异。不要为了“看起来精细”给每个地区都建目录,目录越多,缺项检查越复杂。

项目类型 默认目录 分语言目录 注意点
国内为主 简体中文 values-en、values-zh-rTW 默认目录必须最全
海外为主 英语 values-zh-rCN 中文缺项会回退英文
多地区内部工具 团队工作语言 按实际驻点语言建目录 不要给无人使用的语言建目录
历史遗留双语 先确认现状 合并重复的中文目录 改前做快照,逐页比对

回退的实际顺序,可以用一个例子说明。设备语言是 en-GB,应用里有 values、values-en、values-en-rUS。系统会先找 en-GB 的精确匹配,没有;再找 en 的语言匹配,命中 values-en;如果 values-en 里缺某个键,回退到 values。假如只有 values-en-rUS,没有 values-en,en-GB 设备可能直接回退到 values,因为地区不匹配。这就是“只建了美式英语,英式设备看到中文”的原因。

Android 13 及以上支持按应用设置语言。用户可以在系统设置里只给某个应用切语言,不必改整个系统的语言。这个能力通常需要在清单里声明 localeConfig,并在 res/xml 下提供语言列表。它不是多语言补全的必需项,但如果你的用户会在同一台手机上使用多种语言,加上它体验会更好。加之前先确认目标系统的版本覆盖和工程的编译环境,不要为了一个可选功能引入新的兼容问题。

如果目标语言包含阿拉伯语、希伯来语等从右到左书写的语言,只补字符串是不够的。布局方向、图标方向、内边距、对齐方式都要跟着镜像,否则文字是阿拉伯语,界面还是从左往右排。这类语言建议单独开一轮适配,不要混在普通翻译里。本文的流程负责资源层,RTL 布局检查需要额外的真机走查。

默认语言与分语言目录的对应关系

图 6:默认目录是回退底座,分语言目录只负责覆盖,二者职责不能颠倒。

定完默认语言,建议在项目根目录放一份 README,写清三件事:默认语言是什么、当前支持哪些语言、每个语言的负责人是谁。这份说明不需要给用户看,是给三个月后的自己看的。多语言工程最容易在人员交接时失控,一张纸的说明能省掉大量猜测。README 里还可以记下目录命名风格,避免后来的人一半用 values-en,一半用 values-b+en。

默认语言和回退规则理清后,剩下的工作就是查缺项。缺项检查不能只靠“切语言看一眼”,要有脚本、有伪翻译、有真机走查三层。下一节把这套检查方法拆开讲。

缺项检查:脚本比对、伪翻译与真机走查

第一层检查是键集合比对。前面给过一段小脚本,比较默认目录和目标语言目录的键集合,输出 missing 和 extra。把它跑在每一个语言目录上,要求 missing 为零。extra 可以保留,但要逐条确认:是历史遗留、是某版本特有、还是键名拼错。拼错的键最麻烦,它不会报错,只是永远不会被使用。发现 extra 里有一个看起来像另一个键的变体,先搜索代码引用,再决定删还是留。

第二层检查是占位符比对。用正则从默认文案和目标文案里提取占位符,比较数量、类型、序号。常见的占位符形式包括 %s、%d、%f、%1$s、%2$d、%1$.2f。提取时注意转义:%% 表示一个普通的百分号,不是占位符。逐条比对后,如果目标文案多一个 %s,运行时可能把不存在的参数塞进去;少一个 %d,数字就不会显示。两类问题都不一定在编译期报错,必须在回编前查出来。

import re

pattern = re.compile(r"%(?:\d+\$)?[-#+ 0,(]*\d*(?:\.\d+)?[a-zA-Z]")

def placeholders(text):
    return sorted(pattern.findall(text.replace("%%", "")))

base = placeholders("共 %2$d 件,合计 %1$s")
target = placeholders("%2$d items, total %1$s")
print(base)
print(target)

第三层检查是空值与“假翻译”。空值就是标签里什么都没有,或者只有空白;假翻译是目标文案和默认文案一模一样。两者都会让界面看起来“没翻”。脚本可以把这类条目列出来,人工判断是故意保留(品牌名、代码值)还是漏翻。长度也可以顺便看:目标文案超过默认文案两倍,标记为需要真机检查;低于默认文案三成,标记为可能漏译。长度不是硬门槛,但能快速定位可疑项。

第四层是伪翻译。做法是把目标语言文案统一加上醒目的包裹标记,比如 [[...]],或者换成带重音符号的假英文,再打一个测试包。切成这个伪语言,走一遍主要页面,凡是出现正常中文或正常英文的地方,就是没被资源覆盖的硬编码。伪翻译的好处是不用等真翻译完成,就能提前发现“哪些文字根本不在资源里”。它特别适合在项目早期做,越早发现,改布局和抽字符串的成本越低。

第五层是真机走查。脚本能查键和占位符,查不出截断、错位、语义不通。准备一台测试机,把系统语言切成目标语言,强制停止应用再启动,按用户路径走一遍:启动页、首页、登录、主要功能、设置、关于、错误提示、空状态。每屏截图,和默认语言截图并排看。看到文字被截断,先判断是译文太长还是布局太窄;看到中英混排,回到资源里找漏键或硬编码;看到语义别扭,回到术语表统一口径。

adb shell am force-stop com.example.app
adb shell monkey -p com.example.app -c android.intent.category.LAUNCHER 1

这两条命令,一条停应用,一条按启动器入口拉起。切完系统语言后,很多应用不会自动重建界面,必须先停再开,才能看到真实的多语言效果。走查时不要只开首页就结束,至少覆盖前面列的 P0 和 P1 页面。每个语言都走一遍,不要用“英文看过了,繁体应该差不多”来省略,繁体用词和简中差异很大,截图必须单独看。

检查层 能发现什么 发现不了什么
键集合脚本 缺键、多余键、拼写错误 译文质量、布局截断
占位符脚本 数量、类型、顺序错误 语义错误、硬编码
伪翻译 硬编码、未覆盖页面 翻译准确性、地区用词
真机走查 截断、错位、混排、语义问题 低频页面与极端设备
回归对照 默认语言是否被改坏 新语言独有布局问题

最后一层是回归对照。补完英文,切回中文再看一遍。很多改动是在 values 里做的,中文界面反而最容易受影响。对照默认语言的截图,确认文字、按钮、空状态没有变化。两种语言来回切三次,确认应用不崩溃、不丢登录态、不出现空白页。多语言补全的完成标准不是“英文看起来对了”,而是“每种语言都还能正常用”。

五层检查都过,才进入回编。回编后的安装包还要再走一次主流程,因为资源编译和打包过程可能引入新的问题,比如资源 ID 冲突、文件被压缩坏、签名不一致。下一节用两个具体实例,把“以前怎么做、现在怎么做、改完怎么验证”串起来。

实例一:自家教学 App 的英文补全

第一个实例是一款自有版权的教学应用,内部叫“青禾课堂”,面向成人技能课程。应用原本只有简体中文,后来请了几位英语讲师做课程顾问,他们需要在自己的手机上用英文界面看课程结构、课时列表和作业说明。应用是自己团队开发的,版权和修改权都在自己手里,属于可以放心做多语言补全的范围。

以前怎么做。产品把 strings.xml 导成表格,发给翻译,翻译填完再导回来。听起来流程完整,实际有三个漏洞:第一,导出只导了 strings.xml,arrays.xml 和 plurals.xml 没导,课时列表的筛选项和“剩余 N 课时”一直是中文;第二,翻译表里改了几个键名,回填后代码找不到资源,只能一个个改回来;第三,默认目录本身缺了三个键,英文目录翻得再全,切到英文时那三处还是空白。每次发版都要重新对一遍,三个人花两天,仍然会在真机上发现混排。

现在怎么做。先用修改大师经典版导入 APK,执行反编译,得到完整工程。把工程复制一份作为基线快照,再导出 Android Studio 工程,方便用 Translations Editor 查看所有键和语言列。第一轮不翻译,只做盘点:统计 strings.xml 有多少键、arrays.xml 有多少项、plurals.xml 有多少组,默认目录缺哪些键,英文目录缺哪些键。盘点结果写进清单,按 P0 到 P3 排序。

  1. 在经典版里反编译原始 APK,确认工程目录里的 values 结构,记下默认语言。
  2. 复制工程快照,命名带日期,后续只改工作副本。
  3. 导出键清单,补齐 arrays 与 plurals,标出默认目录缺的键。
  4. 按术语表翻译 P0 和 P1,P2、P3 分批跟进。
  5. 写回 values-en,键名不动,占位符逐条核对。
  6. 跑键集合和占位符脚本,缺项清零后再回编。
  7. 回编、签名、安装,切英文走主流程,切回中文做回归。

这个项目最后统计出两千四百多个字符串键,其中默认目录缺十一个,英文目录缺九百多个,arrays 里有六十多项,plurals 有八组。数字看起来多,但按页面分组之后,P0 只有两百多条,集中在启动页、登录、课程列表、课时详情和作业提交。先翻完 P0,应用就能给英语讲师一个可用的版本;P1 的设置、帮助和错误提示随后补上。

改完怎么验证。第一层用脚本:默认目录与 values-en 的键集合差集为零,占位符差异为零,空值清单里只剩品牌名和代码值。第二层用真机:把系统语言切成 English,强制停止后重新打开,走登录、课程列表、筛选、课时详情、作业提交、设置、关于七个页面,每页截图。第三层切回简体中文,重复同样路径,确认中文没有被改坏。第四层看日志,确认启动和页面切换没有资源找不到的异常。

验收时发现过两个典型问题。一个是课程列表的筛选项只翻了前四项,后面六项还是中文,原因是 arrays.xml 的条目数在翻译时被合并了;另一个是“剩余 %1$d 课时”的占位符被翻译成“%1$s”,英文界面直接崩溃。两个问题都不是翻译质量造成的,而是结构检查没做。把它们加进检查清单后,第二次发版没有再出现。

这个实例最重要的经验,不是“翻了多少条”,而是“先盘点再翻译”。盘点让工作量变得可见,也让验收有了明确的边界。没有盘点,翻译永远像在补一个看不见底的桶;有了盘点,缺多少、先补哪里、什么时候算完成,都能说清楚。

实例二:内部巡检工具的英文与繁体补全

第二个实例是一款内部设备巡检工具,供园区物业和仓储团队使用。应用不大,字符串只有两百六十多条,但使用场景跨了两个地区:内地园区用简体中文,香港仓用繁体中文,还有几位外籍工程师需要英文。以前这三个语言需求被当成三件小事,谁有空谁改,结果三个版本的用词互相对不上,同一个“巡检项”在英文里出现了三种写法。

以前怎么做。开发在源码里直接改字符串,改完重新构建。香港仓的同事把简体转成繁体,外籍工程师用翻译软件看界面,遇到看不懂的就截图问。巡检项是一个十八项的数组,繁体版本在转换时漏了两项,界面上的顺序整体错位,巡检记录导出后对不上编号。英文版本更随意,同一个按钮在不同页面分别是 Save、Submit、Confirm,用户不知道它们是不是同一个动作。

现在怎么做。用修改大师经典版反编译原始 APK,先确认默认目录是简体中文,再检查 values-zh-rTW 和 values-en 是否存在。这个项目原来只有 values 和 values-en,繁体是后来加的,目录名用的是旧式 values-zh-rTW,工程里没有冲突。保留原有命名风格,不改成 BCP 47,避免和旧工具链产生兼容问题。

第一步做术语表。把“巡检项”“巡检记录”“异常上报”“整改完成”四个高频词定死:英文分别用 Inspection item、Inspection record、Issue report、Rectified;繁体分别用巡檢項、巡檢紀錄、異常回報、整改完成。术语表定完,再翻其他文案,所有页面按同一套词走。第二步处理数组:把十八个巡检项逐条对照,保持顺序和数量,英文不合并同义项,繁体不做批量简转繁。第三步处理日期、数字和单位:确认 %d、%s 的占位符不变,日期格式按地区调整,但格式串本身不改结构。

  1. 盘点三个语言目录的键集合,先补默认目录缺的项。
  2. 定术语表,覆盖高频名词、动词和状态词。
  3. 逐条翻译巡检项数组,保持十八项和原顺序。
  4. 补 values-en 和 values-zh-rTW,保留占位符与单位。
  5. 跑键集合、占位符、空值三项脚本检查。
  6. 回编安装,分别用 en-US 和 zh-TW 走巡检流程。
  7. 导出一次巡检记录,核对表头、编号和状态文案。

改完怎么验证。准备两台测试机,一台系统语言 en-US,一台 zh-TW。每台都走“首页、巡检项列表、逐项打分、拍照上传、异常上报、记录导出、设置”七个环节。英文机重点看按钮动词是否统一、巡检项是否齐全、错误提示是否可读;繁体机重点看用词是否符合香港同事的习惯、数组顺序是否与简体一致、导出的记录编号有没有错位。两台机器都切回简体中文再做一遍,确认默认语言没有受到影响。

这个实例的收获是“小应用也需要术语表”。字符串少,反而更容易随手翻,随手翻的结果就是同一个词三种写法。术语表不需要长,四个高频词定死,整份文案就统一了大半。另一个收获是数组必须单独验收,十八项少两项,在界面上可能只是列表短了一点,在导出记录里却是编号整体错位,后者的代价大得多。

两个实例,一个偏内容型应用,一个偏工具型应用,流程是同一套:盘点、清单、术语表、补资源、脚本检查、真机走查、回归。差别只在优先级和验收页面。把流程固定下来,换一个应用也不用重新摸索。

回编、验收清单与常见问题

资源补完,回到修改大师经典版执行回编。回编前先确认三件事:工作副本是这次要用的版本,基线快照还在,改动清单与实际修改的文件一致。回编过程中留意日志,资源相关的错误通常会给出文件名和行号,比如某个 string 缺少结束标签、某个数组的 item 数量不对、某个占位符格式非法。看到报错不要急着重试,先按行号回到文件,改完再编。

回编成功后得到新的 APK,签名、安装、启动。签名要和原包保持同一套证书,否则覆盖安装会失败;如果是首次安装,确认设备上没有旧版本残留。安装后先看启动器名称和图标,再进应用走主流程。多语言补全改的是资源,正常情况下不会影响业务逻辑,但资源 ID 变化、字符串格式错误、布局被撑开,都可能在运行时暴露,所以仍然要按完整流程验收。

多语言回编前检查清单

  • □ 默认语言目录键集合完整,没有空值
  • □ 每个目标语言目录的缺失键为零
  • □ 所有占位符的数量、类型、序号一致
  • □ string-array 条目数量与顺序一致
  • □ plurals 分类符合目标语言语法
  • □ XML 特殊字符已转义,文件可被解析
  • □ 品牌名、URL、代码值已标记不翻译
  • □ 应用名、关于页、分享面板名称已覆盖
  • □ 菜单项与无障碍描述已翻译
  • □ 伪翻译走查没有发现硬编码
  • □ 真机切换语言后主流程无崩溃
  • □ 切回默认语言后界面无回归

常见问题可以按报错信息快速定位。回编提示某个 string 找不到,先看键名是否被改、目标目录是否多写了空格;提示格式字符串非法,先看百分号是否被翻译成全角、占位符类型是否匹配;提示 XML 解析失败,先看 & 和尖括号是否转义、标签是否闭合;安装后应用名没变,先看 AndroidManifest 的 label 指向哪个资源、该资源在目标语言里是否存在;界面局部仍是中文,先看是缺键还是硬编码。下面这张表把症状和处理放在一起,方便对照。

症状 常见原因 处理动作
回编报资源找不到 键名被改、目录名拼错、默认目录缺键 恢复键名,核对目录,补齐默认目录
运行时格式化崩溃 占位符类型或数量被改动 按默认文案逐条比对占位符
XML 解析失败 特殊字符未转义、标签未闭合 用解析器验证,修正实体和闭合
应用名不跟着语言变 label 指向的资源在目标语言缺失 补齐对应 string,确认清单引用
局部页面仍是旧语言 缺键回退或文字硬编码 看键集合差集,再搜布局与 smali
按钮文字被截断 译文过长、布局宽度固定 精简译文或调整布局,真机复查

多语言补全做完,交付物不只是一个 APK。建议把基线快照、改动清单、键集合报告、占位符报告、各语言截图一起归档。下次再来一个语言,直接复用这套流程和脚本;人员交接时,也能从报告里看出当前完成度。下面是几位使用者的反馈,他们的场景不同,提到的共同点是“有清单之后,心里有数”。

用户评价

“以前做英文版,最怕测试同事说‘这里还有中文’。现在先跑键集合,再做伪翻译,硬编码基本在回编前就露出来了,返工少了一大半。” —— 阿策 · 独立开发者
“我们是做教学应用的,课程顾问来自三个国家。经典版把工程摊开之后,数组和复数也能一条条对,英文界面的课时列表终于不会错位了。” —— 林老师 · 教育产品负责人
“内部巡检工具只有两百多条文案,原本觉得没必要做术语表。后来发现同一个‘整改完成’有三种英文写法,才回头补了术语,界面一下统一了。” —— 陈工 · 物业信息化专员
“我最喜欢默认语言那一节。以前默认目录缺键,英文翻得再全也会回退成中文,查了半天以为是翻译没生效,其实是总仓漏货。” —— 小满 · 接单开发者
“导出 Android Studio 工程这一步很实用,翻译可以在熟悉的界面里做,回编还是用经典版,两边各干各擅长的事,交接也方便。” —— 周工 · 企业 IT 维护

最后再把合规边界说一次。本文的流程只适用于自有版权或已获得授权的应用,请勿用于破解他人付费应用、去除授权校验或绕过安全机制。补多语言是对自己产品的整理,不是对别人产品的改造。涉及第三方字体、图片、音频的本地化,还要确认对应的授权范围,不能因为改了语言就忽略了素材版权。

安卓修改大师智改工坊在官网 www.apkeditor.cn 提供了产品介绍和下载入口。修改大师经典版适合这种需要逐条核对的手工精修任务:反编译、改资源、回编、导出工程,每一步都看得见。需要了解完整能力,可以访问 https://www.apkeditor.cn/ai-version.aspx。

只需说话,就能让应用变成你想要的样子。对经典版来说,这句话更像一个目标:把复杂的资源工程拆成一条条可执行的步骤,让人不用猜、不用碰运气。多语言补全没有捷径,但有顺序;顺序对了,剩下的只是耐心。

下次准备做多语言时,先别打开翻译软件。先反编译,先数键,先定默认语言,先建术语表。把这几件事做完,你会发现翻译只是整件事里最轻松的一段。

安卓修改大师智改工坊 · 下载

智能修改安卓版

在 ARM64 手机或平板上导入自有或已授权 APK,本地完成反编译、修改、回编、对齐与签名,成品可直接安装或分享。想了解电脑版与经典版的能力,可访问 https://www.apkeditor.cn/ai-version.aspx。

立即下载