在线API翻译方案介绍:调用百度在线翻译API生成国际化多语言配置文件,Python实现
前言:相较于部署在本地的翻译API方案,使用大厂在线的翻译API得到的翻译结果会更准确,
本文将介绍如何使用在线API执行脚本翻译(包括环境配置和Python脚本示例)。
目前有很多大厂提供了翻译API功能服务,如百度翻译、腾讯翻译、阿里翻译、火山翻译等。并且提供了一定的免费翻译API调用额度,针对个人用户是足够使用的(笔者用于游戏语言国际化翻译需求不大)本文将以百度翻译API的使用为例,至于其他厂商的API使用方式可以上网查询,使用方式都是类似的。
一、百度翻译API环境搭建
1. 登入百度翻译开放平台,注册开发者账号并认证后(个人认证(高级版)),获取API的APP ID和密钥信息,开通翻译API服务即可
参考官方介绍https://api.fanyi.baidu.com/doc/23
具体按照下图官方的接入步骤操作即可

2. 开发者界面,查看用于接入API的APP ID和密钥信息,后续脚本需要用到
3.开发者界面,查看已开通的翻译服务及使用额度

注:以下为官方提供的API免费额度及付费价格
通用文本翻译API,类似机翻(对个人开发者一个月有100W字符的免费额度)
大模型文本翻译API,一般来说比机翻更准(个人开发者认证后送100W字符额度)
二、翻译API调用
官方详细接入文档链接https://fanyi-api.baidu.com/doc/21
官方提供的Python脚本API接入示例
注意:脚本中的appid和appkey需要填写为你的开发者申请信息中的APP ID和密钥
# -*- coding: utf-8 -*-
# This code shows an example of text translation from English to Simplified-Chinese.
# This code runs on Python 2.7.x and Python 3.x.
# You may install `requests` to run this code: pip install requests
# Please refer to `https://api.fanyi.baidu.com/doc/21` for complete api document
import requests
import random
import json
from hashlib import md5
# Set your own appid/appkey.
appid = 'INPUT_YOUR_APPID'
appkey = 'INPUT_YOUR_APPKEY'
# For list of language codes, please refer to `https://api.fanyi.baidu.com/doc/21`
from_lang = 'en'
to_lang = 'zh'
endpoint = 'http://api.fanyi.baidu.com'
path = '/api/trans/vip/translate'
url = endpoint + path
query = 'Hello World! This is 1st paragraph.\nThis is 2nd paragraph.'
# Generate salt and sign
def make_md5(s, encoding='utf-8'):
return md5(s.encode(encoding)).hexdigest()
salt = random.randint(32768, 65536)
sign = make_md5(appid + query + str(salt) + appkey)
# Build request
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
payload = {'appid': appid, 'q': query, 'from': from_lang, 'to': to_lang, 'salt': salt, 'sign': sign}
# Send request
r = requests.post(url, params=payload, headers=headers)
result = r.json()
# Show response
print(json.dumps(result, indent=4, ensure_ascii=False))
以下是笔者使用官方示例执行的结果,参考以下输出可以判断是的调用翻译服务成功

三、实战示例:调用翻译API实现批量语句的多种语言翻译(用于生成语言国际化配置)
先看脚本效果:
输入:带原始文本(英文)的Excel,每行代表一个需要翻译的文本
输出:在输入Excel文件中填充脚本定义的需要翻译的语言(简体中文、繁体中文、俄语、德语、法语、西班牙语、巴西葡萄牙语、日语、韩语、波兰语、意大利语、荷兰语、瑞典语,注:需要翻译的语言可以在脚本中自定义),并重新生成一个Csv文件


脚本如下,供大家参考或使用:
# -*- coding: utf-8 -*-
"""
Game localization: read Excel, add/update 13 translation columns (Baidu lang codes), write Excel + CSV.
Default: overwrite the input .xlsx and write a same-stem .csv beside it. Use -o / --output to write xlsx elsewhere
(still writes .csv next to that xlsx).
Incremental: only rows where column 1 & 2 (must match --key-col / --en-col order) are non-empty and all
13 target columns are blank call the translate API; existing translations are kept.
CSV is written from the final DataFrame only (no extra API calls).
Two backends (same appid/appkey + MD5 sign):
general — 通用翻译 …/api/trans/vip/translate
llm — 大模型文本翻译 …/ait/api/aiTextTranslate
Mode: 未传 --translate-mode 或传 general → 通用翻译;仅当传 --translate-mode llm → 大模型。
进程退出前会将本进程内 BAIDU_TRANSLATE_MODE 设为 general(无法改写已启动的父 shell 环境)。
Credentials: default appid/appkey below (personal use). Optional override:
BAIDU_TRANS_APPID, BAIDU_TRANS_APPKEY
Dependencies:
pip install -r requirements.txt
API reference: https://api.fanyi.baidu.com/doc/21
"""
from __future__ import annotations
import argparse
import json
import os
import random
import sys
import time
from hashlib import md5
import pandas as pd
import requests
# 个人使用:与原先演示脚本一致。也可用环境变量 BAIDU_TRANS_APPID / BAIDU_TRANS_APPKEY 覆盖。
appid = "请输入你的appid"
appkey = "请输入你的appkey"
# Baidu API `to` codes: output column headers use these strings (see API doc language list).
TARGET_LANG_CODES: list[str] = [
"zh",
"cht",
"ru",
"de",
"fra",
"spa",
"pt",
"jp",
"kor",
"pl",
"it",
"nl",
"swe",
]
TRANSLATE_ENDPOINTS: dict[str, str] = {
"general": "https://fanyi-api.baidu.com/api/trans/vip/translate",
"llm": "https://fanyi-api.baidu.com/ait/api/aiTextTranslate",
}
DEFAULT_TRANSLATE_MODE = "general"
# Single-request length guard (doc: upper bound on `q`; stay conservative for UTF-8 / multi-byte)
MAX_Q_CHARS = 4500
# Free tier is often ~1 QPS; adjust if your quota allows higher concurrency
DEFAULT_SLEEP_SEC = 0.35
def _cell_empty(val: object) -> bool:
if val is None:
return True
if isinstance(val, float) and pd.isna(val):
return True
return str(val).strip() == ""
def _all_target_langs_empty(df: pd.DataFrame, idx: int) -> bool:
for code in TARGET_LANG_CODES:
if code not in df.columns:
continue
if not _cell_empty(df.at[idx, code]):
return False
return True
def _row_needs_translate(df: pd.DataFrame, idx: int, key_col: str, en_col: str) -> bool:
"""First two columns = key + source; both non-empty; all 13 lang cells empty."""
if len(df.columns) < 2:
return False
if df.columns[0] != key_col or df.columns[1] != en_col:
return False
if _cell_empty(df.iat[idx, 0]) or _cell_empty(df.iat[idx, 1]):
return False
return _all_target_langs_empty(df, idx)
def make_md5(s: str, encoding: str = "utf-8") -> str:
return md5(s.encode(encoding)).hexdigest()
def translate_one(
appid: str,
appkey: str,
text: str,
from_lang: str,
to_lang: str,
endpoint: str,
session: requests.Session,
timeout: float = 30.0,
) -> tuple[str | None, str | None]:
"""Returns (translated_text, error_message). error_message is None on success."""
text = text if isinstance(text, str) else str(text)
if not text.strip():
return "", None
salt = random.randint(32768, 65536)
sign = make_md5(appid + text + str(salt) + appkey)
payload = {
"appid": appid,
"q": text,
"from": from_lang,
"to": to_lang,
"salt": salt,
"sign": sign,
}
try:
r = session.post(endpoint, data=payload, timeout=timeout)
r.raise_for_status()
data = r.json()
except Exception as exc: # noqa: BLE001 — surface network/parse errors to caller
return None, str(exc)
if "trans_result" in data:
parts = [item.get("dst", "") for item in data["trans_result"]]
return "".join(parts), None
err = data.get("error_msg") or data.get("error_code")
return None, json.dumps(data, ensure_ascii=False) if err is None else f"{data.get('error_code')}: {err}"
def translate_maybe_chunked(
appid: str,
appkey: str,
text: str,
from_lang: str,
to_lang: str,
endpoint: str,
session: requests.Session,
sleep_sec: float,
) -> tuple[str | None, str | None]:
s = text if isinstance(text, str) else str(text)
if len(s) <= MAX_Q_CHARS:
return translate_one(appid, appkey, s, from_lang, to_lang, endpoint, session)
chunks = [s[i : i + MAX_Q_CHARS] for i in range(0, len(s), MAX_Q_CHARS)]
out_parts: list[str] = []
for i, ch in enumerate(chunks):
dst, err = translate_one(appid, appkey, ch, from_lang, to_lang, endpoint, session)
if err:
return None, err
out_parts.append(dst or "")
if sleep_sec > 0 and i < len(chunks) - 1:
time.sleep(sleep_sec)
return "".join(out_parts), None
def run(
input_path: str,
output_path: str | None,
key_col: str,
en_col: str,
from_lang: str,
sleep_sec: float,
sheet: str | int | None,
translate_mode: str,
) -> tuple[str, str]:
aid = (os.environ.get("BAIDU_TRANS_APPID") or appid).strip()
akey = (os.environ.get("BAIDU_TRANS_APPKEY") or appkey).strip()
if not aid or not akey:
print("appid/appkey 为空,请检查脚本内配置或环境变量。", file=sys.stderr)
sys.exit(1)
mode = translate_mode.strip().lower()
endpoint = TRANSLATE_ENDPOINTS.get(mode)
if not endpoint:
print(
f"未知的 translate_mode: {mode!r},可选: {', '.join(TRANSLATE_ENDPOINTS)}",
file=sys.stderr,
)
sys.exit(1)
print(f"translate_mode={mode}\nendpoint={endpoint}", flush=True)
out = output_path or input_path
df = pd.read_excel(input_path, sheet_name=sheet if sheet is not None else 0)
if key_col not in df.columns:
print(f"Column not found: {key_col!r}. Available: {list(df.columns)}", file=sys.stderr)
sys.exit(1)
if en_col not in df.columns:
print(f"Column not found: {en_col!r}. Available: {list(df.columns)}", file=sys.stderr)
sys.exit(1)
if len(df.columns) < 2 or df.columns[0] != key_col or df.columns[1] != en_col:
print(
"增量翻译要求:Excel 第 1、2 列表头须依次为 --key-col 与 --en-col 对应列"
f"(当前前两列为 {list(df.columns[:2])!r},期望 [{key_col!r}, {en_col!r}])。",
file=sys.stderr,
)
sys.exit(1)
for code in TARGET_LANG_CODES:
if code not in df.columns:
df[code] = ""
session = requests.Session()
n = len(df)
translated_rows = 0
skipped_rows = 0
for idx in range(n):
if not _row_needs_translate(df, idx, key_col, en_col):
if (
not _cell_empty(df.iat[idx, 0])
and not _cell_empty(df.iat[idx, 1])
and not _all_target_langs_empty(df, idx)
):
skipped_rows += 1
continue
raw = df.iat[idx, 1]
src = str(raw).strip()
for to_code in TARGET_LANG_CODES:
dst, err = translate_maybe_chunked(
aid, akey, src, from_lang, to_code, endpoint, session, sleep_sec
)
if err:
print(f"Row {idx + 1} KEY={df.at[idx, key_col]!r} -> {to_code} FAILED: {err}", file=sys.stderr)
df.at[idx, to_code] = ""
else:
df.at[idx, to_code] = dst or ""
time.sleep(sleep_sec)
translated_rows += 1
print(f"Row {idx + 1}/{n} translated (KEY={df.at[idx, key_col]!r})")
print(f"Done: API-translated rows={translated_rows}, skipped (already has translation)={skipped_rows}", flush=True)
df.to_excel(out, index=False, engine="openpyxl")
out_csv = os.path.splitext(out)[0] + ".csv"
# CSV 仅为本地导出,不调用翻译 API、不计入接口额度
df.to_csv(out_csv, index=False, encoding="utf-8-sig")
return out, out_csv
def build_arg_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(
description="Excel game localization via Baidu Translate API (13 target columns: Baidu lang codes)."
)
p.add_argument("--input", "-i", required=True, help="输入 .xlsx(默认结果覆盖此文件)")
p.add_argument(
"--output",
"-o",
default=None,
help="输出 .xlsx 路径;省略则覆盖输入文件,并在同目录生成同名 .csv",
)
p.add_argument("--key-col", default="KEY", help="Column name for game string key (default: KEY)")
p.add_argument("--en-col", default="en", help="Column name for source English text (default: en)")
p.add_argument("--from-lang", default="en", help="Baidu source language code (default: en)")
p.add_argument("--sleep", type=float, default=DEFAULT_SLEEP_SEC, help=f"Seconds between API calls (default: {DEFAULT_SLEEP_SEC})")
p.add_argument("--sheet", default=None, help="Sheet name or 0-based index (default: first sheet)")
p.add_argument(
"--translate-mode",
choices=tuple(TRANSLATE_ENDPOINTS.keys()),
default=None,
help="省略或 general=通用翻译;仅 llm=大模型文本翻译。",
)
return p
def main() -> None:
args = build_arg_parser().parse_args()
translate_mode = "llm" if args.translate_mode == "llm" else DEFAULT_TRANSLATE_MODE
sheet: str | int | None
if args.sheet is None:
sheet = None
else:
try:
sheet = int(args.sheet)
except ValueError:
sheet = args.sheet
try:
path_xlsx, path_csv = run(
input_path=args.input,
output_path=args.output,
key_col=args.key_col,
en_col=args.en_col,
from_lang=args.from_lang,
sleep_sec=args.sleep,
sheet=sheet,
translate_mode=translate_mode,
)
print(f"Wrote: {path_xlsx}")
print(f"Wrote: {path_csv}")
finally:
os.environ["BAIDU_TRANSLATE_MODE"] = "general"
if __name__ == "__main__":
main()
对于这个脚本使用方式如下:
1.安装依赖项(新建一个文件requirements.txt,复制以下文本到里面,然后执行CMD进入文件的同一路径下,执行安装依赖指令 pip install -r requirements.txt)
pandas>=1.3.0
openpyxl>=3.0.0
requests>=2.26.0
2.设置脚本中的appid和appkey为你开发者信息中的实际值
3.准备输入文件TransStrings.xlsx,包含需要翻译的原始文本(本脚本使用的是Excel第2列的英文文本做为原始文本,实际上可按照自己的需求做修改),格式如下
4.本脚本支持使用2种翻译API的调用方式(在你已经开通通用文本翻译和大模型文本翻译的前提下)
通用文本翻译指令(其中BaiduTrans_InExcel_OutExcelAndCsv.py为该脚本名称,TransStrings.xlsx为输入文件名,--translate-mode general代表使用通用翻译模型)
python BaiduTrans_InExcel_OutExcelAndCsv.py -i .\TransStrings.xlsx --translate-mode general
大模型文本翻译指令(其中--translate-mode llm代表使用大模型文本翻译模型)
python BaiduTrans_InExcel_OutExcelAndCsv.py -i .\TransStrings.xlsx --translate-mode llm
文本翻译脚本执行过程(参考下图代表翻译完成)

5.扩展功能:为了节省API调用额度,脚本对于已经翻译的行不再重复翻译,检测没有翻译的行,调用翻译API填充翻译结果,以此来实现仅翻译每次新增的翻译项,以前翻译的内容不再重复翻译保留即可,仅翻译第一列和第二列有内容且其他列无内容的行。
示例如下
输入文件
执行该脚本,只翻译了新增的一行文本,其他已经翻译文本不再重复翻译,这样大大节省了使用的API额度

至此结束,如有问题,欢迎大家留言讨论!
更多推荐

所有评论(0)