两种免费的翻译API调用方式详解 - Edge官方API与个人缓存服务

两种免费的翻译API调用方式详解 - Edge官方API与个人缓存服务

一、前言

在日常开发中,翻译功能是一个非常常见的需求。本文将详细介绍两种完全免费的翻译API调用方式,并提供完整的代码实现和部署教程。

1.1 方案对比

对比项 Edge官方翻译API 个人翻译服务
调用方式 直接HTTP请求 通过本地Flask服务
是否需要认证 需要获取Edge Token
是否支持缓存 支持SQLite缓存
并发处理 无限制 支持并发,防止缓存击穿
部署难度 简单 中等
适用场景 少量翻译请求 大量翻译请求

二、环境准备

2.1 Python环境要求

bash 复制代码
# Python 3.7+
python --version

# 安装依赖包
pip install requests flask

2.2 项目结构

复制代码
translation_project/
├── edge_translator.py      # Edge官方API翻译
├── personal_translator.py  # 个人翻译服务(含Flask API)
├── translation_utils.py    # 统一调用接口
├── main.py                 # 主程序入口
└── requirements.txt        # 依赖清单

三、Edge官方翻译API实现

3.1 API接口分析

Edge浏览器的翻译接口不需要任何认证,直接发送POST请求即可使用。接口地址为:

复制代码
https://edge.microsoft.com/translate/translatetext?from=en&to=zh-CHS

3.2 完整代码实现

文件:edge_translator.py

python 复制代码
"""
Edge官方翻译API封装
特点:无需认证,直接调用
"""

import requests
import json
from typing import Optional, List
from urllib.parse import urlencode


class EdgeTranslator:
    """Edge翻译器"""
    
    def __init__(self):
        self.base_url = "https://edge.microsoft.com/translate/translatetext"
        self.headers = {
            "Content-Type": "application/json",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
            "Origin": "https://www.microsoft.com",
            "Referer": "https://www.microsoft.com/"
        }
    
    def translate(self, text: str, from_lang: str = "en", to_lang: str = "zh-CHS") -> str:
        """
        翻译文本
        
        Args:
            text: 待翻译文本
            from_lang: 源语言代码
            to_lang: 目标语言代码
            
        Returns:
            翻译后的文本
        """
        # 构建请求参数
        params = {
            "from": from_lang,
            "to": to_lang,
            "api-version": "3.0"
        }
        
        # 构建完整URL
        url = f"{self.base_url}?{urlencode(params)}"
        
        # 发送请求
        try:
            response = requests.post(
                url, 
                json=[text], 
                headers=self.headers,
                timeout=30
            )
            response.raise_for_status()
            
            # 解析响应
            result = response.json()
            return result[0] if isinstance(result, list) else result.get('translation', '')
            
        except requests.exceptions.RequestException as e:
            raise Exception(f"Edge翻译API调用失败: {e}")
    
    def batch_translate(self, texts: List[str], from_lang: str = "en", to_lang: str = "zh-CHS") -> List[str]:
        """
        批量翻译
        
        Args:
            texts: 待翻译文本列表
            from_lang: 源语言
            to_lang: 目标语言
            
        Returns:
            翻译后的文本列表
        """
        params = {
            "from": from_lang,
            "to": to_lang,
            "api-version": "3.0"
        }
        url = f"{self.base_url}?{urlencode(params)}"
        
        try:
            response = requests.post(url, json=texts, headers=self.headers, timeout=60)
            response.raise_for_status()
            result = response.json()
            return result if isinstance(result, list) else [result.get('translation', '')]
            
        except requests.exceptions.RequestException as e:
            raise Exception(f"Edge批量翻译失败: {e}")
    
    def get_supported_languages(self) -> dict:
        """获取支持的语言列表(部分常用语言)"""
        return {
            "en": "英语",
            "zh-CHS": "简体中文",
            "zh-CHT": "繁体中文",
            "ja": "日语",
            "ko": "韩语",
            "fr": "法语",
            "de": "德语",
            "es": "西班牙语",
            "ru": "俄语",
            "ar": "阿拉伯语"
        }


# 使用示例
if __name__ == "__main__":
    translator = EdgeTranslator()
    
    # 单个翻译
    result = translator.translate("Hello, world!", from_lang="en", to_lang="zh-CHS")
    print(f"翻译结果: {result}")
    
    # 批量翻译
    texts = ["Hello", "World", "Programming"]
    results = translator.batch_translate(texts)
    for original, translated in zip(texts, results):
        print(f"{original} -> {translated}")

四、个人翻译服务实现(带缓存)

4.1 服务架构设计

个人翻译服务基于Flask框架,主要特点:

  • 本地缓存:使用SQLite存储翻译结果,减少API调用
  • Token管理:自动获取和刷新Edge认证Token
  • 缓存击穿防护:使用线程锁防止同一文本被并发重复翻译
  • 高并发支持:采用WAL模式提升数据库并发性能

4.2 完整服务代码

文件:personal_translator.py

python 复制代码
"""
个人翻译服务 - 带本地缓存和并发控制
运行方式: python personal_translator.py
"""

import json
import os
import sqlite3
import time
import threading
from datetime import datetime
from typing import Optional

import requests
from flask import Flask, request, jsonify

app = Flask(__name__)

# 数据库配置
DB_PATH = os.environ.get("DB_PATH", "translate_cache.db")
AUTH_URL = "https://edge.microsoft.com/translate/auth"
TRANSLATE_URL = "https://api.cognitive.microsofttranslator.com/translate"

# 全局变量
_token = None
_token_expire_at = 0
_token_lock = threading.Lock()
_write_lock = threading.Lock()
_text_locks = {}
_text_locks_guard = threading.Lock()


def _get_conn():
    """获取数据库连接"""
    conn = sqlite3.connect(DB_PATH, timeout=30, check_same_thread=False)
    # 启用WAL模式,提升并发性能
    conn.execute("PRAGMA journal_mode=WAL")
    conn.execute("PRAGMA busy_timeout=5000")
    
    # 创建表
    conn.execute("""
        CREATE TABLE IF NOT EXISTS translations (
            src TEXT PRIMARY KEY,
            dst TEXT NOT NULL,
            created_at INTEGER NOT NULL
        )
    """)
    return conn


def get_token() -> str:
    """
    获取Edge翻译Token(带缓存)
    Token有效期约10分钟,这里9分钟后自动刷新
    """
    global _token, _token_expire_at
    
    with _token_lock:
        if _token and time.time() < _token_expire_at:
            return _token
        
        print(f"[{datetime.now()}] 获取新的Edge Token...")
        resp = requests.get(AUTH_URL, timeout=10)
        resp.raise_for_status()
        
        _token = resp.text.strip()
        _token_expire_at = time.time() + 9 * 60  # 9分钟有效期
        
        print(f"[{datetime.now()}] Token获取成功")
        return _token


def db_get(text: str) -> Optional[str]:
    """从缓存查询翻译"""
    conn = _get_conn()
    try:
        row = conn.execute(
            "SELECT dst FROM translations WHERE src = ?", (text,)
        ).fetchone()
        return row[0] if row else None
    finally:
        conn.close()


def db_set(text: str, dst: str):
    """写入缓存"""
    with _write_lock:
        conn = _get_conn()
        try:
            conn.execute(
                "INSERT INTO translations (src, dst, created_at) VALUES (?, ?, ?) "
                "ON CONFLICT(src) DO UPDATE SET dst=excluded.dst, created_at=excluded.created_at",
                (text, dst, int(time.time()))
            )
            conn.commit()
        finally:
            conn.close()


def call_translate_api(text: str, from_lang: str = "zh-CHS", to_lang: str = "en") -> str:
    """
    调用真实翻译API
    
    Args:
        text: 待翻译文本
        from_lang: 源语言
        to_lang: 目标语言
    """
    token = get_token()
    
    # 构建请求参数
    params = {
        "from": from_lang,
        "to": to_lang,
        "api-version": "3.0",
        "includeSentenceLength": "true"
    }
    
    headers = {
        "authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }
    
    payload = json.dumps([{"Text": text}])
    
    # 构建完整URL
    url = f"{TRANSLATE_URL}?{requests.compat.urlencode(params)}"
    
    resp = requests.post(url, headers=headers, data=payload, timeout=10)
    resp.raise_for_status()
    
    data = resp.json()
    return data[0]["translations"][0]["text"]


def translate(text: str, from_lang: str = "zh-CHS", to_lang: str = "en") -> str:
    """
    翻译主函数(带缓存和并发控制)
    
    Args:
        text: 待翻译文本
        from_lang: 源语言
        to_lang: 目标语言
    """
    # 1. 先查缓存
    cached = db_get(text)
    if cached is not None:
        return cached
    
    # 2. 获取该文本的锁,防止缓存击穿
    with _text_locks_guard:
        lock = _text_locks.setdefault(text, threading.Lock())
    
    with lock:
        # 再次检查缓存(可能其他线程已写入)
        cached = db_get(text)
        if cached is not None:
            result = cached
        else:
            # 调用API翻译
            result = call_translate_api(text, from_lang, to_lang)
            # 保存到缓存
            db_set(text, result)
    
    # 3. 清理未使用的锁
    with _text_locks_guard:
        if lock.acquire(False):
            del _text_locks[text]
            lock.release()
    
    return result


@app.route("/translate", methods=["POST"])
def translate_endpoint():
    """翻译接口"""
    body = request.get_json(silent=True) or {}
    
    text = body.get("text")
    from_lang = body.get("from", "zh-CHS")
    to_lang = body.get("to", "en")
    
    if not text or not str(text).strip():
        return jsonify({"error": "缺少参数 text"}), 400
    
    try:
        result = translate(str(text).strip(), from_lang, to_lang)
    except sqlite3.Error as e:
        return jsonify({"error": f"数据库错误: {e}"}), 502
    except requests.RequestException as e:
        return jsonify({"error": f"翻译服务调用失败: {e}"}), 502
    
    return jsonify({
        "translation": result,
        "from": from_lang,
        "to": to_lang
    })


@app.route("/batch_translate", methods=["POST"])
def batch_translate_endpoint():
    """批量翻译接口"""
    body = request.get_json(silent=True) or {}
    
    texts = body.get("texts", [])
    from_lang = body.get("from", "zh-CHS")
    to_lang = body.get("to", "en")
    
    if not texts or not isinstance(texts, list):
        return jsonify({"error": "缺少参数 texts(必须为列表)"}), 400
    
    results = []
    for text in texts:
        if text and str(text).strip():
            result = translate(str(text).strip(), from_lang, to_lang)
            results.append(result)
        else:
            results.append("")
    
    return jsonify({
        "translations": results,
        "from": from_lang,
        "to": to_lang
    })


@app.route("/health", methods=["GET"])
def health():
    """健康检查"""
    return jsonify({
        "status": "ok",
        "timestamp": datetime.now().isoformat()
    })


@app.route("/cache/stats", methods=["GET"])
def cache_stats():
    """缓存统计"""
    conn = _get_conn()
    try:
        size = conn.execute("SELECT COUNT(*) FROM translations").fetchone()[0]
    finally:
        conn.close()
    
    return jsonify({
        "size": size,
        "db_path": DB_PATH
    })


@app.route("/cache/clear", methods=["POST"])
def clear_cache():
    """清空缓存"""
    conn = _get_conn()
    try:
        conn.execute("DELETE FROM translations")
        conn.commit()
        return jsonify({"message": "缓存已清空"})
    finally:
        conn.close()


if __name__ == "__main__":
    print("=" * 60)
    print("个人翻译服务启动")
    print(f"数据库路径: {DB_PATH}")
    print("服务地址: http://localhost:5000")
    print("=" * 60)
    print("接口列表:")
    print("  POST /translate        - 翻译单个文本")
    print("  POST /batch_translate  - 批量翻译")
    print("  GET  /health           - 健康检查")
    print("  GET  /cache/stats      - 缓存统计")
    print("  POST /cache/clear      - 清空缓存")
    print("=" * 60)
    
    # 启动服务
    app.run(host="0.0.0.0", port=5000, debug=False, threaded=True)

五、统一调用接口

为了方便切换两种翻译方式,我们实现一个统一的调用接口。

文件:translation_utils.py

python 复制代码
"""
翻译工具统一接口
支持切换Edge官方API和个人缓存服务
"""

from typing import Optional, List
from enum import Enum
from edge_translator import EdgeTranslator
import requests


class TranslateMethod(Enum):
    EDGE = "edge"
    PERSONAL = "personal"


class Translator:
    """统一翻译器"""
    
    def __init__(self, method: TranslateMethod = TranslateMethod.PERSONAL):
        """
        初始化翻译器
        
        Args:
            method: 翻译方式,EDGE或PERSONAL
        """
        self.method = method
        self.edge_translator = EdgeTranslator() if method == TranslateMethod.EDGE else None
        self.personal_api_url = "http://localhost:5000/translate"
    
    def translate(self, text: str, from_lang: str = "zh-CHS", to_lang: str = "en") -> str:
        """
        翻译文本
        
        Args:
            text: 待翻译文本
            from_lang: 源语言
            to_lang: 目标语言
        """
        if self.method == TranslateMethod.EDGE:
            # 使用Edge API
            return self.edge_translator.translate(text, from_lang, to_lang)
        else:
            # 使用个人服务
            try:
                response = requests.post(
                    self.personal_api_url,
                    json={"text": text, "from": from_lang, "to": to_lang},
                    timeout=30
                )
                response.raise_for_status()
                return response.json()["translation"]
            except requests.exceptions.RequestException as e:
                raise Exception(f"个人翻译服务调用失败: {e}")
    
    def batch_translate(self, texts: List[str], from_lang: str = "zh-CHS", to_lang: str = "en") -> List[str]:
        """批量翻译"""
        if self.method == TranslateMethod.EDGE:
            return self.edge_translator.batch_translate(texts, from_lang, to_lang)
        else:
            try:
                response = requests.post(
                    f"{self.personal_api_url}/batch_translate",
                    json={"texts": texts, "from": from_lang, "to": to_lang},
                    timeout=60
                )
                response.raise_for_status()
                return response.json()["translations"]
            except requests.exceptions.RequestException as e:
                raise Exception(f"个人批量翻译服务调用失败: {e}")
    
    def switch_method(self, method: TranslateMethod):
        """切换翻译方式"""
        self.method = method
        if method == TranslateMethod.EDGE and not self.edge_translator:
            self.edge_translator = EdgeTranslator()


# 使用示例
if __name__ == "__main__":
    # 测试两种翻译方式
    texts = ["你好,世界!", "今天天气很好", "Python是一门优秀的编程语言"]
    
    print("=" * 60)
    print("1. 使用个人翻译服务")
    print("=" * 60)
    translator = Translator(TranslateMethod.PERSONAL)
    for text in texts:
        result = translator.translate(text)
        print(f"{text} -> {result}")
    
    print("\n" + "=" * 60)
    print("2. 使用Edge官方API")
    print("=" * 60)
    translator.switch_method(TranslateMethod.EDGE)
    for text in texts:
        result = translator.translate(text, from_lang="zh-CHS", to_lang="en")
        print(f"{text} -> {result}")

六、主程序入口

文件:main.py

python 复制代码
"""
翻译工具主程序
支持命令行交互和API调用两种模式
"""

import argparse
import sys
from translation_utils import Translator, TranslateMethod


def main():
    parser = argparse.ArgumentParser(description="翻译工具")
    parser.add_argument("-t", "--text", help="待翻译文本")
    parser.add_argument("-f", "--from", dest="from_lang", default="zh-CHS", help="源语言")
    parser.add_argument("-to", "--to", dest="to_lang", default="en", help="目标语言")
    parser.add_argument("--method", choices=["edge", "personal"], default="personal", 
                       help="翻译方式: edge(Edge官方API) 或 personal(个人缓存服务)")
    parser.add_argument("--batch", action="store_true", help="批量翻译模式")
    
    args = parser.parse_args()
    
    # 创建翻译器
    method = TranslateMethod.EDGE if args.method == "edge" else TranslateMethod.PERSONAL
    translator = Translator(method)
    
    # 批量翻译模式
    if args.batch:
        print("批量翻译模式(输入多行文本,Ctrl+D结束):")
        lines = sys.stdin.read().strip().splitlines()
        for line in lines:
            if line.strip():
                try:
                    result = translator.translate(line.strip(), args.from_lang, args.to_lang)
                    print(f"{line.strip()} -> {result}")
                except Exception as e:
                    print(f"翻译失败: {e}")
    else:
        # 单文本翻译
        if not args.text:
            print("请输入待翻译文本: ", end="")
            args.text = sys.stdin.readline().strip()
        
        if not args.text:
            print("错误: 请输入文本")
            sys.exit(1)
        
        try:
            result = translator.translate(args.text, args.from_lang, args.to_lang)
            print(f"翻译结果: {result}")
        except Exception as e:
            print(f"翻译失败: {e}")
            sys.exit(1)


if __name__ == "__main__":
    main()

七、部署和使用指南

7.1 部署个人翻译服务

bash 复制代码
# 1. 创建虚拟环境(可选)
python -m venv venv
source venv/bin/activate  # Linux/Mac
# 或
venv\Scripts\activate     # Windows

# 2. 安装依赖
pip install requests flask

# 3. 启动服务
python personal_translator.py

7.2 使用方式

方式一:命令行调用
bash 复制代码
# 使用个人服务翻译
python main.py -t "你好,世界" --method personal

# 使用Edge API翻译
python main.py -t "Hello, world" -f en -to zh-CHS --method edge

# 批量翻译
python main.py --batch << EOF
你好
世界
编程
EOF
方式二:API调用
bash 复制代码
# 翻译单个文本
curl -X POST http://localhost:5000/translate \
  -H "Content-Type: application/json" \
  -d '{"text": "你好,世界", "from": "zh-CHS", "to": "en"}'

# 批量翻译
curl -X POST http://localhost:5000/batch_translate \
  -H "Content-Type: application/json" \
  -d '{"texts": ["你好", "世界"], "from": "zh-CHS", "to": "en"}'

# 查看缓存统计
curl http://localhost:5000/cache/stats
方式三:Python代码调用
python 复制代码
from translation_utils import Translator, TranslateMethod

# 使用个人服务
translator = Translator(TranslateMethod.PERSONAL)
result = translator.translate("你好,世界")
print(result)

# 切换到Edge API
translator.switch_method(TranslateMethod.EDGE)
result = translator.translate("Hello, world", "en", "zh-CHS")
print(result)

7.3 性能优化建议

1. 高并发部署
bash 复制代码
# 使用gunicorn部署(生产环境)
pip install gunicorn
gunicorn -w 4 -k gthread --threads 8 personal_translator:app
2. 数据库优化
sql 复制代码
-- 创建索引加速查询
CREATE INDEX idx_created_at ON translations(created_at);

-- 定期清理过期缓存(7天前的数据)
DELETE FROM translations WHERE created_at < strftime('%s', 'now', '-7 days');
3. 内存缓存层(可选)
python 复制代码
from functools import lru_cache

@lru_cache(maxsize=10000)
def cached_translate(text: str) -> str:
    return translate(text)

7.4 常见问题解决

Q1: Edge翻译API返回401错误

解决方案:检查User-Agent是否正确,确保包含Edge浏览器标识。

Q2: 个人服务Token过期

解决方案:程序会自动刷新Token,无需手动处理。

Q3: 数据库锁冲突

解决方案:设置合适的超时时间,使用WAL模式。

python 复制代码
conn = sqlite3.connect(DB_PATH, timeout=30)
conn.execute("PRAGMA journal_mode=WAL")
Q4: 翻译速度慢

解决方案

  1. 使用缓存减少API调用
  2. 增加线程数
  3. 考虑使用Redis替代SQLite

八、总结

本文介绍了两种免费的翻译API调用方式:

  1. Edge官方翻译API:简单直接,无需认证,适合偶尔使用
  2. 个人翻译服务:带本地缓存,性能更好,适合大量翻译需求

两种方式各有优势,您可以根据实际需求选择。个人翻译服务的缓存机制可以显著减少API调用次数,提高响应速度,尤其适合需要大量翻译的场景。

8.1 扩展建议

  1. 多语言支持:扩展支持更多语言对
  2. 翻译记忆库:使用翻译记忆库提高翻译质量
  3. Web界面:开发友好的Web界面供非技术人员使用
  4. 监控告警:添加服务监控和异常告警

8.2 参考资源

最简单的参考

python 复制代码
import requests

url = "https://edge.microsoft.com/translate/translatetext?from=en&to=zh-CHS"
headers = {
    "Content-Type": "application/json",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
    "Origin": "https://www.microsoft.com"
}
data = ["Hello world, edge translate api"]

resp = requests.post(url, json=data, headers=headers)
print(resp.json())

输出内容为

php 复制代码
[{'translations': [{'text': '你好,世界,Edge 翻译 API', 'to': 'zh-Hans', 'sentLen': {'srcSentLen': [31], 'transSentLen': [17]}}]}]
相关推荐
新中地GIS开发老师1 小时前
WebGIS开发学生作品|低空航天管理与航线规划系统
前端·javascript·webgis·三维gis开发
用户059540174462 小时前
大模型对话记忆持久化踩坑实录:用 Playwright 自动化测了 300 次,终于揪出会话丢失的真凶
前端·css
丙氨酸長鏈2 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
kyriewen3 小时前
面试官让我手写虚拟列表——AI生成的版本,快速滚动几下就白屏了
前端·javascript·面试
IT_陈寒3 小时前
Vite热更新失效?你可能漏了这个配置
前端·人工智能·后端
Revolution614 小时前
React 组件重新渲染时,到底重新执行了什么
前端·react.js·面试
gwf2164 小时前
SSD读写速度深度解析:顺序读写vs随机读写、IOPS、延迟,你的硬盘性能到底怎么看?
git·嵌入式硬件·缓存·github·智能硬件
用户2181697049305 小时前
Flutter(四)Dart语法 空安全 运算符 流程控制
前端
许彰午5 小时前
政务督办的分合模式:主办协办的并发审批
前端·javascript·政务