You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于changedate元数据合并存在冲突的TMX翻译记忆文件

合并TMX翻译记忆文件并保留最新版本词条

你的核心问题在于当前代码只是简单拼接整个TMX元素,没有处理重复词条,也无法根据changedate判断并保留最新版本。咱们可以通过以源文本为唯一标识,对比时间戳的方式解决这个问题,具体实现步骤如下:

核心思路

  1. 遍历所有TMX文件,解析每个<tu>条目:
    • 提取源语言(这里是ZH-CN)的<seg>内容作为唯一标识
    • 提取目标语言的翻译内容、changeid和changedate属性
  2. 用字典存储每个源文本对应的最新条目:
    • 将changedate转换为可比较的时间对象
    • 遇到相同源文本时,保留时间戳更新的条目
  3. 重新构建完整的TMX结构,将筛选后的<tu>条目放入<body>中,保留原文件的<header>等元数据

完整实现代码

from xml.etree import ElementTree
from datetime import datetime

def parse_tu(tu_element):
    """解析单个tu元素,返回源文本、目标翻译信息和时间戳"""
    source_seg = None
    target_tuv = None
    # 遍历tu下的tuv元素
    for tuv in tu_element.findall('tuv'):
        lang = tuv.attrib.get('lang')
        if lang == 'ZH-CN':
            # 提取源文本
            seg = tuv.find('seg')
            if seg is not None:
                source_seg = seg.text.strip() if seg.text else ''
        elif lang == 'EN-US':
            # 提取目标翻译和元数据
            seg = tuv.find('seg')
            if seg is not None:
                target_seg = seg.text.strip() if seg.text else ''
            changeid = tuv.attrib.get('changeid')
            changedate_str = tuv.attrib.get('changedate')
            # 解析时间戳:格式是YYYYMMDDTHHMMSSZ
            changedate = datetime.strptime(changedate_str, '%Y%m%dT%H%M%SZ')
            target_tuv = {
                'seg': target_seg,
                'changeid': changeid,
                'changedate': changedate,
                'changedate_str': changedate_str
            }
    return source_seg, target_tuv

def build_tu(source_seg, target_info):
    """根据源文本和目标信息构建新的tu元素"""
    tu = ElementTree.Element('tu')
    # 构建源tuv
    source_tuv = ElementTree.Element('tuv', attrib={'lang': 'ZH-CN'})
    source_seg_elem = ElementTree.Element('seg')
    source_seg_elem.text = source_seg
    source_tuv.append(source_seg_elem)
    tu.append(source_tuv)
    # 构建目标tuv
    target_tuv = ElementTree.Element('tuv', attrib={
        'lang': 'EN-US',
        'changeid': target_info['changeid'],
        'changedate': target_info['changedate_str']
    })
    target_seg_elem = ElementTree.Element('seg')
    target_seg_elem.text = target_info['seg']
    target_tuv.append(target_seg_elem)
    tu.append(target_tuv)
    return tu

def merge_tmx_files(files):
    # 存储每个源文本的最新条目,键是源文本,值是目标信息
    tu_dict = {}
    # 记录第一个文件的header信息,用来生成最终的tmx结构
    header = None
    tmx_version = None
    doctype = None

    for filename in files:
        tree = ElementTree.parse(filename)
        root = tree.getroot()
        # 提取header和版本信息(只取第一个文件的)
        if header is None:
            header = root.find('header')
            tmx_version = root.attrib.get('version')
            # 注意:ElementTree不会保留DOCTYPE,需要手动记录
            with open(filename, 'r', encoding='utf-8') as f:
                for line in f:
                    if '<!DOCTYPE' in line:
                        doctype = line.strip()
                        break
        # 遍历body下的所有tu元素
        body = root.find('body')
        if body is not None:
            for tu in body.findall('tu'):
                source_seg, target_info = parse_tu(tu)
                if source_seg and target_info:
                    # 检查字典中是否已有该源文本
                    if source_seg not in tu_dict:
                        tu_dict[source_seg] = target_info
                    else:
                        # 比较时间戳,保留更新的
                        existing_date = tu_dict[source_seg]['changedate']
                        new_date = target_info['changedate']
                        if new_date > existing_date:
                            tu_dict[source_seg] = target_info

    # 构建最终的TMX结构
    if not tu_dict:
        return None
    # 创建根元素
    tmx_root = ElementTree.Element('tmx', attrib={'version': tmx_version})
    # 添加header
    if header is not None:
        tmx_root.append(header)
    # 创建body
    body = ElementTree.Element('body')
    # 将所有tu添加到body
    for source_seg in tu_dict:
        target_info = tu_dict[source_seg]
        tu = build_tu(source_seg, target_info)
        body.append(tu)
    tmx_root.append(body)

    # 生成XML字符串,注意DOCTYPE需要手动添加
    xml_str = ElementTree.tostring(tmx_root, encoding='UTF-8').decode('UTF-8')
    # 插入DOCTYPE和XML声明
    final_str = f'<?xml version="1.0" encoding="UTF-8"?>\n{doctype}\n{xml_str}'
    return final_str

# 使用示例
if __name__ == '__main__':
    merged_result = merge_tmx_files(['file1.tmx', 'file2.tmx'])
    if merged_result:
        print(merged_result)
        # 也可以写入文件
        # with open('merged.tmx', 'w', encoding='utf-8') as f:
        #     f.write(merged_result)

关键细节说明

  • 时间戳解析:changedate格式是YYYYMMDDTHHMMSSZ,用datetime.strptime转换成可比较的时间对象,方便判断新旧版本
  • 字典去重与更新:以源文本为键,确保每个源文本只保留最新的翻译版本
  • DOCTYPE处理:ElementTree默认不会保留DOCTYPE声明,所以需要手动读取原始文件的DOCTYPE行并添加到最终输出中
  • 结构还原:严格按照TMX1.1的结构构建新元素,确保输出格式与原文件完全一致

用这个代码处理你提供的两个示例文件,会得到你期望的输出结果——既合并了所有唯一词条,又自动保留了changedate更新的版本。

内容的提问来源于stack exchange,提问作者Jeremy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:24:23