前言:相较于部署在本地的翻译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额度

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

更多推荐