Skip to content

UE 国际化与文本翻译工具

在游戏开发中,本地化(Localization)往往是项目后期容易让人头大的环节。 Unreal Engine 虽然内置了强大的本地化系统,但原生的工具在多人协作和非技术人对接上略显繁琐。

UE 国际化概述

Unreal Engine 的本地化系统核心围绕着Localization Dashboard(本地化控制面板)展开。

  • 核心机制:UE 使用 FText 类型来处理所有需要显示的文本。
  • 收集:引擎会自动扫描代码(NSLOCTEXT, LOCTABLE 宏)和资源(Assets)中的文本。
  • 文件格式:UE 默认使用 .po (Portable Object) 文件格式来存储翻译源。这是 GNU gettext 标准格式,通用性很强。
  • 编译:翻译完成后,UE 会将 .po 编译成二进制的 .locres 文件,供游戏运行时快速加载。

虽然 Dashboard 能完成闭环,但直接让翻译人员在 UE 编辑器里工作,或者直接编辑纯文本的 .po 文件,效率和容错率都不高。因此,我们需要引入外部工具链。

工具链介绍

为了实现高效协作,我们将工作流拆分为:编辑器(Poedit)、云端协作、格式转换(可选)。

Poedit

地址:https://poedit.net/

Poedit 是最经典的 .po 文件编辑器。相比于用记事本打开 .po 文件面对一堆乱码般的 msgid 和 msgstr,Poedit 提供了清晰的左右对照界面。

主要用途:

  1. 开发者在不上传云端的情况下,程序快速修改几个词条进行测试。
  2. 查错:它自带简单的语法检查,能发现转义字符(如 \n, \")丢失或格式错误的问题。

ParaTranz

https://paratranz.cn/

ParaTranz(P 站)是一个广受独立游戏开发者和汉化组喜爱的在线协作平台。它完美解决了“文件传来传去版本混乱”的问题。

核心优势:

  • 原生支持 .po 文件:不需要转 CSV,直接把 UE 生成的 .po 扔进去就能识别。
  • 多人实时协作:项目主、翻译、校对可以同时在线工作,进度条一目了然。
  • 术语表与机器翻译:可以维护统一的术语表(Glossary),并集成 DeepL/Google 翻译辅助,极大地统一了名词翻译标准。
  • 历史版本管理:谁改了什么,什么时候改的,都有记录,方便追溯。

推荐工作流:

  • UE Gather: 在 Dashboard 点击 Gather Text,生成最新的 en.po (或其他源语言)。
  • Upload: 将 .po 上传至 ParaTranz 项目。
  • Translate: 邀请协作者在网页端进行翻译。
  • Export: 翻译完成后,从 ParaTranz 导出对应的 .po 文件(如 zh-Hans.po)。
  • UE Import & Compile: 将导出的文件覆盖项目中的旧文件,在 Dashboard 点击 Compile Text。

格式转换

如果需要 CSV 等格式的翻译文件,也可以通过 Python 的 polib 库进行转换。

转CSV的代码如下:

python
import polib
import pandas as pd

def po_to_csv(po_path, csv_path):
    po = polib.pofile(po_path)
    data = []
    for entry in po:
        data.append({
            'msgctxt': entry.msgctxt, # 上下文,UE中通常是Key
            'msgid': entry.msgid,     # 源文本
            'msgstr': entry.msgstr    # 翻译文本
        })
    
    df = pd.DataFrame(data)
    df.to_csv(csv_path, index=False, encoding='utf-8-sig')
    print(f"Exported {len(data)} entries to {csv_path}")

回填的代码如下:

python
# 示例代码片段
def csv_to_po(csv_path, original_po_path, output_po_path):
    df = pd.read_csv(csv_path)
    po = polib.pofile(original_po_path) #以此为模板,保留Header信息
    
    # 建立查找表加速
    trans_map = dict(zip(df['msgctxt'], df['msgstr']))
    
    count = 0
    for entry in po:
        if entry.msgctxt in trans_map:
            # 注意:需处理NaN情况
            translation = str(trans_map[entry.msgctxt])
            if translation != 'nan':
                entry.msgstr = translation
                count += 1
                
    po.save(output_po_path)
    print(f"Updated {count} entries in {output_po_path}")