通过python脚本判断两个多语言properties的差异,并生成缺失的文件
前言
在做多语言开发的时候,因为key值较多,可能会有遗漏的情况。通过python脚本查找确实的key值,并生成对应的csv文件,方便校验和补充缺失的值。
代码
import os
from datetime import datetimedef read_properties_keys_and_lines(file_path):"""读取properties文件中的所有key及其对应的完整行,忽略空行和注释行:param file_path: properties文件路径:return: 包含所有key的集合和key到完整行的映射字典"""keys = set()key_to_line = {}if not os.path.exists(file_path):print(f"警告: 文件 {file_path} 不存在")return keys, key_to_linetry:with open(file_path, 'r', encoding='utf-8') as f:line_count = 0valid_line_count = 0for line in f:line_count += 1# 去除行首行尾的空白字符stripped_line = line.strip()# 忽略空行和以#开头的注释行if not stripped_line or stripped_line.startswith('#'):continuevalid_line_count += 1# 分割key和valueif '=' in stripped_line:key = stripped_line.split('=', 1)[0].strip()keys.add(key)key_to_line[key] = line.rstrip('\n')print(f"从文件 {file_path} 中读取了 {len(keys)} 个key (共{line_count}行,有效行{valid_line_count}行)")except UnicodeDecodeError:# 尝试使用其他编码读取文件try:with open(file_path, 'r', encoding='latin-1') as f:for line in f:stripped_line = line.strip()if not stripped_line or stripped_line.startswith('#'):continueif '=' in stripped_line:key = stripped_line.split('=', 1)[0].strip()keys.add(key)key_to_line[key] = line.rstrip('\n')print(f"从文件 {file_path} 中读取了 {len(keys)} 个key (使用latin-1编码)")except Exception as e:print(f"读取文件 {file_path} 时出错: {e}")except Exception as e:print(f"读取文件 {file_path} 时出错: {e}")return keys, key_to_linedef check_missing_keys_and_lines(source_file, target_file):"""检查在source_file中有但在target_file中没有的key及其对应的完整行:param source_file: 源文件路径:param target_file: 目标文件路径:return: 缺失的key集合和key到完整行的映射字典"""# 读取两个文件的key集合和key到行的映射source_keys, source_key_to_line = read_properties_keys_and_lines(source_file)target_keys, target_key_to_line = read_properties_keys_and_lines(target_file)# 找出在source_keys中但不在target_keys中的keymissing_keys = source_keys - target_keys# 构建缺失key到完整行的映射missing_key_to_line = {key: source_key_to_line[key] for key in missing_keys}# 添加调试信息print(f"源文件中key数量: {len(source_keys)}")print(f"目标文件中key数量: {len(target_keys)}")print(f"共同拥有的key数量: {len(source_keys & target_keys)}")print(f"缺失的key数量: {len(missing_keys)}")# 随机选取几个key进行验证(如果有缺失的key)if len(missing_keys) > 0:# 检查是否存在一些可能被误判的情况sample_size = min(5, len(missing_keys))sample_keys = list(missing_keys)[:sample_size]print(f"\n随机选取{sample_size}个被标记为缺失的key进行验证:")for key in sample_keys:# 检查是否因为大小写或空格问题导致误判similar_keys = [t_key for t_key in target_keys if key.lower() == t_key.lower()]if similar_keys:print(f" - '{key}' 可能是大小写或空格问题,目标文件中有类似的key: {similar_keys}")else:print(f" - '{key}' 在目标文件中确实不存在")return missing_keys, missing_key_to_linedef main():projectName ='part-eu'# 定义文件路径 - 使用双反斜杠确保正确解析i18n_file = f'D:\\work\\src\\{projectName}\\{projectName}-boot\\src\\main\\resources\\i18n.properties'es_file = f'D:\\work\\src\\{projectName}\\{projectName}-boot\\src\\main\\resources\\i18n_fr_FR.properties'lack_file = f'D:\\work\\src\\{projectName}\\{projectName}-boot\\src\\main\\resources\\i18n-lack.properties'print(f"正在校验资源文件: {i18n_file} 和 {es_file}")# 读取源文件和目标文件的keysource_keys, source_key_to_line = read_properties_keys_and_lines(i18n_file)target_keys, _ = read_properties_keys_and_lines(es_file)# 检查缺失的key及其对应的完整行missing_keys = source_keys - target_keysmissing_key_to_line = {key: source_key_to_line[key] for key in missing_keys}# 添加统计信息print(f"源文件中key数量: {len(source_keys)}")print(f"目标文件中key数量: {len(target_keys)}")print(f"共同拥有的key数量: {len(source_keys & target_keys)}")print(f"缺失的key数量: {len(missing_keys)}")# 随机选取几个key进行验证(如果有缺失的key)if len(missing_keys) > 0:# 检查是否存在一些可能被误判的情况sample_size = min(5, len(missing_keys))sample_keys = list(missing_keys)[:sample_size]print(f"\n随机选取{sample_size}个被标记为缺失的key进行验证:")for key in sample_keys:# 检查是否因为大小写或空格问题导致误判similar_keys = [t_key for t_key in target_keys if key.lower() == t_key.lower()]if similar_keys:print(f" - '{key}' 可能是大小写或空格问题,目标文件中有类似的key: {similar_keys}")else:print(f" - '{key}' 在目标文件中确实不存在")# 输出结果if missing_keys:print(f"在 {i18n_file} 中有但在 {es_file} 中没有的key ({len(missing_keys)}个):")print("=" * 80)for key in sorted(missing_keys):print(f"{missing_key_to_line[key]}")print("=" * 80)print(f"总计缺失 {len(missing_keys)} 个key")# 将缺失的key保存到新文件try:# 确保目标目录存在os.makedirs(os.path.dirname(lack_file), exist_ok=True)with open(lack_file, 'w', encoding='utf-8') as f:# 按顺序写入缺失的key及其行for key in sorted(missing_keys):f.write(f"{missing_key_to_line[key]}\n")print(f"已成功将缺失的key保存到文件: {lack_file}")except Exception as e:print(f"保存缺失的key到文件 {lack_file} 时出错: {e}")print(f"错误详情: {str(e)}")else:print(f"很好! {i18n_file} 中的所有key都在 {es_file} 中找到了")# 如果没有缺失的key,删除lack_file(如果存在)if os.path.exists(lack_file):try:os.remove(lack_file)print(f"已删除多余的文件: {lack_file}")except Exception as e:print(f"删除文件 {lack_file} 时出错: {e}")if __name__ == "__main__":main()解释
通过下面这里配置项目路径和对比的源文件,目标文件,以及生成的缺失文件
projectName ='part-eu'# 定义文件路径 - 使用双反斜杠确保正确解析i18n_file = f'D:\\work\\src\\{projectName}\\{projectName}-boot\\src\\main\\resources\\i18n.properties'es_file = f'D:\\work\\src\\{projectName}\\{projectName}-boot\\src\\main\\resources\\i18n_fr_FR.properties'lack_file = f'D:\\work\\src\\{projectName}\\{projectName}-boot\\src\\main\\resources\\i18n-lack.properties'