如何翻译大型 TXT 文件:编码、章节与换行
在翻译长篇 .txt 文件之前,先修正编码、标记章节并合并硬换行。本文提供示例文件、免费检查工具以及 9 次测试结果。

要翻译大型 TXT 文件,在上传到任何地方之前,请先做好三件事。第一,确保文本被正确解码,并保存为 UTF-8。第二,让每个章节标题独占一行,并在其前后各留一个空行。第三,如果文件按固定宽度换行,请将这些行合并,使每个段落成为一行,段落之间用空行分隔。然后翻译整个文件,之后对比原文与译文的段落数和章节数。
纯文本文件没有样式、没有标题,也没有元数据。翻译工具对其结构的所有了解都来自字节和换行符。这就是为什么同样三个问题反复出现:字节以错误的编码被读取,章节无法与普通行区分,或者换行符完全无法表明句子在哪里结束。
我们制作了四种编码的示例文件,编写了一个免费检查工具,并用本地模型将一篇硬换行的短篇小说翻译成简体中文九次。当模型看到整个文件时,它能很好地处理硬换行。但在三次按行数将文件切分成块的运行中,模型都出现了断句错误,并将一个角色的动作安到了另一个角色身上。
快速检查清单
| 检查项 | 理想状态 | 如何修正 |
|---|---|---|
| 编码 | 开头几行读取正确;文件为 UTF-8 | 用正确的编码重新打开,然后另存为 UTF-8 |
| 字节顺序标记 | 没有,或者有一个你知情的标记 | 如果工具报错,请保存为“UTF-8”而非“UTF-8 with BOM” |
| 章节标题 | 每个标题独占一行,前后各有一个空行 | 修正少数与正文连在一起的标题 |
| 段落 | 段落之间有一个空行 | 在仅以缩进开头的段落处添加空行 |
| 硬换行 | 每个段落是一长行 | 合并段落内的行,但诗歌、信件和列表除外 |
| 换行符 | 全文统一风格 | 转换旧 Mac 的 CR 换行;LF 和 CRLF 均可 |
| 文本损坏 | 没有 � 字符 | 获取更好的副本。转换无法恢复丢失的字符 |
检查器会报告每一行的情况,并修复编码、字节顺序标记、换行符和硬换行。章节标题和缺失的空行需要你手动修复。运行 python3 check_txt.py inspect yourfile.txt 查看报告,运行 python3 check_txt.py convert yourfile.txt clean.txt --unwrap 写出合并段落的 UTF-8 副本。它只需要 Python 3,并且从不更改原始文件。
第 1 步:正确设置编码
TXT 文件是一串字节。编码是将这些字节转换为字符的规则,而文件本身并不说明使用了哪条规则。如果程序猜错了,就会出现乱码:文本变得混乱,或者更糟,文本看起来正常但并非原本写入的内容。
下面是同一个中文短语“最后一班渡轮”(“the last ferry”),用错误的规则读取的结果。我们用 Python 内置的编解码器生成了这些结果,你可以用示例文件复现。
| 保存为 | 读取为 | 你看到的内容 |
|---|---|---|
| GB18030 | Windows-1252 | ×îºóÒ»°à¶ÉÂÖ |
| GB18030 | UTF-8 | ���һ����� |
| UTF-8 | GBK | 鏈�鍚庝竴鐝�娓¤疆 |
| Shift_JIS(日文 最後のフェリー) | GBK | 嵟屻偺僼僃儕乕 |
最后一行是危险的那一个。日文字节被当作中文读取,会产生真正的中文字符,没有错误,也没有 �。翻译工具会欣然翻译它们,结果将是语法正确但毫无意义的文本。
我们的检查器说明了为什么不能依赖“打开时没有报错”。当我们在 Shift_JIS 示例上运行它时,有两种编码在解码整个文件时没有出现任何错误:
encoding: unknown (not UTF-8)
these legacy encodings decode without errors; read the previews,
because a wrong one can still produce real-looking characters:
gb18030 戞堦榖丂嵟屻偺僼僃儕乕
cp932 第一話 最後のフェリー
只有第二行是日文。第一行是一串没人写过的生僻汉字。在 GB18030 中文示例上,有五种编码解码无错误,其中只有一种(GB18030)显示了章节标题“第一章 最后一班渡轮”。所以规则很简单:通过阅读前几行来决定编码,而不是看程序是否报错。
猜测通常出错的地方:
- 来自旧版 Windows 系统或中文网站的简体中文文本通常是 GBK 或 GB18030。GB18030 覆盖了 GBK 的所有内容,而浏览器遵循的 WHATWG 编码标准 更进一步:它指出“GBK 的解码器就是 gb18030 的解码器”。如果文件是 GBK,按 GB18030 打开即可。
- 繁体中文(来自台湾或香港)通常是 Big5。
- 日文通常是 Shift_JIS,或微软的扩展版本,Windows 和 Python 称之为 cp932。
- 韩文通常是 EUC-KR。
- 一个充满 NUL 字节的文件,或者每隔一个字符看起来像空白的文件,通常是缺少字节顺序标记的 UTF-16。
字节顺序标记(BOM)是文件开头的一小段不可见代码,用于声明 UTF-8、UTF-16 或 UTF-32。如果存在 BOM,就相信它。同一标准指出“字节顺序标记比其他任何东西都更具权威性”。我们的检查器首先读取 BOM,只有在没有 BOM 时才进行猜测。
将文件保存为 UTF-8
一旦文本读取正确,就将其保存为 UTF-8。WHATWG 标准称 UTF-8 是“Unicode 交换中最合适的编码”,并且它是任何翻译工具最安全的选择。
还有第二个原因对翻译尤为重要。传统编码只覆盖本地区的字符。Shift_JIS 没有“这”的编码,即“这是最后一班渡轮”的第一个字符,Big5 也没有,因为它是简体中文字符。Windows-1252 无法存储西里尔字母。如果翻译后的文件必须用原始传统编码写回,目标语言可能无法容纳。BookTranslator 的 TXT 翻译器 表示它会自动检测常见编码,并返回“与输入编码相同”的翻译文件,因此从 UTF-8 开始就完全消除了这个问题。
你可以在文本编辑器中转换(用正确的编码打开,然后“另存为”UTF-8),在 macOS 或 Linux 上使用 iconv -f GB18030 -t UTF-8 in.txt > out.txt,或者使用检查器:
python3 check_txt.py convert book.txt book-utf8.txt --encoding gb18030
如果文件已经包含 � 字符,损坏在你拿到之前就已经发生。再次转换不会恢复丢失的字符。寻找更好的源文件副本。
第 2 步:让章节易于查找
章节很重要,原因有三。长文件是分块翻译的,章节分隔是最干净的切割点。翻译后你会想检查每一章。而且如果你以后将文本转换为电子书,章节标题会成为目录。
将每个标题放在单独一行,前后各空一行,并在整本书中使用一种模式。以下是我们的检查器计数的模式:
Chapter 1,Chapter One: The Last Ferry,Part Two,Prologue,Epilogue第一章,第12回,第三話,第二卷- 一行中单独的数字或罗马数字,例如
12或XII.
运行 inspect 并阅读它找到的标题列表。如果书有 40 章而检查器找到 37 个,那么有三个标题隐藏了:一个与第一句连在一起,一个使用了不同的词如“第 7 章”,或者一个在同一行有文本。手动修复这三个。这比在翻译文件中发现问题所花的时间更少。
第 3 步:小心地取消硬换行
有些 TXT 文件在固定宽度处断行,以便文本适合纯终端或窄窗口。从 PDF 和 OCR 输出中复制的文本在打印页面的宽度处也会这样。在这些文件中,换行意味着“行已满”,而不是“句子或段落结束”。
硬换行很容易发现。在我们的硬换行样本中,检查器报告:
non-empty lines: 43; longest line: 66 chars; 25 lines within 12 chars of the longest
line breaks inside paragraphs that do not end a sentence: 23
looks hard-wrapped: consider convert --unwrap
修复方法是连接每个段落内的行,并保留段落之间的空行。陷阱在于换行是真实的文本:诗歌、歌词、信件、地址、食谱和列表。我们的样本包括一封五行信:
My dear Mara,
The key is under the blue pot.
Do not let your uncle sell the boat.
With love, always,
Nonna
一个直截了当的“将每个单换行替换为空格”会将其变成一行连续文本。检查器的 --unwrap 仅在段落的大多数行接近全宽时才连接该段落,因此像这封信这样的短行块会被保留。在我们的样本上,它逐字节地精确重建了原始未换行文件,包括信件。在你自己的文件上,在信任它之前,检查几个连接的段落和每个诗歌块。
还有两个细节。当你连接中文或日文文本的行时,不要在它们之间添加空格;检查器连接 CJK 行(包括以 CJK 标点结尾的行)时不加空格。如果你的文本来自 OCR,单词也可能在行尾用连字符拆分,这需要单独决定。我们的 修复 OCR 换行和连字符指南 涵盖了这一点。
我们测试了什么:硬换行文本,整体与切割
我们想知道硬换行是否真的会影响翻译质量,还是仅仅看起来不整洁。我们为测试写了一篇 396 词的短篇小说:三章、十五个段落、对话、上面那封信,以及一个 * * * 场景分隔符。我们用相同的文字保存了两次:未换行版本,每段一行;以及在 66 个字符处硬换行的版本,后者有 43 个非空行,而不是 19 个。
然后我们让一个本地模型用三种方式将其翻译成简体中文,每种方式运行三次:
- 硬换行,整个文件。 将硬换行文件放在一个请求中。
- 未换行,整个文件。 将未换行文件放在一个请求中。
- 硬换行,每 12 行切分。 将硬换行文件每 12 行切分,每段一个请求,然后将回复重新拼接。这就是脚本或工具按行数而非段落切分长文件时会发生的情况。
模型是 LM Studio 中的 Qwen 3.6 27B (Q4_K_M),关闭思考功能,温度设为 0.3,运行在配备 64 GB 内存的 Apple M4 Max 上。每个请求都使用相同的单句提示。我们在 2026 年 10 月 28 日运行了测试。脚本是 run_llm_txt_test.py,所有九个输出均未经编辑发布,results.csv 每次运行一行。
| 硬换行,整个文件 | 未换行,整个文件 | 硬换行,每 12 行切分 | |
|---|---|---|---|
| 保留的段落数(15) | 3 次运行中 3 次 | 3 次运行中 3 次 | 3 次中 0 次(每次 14 段) |
| 保留的章节标题数(3) | 3 次中 3 次 | 3 次中 3 次 | 3 次中 3 次 |
| 信件保留为五行 | 3 次中 3 次 | 3 次中 3 次 | 3 次中 3 次 |
| 在切分点被截断的句子数 | 0 | 0 | 每次运行 3 句 |
| 动作被赋予错误的角色 | 0 | 0 | 3 次运行中的 3 次 |
第一个发现让我们感到意外。当模型看到整个硬换行文件时,它自己把各行连接了起来。三次输出都是每行一个段落,与未换行的运行相同的 19 行,读起来同样通顺。因此,仅硬换行本身并没有在这个短文件上损害这个模型。
按行数切分文件确实造成了损害,而且每次都在相同的位置。12 行片段中有三个在句子中间结束。第一个结束于“He pointed with his”,下一个片段以“pen at a three-storey building on the corner.”开头。分开翻译时,后半部分失去了主语。在两次运行中,它返回为 她瞥了一眼街角那栋三层楼的建筑,“she glanced at the three-storey building on the corner.”在第三次运行中,它以 随后她重新回到填字游戏上 结束,“then she went back to the crossword.”在故事中,售票亭里的男人指了指,然后回去做他的填字游戏。在三次运行中,中文读者都会认为是玛拉做了这件事。
第二个切分点在“the careful, slightly old-fashioned hand she had learned at a”和“convent school,”之间,使中文句子在三次运行中都悬在 那是她在,“that was where she,”(一次运行多了一个 一),而“learned”这个词消失了。第三个切分点把关于百叶窗的句子分成两行,后半部分把“painted, not well, but not long ago”变成了剥落的油漆:两次运行中是 油漆虽已斑驳,第三次是 油漆剥落。而且由于片段之间用单个换行符连接,场景分隔前的空行消失了,这就是为什么每次运行都有 14 个段落而不是 15 个。我们的检查器发现了段落数。它无法发现错误的字符;我们是通过阅读发现的。
这对你的文件意味着什么:
- 取消换行可以保护你免受你无法控制的分割器的影响。 每个长文件都会在某处被分割,无论是被你自己的脚本、聊天窗口的限制,还是你上传到的工具。如果段落是单行并由空行分隔,任何合理的分割器都可以在段落之间而不是句子内部进行切割。
- 最严重的错误是流畅的。“She glanced at the building”是好的中文。读者会注意到每个切分点处奇怪的换行和悬空的 那是她在,但没有什么能把错误的字符或剥落的油漆标记为错误。分割点处的错误首先是意义错误,其次是格式错误。
- 这是一个模型和一个短篇故事。 这么短的文件可以放在一个请求中,所以整个文件的运行从来不需要分割任何东西。一整本小说确实需要分割,这正是步骤 1 到 3 中的准备工作发挥作用的时候。这些文件测试的是准备和分割,而不是 BookTranslator 自己的流程。
一个较小的观察:在六次整个文件的运行中,模型在五次中将玛拉的名字写成 玛拉,在一次中写成 马拉。每个输出自身是一致的,但不同的请求彼此不一致。对于分成许多片段翻译的长书,一份名字列表及其商定的拼写可以让每一章保持一致。我们的术语表指南展示了如何构建一个。
步骤 4:翻译,然后检查计数
当文件干净时,翻译它是容易的部分。你可以将其上传到 BookTranslator 的 TXT 翻译器,它接受 .txt、.md 和 .mdx 文件,声称处理高达 300 MB 的 TXT 文件,并在结账前显示价格。没有免费的完整翻译,但上传本身就会告诉你费用。如果你更喜欢使用聊天模型或本地 LLM,请自己在章节或段落边界处分割文件,并为名字保留一份术语表。如果你的文本是 Markdown 而不是纯散文,请参阅我们的 Markdown 翻译指南,因为 Markdown 语法需要自己的规则。
翻译后,比较两个文件:
python3 check_txt.py compare book-utf8.txt book-translated.txt
如果任一文件不是 UTF-8,请添加 --source-encoding 或 --translated-encoding。章节检查知道英语和中文/日文的标题模式;对于其他目标语言,请将“chapter”的本地词添加到脚本顶部的模式中。
这是我们一次切分运行的报告:
source translated
paragraphs 15 14 <- differs
chapter headings 3 3
non-empty lines 43 24 <- differs
scene breaks (* * *) 1 1
replacement chars 0 0
source script LATIN characters left in translation: 0
这样读它:
- 段落和章节标题应该匹配。缺少一个段落通常意味着两个段落被合并或一个被丢弃。
- 非空行可能因正当理由而不同。我们的整个文件换行运行从 43 行变为 19 行,因为模型连接了硬换行的行,这是一种改进。仅当源文件已经取消换行时才比较行数。
- 残留的源文字字符指向完全未翻译的段落。少数几个对于名字、产品术语或引文是正常的;一连串则意味着跳过了某个部分。
- 翻译中的替换字符意味着输出过程中出现了编码问题。
计数无法告诉你翻译是否正确。阅读每章的第一段和最后一段,以及文件被分割的每个位置两侧的段落。我们的测试就是在这些地方发现了每一个严重错误。
常见问题
为什么我的 TXT 文件在一个程序中看起来正常,在另一个程序中却乱码?
两个程序猜测了不同的编码。一个猜对了。找到能正确显示文本的编码,然后将文件保存为 UTF-8,以便每个程序都以相同方式读取它。
在翻译之前,我应该将 TXT 文件转换为 EPUB 或 DOCX 吗?
只有当你需要这些格式带来的额外功能时才需要转换。一个章节清晰、干净的 TXT 文件本身就能很好地翻译。如果你想要目录、章节导航以及可以在设备上阅读的电子书,我们的指南将网络小说转换为可翻译的 EPUB 中有详细说明。
我可以翻译包含多种语言的 TXT 文件吗?
可以,但要告诉翻译工具哪些内容需要保留。对于第三种语言的引文或术语,以及应保留原文拼写的名称,使用术语表或简短说明来保护它们,比事后修正更容易。
那从网站下载的 TXT 文件呢?
请确认你有权使用该文件。对于公共领域的书籍或你自己编写的文件,上述步骤适用。文件的编码或格式并不能说明其版权状况。





