在实际软件本地化工作中,JSON 文件是存储界面文本、提示信息等可翻译内容的主流格式。无论是开发桌面应用、Web 前端,还是配置各种开发工具(如 VSCode、Postman、Cursor),都离不开对 JSON 文件的汉化。传统做法是使用机器翻译工具(如某些在线翻译或 MTool 等集成工具)进行批量处理,但结果往往生硬、不符合技术语境,甚至出现严重歧义,后期需要投入大量人工进行校对,效率低下。
随着大语言模型(LLM)在自然语言理解与生成上的突破,利用 AI 进行高质量、上下文感知的翻译已成为可能。本文将围绕“如何利用免费 AI 工具,对 JSON 文件进行高质量、可定制化的汉化”这一核心主线展开。你将了解到一套完整的实践方案:从理解 JSON 结构对翻译的影响开始,到选择并配置合适的免费 AI 工具,再到编写脚本实现自动化、保持 JSON 结构完整的翻译流程,最后处理翻译中的特殊问题(如占位符、代码、专有名词)并验证结果。整个过程无需付费 API,完全基于可公开访问的模型服务或本地模型,旨在提供一套可复现、可集成到现有工作流中的工程化解决方案。
1. 理解 JSON 汉化的核心挑战与 AI 优势
在动手之前,必须清楚我们面对的不是纯文本翻译,而是结构化数据的本地化。这带来了几个独特的挑战,也正是 AI 能够发挥优势的地方。
1.1 JSON 结构带来的翻译约束
JSON 文件用于存储数据,其键值对(key-value)结构在汉化时需要区别对待。通常,需要翻译的是value部分,而key作为程序引用的标识符,必须保持不变。一个典型的待翻译 JSON 可能如下所示:
{ "welcome_message": "Hello, {user}! Welcome to our application.", "error_invalid_email": "The email address you entered is invalid.", "menu": { "file": "File", "edit": "Edit", "help": "Help" }, "config": { "timeout": 3000, "retries": 3 } }挑战在于:
- 保持结构完整:翻译脚本必须能递归遍历 JSON 对象,精准定位需要翻译的字符串值(
String类型),同时跳过数字、布尔值、null以及关键的key。 - 处理嵌套与数组:JSON 结构可能多层嵌套,并且值可能是字符串数组(如
["Option A", "Option B"]),需要能深入处理。 - 保留占位符与格式:字符串中常包含像
{user}、%s、\n这样的变量占位符或转义字符,翻译时必须原样保留,否则会导致程序运行时出错。 - 上下文缺失:独立的键值对使翻译模型缺乏上下文,可能导致歧义。例如,“File” 翻译成“文件”还是“归档”?“Submit” 翻译成“提交”还是“递交”?
1.2 传统机翻(如 MTool)为何成为“垃圾翻译”
这里提到的“垃圾翻译”并非指工具本身完全无用,而是指其输出结果在技术本地化场景下质量堪忧,原因如下:
- 缺乏领域知识:通用机器翻译模型不理解软件UI、技术文档、错误信息的特定表达方式。
- 破坏结构:某些工具粗暴处理整个文件,可能误修改
key或数字值。 - 忽略上下文:以单词或短句为单位翻译,无法利用整个 JSON 文件甚至相邻键值对提供的语义线索。
- 无法处理代码与占位符:容易将变量名、代码片段当作普通文本翻译,导致功能失效。
1.3 AI 模型如何提供高质量汉化
现代大语言模型(LLM)如 GPT、Claude、DeepSeek 等,为解决上述问题提供了新思路:
- 指令跟随与上下文理解:你可以通过系统提示词(System Prompt)明确翻译任务、目标语言、专业领域(如“软件界面”、“技术文档”),并要求模型保留 JSON 结构和特定占位符。
- 零样本/少样本学习:即使没有专门训练,通过提供几个正确的翻译示例(Few-shot),模型也能迅速掌握你想要的风格和术语。
- 处理复杂语义:模型能理解较长句子的整体含义,并根据软件界面常见的表达习惯给出更地道的翻译。
- 免费或低成本:存在大量提供免费额度或完全开源的模型,如 DeepSeek、Ollama 本地模型、Google Gemini API 免费 tier 等,足以应对中小型项目的翻译需求。
2. 环境准备与工具选型
实现 AI 汉化的核心是“一个能处理 JSON 的脚本” + “一个能理解指令的 AI 模型”。我们将分步搭建这个环境。
2.1 基础编程环境
你需要一个能运行 Python 或 Node.js 脚本的环境。本文以 Python 为例,因为它拥有丰富的 JSON 处理和 HTTP 请求库。
- 安装 Python:确保系统已安装 Python 3.8 或更高版本。在终端输入
python --version或python3 --version检查。 - 安装必要库:我们将使用
requests调用在线 API,或使用openai/anthropic等官方库(如果选用对应模型)。使用 pip 安装:pip install requests # 如果计划使用 OpenAI 格式的 API(包括许多开源模型服务),也可以安装 openai 库 # pip install openai
2.2 AI 模型/API 选型(免费方案)
这是最关键的一步。你需要选择一个提供免费额度或完全免费的 AI 服务。以下是几个可靠选项:
| 方案 | 核心工具/平台 | 免费额度/方式 | 优点 | 注意事项 |
|---|---|---|---|---|
| 在线大模型 API | DeepSeek API | 免费,拥有 128K 上下文。 | 完全免费,性能强大,支持联网搜索(需手动开启)。 | 需要注册获取 API Key,有每秒请求数限制。 |
| Google Gemini API | 免费 tier 足够个人使用。 | 由 Google 支持,翻译质量高。 | 需要注册 Google AI Studio 获取 API Key。 | |
| 其他国内大模型平台 | 通常有新用户免费额度。 | 访问速度快。 | 需关注各平台政策变化。 | |
| 本地运行模型 | Ollama + 轻量模型 | 完全免费,本地运行。 | 数据完全本地,无网络依赖,无使用限制。 | 需要一定的本地算力(CPU/GPU),模型效果取决于所选模型大小。 |
| ChatGPT 等替代前端 | 某些第三方客户端 | 可能提供免费访问通道。 | 使用熟悉的模型。 | 稳定性、合规性和数据安全风险极高,不推荐用于生产。 |
推荐选择:对于大多数用户,DeepSeek API是平衡易用性、免费性和效果的最佳起点。我们将以它为例进行后续演示。
2.3 获取 DeepSeek API Key
- 访问 DeepSeek 平台官网并注册账号。
- 登录后,在控制台找到“API Keys”或类似部分。
- 创建一个新的 API Key 并妥善保存。它看起来像一串长字符:
sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx。
3. 构建核心翻译脚本
我们将编写一个 Python 脚本,它能够读取 JSON 文件,识别出所有需要翻译的字符串,调用 AI API 进行翻译,并写回一个新的、结构完整的汉化 JSON 文件。
3.1 项目结构与依赖
创建一个新的项目目录,例如ai_json_translator,并在其中创建以下文件:
ai_json_translator/ ├── config.py # 存放 API Key 等配置(不要提交到 Git!) ├── translator.py # 核心翻译逻辑 ├── sample.json # 待翻译的示例 JSON 文件 └── translated.json # 脚本输出的汉化文件首先,在config.py中配置你的 API Key:
# config.py DEEPSEEK_API_KEY = "你的实际 API Key" # 其他模型的配置也可以放在这里,如 BASE_URL, MODEL_NAME 等3.2 核心翻译脚本实现
以下是translator.py的完整代码,包含了递归遍历、API 调用和错误处理。
# translator.py import json import os import time from typing import Any, Dict, List import requests from config import DEEPSEEK_API_KEY # 导入配置 class JSONTranslator: def __init__(self, api_key: str, base_url: str = "https://api.deepseek.com"): self.api_key = api_key self.base_url = base_url self.model = "deepseek-chat" # DeepSeek 的模型名称 self.headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } # 简单的缓存,避免重复翻译完全相同的字符串 self.translation_cache = {} def _is_translatable(self, value: Any) -> bool: """判断一个值是否需要翻译。目前只翻译字符串类型,且非空。""" return isinstance(value, str) and value.strip() != "" def _extract_strings(self, data: Any) -> List[str]: """从 JSON 数据中递归提取所有需要翻译的字符串。""" strings = [] if isinstance(data, dict): for v in data.values(): strings.extend(self._extract_strings(v)) elif isinstance(data, list): for item in data: strings.extend(self._extract_strings(item)) elif self._is_translatable(data): strings.append(data) return strings def _translate_batch(self, texts: List[str]) -> List[str]: """调用 DeepSeek API 批量翻译一组文本。""" if not texts: return [] # 构建系统提示词,明确翻译任务和要求 system_prompt = """你是一个专业的软件本地化助手。请将用户提供的英文文本翻译成简体中文。 要求: 1. 翻译结果必须专业、准确、符合软件界面用语习惯。 2. **绝对保留**所有原文本中的占位符、变量、代码、JSON 键名和特殊符号,例如 {name}, %s, `code`, \\n, \\t 等,不允许做任何修改或翻译。 3. 如果原文是单个单词(如菜单项),请给出最符合软件上下文的中文翻译。 4. 直接返回翻译后的文本,不要添加任何解释、标记或额外内容。 5. 如果遇到无法确定的内容,保持原文不变。""" # 将文本列表拼接成一个清晰的待翻译列表 user_content = "请翻译以下文本,每行一条:\n" + "\n".join([f"{i+1}. {text}" for i, text in enumerate(texts)]) payload = { "model": self.model, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_content} ], "temperature": 0.1, # 低温度,使输出更确定、更一致 "stream": False } try: response = requests.post( f"{self.base_url}/chat/completions", headers=self.headers, json=payload, timeout=30 # 设置超时 ) response.raise_for_status() # 如果状态码不是 200,抛出异常 result = response.json() translated_text = result["choices"][0]["message"]["content"].strip() # 解析 API 返回的文本,按行分割,并去除可能的前置序号 lines = [line.strip() for line in translated_text.split('\n') if line.strip()] # 清理行首的“1. ”、“2. ”等序号 cleaned_lines = [] for line in lines: # 简单移除行首的数字和点号(如“1. ”) if '. ' in line[:4]: parts = line.split('. ', 1) if len(parts) > 1 and parts[0].isdigit(): cleaned_lines.append(parts[1]) continue cleaned_lines.append(line) # 安全检查:返回行数应与输入行数一致 if len(cleaned_lines) != len(texts): print(f"警告:翻译返回行数({len(cleaned_lines)})与输入行数({len(texts)})不符。使用原始文本。") return texts return cleaned_lines except requests.exceptions.RequestException as e: print(f"API 请求失败: {e}") # 失败时返回原文,避免数据丢失 return texts except (KeyError, IndexError, json.JSONDecodeError) as e: print(f"解析 API 响应失败: {e}") return texts def _replace_strings(self, data: Any, translation_map: Dict[str, str]) -> Any: """使用翻译映射表递归替换 JSON 数据中的字符串。""" if isinstance(data, dict): return {k: self._replace_strings(v, translation_map) for k, v in data.items()} elif isinstance(data, list): return [self._replace_strings(item, translation_map) for item in data] elif self._is_translatable(data): # 使用缓存或映射表进行替换 return translation_map.get(data, data) else: return data def translate_file(self, input_path: str, output_path: str, batch_size: int = 20): """主方法:翻译 JSON 文件。""" print(f"正在读取文件: {input_path}") with open(input_path, 'r', encoding='utf-8') as f: original_data = json.load(f) # 1. 提取所有唯一字符串 all_strings = self._extract_strings(original_data) unique_strings = list(dict.fromkeys(all_strings)) # 去重并保持顺序 print(f"共发现 {len(unique_strings)} 个唯一字符串需要翻译。") if not unique_strings: print("没有需要翻译的内容。") with open(output_path, 'w', encoding='utf-8') as f: json.dump(original_data, f, ensure_ascii=False, indent=2) return # 2. 分批翻译 translation_map = {} for i in range(0, len(unique_strings), batch_size): batch = unique_strings[i:i + batch_size] print(f"翻译批次 {i//batch_size + 1}/{(len(unique_strings)-1)//batch_size + 1}...") translated_batch = self._translate_batch(batch) # 构建映射 for orig, trans in zip(batch, translated_batch): translation_map[orig] = trans # 避免请求频率过高 time.sleep(0.5) # 3. 替换原数据中的字符串 print("正在生成翻译后的 JSON...") translated_data = self._replace_strings(original_data, translation_map) # 4. 写入输出文件 with open(output_path, 'w', encoding='utf-8') as f: json.dump(translated_data, f, ensure_ascii=False, indent=2) print(f"翻译完成!结果已保存至: {output_path}") def main(): # 从配置文件加载 API Key api_key = DEEPSEEK_API_KEY if not api_key or api_key == "你的实际 API Key": print("错误:请在 config.py 中配置有效的 DEEPSEEK_API_KEY。") return translator = JSONTranslator(api_key) input_file = "sample.json" # 你的输入 JSON 文件 output_file = "translated.json" # 输出文件 if not os.path.exists(input_file): print(f"错误:输入文件 '{input_file}' 不存在。") return translator.translate_file(input_file, output_file) if __name__ == "__main__": main()3.3 关键代码与配置详解
系统提示词(System Prompt):这是保证翻译质量的核心。我们明确要求模型:
- 扮演专业本地化助手。
- 保留所有占位符和特殊符号。
- 直接返回翻译结果,不添加额外内容。
- 低确定性(
temperature=0.1)确保结果稳定。
递归遍历与类型判断:
_extract_strings和_replace_strings方法使用递归处理任意深度的 JSON 对象和数组,并且只对String类型进行操作。批处理与缓存:为了减少 API 调用次数(尤其是免费额度有限时),脚本将提取出的唯一字符串分批发送(默认 20 条一批)。
translation_cache逻辑可以进一步扩展,将结果保存到本地文件,实现永久缓存。错误处理与降级:网络请求和 API 响应解析都可能出错。脚本捕获了这些异常,并在失败时返回原始文本,确保不会因为单次翻译失败而丢失整个文件的数据。
输出格式:
json.dump(..., ensure_ascii=False, indent=2)确保中文字符正常显示(而非 Unicode 转义符),并保持美观的缩进格式。
4. 运行验证与结果分析
现在,让我们用一个实际的 JSON 文件来测试整个流程。
4.1 准备测试文件
在项目根目录创建sample.json,内容如下:
{ "app": { "name": "AI Config Manager", "version": "1.0.0" }, "ui": { "buttons": { "submit": "Submit", "cancel": "Cancel", "delete": "Delete", "confirm_delete": "Are you sure you want to delete {item_name}? This action cannot be undone." }, "messages": { "loading": "Loading, please wait...", "success": "Operation completed successfully!", "error": "An error occurred: {error_code}. Please check the logs or contact support." }, "menu": ["File", "Edit", "View", "Help"], "placeholder": "Enter your %s here" }, "errors": { "network": "Network connection failed. Check your internet settings.", "auth": "Authentication failed. Invalid username or password.", "validation": "The input value `{field}` is not valid." } }这个文件包含了软件翻译的典型元素:简单单词、带占位符的句子、字符串数组、嵌套结构。
4.2 执行翻译脚本
在终端中,确保位于项目目录,然后运行:
python translator.py你将看到类似以下的输出:
正在读取文件: sample.json 共发现 11 个唯一字符串需要翻译。 翻译批次 1/1... 正在生成翻译后的 JSON... 翻译完成!结果已保存至: translated.json4.3 检查翻译结果
打开生成的translated.json文件,你应该看到类似下面的内容(具体翻译结果可能因模型略有差异):
{ "app": { "name": "AI 配置管理器", "version": "1.0.0" }, "ui": { "buttons": { "submit": "提交", "cancel": "取消", "delete": "删除", "confirm_delete": "您确定要删除 {item_name} 吗?此操作无法撤销。" }, "messages": { "loading": "正在加载,请稍候...", "success": "操作成功完成!", "error": "发生错误:{error_code}。请检查日志或联系支持人员。" }, "menu": ["文件", "编辑", "视图", "帮助"], "placeholder": "在此处输入您的 %s" }, "errors": { "network": "网络连接失败。请检查您的互联网设置。", "auth": "认证失败。用户名或密码无效。", "validation": "输入值 `{field}` 无效。" } }验证要点:
- 结构完整:所有
key(如app,buttons,submit)均未改变。 - 类型正确:数字
1.0.0未被翻译。 - 占位符保留:
{item_name},{error_code},{field},%s都被原样保留。 - 翻译质量:对比传统机翻,“Submit”被译为“提交”而非“提交申请”,“Delete”译为“删除”而非“删掉”,更符合软件按钮用语。“Loading, please wait...” 被自然地译为“正在加载,请稍候...”。
- 数组处理:菜单数组
["File", ...]被正确遍历并翻译。
5. 常见问题排查与进阶优化
脚本运行起来只是第一步,在实际项目中你可能会遇到各种问题。以下是典型的排查路径和优化方案。
5.1 常见错误与解决方案
| 问题现象 | 可能原因 | 检查与解决步骤 |
|---|---|---|
运行脚本时报ModuleNotFoundError | 依赖库未安装。 | 在终端执行pip install requests。 |
报错KeyError: ‘choices’或IndexError | API 响应格式与预期不符,可能是 API Key 无效、模型不可用或服务端错误。 | 1. 检查config.py中的 API Key 是否正确且未过期。2. 打印完整的 API 响应 ( print(result)),查看错误信息。3. 确认 API 基础 URL 和模型名称是否正确。 |
| 翻译结果为空或全是原文 | 1. 系统提示词未被遵守。 2. 网络请求失败,脚本降级返回了原文。 3. 字符串提取逻辑有误。 | 1. 检查_translate_batch方法中system_prompt是否明确要求翻译。2. 查看控制台是否有“API 请求失败”的警告。 3. 在 _extract_strings方法后打印unique_strings,确认提取到了内容。 |
占位符{xxx}被翻译或破坏 | 系统提示词中关于保留占位符的指令不够强,或模型未完全遵循。 | 强化系统提示词,使用更严厉的语气,例如:“必须保留所有花括号{}、百分号%、反引号`及其内部的内容,绝对不允许翻译或修改它们。” |
| 翻译速度慢 | 1. 网络延迟。 2. 单次请求字符串太多或太少。 3. 未使用批处理。 | 1. 适当增加batch_size(如到30),但注意模型可能有单次上下文长度限制。2. 在 time.sleep中增加间隔,避免触发 API 的速率限制。 |
| API 额度耗尽或收费 | 免费额度用完。 | 1. 切换到另一个免费 API 服务(如 Gemini)。 2. 考虑使用本地模型方案(如 Ollama)。 3. 实现本地缓存,避免重复翻译相同内容。 |
5.2 针对特定场景的优化策略
术语一致性:软件中同一个词(如“Server”、“Client”)应在各处翻译一致。
- 方案:在脚本中维护一个全局的“术语表”字典。在
_translate_batch方法调用前,先根据术语表替换原文中的特定词汇为统一标记(如__SERVER__),翻译后再替换回来。
- 方案:在脚本中维护一个全局的“术语表”字典。在
上下文增强:对于短词或歧义词,单独翻译效果差。
- 方案:修改
_extract_strings方法,在提取字符串时,同时收集其“上下文路径”(如ui.buttons.submit)。在调用 API 时,将路径作为上下文信息一并发送给模型,例如:“路径ui.buttons.submit的文本是 ‘Submit’,请翻译。”
- 方案:修改
处理超长 JSON 文件:文件太大可能导致内存问题或 API 令牌超限。
- 方案:实现分块处理。将大 JSON 按顶级 Key 或一定深度进行分割,分别翻译后再合并。同时,在
_translate_batch中计算文本的令牌数(粗略可用字符数/4估算),确保单次请求不超过模型上限。
- 方案:实现分块处理。将大 JSON 按顶级 Key 或一定深度进行分割,分别翻译后再合并。同时,在
本地模型集成:完全脱离网络,保护数据隐私。
- 方案:使用Ollama。安装 Ollama 后,拉取一个轻量级双语模型,如
qwen2.5:7b或llama3.2:3b。将translator.py中的_translate_batch方法改为调用本地 Ollama API(默认端口 11434)。这需要将base_url改为http://localhost:11434/v1,并使用对应的模型名。虽然速度可能慢于云端 API,但数据完全本地,无使用限制。
- 方案:使用Ollama。安装 Ollama 后,拉取一个轻量级双语模型,如
5.3 生产环境最佳实践
当需要将此类脚本集成到 CI/CD 流水线或用于团队项目时,需考虑更多:
配置管理:绝对不要将 API Key 硬编码在脚本中或提交到版本控制系统。使用环境变量或专门的 secrets 管理工具。
# 在运行脚本前设置环境变量 export DEEPSEEK_API_KEY='your_key_here' python translator.py在
config.py中改为:import os DEEPSEEK_API_KEY = os.getenv('DEEPSEEK_API_KEY')缓存持久化:将
translation_cache字典保存到本地文件(如.translation_cache.json)。每次翻译前先加载缓存,翻译后更新并保存缓存。这能极大减少重复 API 调用,节省成本和时间。日志与监控:增加更详细的日志记录,记录翻译开始/结束时间、处理的键值对数量、API 调用次数和失败情况,便于问题追踪。
回滚与手动校对:AI 翻译并非 100% 准确。生成的
translated.json应被视为初稿。建立流程,让熟悉产品的语言专家进行最终校对。脚本可以生成一个“翻译报告”,列出所有修改项,方便人工复核。版本控制:将原始的
source.json和翻译后的locale/zh-CN.json都纳入版本控制。当源文件更新时,通过对比工具(如diff)找出新增或修改的字符串,只将这些增量部分提交给 AI 翻译,再合并到现有翻译文件中。
通过上述步骤,你不仅获得了一个可运行的免费 AI 汉化工具,更掌握了一套可扩展、可维护的工程化本地化解决方案的核心逻辑。你可以根据实际需求,调整提示词、更换模型、增加预处理和后处理步骤,使其完美适配你的项目。