thumbnail

背景

一直对容器化主机非常感兴趣,其对物理机的资源使用和租户的隔离型是非常有利的,可惜在国内IDC系统中,无论是魔方还是 Prokvm,还是延续着传统的VM 虚拟化。

这不得不让我关注国外的主机面板,其中 OpenPanel 吸引了我的兴趣,虽然其并没有完全开源,属于半开源的状态,但是他的设计理念和我理想的几乎一致,怀着激动的心情,我尝试了一下,发现它目前还处在发展阶段,还有一些 BUG 没有解决,其次,就是它没有中文,我决定自己贡献一下中文翻译。

由于我的英语一向不太好,不能指望自己一点点的翻译,我决定使用大模型gemma3:12b进行翻译,为此,我写了一个脚本,专门读取他的标准文件,在我的本地大模型上进行翻译,采用了多进程(Python的多线程🐶都不用)安全翻译,代码如下:

import time
import multiprocessing
from functools import partial
import os
import random
from openai import OpenAI
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type

# 翻译函数,调用 OpenAI 接口将英文翻译为简体中文
@retry(
    stop=stop_after_attempt(5),  # 最多重试5次
    wait=wait_exponential(multiplier=1, min=2, max=30),  # 指数级退避重试间隔
    retry=retry_if_exception_type((Exception))  # 任何异常都重试
)
def OpenPanel_text(text, api_key, base_url):
    if not text:
        return ""
    
    try:
        client = OpenAI(
            api_key=api_key,
            base_url=base_url
        )
        
        response = client.chat.completions.create(
            model="gemma3:12b",
            messages=[
                {"role": "system", "content": "You are now a professional assistant for multilingual translation. My website needs multiple languages. I already have an English version, and I need to translate it into Chinese. Please ensure the translation is authentic and idiomatic, without changing the meaning. Also, any punctuation should remain consistent with the English version."},
                {"role": "user", "content": f"You need to output only the translated content, without any other information. This is the English content that needs to be translated: {text}"}
            ],
            temperature=0.3,
            max_tokens=1000,
        )
        translated_text = response.choices[0].message.content.strip()
        print(f'原始: {text}\n翻译后: {translated_text}\n---')
        return translated_text
    except Exception as e:
        print(f"Error translating '{text}': {str(e)}")
        raise

def parse_pot_file(pot_file_path):
    with open(pot_file_path, 'r', encoding='utf-8') as pot_file:
        content = pot_file.read()
    
    # 将文件分割为每个翻译条目
    blocks = content.split('\n\n')
    parsed_blocks = []
    
    for block in blocks:
        if not block.strip():
            parsed_blocks.append(('', block))  # 空块
            continue
            
        lines = block.split('\n')
        msgid_value = ""
        
        # 查找 msgid 行
        for line in lines:
            if line.startswith('msgid "'):
                # 提取 msgid 值,假设它只在一行
                msgid_value = line[6:].strip('"')
                break
        
        parsed_blocks.append((msgid_value, block))
        
    return parsed_blocks

# 单个翻译工作函数
def translate_block(item, api_key, base_url):
    msgid_value, original_block = item
    
    if not msgid_value or msgid_value == '""':
        return original_block
    
    # 查找原始 msgstr 行并替换为翻译内容
    lines = original_block.split('\n')
    
    for i, line in enumerate(lines):
        if line.startswith('msgstr "'):
            # 翻译 msgid 内容
            translated_text = translate_text(msgid_value, api_key, base_url)
            # 替换原始 msgstr 内容
            lines[i] = f'msgstr "{translated_text}"'
            break
    
    # 添加随机延迟避免API限制
    time.sleep(random.uniform(0.5, 1.5))
    
    return '\n'.join(lines)

# 使用多进程翻译 POT 文件
def translate_pot_file_multiprocessing(pot_file_path, output_file_path, num_processes=4):
    api_key = "sk-XXXXXX"
    base_url = "https://aiapi.xing-yun.cn/v1"
    
    print(f"Parsing POT file {pot_file_path}...")
    parsed_blocks = parse_pot_file(pot_file_path)
    
    # 创建部分函数,设置固定参数
    translate_func = partial(translate_block, api_key=api_key, base_url=base_url)
    
    print(f"Starting translation with {num_processes} processes for {len(parsed_blocks)} blocks...")
    
    translated_blocks = []
    with multiprocessing.Pool(processes=num_processes) as pool:
        # 使用 imap 保持顺序并显示进度
        for i, result in enumerate(pool.imap(translate_func, parsed_blocks)):
            translated_blocks.append(result)
            print(f"Progress: {i+1}/{len(parsed_blocks)} completed")
    
    print("Translation completed. Writing to output file...")
    
    with open(output_file_path, 'w', encoding='utf-8') as output_file:
        output_file.write('\n\n'.join(translated_blocks))
    
    print(f"Translation saved to {output_file_path}")

if __name__ == '__main__':
    output_dir = '/Users/wang/Desktop/openpanel-translations/zh_cn'
    os.makedirs(output_dir, exist_ok=True)
    
    # 根据CPU核心数设置进程数(留一个核心给系统)
    cpu_count = max(1, multiprocessing.cpu_count() - 1)
    
    translate_pot_file_multiprocessing(
        '/Users/wang/Desktop/openpanel-translations/en-us/messages.pot', 
        '/Users/wang/Desktop/openpanel-translations/zh_cn/messages.pot',
        num_processes=cpu_count
    )

结果

最后,毫无疑问,翻译的质量很高,我认为主要是gemma3能力确实比较强,大模型翻译之后,我仅修改了几处不合适的地方,其余的都是正确的🍻。