上一篇文章收到了很多小伙伴的反馈,总结了一下主要以下几点:
-
说不知道怎么调api
-
目前只是把所有的中文变成了英文,如果想要做多语言还需要把这些关键字提炼出来成放到message_zh.properties和message_en.properties文件中,否则的话这样的翻译没有意义,后续如果要加俄语或阿拉伯语就没办法进行动态切换了
-
日志中的中文不需要做多语言,只有返回前端的数据需要做多语言
所以针对上面三点,我又对代码做了些改动,来让整个国际化更加智能。
直接上代码,代码解决了第二个和第三个问题
python
import json
import os
import re
import tempfile
import shutil
import difflib
from pydantic import BaseModel
from OpenAIClient import client
# 判断文本中是否包含中文字符(这里只检测实际内容,不包括缩进)
def has_chinese(text: str) -> bool:
return bool(re.search(r"[\u4e00-\u9fff]", text))
# 调用大语言模型进行翻译的函数
def translate_text(text: str) -> str:
return get_completion(text)
class TransResult(BaseModel):
result: str
key: str
value_zh: str
value_en: str
# gpt-4o-mini
def get_completion_eng_word(code_segment, model="gpt-4o-mini"):
# return 'return Result.error("FILE_UPLOAD_FAILED," + state.getState());'
messages = [
{
"role": "system",
"content": (
"你是一个专业的代码国际化助手。请将代码中所有的中文提示信息翻译成英文。翻译后的英文应该简短、准确,并且遵循以下规则:"
"1. 使用单个英文单词来表示中文内容,如果一个中文句子由多个词组成,请用下划线连接多个单词。"
"2. 所有被翻译的英文单词应全部用小写。未翻译的单词保持原状"
"3. 请确保替换后的翻译尽量简洁,避免过长的英文描述。"
"4. 保持代码结构和格式不变,仅替换中文字符串内容。不改变代码的其它部分。"
'5. 如果输入的代码中字符串中需要拼接变量的,类似 return Result.succeed("导入数据成功,一共【"+rowNum+"】行"); ,需要把变量提取出来,当成参数传入,输出应为:''
'{"result":"return Result.succeed("import_data_success_count", rowNum);", "key":"import_data_success_count", "value_zh":"导入数据成功,一共【"+rowNum+"】行", "value_en":"The data import is successful, and there are a total of ["+rowNum+"] rows"}'
"6. 输出的内容为一个json结构, 包含result,为翻译之后完整的结果(结果中可能有双引号需要做转义),key为翻译出来的以下划线连接的那个单词, value_zh为原来的中文,value_en为原来的中文直接翻译的英文的句子"
"例如:"
"请翻译以下代码:"
'@NotEmpty(message = "前置经纬度不能为空")'
"输出应为:"
'{"result":"@NotEmpty(message = "pre_points_is_empty")", "key":"pre_points_is_empty", "value_zh":"前置经纬度不能为空", "value_en":"pre points is empty"}'
"请翻译以下代码:"
'throw new BusinessException("获取分布式锁失败,请稍后再试");'
"输出应为:"
""
'{"result":"throw new BusinessException("get_lock_error");", "key":"get_lock_error", "value_zh":"获取分布式锁失败,请稍后再试", "value_en":"Failed to obtain distributed locks, please try again later"}'
),
},
{"role": "user", "content": f"请翻译以下代码:\n{code_segment}"},
]
response1 = client.beta.chat.completions.parse(
model=model,
messages=messages,
temperature=0,
response_format=TransResult,
)
return response1.choices[0].message.parsed
def get_completion(code_segment, model="gpt-4o-mini"):
messages = [
{
"role": "system",
"content": (
"你是一个专业的代码翻译助手。请将代码中的中文文本翻译成英文,"
"保持代码结构和格式不变,仅替换字符串内容。保持变量名和函数名不变。"
"你只需要输出翻译之后的内容,不需要添加额外的其它的内容,"
"输出与输入除了翻译的内容变化,其它应该完全保持完全一致,不要输出markdown的格式。"
),
},
{"role": "user", "content": f"请翻译以下代码:\n{code_segment}"},
]
response1 = client.chat.completions.create(
model=model,
messages=messages,
temperature=0,
)
return response1.choices[0].message.content
# 定义全局数组来存储翻译结果
translated_values_zh = []
translated_values_en = []
# 处理单个文件:逐行读取,遇到中文的行进行翻译替换,同时保留原有缩进
def process_file(
file_path: str, max_line_length: int = 2000, special_keywords: list = None
) -> None:
temp_file = tempfile.NamedTemporaryFile(mode="w", delete=False, encoding="utf-8")
try:
with open(file_path, "r", encoding="utf-8") as f:
for line in f:
# 提取行的前导缩进和实际内容(去除换行符)
indent_match = re.match(r"^(\s*)", line)
indent = indent_match.group(1) if indent_match else ""
content = line[len(indent) :].rstrip("\n")
if has_chinese(content):
# 如果content中包含Result或包含@NotNull,或包含@Size或包含@NotEmpty,则用另一种方式进行翻译
if any(keyword in content for keyword in special_keywords):
translated_json = get_completion_eng_word(content)
# 提取result, key, value_zh, value_en
translated_line = translated_json.result
key = translated_json.key
value_zh = translated_json.value_zh
value_en = translated_json.value_en
translated_line = "\n".join(
indent + part for part in translated_line.splitlines()
)
line = translated_line + "\n"
print(
f"Processed: {file_path}, zh: {key} = {value_zh}, en: {key} = {value_en}"
)
translated_values_zh.append(f"{key}={value_zh}")
translated_values_en.append(f"{key}={value_en}")
else:
translated_line = translate_text(content)
# 保留每一行的缩进
translated_line = "\n".join(
indent + part for part in translated_line.splitlines()
)
line = translated_line + "\n"
temp_file.write(line)
temp_file.close()
shutil.move(temp_file.name, file_path)
except Exception as e:
print(f"Error processing {file_path}: {e}")
if os.path.exists(temp_file.name):
os.remove(temp_file.name)
# 遍历目录,对指定后缀的文件进行处理
def process_directory(
root_dir: str,
file_extensions: list,
special_keywords: list = None,
max_line_length: int = 2000,
) -> None:
for subdir, _, files in os.walk(root_dir):
for file in files:
if any(file.endswith(ext) for ext in file_extensions):
file_path = os.path.join(subdir, file)
process_file(file_path, max_line_length, special_keywords)
if __name__ == "__main__":
root_directory = "D:\\XX\\xxx\\"
special_keywords = [
"Result.",
"@NotNull",
"@Size",
"@NotEmpty",
"@NotBlank",
"@Pattern",
"@Min",
"@Max",
"Exception",
"Assert.",
]
extensions = [".java"]
process_directory(root_directory, extensions, special_keywords)
# 输出翻译结果到 .properties 文件
with open(
"messages_zh.properties",
"w",
encoding="utf-8",
) as f_zh, open(
"messages_en.properties",
"w",
encoding="utf-8",
) as f_en:
# 写入中文翻译结果
for value in translated_values_zh:
f_zh.write(value + "\n")
# 写入英文翻译结果
for value in translated_values_en:
f_en.write(value + "\n")
print(
"翻译结果已写入 translated_values_zh.properties 和 translated_values_en.properties 文件。"
)
这里使用了 pydantic对输出的结果进行格式化为了json,相比上一篇的直接输出翻译后的结果优势是:可以让大模型同时提取其中的key和value_zh和value_en,这样可以直接把这两个结果写入properties配置文件,省去了自己生成properties文件的过程。
针对日志和注释不需要做多语言的,直接通过另一个propmt将中文全部翻译成英文即可。
再来看问题1,不知道怎么调api,非常简单
python
from openai import OpenAI
openai_api_key = "sk-xxxxxxxxxxxxxxxxxx"
openai_api_base = "https://api.gptsapi.net/v1"
client = OpenAI(
api_key=openai_api_key,
base_url=openai_api_base,
)
因为openai需要翻墙到国外,所以我买了国内的代理的api,非常便宜,先冲5刀,一共也就一顿饭钱。我翻译了一整个项目才花了1.5刀,真是便宜哇。下面是我调用的记录,真是很省钱哇。
有了这个便宜的api我感觉我可以干好多事了,后续我也会用这个api来做各种智能化的应用,欢迎关注我。另外,我这边也同步开通了哔站,录了一些视频来更加透彻的带大家来一起学习AI,让AI成为我们最忠实的硅基家人。
哔站主页