2121from pathlib import Path
2222from typing import Any
2323
24- # Ensure project root is on path
2524ROOT_DIR = Path (__file__ ).resolve ().parent .parent
2625sys .path .insert (0 , str (ROOT_DIR ))
2726
@@ -63,7 +62,6 @@ def scan_module_files() -> dict[str, tuple[Path, str]]:
6362 """
6463 var_to_file : dict [str , tuple [Path , str ]] = {}
6564
66- # 匹配变量赋值的正则表达式,例如:variable_name = {
6765 var_pattern = re .compile (r"^([a-z_][a-z0-9_]*)\s*=\s*\{" , re .MULTILINE )
6866
6967 for py_file in LANGUAGE_MODULES_DIR .glob ("*.py" ):
@@ -74,8 +72,6 @@ def scan_module_files() -> dict[str, tuple[Path, str]]:
7472 content = py_file .read_text (encoding = "utf-8" )
7573 for match in var_pattern .finditer (content ):
7674 var_name = match .group (1 )
77- # 检查这是否看起来像语言字典(包含"ZH_CN")
78- # 查找字典内容
7975 start = match .end () - 1
8076 if '"ZH_CN"' in content [start : start + 500 ]:
8177 var_to_file [var_name ] = (py_file , var_name )
@@ -101,13 +97,11 @@ def group_by_module(entries: list[dict[str, Any]]) -> dict[str, dict[str, str]]:
10197 if not identifier or not translation :
10298 continue
10399
104- # Split identifier: "basic_settings.title.name" -> ["basic_settings", "title", "name"]
105100 parts = identifier .split ("." )
106101 if len (parts ) < 2 :
107102 continue
108103
109104 module_name = parts [0 ]
110- # The rest is the key path within the module
111105 key_path = "." .join (parts [1 :])
112106
113107 if module_name not in modules :
@@ -131,11 +125,9 @@ def set_nested_value(d: dict, key_path: str, value: Any) -> None:
131125 if key not in current :
132126 current [key ] = {}
133127 elif not isinstance (current [key ], dict ):
134- # If current value is not a dict, we need to convert it
135128 current [key ] = {}
136129 current = current [key ]
137130
138- # Set the final value
139131 final_key = keys [- 1 ]
140132 current [final_key ] = value
141133
@@ -169,7 +161,6 @@ def format_dict_as_python(d: dict, indent: int = 0) -> str:
169161 nested = format_dict_as_python (value , indent + 1 )
170162 lines .append (f'{ inner_prefix } "{ key } ": { nested } { comma } ' )
171163 elif isinstance (value , str ):
172- # Escape backslashes, quotes, and newlines in strings
173164 escaped = (
174165 value .replace ("\\ " , "\\ \\ " )
175166 .replace ('"' , '\\ "' )
@@ -206,12 +197,9 @@ def update_module_file(
206197
207198 content = module_path .read_text (encoding = "utf-8" )
208199
209- # 构建该语言的嵌套字典
210200 lang_dict = build_language_dict (translations )
211201
212202 # 检查模块中是否已存在该语言
213- # 查找变量字典定义的正则表达式
214- # 例如:"basic_settings = {"
215203 dict_pattern = rf"^{ re .escape (var_name )} \s*=\s*\{{"
216204 match = re .search (dict_pattern , content , re .MULTILINE )
217205
@@ -225,34 +213,15 @@ def update_module_file(
225213 print (
226214 f" 语言 '{ language_code } ' 已存在于 { module_path .name } :{ var_name } 中,跳过..."
227215 )
228- # 目前,我们将跳过更新现有条目以避免复杂性
229- # 更复杂的方法是解析并合并
230- # 为了安全起见,我们只在不存在时添加
231216 return False
232217
233- # 查找插入新语言的位置
234- # 我们将在 "ZH_CN": {...} 之后插入(如果存在)
235- # 策略:找到主字典的结束位置并在其之前插入
236-
237- # 解析文件以找到插入位置
238- # 简单方法:找到关闭模块字典的最后一个 "}"
239-
240- # 查找所有语言条目及其位置
241- # 模式:"LANG_CODE": {
242218 lang_entries = list (re .finditer (r'"([A-Z_]+)":\s*\{' , content ))
243219
244220 if not lang_entries :
245221 print (f"警告:在 { module_path .name } 中未找到语言条目" )
246222 return False
247223
248- # 查找最后一个语言条目的结束位置
249- # 由于嵌套大括号的存在,这很棘手,所以我们使用不同的方法:
250- # 在字典末尾、最后一个 } 之前插入新的语言条目
251-
252- # 查找模块字典定义的开始位置
253- dict_start = match .end () - 1 # 左大括号的位置
254-
255- # 计算大括号数量以找到匹配的右大括号
224+ dict_start = match .end () - 1
256225 brace_count = 0
257226 dict_end = - 1
258227 in_string = False
@@ -282,26 +251,19 @@ def update_module_file(
282251 print (f" 警告:在 { module_path .name } 中找不到 { var_name } 的右大括号" )
283252 return False
284253
285- # 格式化新的语言条目
286254 formatted_dict = format_dict_as_python (lang_dict , indent = 1 )
287255 new_entry = f' "{ language_code } ": { formatted_dict } ,\n '
288256
289- # 检查右大括号前是否有尾随逗号
290- # 从dict_end向前查找最后一个非空白字符
291257 before_close = content [dict_start :dict_end ]
292258 last_non_ws_idx = len (before_close ) - 1
293259 while last_non_ws_idx >= 0 and before_close [last_non_ws_idx ] in " \t \n \r " :
294260 last_non_ws_idx -= 1
295261
296- # 如果最后一个非空白字符不是逗号,我们需要添加一个
297262 if last_non_ws_idx >= 0 and before_close [last_non_ws_idx ] != "," :
298- # 在最后一个非空白字符后插入逗号
299263 insert_comma_pos = dict_start + last_non_ws_idx + 1
300264 content = content [:insert_comma_pos ] + "," + content [insert_comma_pos :]
301- # 调整dict_end,因为我们添加了一个字符
302265 dict_end += 1
303266
304- # 在字典末尾、右大括号之前插入新的语言
305267 new_content = content [:dict_end ] + new_entry + content [dict_end :]
306268
307269 if dry_run :
@@ -324,44 +286,37 @@ def main() -> None:
324286 print (f"错误:文件未找到:{ crowdin_file } " )
325287 sys .exit (1 )
326288
327- # 从文件名中提取语言代码
328289 language_code = extract_language_code (crowdin_file .name )
329290 print (f"正在导入语言:{ language_code } " )
330291 print (f"源文件:{ crowdin_file } " )
331292 print (f"目标目录:{ LANGUAGE_MODULES_DIR } " )
332293 print ()
333294
334- # 扫描模块文件以查找实际变量名
335295 print ("正在扫描模块文件..." )
336296 var_to_file = scan_module_files ()
337297 print (
338298 f"找到 { len (var_to_file )} 个语言变量:{ ', ' .join (sorted (var_to_file .keys ()))} "
339299 )
340300 print ()
341301
342- # 加载Crowdin数据
343302 entries = load_crowdin_json (crowdin_file )
344303 print (f"已加载 { len (entries )} 个翻译条目" )
345304
346- # 按模块(标识符前缀)分组
347305 modules = group_by_module (entries )
348306 print (f"在Crowdin文件中找到 { len (modules )} 个标识符前缀" )
349307 print ()
350308
351- # 将Crowdin模块与实际变量名匹配
352309 updated_count = 0
353310 unmatched_modules = []
354311
355312 for module_name , translations in sorted (modules .items ()):
356- # 首先,尝试通过精确变量名匹配
357313 if module_name in var_to_file :
358314 file_path , var_name = var_to_file [module_name ]
359315 if update_module_file (
360316 file_path , var_name , language_code , translations , args .dry_run
361317 ):
362318 updated_count += 1
363319 else :
364- # 模块未在任何文件中找到
365320 unmatched_modules .append (module_name )
366321
367322 print ()
0 commit comments