汉化与多语言:修改大师经典版的 values 目录与抽查法
先说一个常见的场面。有人拿着一份反编译出来的工程,打开 res/values/strings.xml,把能看懂的条目一条条改成自己的语言,改了两百多条,回编、签名、装到手机上,打开一看——首页那排按钮还是原来的字。他以为漏了,又翻了一遍,确实每条都改了。真正的原因不是"漏",而是那排按钮压根不读 strings.xml:文字直接写在布局里,或者干脆写死在代码里。
这类事在手动流的汉化里几乎人人遇到过一次。原因很朴素:一个安卓应用的界面文字,从来不是集中放在一个地方的。它至少分布在三层——字符串资源、布局内联、代码硬编码;再叠加一层多语言目录的选择问题,同一个 name 在五六个目录里各有一份值,设备用哪一份由语言环境决定。不先把这张地图画出来,后面所有的"批量替换"都是在猜。
这篇文章讲的是手动流:工程文件全在本地,资源、AndroidManifest、smali 都摊开在你面前,改哪一条、改成什么,全由你决定。这条路慢,但它把每一处改动都交回你手里。配套工具是修改大师经典版(Windows 手动精修版,当前版本 V11.27.00.00),它的能力清单里写着"替换界面上任何文字和图片、翻译或汉化做多语言版本"。这篇要做的,就是把这句话拆成一套能照着走的工序。
一、手动流的汉化,为什么先要"看清三层"
先把两种流的差别说清楚,免得走错门。AI 流(安卓修改大师智改工坊旗下的智能修改电脑版、智能修改安卓版)是"你说要什么,它去找、去改、去打包",你要做的是把范围说准、把验收说清;手动流是"你自己进工程,自己定位、自己替换",工具负责把工程摊开、把回编和签名跑通,判断全在你这边。
汉化恰好是两种流差别最明显的地方。它不是"改一个点",而是"改一批点",而这批点长在三种完全不同的地方:
- 长在字符串资源里的,是规范的、可批量的、能被多语言机制管理的;
- 长在布局文件里的,是散落的、一处一处的、改完切语言不会跟着变的;
- 长在代码里的,是最难找的、最需要小心的、也是漏得最多的。
为什么必须先看清?因为三层的改法、风险、返工成本完全不同。字符串资源改错了,回编直接报错,你能立刻知道;布局里的内联文字改错了,可能只是某一行不显示;代码里的硬编码改错了,轻则该页面文案不对,重则 smali 编译不过、装上去启动就崩。三层混在一起批量替换,最后只会得到一堆"改了但不生效"和"生效了但崩了",还分不清是哪一类。
还有一层现实原因:你没法一次改完。中等规模的应用,文案少则几百条,加上错误提示、空状态、帮助文本,工作量比多数人预估的大。改不完就得排顺序,要排顺序就得先知道每层各有多少、在哪、要多久——看清三层的用途不是知识,是排期依据。
图 1:工程摊开之后,第一件事不是动手改,而是把文案的位置画成一张地图
手动汉化的第一原则:先定位,再替换。定位花的每一分钟,都会在后面以"少返工一轮"的形式还回来。
二、摸清文案分布:字符串资源、布局内联、代码硬编码
三层不是三个概念,是三个具体位置。反编译完成后,在工程目录里按下面的顺序翻一遍,基本能把文案分布摸个七八成。
第一层:字符串资源。位置在 res/values/ 下的 strings.xml,形式是 <string name="xxx">文案</string>。同目录常有几个兄弟文件:arrays.xml(列表项、下拉选项)、plurals.xml(单复数,多见于英文)。这一层的特征是"有名字":每条都有唯一的 name,界面用 @string/name 引用,代码用 getString(R.string.name) 取。两个容易忘的引用点:AndroidManifest.xml 里的 android:label(桌面应用名)、res/xml/ 下的菜单与偏好设置项标题。
第二层:布局内联文字。位置在 res/layout/ 下的 XML,形式是 android:text="确定" 这样把文字直接写进属性。判断很简单:值以 @ 开头的是引用,不在这里改;引号包着一段文字的是内联,属于这一层。除 android:text 外还有四个高频属性:android:hint(输入提示)、android:title(分组标题)、android:contentDescription(无障碍描述)、android:textOn / textOff(开关两侧)。前两个大家都记得,后两个是漏改重灾区——尤其 contentDescription,界面不显示,读屏却会念出来。
第三层:代码硬编码。位置在 smali/ 目录里的 .smali 文件,形式是 const-string v1, "确认删除?"。这一层包括:运行时才弹的提示(Toast、对话框标题与按钮)、拼接出来的句子、空列表占位文字、错误码对应的人话、日期格式模板(yyyy年MM月dd日 也是文案)、以及初始化时用 setText("...") 覆盖布局文字的那部分。
三层摸完,做一张表,它是给你自己排期用的:
| 层 |
在哪 |
改法 |
主要风险 |
| 字符串资源 |
res/values 下 strings / arrays / plurals |
改值不动 name,可批量 |
占位符丢失、转义破坏、误删条目 |
| 布局内联 |
res/layout 的 text / hint / title / contentDescription |
逐处改;双语项目要提成资源 |
切语言不跟随、长文案挤压布局 |
| 代码硬编码 |
smali 里的 const-string 与拼接串 |
只动引号内文字,一条一条核 |
指令被破坏、语序错乱、崩在运行时 |
搜索是摸清分布最快的办法。拿一个高频词("设置""确认""取消"这类通用词)在工程里全局搜一遍,命中在哪一层、多少处,就是一张可靠的分布图。两个坑:别把 res/values-xx 这类多语言目录算进工作量(那是后面要同步的另一件事);别漏掉 assets/ 里的内嵌网页与手册,那是另一套文案。
三、values 目录与多语言目录的关系
这一节是手动汉化最容易被误解的地方,也是"我明明改了"的头号来源。结论放在前面:同一个 name 可以在多个目录里各有一份值,运行时只会用其中一份。用哪一份由设备的语言环境决定,不由你改了几份决定。
命名规则是"values + 语言 + 区域"。不带任何后缀的 res/values/ 是默认资源,也叫兜底资源:任何语言下,只要某个 name 在当前语言的目录里找不到,系统就回退到默认那份。这条规则解释了两种相反现象:为什么有的应用切到英文还是满屏中文(默认那份就是中文,英文目录里没翻译),也为什么你新增的英文目录只填一半、剩下自动显示中文(同样因为兜底)。
| 目录 |
含义 |
什么时候动它 |
| values |
默认资源,所有语言的兜底 |
包里只有它、且装的是原文时,汉化就改它 |
| values-zh |
简体中文(广义) |
设备语言是中文时生效;改中文先看它在不在 |
| values-zh-rCN / values-zh-rTW |
按区域细分的大陆简体 / 台湾繁体 |
做繁体版单独补;只改简体别碰它 |
| values-en / values-ja 等 |
英文、日文等目标语言 |
做外语版时新建或补齐,缺条目自动回退 |
| values-b+zh+Hans 一类 |
较新的 BCP47 写法,语义与旧写法等价 |
包里已经这么写就跟着写,别另起一套 |
图 2:同一个 name 在多份目录里各有一份值,读哪一份由语言环境决定
于是"只改中文该动哪一份"有了三步判断。第一步,列目录:打开 res/,看有几个 values*。第二步,认默认那份的语言:看 res/values/strings.xml 的内容——是中文就说明这个应用以中文为默认,改它,但要知道所有没有对应语言目录的设备都会看到你改后的内容;是英文就说明默认是英文,中文另有 values-zh 或 values-zh-rCN,动那一份。第三步,实测一处:只改一条最显眼的文案,回编装机看变没变。变了说明猜对目录;没变说明生效的不是这一份。
还有个必须知道的机制:这些 XML 打包时会被编译进 resources.arsc 这份资源表。改 XML 只是改源料,应用真正读的是回编后重新生成的资源表。保存了没重新打包,或者打包失败但你装了旧包,界面上当然不会有变化。
判断口诀:默认那份是给所有人兜底的,语言目录那份是给对应语言的人看的。改之前问一句"我要影响谁",答案就出来了。
四、术语表先定:动第一批之前的四件事
如果这篇只留一句话,我留这句:术语表先定,再动第一批。做到第三百条才发现"设置"前面写的是"设定"、"保存"有时写"存储",那不是笔误,是返工——前面三百条要重过一遍,还要重新回编、装机、抽查。
术语表不用很正式,一张三列的表就够:原文、目标译文、备注。但它必须在开工前存在,并包含四件事。
第一件:抽样本。从 strings.xml 里挑高频词,五六十条就足以暴露全部矛盾。按功能覆盖面挑:导航与菜单、按钮动作、表单字段、设置项、状态提示。这些词出现频率最高,定下来之后大量长句子都能顺着走。
第二件:分三类词。功能名词(账号、订单、任务、项目)、动作词(保存、取消、提交、返回、重试)、专有名词(产品名、品牌名、模块名、缩写)。前两类要统一,第三类要决定"译还是不译"——多数情况下产品名与品牌名不译,缩写首次出现可带全称。这个决定要一次做完,不能每条临时想。
第三件:定风格。四件小事:称呼用"你"还是"您"(全篇统一);标点用全角还是半角(中文句子全角,英文短语半角,数字与英文两侧留空格);按钮文字不加句末标点;日期与数字格式(2026-10-25 还是 2026年10月25日)。这四条是第八节"按标点抽查"的直接依据。
第四件:落成表并冻结。表定完就贴在手边,改的过程中只允许追加,不允许推翻。真要改,就停下来把已改的批量对齐,别一边改一边漂。
| 原文 |
统一译法 |
备注 |
| 设置 |
Settings |
名词,作页面标题用单数;"设置项"另立条目 |
| 保存 / 存储 |
Save |
动作一律 Save;"存储空间"是名词,另立条目 |
| 确认 / 确定 |
OK |
对话框按钮用 OK;句子里的"确认"用 Confirm |
| 产品名(示例) |
保留原文 |
不译,也不加解释性后缀 |
| 用户协议 / 隐私政策 |
保留原文或经法务确认 |
法律文本不自行改写含义,译错的风险远大于收益 |
五、批量替换怎么推进:分批、按页面、先主干后长尾
有了地图和术语表,接下来是推进方式。汉化最常见的失败不是"改不对",而是"改不完":一口气开干,改了两百条,回编报错,不知道哪条弄坏的,然后就没有然后了。避免这个结局的办法有三条。
一、分批。每批五十到一百五十条,或控制在一个页面的量级。一批就是一次完整闭环:改 → 回编 → 签名 → 装机 → 抽查 → 记一笔。为什么要小批?回编报错时,定位成本和自上次成功以来的改动量成正比。一批一百条,最坏是二分排查;一批八百条,只能整体回退。记一笔同样重要:这批改了什么、还剩多少、有没有临时决定(某条决定不译),下次接着干不用重新想。
二、按页面。这是最推荐的组织方式。不要"先把所有 strings.xml 改完,再改所有布局",而是"把这个页面上的三层文字一次改完"。理由很实际:验证是按页面看的。把首页的资源、内联、硬编码一起改完,装上一看就知道这页过没过;反过来全量改资源再全量改布局,验证时面对"一半新一半旧"的混合状态,根本判断不出哪层漏了。
三、先主干后长尾。主干是用户一进来就看到的:启动页、首页、底部导航、登录注册、设置、关于。长尾是其余部分:二级页面、错误提示、空状态、帮助与条款。先主干有三个好处:最快跑通一次完整链路,确认这个包能回编、能签名、能装、能开;主干往往也是术语最集中的地方,先做主干等于先把术语表落地;手里先有一个"已经能看的版本",做长尾时心态完全不一样。
图 3:按页面切批,每批走完一次"改—编—装—验",比一次性全量改安全得多
| 批次 |
范围 |
这一批必须过什么 |
| 第 0 批 |
一条最显眼的文案(首页大标题或应用名) |
确认生效目录猜对了、回编签名装机链路通 |
| 第 1 批 |
首页 / 底部导航 / 登录(三层都改) |
五个主入口文字全对,长文案不挤压布局 |
| 第 2 批 |
设置 / 关于 / 二级页面标题 |
设置项与开关两侧文字无残留、无截断 |
| 第 3~N 批 |
长尾:提示、错误、空状态、帮助、条款入口 |
随手点一遍能触发到的提示都看过 |
| 收尾批 |
反向搜残留、按标点统一、术语对齐 |
残留清单清空,抽查表全绿 |
反向推进(先干长尾、最后才动首页)几乎没人成功:干了一整天,装上去看到的还是原来那个界面,人会怀疑自己在做无用功。这不是意志力的事,是流程设计的事。
六、主干批:strings.xml 的六条纪律
主干批大部分工作量在字符串资源上,也是唯一适合"批量替换"的一层。但批量不等于盲改,strings.xml 里有六条纪律,违反了轻则编译报错、重则装机崩溃。
纪律一:只改值,不动 name。name 是引用键,界面、代码、清单都靠它找条目。把 name="btn_ok" 顺手改成 name="button_ok",所有 @string/btn_ok 引用立刻断链,回编报找不到资源,运气差时回编能过、运行时取到空值。只改引号之间那段文字。
纪律二:占位符原样保留。%1$s、%d、%s 是留给运行时填的(数量、名字、时间),翻译时一个不少。数量不能变、序号不能重,需要调换位置时用带序号的写法(%1$s ... %2$s)。中文"共 3 件"译成英文是 "3 items",位置变了,序号写法才安全。有的条目还会用 <xliff:g> 包住占位符标注用途,整个标签要留着,只动标签外的文字。
纪律三:转义与特殊字符。XML 里裸的 & 会让文件结构失效,必须写成 &;单引号在部分写法下要转义成 \',或整条用双引号包住;换行写 ,不能真敲回车;行首行尾空格会被吃掉,要保留得用实体写法。目标语言里出现 < >(比如"小于 5MB")也要实体化。这一条最容易在"看起来没问题"时把整个文件弄坏。
纪律四:不动 translatable="false" 的条目。标了这个属性就是明确声明"不要翻译":包名、渠道标识、格式串模板、协议里的固定字段。改了轻则功能异常,重则相关字符串对不上。同理不要删条目——哪怕你觉得它没用了,代码里某个分支可能还在取它,删掉就是运行时崩溃。
纪律五:富文本只改文字,不改结构。有些文案带简单标签(加粗、斜体、超链接),甚至带 CDATA 段。原则是:标签开闭配对、属性里的链接地址、CDATA 的包裹形态全部保持原样,只替换标签之间的可见文字,改完检查括号与斜杠。
纪律六:编码与格式稳定。文件保持 UTF-8,不要中途被编辑器另存成别的编码;缩进乱了不影响编译,但会让 diff 一片红,自己看不清改了什么;注释可以留,别把"这里待定"之类的临时标记带进交付。
六条之外还有一个小动作值得养成:每批改完先只回编、不装机。回编通过说明语法层面没坏;失败时报错通常会指到具体文件和行,趁着记忆还热,定位最快。等回编稳定了再签名装机,一次成功率高很多。
七、长尾批:布局内联与代码硬编码的处理
主干改完,剩下的是长尾,也是漏改最集中的地方。这一层没有批量捷径,只能一处一处来,但有两套明确的原则。
布局内联:先分清改还是提。如果目标只是"把这个包的文字换成另一种语言",直接把 android:text="确定" 改成目标语言就行,简单直接。但如果目标是"做一个能随系统语言切换的双语版本",直接改是错的——内联文字不参与多语言机制,不会跟着语言环境变。正确做法是把它"提"成资源:新建一条 <string name="xxx">,布局属性改成 android:text="@string/xxx",再在每个语言目录各写一份。工作量比直接改大,但这是双语项目唯一正确的路。
这一类改动有两个连带影响必须检查。一是长度:中文四五个字的地方,英文可能要十几个字母,按钮会挤、标题会换行、列表项会被截断,改完必须看实际渲染。二是引用完整性:属性从文字改成 @string/xxx,那个 name 就必须真的存在,否则编译直接报错——这算好事,错误暴露得早。
代码硬编码:只动引号里的字,一条一条核。反编译产物是 smali,文案长这样:const-string v1, "确认删除?"。要改的只有引号之间的部分,前面的寄存器编号、后面的指令结构一个字都不能动。手一滑把 v1 改成别的,或者少写一个引号,结果就是 smali 编译失败,或者更糟——编译过了,运行到这一行抛校验错误。
第二条铁律是拼接串按片段改,注意语序。很多提示不是一整句,而是拼出来的:先 const-string 一段"共",再拼数字,再拼"件商品"。中文语序是"共 N 件商品",英文是"N items",片段顺序得跟着调整,否则会得到"Total 3 items商品"这种半截话。遇到拼接,先把相邻几行的 const-string 都找出来,读一遍顺序,再决定每段怎么译。这类地方返工率最高,值得多花五分钟。
还要判断哪句值得改。硬编码里混着大量用户看不到的东西:日志、调试信息、内部异常描述、请求参数名。改了没有收益,只增加破坏指令的风险。标准很朴素:这句话会不会显示在屏幕上、会不会被念出来。不会,就别动。
代码层还有一个容易忽略的入口:用 setText 覆盖布局文字的地方。你明明改了布局里那行字,装上去还是旧的,很可能就是初始化代码又覆盖了一遍。处理顺序反过来:先在 smali 里搜这处文案的原文,确认有没有硬编码同名文字;有,就说明真正的来源在代码里,布局那处改了也白改。
八、抽查法:按页面、按长度、按标点
汉化不可能"全部看一遍",因为有些文字要特定条件才出现(断网、空列表、权限被拒)。所以必须有抽查法:用少量样本最大化发现问题的概率。三个维度足够覆盖绝大多数漏改。
维度一:按页面抽。从主干页面挑五到八个,每页看四类控件:页面标题、主按钮、提示文字、空状态。不追求看完,追求覆盖控件类型。这里有个反直觉的经验:最该抽的不是最显眼的按钮,而是四个隐蔽角落——对话框的取消按钮、开关控件两侧文字、列表项的右侧操作、图标的无障碍描述。前三个藏在交互里,不点开看不到;最后一个界面上根本不显示,只有读屏会念。它们恰恰是批量替换最容易漏的。
维度二:按长度抽。抽三条最长、三条最短、两条带变量的。最长的三条查截断与换行——英文通常比中文长,同一个按钮英文塞不下就会变省略号或挤成两行;最短的三条抓漏改——"是/否""开/关""确定"这种一两个字的条目最容易被眼睛跳过;带变量的两条验证占位符有没有错位,比如本该"共 3 件"却显示成"共 3 件 3"。
维度三:按标点抽。这一招专治"翻译对了但一看就不专业"。看四件事:句末标点是否统一、中英标点是否混排(中文句子里冒出半角逗号)、省略号写法是否一致(…… 与 ... 混用)、括号与引号是否成套。标点不影响功能,但它是"这批活做没做完"的最直观信号。
| 抽查维度 |
抽多少 |
看什么 |
| 按页面 |
5~8 个主干页,每页 4 类控件 |
对话框按钮、开关两侧、列表操作、无障碍描述 |
| 按长度 |
最长 3 条 + 最短 3 条 + 带变量 2 条 |
截断、换行、漏改、占位符错位 |
| 按标点 |
随手翻 20 条长句 |
句末标点、中英混排、省略号、括号引号成套 |
| 按残留(反向) |
全工程搜 3~5 个原语言高频词 |
还剩哪些没改,命中位置按层归类 |
图 4:抽查是带着清单去看,不是随便翻两页
第四个维度是反向抽查,也是效率最高的一招:不去看改了哪些,去看还剩哪些。拿原语言的高频词在各处搜一遍,命中的每一处都列进残留清单,确认它是"不该改的"(日志、参数名)还是"漏掉的"(界面文案)。清单清空,这件事才算收口。它比正向翻页面可靠,因为人的眼睛会跳过熟悉的东西,搜索不会。
抽查还有个流程要求:发现问题先记,攒够一批再改。发现一处就改、改完立刻回编,你会在"改—编—装"的循环里耗掉大半时间。正确做法是一张问题表:位置、原文、问题类型、改成什么;攒到十几二十条,一次改完、一次回编、一次装机复核。
抽查不是"随便看看",是带着清单去看。看不完不要紧,看过的每一类都要有着落。
九、"改了不生效"的三种原因
这一节可以当排查手册用。汉化改到一半,最常见的求助就是"我明明改了,装上还是原来的样子"。原因基本落在三类里,每一类都有明确的确认动作。
原因一:改的不是生效的那一份。占比最高,下面有五种形态。其一,目录选错:改了 values-zh,但设备语言是繁体,读的是 values-zh-rTW。其二,默认那份在起作用:包里只有 values(英文)和你新加的 values-en,设备语言两种都不是,兜底回英文。其三,同名不同源:界面显示的那条文案有另一个 name,你改的是废弃旧条目。其四,文案不在本地:有些内容由服务端下发(远程配置、公告、活动文案),包里那条只是占位。其五,拆分包:APKS、XAPK、APKM 这类包资源可能分散在多个子包,语言资源单独成包,你只改了主包。确认动作:全局搜目标文本,看有几处命中、分别在哪一层、哪个目录,一处一处对照。
原因二:装上去的不是新包。特征是"文件明明改了"。三种形态:保存了但没回编,或回编失败你以为成功——resources.arsc 还是旧的;回编成功但签名没走完,装的时候失败,系统里留的还是旧版本;覆盖安装被系统拦下(版本号更低、签名不一致),你以为装上了,其实提示被忽略。确认动作:装之前先卸载旧包;或者改一下版本号让系统明确认它是新的;装完看版本信息对不对得上。
原因三:改的位置被覆盖了。最隐蔽,因为"你改的地方确实改了,只是它不是最终显示的那一处"。三种形态:布局里改了一行,代码初始化又 setText 了一遍;同一句话多处各写一份,你改了 A 处,显示的却是 B 处("关于"页与设置页各有一套很常见);应用自带语言切换,内部强制了某个 Locale,你按系统语言判断的目录根本不是它读的那个。确认动作:搜原文在工程里出现的所有位置逐一排除;布局与代码各有一份时优先改代码那份;应用有内置语言设置就在应用内切一遍。
| 现象 |
最可能的原因 |
先做哪个动作 |
| 整个界面没变化 |
没回编 / 装的是旧包 |
卸载旧包,重装这次的回编产物 |
| 一部分变了、一部分没变 |
没变的那部分在布局或代码里 |
搜原文,按层归类后补改 |
| 单条文案始终不变 |
同名不同源 / 服务端下发 / 被覆盖 |
搜全部命中位置,找真正显示的那一处 |
| 切语言后仍是原文 |
该语言目录缺条目,兜底到默认 |
补条目,或调整默认那份 |
把三类排在一起看,共同点很清楚:都不是"手抖",而是"没确认"。没确认改的是哪一份、没确认装的是哪个包、没确认显示的是哪一处。所以预防办法不是更小心,而是每批固定三个动作:改完搜一次原文看命中、回编后看产物时间、装机前卸载旧包。
十、两个完整实例
下面两个例子都来自自家与内部的应用,流程可以照搬,场景不要照搬——他人应用必须取得授权。
实例一:把自家运维小工具汉化成英文版
背景:团队自研的内部运维小工具,安卓端,界面全中文,要给海外同事用。它没做过多语言,res/values/strings.xml 是唯一一份文案,界面里还散着不少内联文字。
以前怎么做。打开工程,从头往下翻 strings.xml,一条条译,译完回编装机。装上一看,首页那排功能入口还是中文——它们写在布局里,压根没进资源表。补完布局,提示语又漏了,再补;补到第三轮,发现同一个词前面译成 "Setting"、后面译成 "Preferences"。整个过程返工四轮,最后交付的版本里还留着两处中文:断网提示和权限被拒的弹窗,因为正常路径根本触发不到。
现在怎么做。第一步,全局搜"设置""确认""失败",把命中位置按三层分类做成一张表:资源层最多,布局二十来处,代码十来处(含拼接串)。第二步,术语表先定,三十条左右——"设置"统一 Settings,"保存"统一 Save,产品名保留原文,"用户协议"保留原文。第三步,新建 values-en/strings.xml,只放要译的条目,translatable="false" 的一律跳过,占位符一个不动。第四步,主干批:首页、底部导航、设置、关于,同批把这几页的内联文字一起处理——这个包只做英文版、不要求切换语言,内联就直改,不折腾提资源。第五步,长尾批:对话框、Toast、空状态、错误提示,代码里的拼接串先读上下文再译。第六步,反向抽查。
校验。回编后先不装机,看回编是否通过(这一步抓出两处 XML 里裸的 &)。装机前卸载旧包,装上后按抽查表看:五个主干页每页四类控件;最长三条(两个说明段落、一个授权提示)确认不截断;带变量的两条确认占位符正常;最后搜"的""设置"这类中文高频串,残留清单只剩日志与参数名,收工。整个流程走了两轮,比以前的四轮少一半,也没再出现术语不一致。
实例二:给内部应用做中英双语(同包切换)
背景:另一个内部应用要长期维护,需求是"一个安装包,中文用户看中文、英文用户看英文,跟着系统语言走"。
以前怎么做。做两个包:中文版、英文版,分开维护。问题很快出现——改一个功能要改两遍,改文案要改两遍,两个包版本号还得手动对齐;更麻烦的是英文版从中文版复制,某次修复只修了中文版,英文版带着旧 bug 发了出去。
现在怎么做。先认清楚默认那份是中文(res/values/ 里是中文),结构定成:默认 values 保持中文,新增 values-en 放英文。关键一步是"提资源":布局里所有内联文字改成 @string/xxx 引用,每提一处就在两个目录各加一条;contentDescription 一并提。代码里的硬编码同理:能挪进资源的就挪,挪不动的(某些拼接)至少保证两种语言下都读得通。然后按页面分四批推进,每批结束做一次双语装机。
校验。四步。第一,切系统语言到英文,冷启动,走一遍五个主干页,看有没有中文残留(有残留说明该条目没进 values-en,兜底回中文了)。第二,切回中文,确认中文没被改坏——这步很多人省掉,结果交付时中文界面冒出了英文片段。第三,切到第三种语言(比如日语),确认兜底行为符合预期:显示中文而不是空白或报错。第四,检查长文案与占位符:英文按钮是否挤成两行、带数量的提示读不读得通、日期格式是否还在用中文模板。四步走完,交付的是一个包、一套结构、一份术语表。
两个实例的差别值得留意:实例一只需要"换成另一种语言",所以布局直改最省事;实例二需要"两种语言共存",所以必须提资源。判断标准不是哪个更高级,而是你要的是替换,还是并存。这个决定做错,后面全是返工。
十一、手机端接着改:安卓客户端的便利与互补
手动流的汉化主战场在电脑上,这没什么争议:批量替换几百条资源、翻布局、读 smali,屏幕越大越舒服。但汉化有两个环节天然长在手机上——看效果和补漏。
看效果不用解释:文案的最终裁判是那块屏幕。字号、行距、截断、暗色模式下的对比度,只有真机算数。补漏则是汉化的日常:装上去翻两页,发现"权限被拒"的弹窗还是原文,这时候要么回工位开电脑,要么就地解决。后者显然更快。
就地解决用的是安卓修改大师智改工坊旗下的智能修改安卓版(当前版本 V50.07.00.00,安装包约 7MB,Android 10 及以上)。它在手机上把反编译、改包、回编、对齐、签名、校验全放在本地完成,改完直接装到本机或一键分享。对汉化补漏来说有三个实际好处:可以从「已安装应用」里直接选正在用的那个包,省掉导出;可以只写一句需求把漏掉的那几处改掉,不用重走一遍完整工程;改完立刻装上看,不对再补一句,节奏是"看一眼改一处",比在电脑与手机之间来回传包快得多。
分工也很清楚:电脑端做批量与深改——values 目录的成批替换、布局与 smali 的精修、术语的统一对齐;手机端做验收与临时补——装上看效果、抓漏改、把最后一两处解决掉。经典版与智能修改电脑版可以装在同一台电脑上,各自管理各自的项目,互不冲突;手机端的项目留在手机里,适合通勤、会议间隙这种碎片时间。想在手机上随时随地改就装安卓版,想逐条掌控工程里每一处文字就回经典版。
合规提醒
本工具面向自有版权或已获授权的应用,适用于学习研究与企业内部测试等合法场景,请勿用于破解他人付费应用或绕过安全机制。反编译功能仅供安卓开发爱好者对安装包进行反编译研究之用,严禁将反编译之后的安装包作为商业用途。文中所有场景均为自有或已获授权的应用;如需处理他人应用,请先取得相应授权,并在目标应用服务条款与相关法律法规允许的范围内使用。
另外提醒一句:翻译用户协议、隐私政策这类法律文本,不要为了"看起来完整"而自行改写含义,保留原文或经法务确认更稳妥。
十二、常见问题与用户怎么说
九个高频问题
1. 汉化必须会外语吗?不一定,但要有判断力。可以先用机器翻译出初稿,再按术语表逐条校订,重点看术语是否统一、占位符是否完整、语序是否读得通。最省事的做法不是"译得好",而是"错得少":宁可句子朴素,也不要生造词。
2. 只改中文,该动 values 还是 values-zh?看默认那份是什么语言。打开 res/values/strings.xml,里面是中文就改它;是英文就改 values-zh 或 values-zh-rCN。不确定就先改一条最显眼的文案试装一次,一次就能确认。
3. 改了 strings.xml 为什么没生效?先分三类:改的不是生效的那份目录;改了但没回编、或装的是旧包;这条文案实际来自布局内联、代码硬编码或服务端下发。按"整页没变/部分没变/单条没变"三种现象对号入座最快,确认动作在第九节的表里。
4. 布局里的文字能不能直接改?能,而且改动最小。但如果你要的是"随系统语言切换的双语版本",就必须把它提成 @string 引用,否则切语言时它不会跟着变——这是双语项目最常见的结构性错误。
5. smali 里的 const-string 能批量替换吗?可以按文件全局搜,但必须一条一条核。只改引号之间的文字,寄存器与指令结构一个字都不能动;拼接串要读出相邻几条的语序再译;日志、参数名这类用户看不到的别动,改了只有风险没有收益。
6. 汉化完要不要重新签名?要。回编产物是未签名的,必须签名才能装。用自己的 jks 或 keystore 都行,但要注意:如果设备上装的是别人签的旧版本,签名不一致会装不上,得先卸载(会清数据,先备份)。
7. 一次改多少条合适?五十到一百五十条,或者一个页面。判断标准是"回编报错时你能不能十分钟内定位"。超过这个量,出错得二分排查;小于这个量,回编装机的次数太多,时间都花在等待上。
8. 术语表一定要做吗?就我一个人改。一个人更要作。你不是记不住词,你是记不住三百条之前的那个决定。它的最大作用不是给别人看,是给三天后的自己看;它同时也是抽查的依据——没有它,抽查只能靠感觉。
9. 做多语言会让包变大吗?会略有增加,因为每种语言各有一份文案,编译进资源表后体积会涨一些。但文案本身体量通常不大,真正影响体积的是图片与库;如果包体敏感,先做必要的几种语言,长尾语言留到后面再加。
他们做完第一批之后
"以前我最怕回编报错,一报错就得整体回退。按页面切批之后,最多回退一个页面,心里有底了。"
—— 老陈 · 独立开发者
"术语表我一开始嫌麻烦,做到两百条时庆幸自己做了。前后不一致真的只能靠回头全改。"
—— 小林 · 本地化兼职
"抽查按标点那一招挺狠的。句号有没有、中英逗号混着用,一眼就能看出这批活是不是赶出来的。"
—— 阿哲 · 逆向研究爱好者
"我们内部工具以前出中英两个包,改一次要改两遍。提成资源之后只维护一套结构,省的不只是时间,是不会漏。"
—— 王工 · 企业内部工具维护
"工程全可见这件事对汉化太重要了。我能亲眼看到这条文案是从哪个目录读的,不用猜,也不用问人。"
—— 周航 · 安卓逆向爱好者
"漏改基本都藏在对话框和开关上,界面上看不见就不容易想起来。现在每批结束我都专门点一遍这些角落。"
—— Nina · 出海小团队运营
"我接的活里,客户最常打回的不是译错,是同一句话两种写法。术语表等于提前把这类返工按掉了。"
—— 大刘 · 外包接单
"拿自己的课程设计应用练手,第一遍只做了首页,装上去看到全是自己的字,那种感觉很上瘾。"
—— 苏苏 · 在校学生
汉化真正难的地方不在翻译,而在确定"这条文案从哪来"和"改完怎么确认它真的生效了"。三层地图解决第一个问题,批次推进与抽查法解决第二个问题,术语表让这一切不用返工。这套流程慢,但每一步都踩得实;手动流的价值,本来就在"每一步都看得见"。
想自己走一遍:安卓修改大师智改工坊旗下的修改大师经典版(Windows 手动精修版,V11.27.00.00,需 ASP.Net 4.5 以上与 JDK 1.8 以上),介绍与下载入口在 https://www.apkeditor.cn/ai-version.aspx,官网 www.apkeditor.cn。挑一个自己的小应用,只改首页那一个页面,把三层都摸一遍——第一轮走通,后面的批就有节奏了。只需说话,就能让应用变成你想要的样子;愿意动手,就每一处都由你说了算。
安卓修改大师 · 修改大师经典版
Windows 手动精修 · 工程全可见 · 资源与 smali 都能改 · 汉化与多语言批量替换
立即下载 修改大师经典版
当前版本 V11.27.00.00 · Windows · 大小 13.74MB · 需 ASP.Net 4.5 以上 + JDK 1.8 以上 · 与智能修改电脑版可同机共存
想在手机上随时随地改:智能修改安卓版 约 7MB、Android 10 及以上,反编译到签名全在手机本地完成
修改大师经典版详细介绍 · 智改工坊介绍页 · 官网 www.apkeditor.cn