common.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. '''
  2. Author: deng.yinping deng.yinping@muchinfo.cn
  3. Date: 2024-12-06 10:22:52
  4. LastEditors: deng.yinping deng.yinping@muchinfo.cn
  5. LastEditTime: 2025-03-07 16:16:35
  6. FilePath: \MTP20_WEB_GLOBAL_i18n_Tool\common.py
  7. Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  8. '''
  9. import json
  10. import pandas as pd
  11. from openpyxl import load_workbook
  12. from openpyxl.styles import PatternFill
  13. import os
  14. class CommonUti:
  15. @staticmethod
  16. def read_from_json(file_path):
  17. # 从JSON文件中读取内容
  18. with open(file_path, 'r', encoding='utf-8') as file:
  19. data = json.load(file)
  20. return data
  21. @staticmethod
  22. def get_leaf_paths(data, path="", result=None):
  23. # 递归函数,遍历所有终节点并将全路径和值存入字典
  24. # 不需要翻译的Key
  25. ignore_data = ['app.name', 'mine.setting.chinese',
  26. 'mine.setting.english', 'mine.setting.enth', 'app.left1', 'app.left2']
  27. if result is None:
  28. result = {}
  29. if isinstance(data, dict):
  30. # 如果是字典,继续遍历字典中的每个键
  31. for key, value in data.items():
  32. current_path = f"{path}.{key}" if path else key
  33. CommonUti.get_leaf_paths(value, current_path, result)
  34. elif isinstance(data, list):
  35. # 如果是列表,遍历每个元素
  36. for index, item in enumerate(data):
  37. current_path = f"{path}[{index}]"
  38. CommonUti.get_leaf_paths(item, current_path, result)
  39. else:
  40. # 如果是终节点,将当前路径和值保存到字典中
  41. if path not in ignore_data:
  42. result[path] = data
  43. return result
  44. @staticmethod
  45. def generate_dict_from_json(file_path):
  46. data = CommonUti.read_from_json(file_path)
  47. # 生成全路径的字典
  48. leaf_paths_dict = CommonUti.get_leaf_paths(data)
  49. return leaf_paths_dict
  50. @staticmethod
  51. def generate_excle_by_oem(oem, output_folder, zh_data, en_data, th_data, tw_data, vi_data):
  52. df = pd.DataFrame.from_dict(zh_data, orient='index', columns=['zh-CN'])
  53. # 将 其它 的值合并到 DataFrame 中
  54. df['en-US'] = df.index.map(en_data).fillna('')
  55. df['th-TH'] = df.index.map(th_data).fillna('')
  56. df['zh-TW'] = df.index.map(tw_data).fillna('')
  57. df['vi-VN'] = df.index.map(vi_data).fillna('')
  58. # 重置索引,以便将索引变为一列
  59. df.reset_index(inplace=True)
  60. df.rename(columns={'index': 'Key'}, inplace=True) # 将索引列重命名为 'Key'
  61. # 导出到 Excel 文件
  62. output_file = output_folder + '/excels/' + oem + '.xlsx'
  63. df.to_excel(output_file, index=False)
  64. # 使用 openpyxl 设置列宽
  65. wb = load_workbook(output_file)
  66. ws = wb.active
  67. # 指定列宽
  68. ws.column_dimensions['A'].width = 40 # 设置第一列宽度 KEY
  69. ws.column_dimensions['B'].width = 40 # 设置第二列宽度 中文
  70. ws.column_dimensions['C'].width = 40 # 设置第三列宽度 英文
  71. ws.column_dimensions['D'].width = 40 # 设置第四列宽度 泰文
  72. ws.column_dimensions['E'].width = 40 # 设置第五列宽度 繁体
  73. ws.column_dimensions['F'].width = 40 # 设置第六列宽度 越南语
  74. # 保存更改
  75. wb.save(output_file)
  76. print("Excel已成功输出到 " + output_file)
  77. @staticmethod
  78. def update_excel_by_inc(oem, output_folder, inc_name):
  79. ''' 增量更新,在生成excel里标注新增的key为黄色 '''
  80. # 读取输出的Excel文件, 格式:key(A) zh-CN(B) en-US(C) th-TH(D) zh-TW(E) vi-VN(F)
  81. inc_file = output_folder + "/excels/" + inc_name + ".xlsx"
  82. if not os.path.exists(inc_file):
  83. return
  84. df = pd.read_excel(inc_file)
  85. # 将 A 列和 C 列转换为zh-CN字典
  86. old_dic = dict(zip(df.iloc[:, 0], df.iloc[:, 1]))
  87. new_file = output_folder + "/excels/" + oem + ".xlsx"
  88. wb = load_workbook(new_file)
  89. sheet = wb.active
  90. # 定义黄色填充样式
  91. yellow_fill = PatternFill(
  92. start_color="FFFF00", end_color="FFFF00", fill_type="solid")
  93. # 遍历第一列
  94. for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row, min_col=1, max_col=1):
  95. cell = row[0]
  96. if cell.value not in old_dic:
  97. cell.fill = yellow_fill
  98. # 保存文件
  99. update_file = output_folder + "/excels/" + oem + "_inc.xlsx"
  100. wb.save(update_file) # 保存为新文件,避免覆盖原文件
  101. print("增量Excel已成功输出到 " + update_file)
  102. @staticmethod
  103. def generate_excle(oem, output_folder, json_folder, oem_json_folder):
  104. # 据JSON生成excel文件
  105. zh_data = CommonUti.read_data_from_json(
  106. oem, json_folder, oem_json_folder, 'zh-CN')
  107. en_data = CommonUti.read_data_from_json(
  108. oem, json_folder, oem_json_folder, 'en-US')
  109. th_data = CommonUti.read_data_from_json(
  110. oem, json_folder, oem_json_folder, 'th-TH')
  111. tw_data = CommonUti.read_data_from_json(
  112. oem, json_folder, oem_json_folder, 'zh-TW')
  113. vi_data = CommonUti.read_data_from_json(
  114. oem, json_folder, oem_json_folder, 'vi-VN')
  115. CommonUti.generate_excle_by_oem(
  116. oem, output_folder, zh_data, en_data, th_data, tw_data, vi_data)
  117. @staticmethod
  118. def read_data_from_json(oem, json_folder, oem_json_folder, lang):
  119. common_file = json_folder + lang + '.json'
  120. common_data = CommonUti.generate_dict_from_json(common_file)
  121. # 处理OEM数据
  122. oem_file = oem_json_folder + oem + '/locales/extras/' + lang + '.json'
  123. if os.path.exists(oem_file):
  124. oem_data = CommonUti.generate_dict_from_json(oem_file)
  125. if oem_data:
  126. for key, value in oem_data.items():
  127. # 更新通用字典的oem个性化值(有则更新,无则添加)
  128. common_data[key] = value
  129. return common_data
  130. @staticmethod
  131. def read_from_excel(oem, output_folder):
  132. # 读取输出的Excel文件, 格式:key(A) zh-CN(B) en-US(C) th-TH(C) zh-TW(D)
  133. excel_filename = output_folder + "/excels/" + oem + ".xlsx"
  134. df = pd.read_excel(excel_filename)
  135. # 将 A 列和 C 列转换为zh-CN字典
  136. dict_cn = dict(zip(df.iloc[:, 0], df.iloc[:, 1]))
  137. # 将 A 列和 C 列转换为en-US字典
  138. dict_en = dict(zip(df.iloc[:, 0], df.iloc[:, 2]))
  139. # 将 A 列和 D 列转换为th-TH字典
  140. dict_th = dict(zip(df.iloc[:, 0], df.iloc[:, 3]))
  141. # 将 A 列和 E 列转换为zh-TW字典
  142. dict_tw = dict(zip(df.iloc[:, 0], df.iloc[:, 4]))
  143. # 将 A 列和 F 列转换为vi-VN字典
  144. dict_vi = dict(zip(df.iloc[:, 0], df.iloc[:, 5]))
  145. return dict_cn, dict_en, dict_th, dict_tw, dict_vi
  146. @staticmethod
  147. def modify_json_values(data, modify_func, path="", extra_data=None, exclude_data=None):
  148. if isinstance(data, dict): # 如果是字典类型,遍历键值对
  149. for key, value in data.items():
  150. new_path = f"{path}.{key}" if path else key # 更新路径
  151. if isinstance(value, (dict, list)): # 如果值是字典或列表,递归调用
  152. CommonUti.modify_json_values(value, modify_func,
  153. new_path, extra_data, exclude_data)
  154. else:
  155. # 对终节点进行修改,传递完整路径和辅助字典
  156. data[key] = modify_func(
  157. value, new_path, extra_data, exclude_data)
  158. elif isinstance(data, list): # 如果是列表类型,遍历列表中的每个元素
  159. for index, item in enumerate(data):
  160. new_path = f"{path}[{index}]" # 更新路径为列表的索引
  161. if isinstance(item, (dict, list)):
  162. CommonUti.modify_json_values(item, modify_func,
  163. new_path, extra_data, exclude_data)
  164. else:
  165. # 修改列表中的值,并传递完整路径
  166. data[index] = modify_func(item, new_path, extra_data)
  167. @staticmethod
  168. def modify_func(value, path, extra_data, exclude_data):
  169. # 修改函数,基于额外字典的内容修改值
  170. if extra_data and path in extra_data:
  171. # exclude_data 为空 或是path不在exclude_data
  172. if (exclude_data is None) or (exclude_data and path not in exclude_data):
  173. new_value = extra_data[path].strip().replace('\r\n', '\n')
  174. return new_value.replace('\n', '\r\n') # 从 extra_data 中取出新值
  175. return value # 如果路径不在 extra_data 中,保持原值
  176. @staticmethod
  177. def save_to_json(path, data):
  178. # 创建目录(如果不存在)
  179. directory = os.path.dirname(path) # 获取文件路径的目录部分
  180. if not os.path.exists(directory):
  181. os.makedirs(directory) # 创建目录
  182. # 将修改后的字典保存为 .json 文件
  183. with open(path, 'w', encoding='utf-8') as json_file:
  184. json.dump(data, json_file, ensure_ascii=False, indent=4)
  185. @staticmethod
  186. def generate_json(oem, excel_dic, lang, output_folder, json_folder, oem_json_folder):
  187. # OEM的Lang文件
  188. oem_input = oem_json_folder + oem + '/locales/extras/' + lang + '.json'
  189. # OEM输出文件地址
  190. oem_output = output_folder + '/jsons/' + oem + '/' + lang + '.json'
  191. oem_dic = None
  192. if os.path.exists(oem_input):
  193. # 读取OEM的JSON文件
  194. oem_data = CommonUti.read_from_json(oem_input)
  195. # 更新 common_data
  196. CommonUti.modify_json_values(
  197. oem_data, CommonUti.modify_func, extra_data=excel_dic)
  198. # 另存为OEM的json文件
  199. CommonUti.save_to_json(oem_output, oem_data)
  200. # 通用JSON:oem中存在的Key,则不更新common的值
  201. oem_dic = CommonUti.generate_dict_from_json(oem_input)
  202. print("OEM %s JSON文件已成功输出到 %s" % (lang, oem_output))
  203. # 通用的Lang文件
  204. common_input = json_folder + lang + '.json'
  205. # 输出文件地址
  206. common_output = output_folder + '/jsons/' + lang + '.json'
  207. # 读取JSON文件
  208. common_data = CommonUti.read_from_json(common_input)
  209. # 更新 common_data
  210. CommonUti.modify_json_values(common_data, CommonUti.modify_func,
  211. extra_data=excel_dic, exclude_data=oem_dic)
  212. # 另存为json文件
  213. CommonUti.save_to_json(common_output, common_data)
  214. print("%s JSON文件已成功输出到 %s" % (lang, common_output))