python3本地翻译工具

当你需要在开发的时候把语言包翻译成不同地区的语言时,有不想搭建一个翻译服务。可以使用python开发遍历整个目录包括子目录的所有.lang后缀的文件,判断文件每一行的内容中等号后面是否为英文,是的话翻译成指定语言。我目前只使用了英文、简体中文,繁体中文。更多语言暂未测试,目前用的是百度翻译的接口。有问题可以在下面评论,我会尽力回复!

选择python3的原因是我电脑本身存在

如果你需要其他语言也可以提出,后续有空我也会发出来,目前这份代码已经解决了我的问题,并不一定适用所有场景,有需求可以告诉我

如果你想使用百度翻译接口来将英文翻译成中文,你需要先到百度翻译开放平台([https://fanyi-api.baidu.com/])注册并获取API密钥。

在根目录创建一个.env文件

BAIDU_TRANSLATE_APP_ID=你获得百度翻译的app_id
BAIDU_TRANSLATE_SECRET_KEY=你获得百度翻译的key

代码实现

import os
import re
import requests
from dotenv import load_dotenv
import argparse
import random
import hashlib

# 加载环境变量
load_dotenv()

# 读取环境变量中的API密钥
APP_ID = os.getenv("BAIDU_TRANSLATE_APP_ID")
SECRET_KEY = os.getenv("BAIDU_TRANSLATE_SECRET_KEY")

# 解析命令行参数
parser = argparse.ArgumentParser()
parser.add_argument("--extension", "-e", default=".lang", help="File extension to search for")
parser.add_argument("--directory", "-d", default=".", help="Directory to search in")
args = parser.parse_args()

# 原来语言
original_language = 'auto'
# 目标语言
target_language = 'zh'
# 统计
statistics = 0
LANGUAGES = {
    'bs_BA': {
        'title': '波斯尼亚语(拉丁文)',
        'baidu': 'bos',
    },
    'en_CA': {
        'title': '英语(加拿大)',
        'baidu': 'en',
    },
    'es_CR': {
        'title': '西班牙语(哥斯达黎加)',
        'baidu': 'spa',
    },
    'es_UY': {
        'title': '西班牙语(乌拉圭)',
        'baidu': 'spa',
    },
    'fr_GA': {
        'title': '法语(加蓬)',
        'baidu': 'fra',
    },
    'ka_GE': {
        'title': '格鲁吉亚语',
        'baidu': 'geo',
    },
    'nb_NO': {
        'title': '挪威语(伯克梅尔)',
        'baidu': 'nor',
    },
    'sk_SK': {
        'title': '斯洛伐克语',
        'baidu': 'sk',
    },
    'uz_UZ': {
        'title': '乌兹别克语(拉丁文)',
        'baidu': '',
    },
    'am_ET': {
        'title': '阿姆哈拉语',
        'baidu': 'amh',
    },
    'ca_ES': {
        'title': '加泰罗尼亚语',
        'baidu': 'cat',
    },
    'en_GB': {
        'title': '英语(英国)',
        'baidu': 'en',
    },
    'es_DO': {
        'title': '西班牙语(多米尼加共和国)',
        'baidu': 'spa',
    },
    'es_VE': {
        'title': '西班牙语(委内瑞拉)',
        'baidu': 'spa',
    },
    'fr_NC': {
        'title': '法语(新喀里多尼亚)',
        'baidu': 'fra',
    },
    'kk_KZ': {
        'title': '哈萨克语',
        'baidu': '',
    },
    'ne_NP': {
        'title': '尼泊尔语',
        'baidu': 'nep',
    },
    'sl_SI': {
        'title': '斯洛文尼亚语',
        'baidu': 'slo',
    },
    'vi_VN': {
        'title': '越南语',
        'baidu': 'vie',
    },
    'ar_DZ': {
        'title': '阿拉伯语(阿尔及利亚)',
        'baidu': 'ara',
    },
    'cs_CZ': {
        'title': '捷克语',
        'baidu': 'cs',
    },
    'en_IN': {
        'title': '英语(印度)',
        'baidu': 'en',
    },
    'es_EC': {
        'title': '西班牙语(厄瓜多尔)',
        'baidu': 'spa',
    },
    'et_EE': {
        'title': '爱沙尼亚语',
        'baidu': 'est',
    },
    'gl_ES': {
        'title': '加利西亚语',
        'baidu': 'glg',
    },
    'km_KH': {
        'title': '高棉语',
        'baidu': 'hkm',
    },
    'nl_BE': {
        'title': '荷兰语(比利时)',
        'baidu': 'nl',
    },
    'sq_AL': {
        'title': '阿尔巴尼亚语',
        'baidu': 'alb',
    },
    'zh_CN': {
        'title': '中文(简体)',
        'baidu': 'zh',
    },
    'ar_EG': {
        'title': '阿拉伯语(埃及)',
        'baidu': 'ara',
    },
    'cy_GB': {
        'title': '威尔士语',
        'baidu': 'wel',
    },
    'en_NZ': {
        'title': '英语(新西兰)',
        'baidu': 'en',
    },
    'es_ES': {
        'title': '西班牙语(西班牙)',
        'baidu': 'spa',
    },
    'eu_ES': {
        'title': '巴斯克语',
        'baidu': 'baq',
    },
    'he_IL': {
        'title': '希伯来语',
        'baidu': 'heb',
    },
    'kn_IN': {
        'title': '卡纳达语',
        'baidu': 'kan',
    },
    'nl_NL': {
        'title': '荷兰语',
        'baidu': 'nl',
    },
    'sr_RS': {
        'title': '塞尔维亚语',
        'baidu': 'srp',
    },
    'zh_HK': {
        'title': '中文(香港)',
        'baidu': 'cht',
    },
    'ar_IQ': {
        'title': '阿拉伯语(伊拉克)',
        'baidu': 'ara',
    },
    'da_DK': {
        'title': '丹麦语',
        'baidu': 'dan',
    },
    'en_SA': {
        'title': '英语(沙特阿拉伯)',
        'baidu': 'en',
    },
    'es_GT': {
        'title': '西班牙语 - 危地马拉',
        'baidu': 'spa',
    },
    'fa_IR': {
        'title': '波斯语 - 伊朗',
        'baidu': 'per',
    },
    'hi_IN': {
        'title': '印地语 - 印度',
        'baidu': 'hi',
    },
    'ko_KR': {
        'title': '韩语 - 韩国',
        'baidu': 'kor',
    },
    'pl_PL': {
        'title': '波兰语 - 波兰',
        'baidu': 'pl',
    },
    'sv_SE': {
        'title': '瑞典语 - 瑞典',
        'baidu': 'swe',
    },
    'zh_TW': {
        'title': '中文 - 台湾',
        'baidu': '',
    },
    'ar_JO': {
        'title': '阿拉伯语 - 约旦',
        'baidu': 'ara',
    },
    'de_AT': {
        'title': '德语 - 奥地利',
        'baidu': 'de',
    },
    'en_SG': {
        'title': '英语 - 新加坡',
        'baidu': 'en',
    },
    'es_HN': {
        'title': '西班牙语 - 洪都拉斯',
        'baidu': 'spa',
    },
    'fi_FI': {
        'title': '芬兰语 - 芬兰',
        'baidu': 'fin',
    },
    'hr_HR': {
        'title': '克罗地亚语 - 克罗地亚',
        'baidu': 'hrv',
    },
    'lo_LA': {
        'title': '老挝语 - 老挝',
        'baidu': 'lao',
    },
    'pt_AO': {
        'title': '葡萄牙语 - 安哥拉',
        'baidu': 'pt',
    },
    'sw_SW': {
        'title': '斯瓦希里语 - 坦桑尼亚',
        'baidu': 'swa',
    },
    'ar_SA': {
        'title': '阿拉伯语 - 沙特阿拉伯',
        'baidu': 'ara',
    },
    'de_CH': {
        'title': '德语 - 瑞士',
        'baidu': 'de',
    },
    'en_US': {
        'title': '英语 - 美国',
        'baidu': 'en',
    },
    'es_MX': {
        'title': '西班牙语 - 墨西哥',
        'baidu': 'spa',
    },
    'fr_BE': {
        'title': '法语 - 比利时',
        'baidu': 'fra',
    },
    'hu_HU': {
        'title': '匈牙利语 - 匈牙利',
        'baidu': 'hu',
    },
    'lt_LT': {
        'title': '立陶宛语 - 立陶宛',
        'baidu': 'lit',
    },
    'pt_BR': {
        'title': '葡萄牙语 - 巴西',
        'baidu': 'pt',
    },
    'ta_IN': {
        'title': '泰米尔语 - 印度',
        'baidu': 'tam',
    },
    'ar_SY': {
        'title': '阿拉伯语 - 叙利亚',
        'baidu': 'ara',
    },
    'de_DE': {
        'title': '德语 - 德国',
        'baidu': 'de',
    },
    'en_ZA': {
        'title': '英语 - 南非',
        'baidu': 'en',
    },
    'es_PA': {
        'title': '西班牙语 - 巴拿马',
        'baidu': 'spa',
    },
    'fr_CA': {
        'title': '法语 - 加拿大',
        'baidu': 'fra',
    },
    'id_ID': {
        'title': '印尼语 - 印度尼西亚',
        'baidu': 'id',
    },
    'lv_LV': {
        'title': '拉脱维亚语 - 拉脱维亚',
        'baidu': 'lav',
    },
    'pt_MZ': {
        'title': '葡萄牙语 - 莫桑比克',
        'baidu': 'pt',
    },
    'tg_TJ': {
        'title': '塔吉克语 - 塔吉克斯坦',
        'baidu': 'tgk',
    },
    'az_AZ': {
        'title': '阿塞拜疆语 - 阿塞拜疆',
        'baidu': 'aze',
    },
    'el_CY': {
        'title': '希腊语 - 塞浦路斯',
        'baidu': 'el',
    },
    'es_AR': {
        'title': '西班牙语 - 阿根廷',
        'baidu': 'spa',
    },
    'es_PE': {
        'title': '西班牙语 - 秘鲁',
        'baidu': 'spa',
    },
    'fr_CH': {
        'title': '法语 - 瑞士',
        'baidu': 'fra',
    },
    'is_IS': {
        'title': '冰岛语 - 冰岛',
        'baidu': 'ice',
    },
    'mk_MK': {
        'title': '马其顿语 - 马其顿',
        'baidu': 'mac',
    },
    'pt_PT': {
        'title': '葡萄牙语',
        'baidu': 'pt',
    },
    'th_TH': {
        'title': '泰语',
        'baidu': 'th',
    },
    'bg_BG': {
        'title': '保加利亚语',
        'baidu': 'bul',
    },
    'el_GR': {
        'title': '希腊语',
        'baidu': 'el',
    },
    'es_BO': {
        'title': '玻利维亚语',
        'baidu': '',
    },
    'es_PR': {
        'title': '波多黎各语',
        'baidu': '',
    },
    'fr_CI': {
        'title': '科特迪瓦语',
        'baidu': '',
    },
    'it_CH': {
        'title': '意大利语',
        'baidu': 'it',
    },
    'mn_MN': {
        'title': '蒙古语',
        'baidu': '',
    },
    'ro_RO': {
        'title': '罗马尼亚语',
        'baidu': 'rom',
    },
    'tr_TR': {
        'title': '土耳其语',
        'baidu': 'tr',
    },
    'bn_BD': {
        'title': '孟加拉语',
        'baidu': 'ben',
    },
    'en_AE': {
        'title': '英语',
        'baidu': 'en',
    },
    'es_CL': {
        'title': '智利语',
        'baidu': '',
    },
    'es_PY': {
        'title': '巴拉圭语',
        'baidu': '',
    },
    'fr_CM': {
        'title': '喀麦隆语',
        'baidu': '',
    },
    'it_IT': {
        'title': '意大利语',
        'baidu': 'it',
    },
    'ms_MY': {
        'title': '马来语',
        'baidu': 'may',
    },
    'ru_RU': {
        'title': '俄语',
        'baidu': 'ru',
    },
    'uk_UA': {
        'title': '乌克兰语',
        'baidu': 'ukr',
    },
    'bn_IN': {
        'title': '孟加拉语',
        'baidu': 'ben',
    },
    'en_AU': {
        'title': '英语',
        'baidu': 'en',
    },
    'es_CO': {
        'title': '哥伦比亚语',
        'baidu': '',
    },
    'es_US': {
        'title': '美国西班牙语',
        'baidu': 'spa',
    },
    'fr_FR': {
        'title': '法语',
        'baidu': 'fra',
    },
    'ja_JP': {
        'title': '日语',
        'baidu': 'jp',
    },
    'my_MM': {
        'title': '缅甸语',
        'baidu': 'bur',
    },
    'ru_UA': {
        'title': '俄语',
        'baidu': 'ru',
    },
    'ur_PK': {
        'title': '乌尔都语',
        'baidu': 'urd',
    },
}

def is_valid_language(path):
    for lang in path.split('/'):
        if lang in LANGUAGES:
            if LANGUAGES[lang]['baidu']:
                return LANGUAGES[lang]['baidu']
    return False

# 遍历目录中的所有文件
for root, dirs, files in os.walk(args.directory):
    for file in files:
        # 如果文件名以指定的扩展名结尾
        if file.endswith(args.extension):
            target_language = is_valid_language(root)
            if target_language and not original_language == target_language:
                # 打开文件进行处理
                with open(os.path.join(root, file), "r", encoding="utf-8") as f:
                    print(os.path.join(root, file))
                    new_line = ''
                    for line in f:
                        # 使用正则表达式匹配等号后面的英文
                        match = re.search(r'([^=\n]+)=([^\u4e00-\u9fa5\n]+)', line)
                        if match:
                            # 如果找到了英文,将其翻译成中文
                            en_text = match.group(2)
                            if not line == match.group(1) + '=' + match.group(2) + "\n":
                                print('匹配错误:')
                                print(line)
                                print(match.group(1))
                                print(match.group(2))
                                print(match.group(1) + '=' + match.group(2))
                                new_line += line
                                continue
                            print(en_text)
                            salt = str(random.randint(1000000000, 9999999999))
                            sign = hashlib.md5((APP_ID + en_text + salt + SECRET_KEY).encode("utf-8")).hexdigest()
                            # 发送HTTP请求到百度翻译接口
                            url = f"http://api.fanyi.baidu.com/api/trans/vip/translate"
                            data = {
                                'appid': APP_ID,
                                'q': en_text,
                                'from': original_language,
                                'to': target_language,
                                'salt': salt,
                                'sign': sign
                            }
                            response = requests.get(url, params=data)
                            res = response.json()
                            if 'error_code' in res:
                                print('接口错误')
                                print(root, file)
                                print('原语言', original_language)
                                print('目标语言', target_language)
                                print(res)
                                print(f"总共翻译了{statistics}行")
                                exit()
                            # 解析响应中的中文翻译结果
                            zh_text = res["trans_result"][0]["dst"]
                            # 将中文替换英文
                            line = line.replace(en_text, zh_text)
                            statistics += 1
                        new_line += line
                    # 处理完一行后,写入新的文件中
                    print(os.path.join(root, file), f"总共翻译了{statistics}行")
                    with open(os.path.join(root, file), "w", encoding="utf-8") as new_f:
                        new_f.write(new_line)
print(f"总共翻译了{statistics}行")

运行

-d 语言包根目录(默认值:当前目录)
-e 语言包文件后缀(默认值:.lang)

python3 main.py -d /path/code/langs -e .lang

我的语言包根目录下面是这三个目录,工具会分别识别每个目录找到里面的英文内容翻译成对应的语言,所以英文目录其实不起作用,稍后再优化!
/path/code/langs/zh_CN
/path/code/langs/zh_HK
/path/code/langs/en_US

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343