scan.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import ast
  2. import glob
  3. import json
  4. from collections import OrderedDict
  5. from pathlib import Path
  6. from loguru import logger
  7. from .core import DEFAULT_LANGUAGE, I18N_FILE_PATH
  8. def extract_i18n_strings(node):
  9. i18n_strings = []
  10. if (
  11. isinstance(node, ast.Call)
  12. and isinstance(node.func, ast.Name)
  13. and node.func.id == "i18n"
  14. ):
  15. for arg in node.args:
  16. if isinstance(arg, ast.Str):
  17. i18n_strings.append(arg.s)
  18. for child_node in ast.iter_child_nodes(node):
  19. i18n_strings.extend(extract_i18n_strings(child_node))
  20. return i18n_strings
  21. # scan the directory for all .py files (recursively)
  22. # for each file, parse the code into an AST
  23. # for each AST, extract the i18n strings
  24. strings = []
  25. folders = ["fish_speech", "tools"]
  26. # for filename in glob.iglob("**/*.py", recursive=True):
  27. for folder in folders:
  28. for f in Path(folder).rglob("*.py"):
  29. code = f.read_text(encoding="utf-8")
  30. if "i18n(" in code:
  31. tree = ast.parse(code)
  32. i18n_strings = extract_i18n_strings(tree)
  33. logger.info(f"Found {len(i18n_strings)} i18n strings in {f}")
  34. strings.extend(i18n_strings)
  35. code_keys = set(strings)
  36. logger.info(f"Total unique: {len(code_keys)}")
  37. standard_file = I18N_FILE_PATH / f"{DEFAULT_LANGUAGE}.json"
  38. with open(standard_file, "r", encoding="utf-8") as f:
  39. standard_data = json.load(f, object_pairs_hook=OrderedDict)
  40. standard_keys = set(standard_data.keys())
  41. # Define the standard file name
  42. unused_keys = standard_keys - code_keys
  43. logger.info(f"Found {len(unused_keys)} unused keys in {standard_file}")
  44. for unused_key in unused_keys:
  45. logger.info(f"\t{unused_key}")
  46. missing_keys = code_keys - standard_keys
  47. logger.info(f"Found {len(missing_keys)} missing keys in {standard_file}")
  48. for missing_key in missing_keys:
  49. logger.info(f"\t{missing_key}")
  50. code_keys_dict = OrderedDict()
  51. for s in strings:
  52. code_keys_dict[s] = s
  53. # write back
  54. with open(standard_file, "w", encoding="utf-8") as f:
  55. json.dump(code_keys_dict, f, ensure_ascii=False, indent=4, sort_keys=True)
  56. f.write("\n")
  57. logger.info(f"Updated {standard_file}")
  58. # Define the standard file name
  59. standard_file = I18N_FILE_PATH / f"{DEFAULT_LANGUAGE}.json"
  60. # Find all JSON files in the directory
  61. dir_path = I18N_FILE_PATH
  62. languages = [f for f in dir_path.glob("*.json") if f.stem != DEFAULT_LANGUAGE]
  63. # Load the standard file
  64. with open(standard_file, "r", encoding="utf-8") as f:
  65. standard_data = json.load(f, object_pairs_hook=OrderedDict)
  66. # Loop through each language file
  67. for lang_file in languages:
  68. # Load the language file
  69. with open(lang_file, "r", encoding="utf-8") as f:
  70. lang_data = json.load(f, object_pairs_hook=OrderedDict)
  71. # Find the difference between the language file and the standard file
  72. diff = set(standard_data.keys()) - set(lang_data.keys())
  73. miss = set(lang_data.keys()) - set(standard_data.keys())
  74. # Add any missing keys to the language file
  75. for key in diff:
  76. lang_data[key] = "#!" + key
  77. logger.info(f"Added missing key: {key} to {lang_file}")
  78. # Del any extra keys to the language file
  79. for key in miss:
  80. del lang_data[key]
  81. logger.info(f"Del extra key: {key} from {lang_file}")
  82. # Sort the keys of the language file to match the order of the standard file
  83. lang_data = OrderedDict(
  84. sorted(lang_data.items(), key=lambda x: list(standard_data.keys()).index(x[0]))
  85. )
  86. # Save the updated language file
  87. with open(lang_file, "w", encoding="utf-8") as f:
  88. json.dump(lang_data, f, ensure_ascii=False, indent=4, sort_keys=True)
  89. f.write("\n")
  90. logger.info(f"Updated {lang_file}")
  91. logger.info("Done")