From f36d91742828f6e5b60531f70306f0addfc98091 Mon Sep 17 00:00:00 2001 From: haojun0823 Date: Wed, 26 Aug 2026 20:16:21 +0800 Subject: [PATCH 1/2] 2026-08-26: Added new Chinese translation. --- loc/CN/strings_db.lua | 335 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 334 insertions(+), 1 deletion(-) diff --git a/loc/CN/strings_db.lua b/loc/CN/strings_db.lua index 68f47df04b..950b50c59f 100644 --- a/loc/CN/strings_db.lua +++ b/loc/CN/strings_db.lua @@ -8973,4 +8973,337 @@ lobui_0803="提供一个选项,用于取消游戏的评级。请注意,即 lobui_0804="否" lobui_0805="如果满足评级游戏的所有标准,则该游戏将被评级。" lobui_0806="是" -lobui_0807="该游戏不会被评级。" \ No newline at end of file +lobui_0807="该游戏不会被评级。" + +-- 2026-08-26 updated + +AutoLobbyConnectionsTextPlural = "%s / %s 位玩家已连接" +AutoLobbyConnectionsTextPluralNoTotal = "%s 位玩家已连接" +AutoLobbyConnectionsTextSingular = "%s / %s 位玩家已连接" +AutoLobbyConnectionsTextSingularNoTotal = "%s 位玩家已连接" +AutoLobbyHeaderText = "连接状态" +ChangelogDescriptionIdentifier = "说明" +Unit_Description_0457 = "飞行无人机,可协助、修理和回收任何单位。可被命令执行 T1 建筑的建造工作。易受任何空中战斗机和防空部队的攻击。" +Unit_Description_0466_faf = "进一步增加 ACU 的射程" +_MaxTech = "最高科技" +_Obs = "仅观察" +_OnlyT1 = "仅 T1" +_Tech = "T" +ability_building = "建筑" +ability_capture = "占领" +ability_flying = "飞行" +ability_personal_teleporter = "个人传送器" +ability_scry = "预视" +ability_snipemode_prioritizes_acu = "目标优先级 - 可优先攻击 ACU" +ability_stealth_sonarfield = "声纳匿踪力场" +ability_transportable = "可运输" +ability_visionfield = "视野力场" +adaptive_jamming_2_help = "在地图上增加多个瑟拉芬干扰水晶,以制造虚假雷达信号。" +adaptive_jamming_help = "在地图上增加一个瑟拉芬干扰水晶,以制造虚假雷达信号。" +adaptive_jamming_label = "干扰" +an_CzarBeam = "沙皇光束" +an_Deathnuke = "死亡核爆" +an_ExperimentalFootfall = "实验性单位踏击" +an_FireBeetleExplosion = "火甲虫爆炸" +an_Normal = "普通" +an_OtheTacticalBomb = "阿瓦萨炸弹" +an_Overcharge = "超充能" +an_TacticalMissile = "战术飞弹" +at_ASF = "空优战斗机" +at_Commander = "指挥官" +at_Default = "默认" +at_Experimental = "实验性" +at_ExperimentalStructure = "实验性建筑" +at_Light = "轻型" +at_Normal = "普通" +at_Structure = "建筑" +at_TMD = "战术飞弹防御" +chat_engineers_received_many = "%s 向 %s 派遣了 %d 名工程师。" +chat_engineers_received_one = "%s 向 %s 派遣了一名工程师。" +chat_private_message_as_observer = "观察员无法发送私人信息。" +chat_resources_received_both = "%s 向 %s 发送了 %d 质量和 %d 能源。" +chat_resources_received_energy = "%s 向 %s 发送了 %d 能源。" +chat_resources_received_mass = "%s 向 %s 发送了 %d 质量。" +chat_send_type_description = "启用时,按回车键向盟友发送信息,按住 Shift+回车键向所有人发送。禁用时,行为相反。" +chat_send_type_title = "默认接收者:盟友" +chat_units_received_many = "%s 向 %s 派遣了 %d 个单位。" +chat_units_received_one = "%s 向 %s 派遣了一个单位。" +debug_0000 = "行 %d:" +diplomacy_0015 = "召回" +diplomacy_0016 = "是" +diplomacy_0017 = "否" +diplomacy_0018 = "准备召回" +diplomacy_0019 = "您确定要" +diplomacy_0020 = "队伍 %s 已从战场召回。" +diplomacy_0021 = "召回投票通过。" +diplomacy_0022 = "召回投票未通过。" +diplomacy_0023 = "召回中……" +diplomacy_0024 = "未准备召回" +diplomacy_0025 = "等待队友响应……" +diplomacy_0026 = "你的队友已请求你召回" +diplomacy_0027 = "您确定要从战场召回吗?" +enabled_no_mods = "未启用任何模组。" +enabled_sim_mods = "主机已启用以下模拟模组:" +enabled_ui_mods = "您已启用以下界面模组:" +fullshare_announcement = "%s 的" +key_binding_0024 = "您确定要将所有按键绑定重置为备用(FAF)预设吗?(更易上手)" +key_binding_0025 = "备用预设" +key_binding_0026 = "将所有按键绑定重置为备用(FAF)预设(更易上手)" +key_desc_0389 = "建造工厂与量子闸道 + 工程师与副指挥官" +key_desc_0390 = "建造雷达(含周边与蕾安妮之眼)+ 陆军侦察单位 + 空军侦察单位" +key_desc_0391 = "建造护盾 + 机动护盾与护盾干扰器 + 护盾艇" +key_desc_0392 = "建造战术飞弹防御与战略飞弹防御" +key_desc_0393 = "建造实验性单位 + 机动炸弹 + 导引飞弹" +key_desc_0394 = "建造声纳 + 运输机 + 两栖/悬浮坦克" +key_desc_0395 = "建造质量萃取机/制造机 + 坦克 + 轰炸机 + 护卫舰/驱逐舰/战列巡洋舰/战列舰" +key_desc_0396 = "建造匿踪力场与塞布兰 T3 声纳 + 机动匿踪力场 + 反情报艇" +key_desc_0397 = "建造发电机/仓库 + 狙击单位与忠诚者/泰坦与格林机器人/火箭机器人及轻型攻击机器人 + 炮艇" +key_desc_0398 = "循环用户模板 + 工厂建造队列模板" +key_desc_0399 = "建造工程站 + 战地工程师" +key_desc_0400 = "建造点防御与墙 + 建筑升级" +key_desc_0401 = "建造固定防空 + 空中整备设施 + 机动防空与高射炮 + 空军战斗机 + 航空母舰/巡洋舰/攻击艇" +key_desc_0402 = "建造鱼雷防御 + 鱼雷轰炸机 + 潜艇与鱼雷艇" +key_desc_0403 = "建造固定火炮 + 机动炮兵" +key_desc_0404 = "建造战术飞弹发射器与战略飞弹发射器 + 机动飞弹发射车 + 核潜艇/战列舰与导弹舰及瑟拉芬/UEF巡洋舰" +key_desc_0406 = "循环上下文模板并建造 T2 悬浮坦克 + T2 炮艇 + T2 巡洋舰" +key_desc_0407 = "选择所有轰炸机(普通)" +key_desc_0408 = "选择所有轰炸机(鱼雷)" +key_desc_quick_load = "从专用快速存档载入游戏" +keymap_category_091 = "热键建造" +keymap_category_092 = "热键建造 - 额外按键" +keymap_category_093 = "备用热键建造" +loadingtip_0036 = "撒冷级驱逐舰无法向后射击" +loadingtip_0037 = "撒冷级驱逐舰有一个切换能力,使其可以在陆地上行走" +loadingtip_0038 = "一般而言,只有在建造了钻石之后才建造救赎" +loadingtip_0039 = "执行攻击移动或巡逻命令的工程师,当你的仓库接近满时会停止回收" +loadingtip_0040 = "匿踪只让单位避开雷达,隐蔽只避开视觉——全向侦测可同时看穿两者" +loadingtip_0041 = "经验等级基于被摧毁单位的质量价值以及每个单位造成的伤害比例" +loadingtip_0042 = "要使用一次超充能摧毁一个单位,T1 单位需要 1 个能源仓库,T2 最多需要 2 个,T3 最多需要 6 个" +loadingtip_0043 = "要看见隐蔽的水下单位,你需要水下视野或全向侦测" +loadingtip_0044 = "始终持续在地图上建造可用的质量萃取机" +loadingtip_0045 = "使用战斗部队夺取质量矿床,控制地图,并反击敌人" +loadingtip_0046 = "在比赛早期使用你的 ACU 巩固质量矿床群并参与战斗" +loadingtip_0048 = "在整场游戏中持续侦察;掌握敌人情报可能是获胜的关键" +loadingtip_0049 = "当你能看到敌方基地时,注意侦察到的情况" +loadingtip_0051 = "选择正确的战斗并避免错误的战斗,在空战中尤为重要" +loadingtip_0052 = "不要拉得太近——完美的邻接和基地布局之外有更重要的事!" +loadingtip_0053 = "宏观管理几乎总是比微观管理更重要" +loadingtip_0055 = "通常尽量避免无故闲置单位,尤其在比赛早期" +loadingtip_0056 = "设置良好的快捷键可以节省时间——游戏中按 {k toggle_key_bindings} 尝试一种按键预设" +loadingtip_0057 = "专注于尽力而为,学习如何做得更好,而不是责怪他人" +loadingtip_0058 = "充分的侦察能让你了解敌人的动向并反制其策略" +loadingtip_0059 = "轰炸机对防空薄弱且没有空中支援的部队非常有效" +loadingtip_0060 = "如果敌人使用大量固定防御,你可以绕过它们、超出射程攻击,或无视它们并发展经济" +loadingtip_0061 = "如果敌人使用大量 T1 或 T2 飞机,你可以建造截击机和 T2 机动高射炮" +loadingtip_0062 = "如果敌人的经济远大于你,他们可能没有足够的部队来防守它" +loadingtip_0063 = "如果敌人龟缩而不控制地图,他们可能没有足够的经济赢得后期" +loadingtip_0064 = "如果敌人行动激进,你可以尝试引诱他们进入对你更有利的战斗" +loadingtip_0067 = "在比赛非常早期,当你没有更好事情可做时,手动回收是有用的" +loadingtip_0068 = "在大多数情况下,攻击移动命令优于巡逻命令,以便你知道命令何时完成" +loadingtip_0070 = "在你容易回收残骸而敌人不能的位置进行战斗" +loadingtip_0071 = "残骸可回收单位质量成本的 81%,具体取决于单位等级" +loadingtip_0072 = "回收旧的低科技单位或严重受损的高科技单位以获得额外质量是值得的" +loadingtip_0073 = "考虑价值和机会成本(例如,你宁愿要大约 16 辆 T1 坦克还是 1 座 T2 质量萃取机?)" +loadingtip_0074 = "低科技单位每成本造成的伤害通常较高,但每成本的生命值低于高科技单位" +loadingtip_0075 = "升级工厂需要投入可用于生产单位的资源,因此不要过早升级" +loadingtip_0077 = "如果需要帮助,请告知你的队友" +loadingtip_0078 = "如果你不知道该怎么办,向队友寻求建议" +loadingtip_0079 = "如果你有多余质量且无法快速花费,可以赠送给能花掉的队友" +loadingtip_0081 = "标记或指出队友尚未注意到的敌方威胁" +loadingtip_0082 = "与队友协调行动比各自为战更有效" +loadingtip_0083 = "保持积极心态有助于你打得更好、学得更多,并获得更多乐趣" +loadingtip_0084 = "分析录像可以学到很多" +loadingtip_0085 = "记得享受乐趣——获胜固然愉快,但不是全部!" +loadingtip_0087 = "你可以在 FAF Discord 上寻求游戏建议和录像复盘" +loadingtip_0088 = "FAF 维基上有用的指南可以教你如何在最高指挥官中进步" +loadingtip_0089 = "随时间扩大你的经济(质量收入、能源收入和建造能力)" +loadingtip_0090 = "大量生产低科技单位通常非常有效,但别忘了过渡到高科技单位" +loadingtip_0091 = "非万古的 T2 战斗机/轰炸机控制空域效率不高——使用 T1 截击机直到获得 T3 空优战斗机" +loadingtip_0092 = "避免能源停滞——需要能源维持的单位和建筑在你停滞时会逐渐丧失其优势" +loadingtip_0093 = "花费质量比让质量囤积在仓库里更好" +loadingtip_0094 = "避免建造过多发电机——它们消耗的资源可以花在更有用的单位上" +loadingtip_0095 = "如果你质量停滞,让更多工程师去回收可能是个好主意" +loadingtip_0096 = "通常早期在地图周围扩张是个好办法,以获取质量矿床、残骸和地图控制权" +loadingtip_0097 = "如果所有玩家同意平局,你可以以平局结束缓慢或不公平的比赛" +loadingtip_0098 = "如果你无法花掉资源,可能是建造能力不足(工程师、工厂、工程站或副指挥官)" +loadingtip_0099 = "如果你认为你的队伍无法再获胜,你可以请求他们从战场召回,同时你继续为他们战斗" +loadingtip_0100 = "你可以在 FAF Discord 上找到其他玩家组队或讨论最高指挥官:钢铁同盟" +lob_0009 = "部分玩家使用的客户端版本不兼容。" +lobui_0152 = "斩首" +lobui_0153 = "当所有友方指挥官被摧毁时游戏结束" +lobui_0444 = "自动平衡" +lobui_0445 = "自动将玩家平衡为两支人数相等的队伍" +lobui_0446 = "已启用固定出生位置" +lobui_0625 = "玩家将被分入两支人数相等、镜像且基于基础评级和不确定性平衡的队伍" +lobui_0626 = "自动平衡完成" +lobui_0702 = "队伍评级:" +lobui_0703 = "队伍 %d:%d(%d±%d)" +lobui_0790 = "手动单位共享" +lobui_0791 = "是否允许玩家手动给予单位?" +lobui_0792 = "允许手动单位共享" +lobui_0793 = "允许,建造者除外" +lobui_0794 = "不允许手动共享建造者/工厂" +lobui_0795 = "不允许手动共享单位" +lobui_0796 = "部分共享" +lobui_0797 = "当你死亡时,你的建筑和工程师将转移给你评级最高的盟友。你的其他单位将在你死亡时被摧毁,除非被敌军占领。" +lobui_0808 = "断开延迟" +lobui_0809 = "设定玩家连接困难时的断开延迟。" +lobui_0810 = "比赛" +lobui_0811 = "踢出延迟设为 10 秒,90 秒后自动踢出玩家。" +lobui_0812 = "快速" +lobui_0813 = "踢出延迟设为 30 秒,90 秒后自动踢出玩家。" +lobui_0814 = "常规" +lobui_0815 = "踢出延迟设为 90 秒,180 秒后自动踢出玩家。" +lobui_666 = "检测到与 %s 的游戏版本不匹配。\r\n - 主机:%s(@%s)\r\n - %s:%s(@%s)\r\n\r\n为防止同步错误,%s 被自动踢出。可能是新游戏版本已发布。如果这种情况持续发生,最好重新建主。" +lobui_CACDesc = "每支队伍为一个整体军队。所有单位和资源共享,所有队员均可下达命令。" +lobui_CACommon = "单一军队,联合指挥" +lobui_CADDesc = "每位玩家拥有自己的军队和资源。盟友不能对你的军队下达命令。这是最高指挥官的默认体验。" +lobui_CADesc = "允许你调整队伍与军队之间的合作方式。范围从最高指挥官的默认体验,到整个队伍共享一个军队。" +lobui_CAName = "共同指挥" +lobui_CAUDesc = "每位玩家拥有自己的军队和资源。盟友可以切换焦点到你的军队并下达命令。" +lobui_CAUnion = "多支军队,联合指挥" +lobui_CAUponDisconnectDescription = "初始每位玩家拥有自己的军队和资源。当玩家断开连接时,其军队不被视为失败,共享条件不触发。相反,盟友可以切换焦点到断连的军队以下达命令。" +lobui_CAUponDisconnectTitle = "断连时联合指挥" +lobui_dc_share_01 = "断连共享条件" +lobui_dc_share_02 = "设定当玩家" +lobui_dc_share_03 = "与共享条件相同" +lobui_dc_share_04 = "将断连玩家视为失败玩家处理。" +lobui_dc_share_05 = "断连 ACU 共享条件" +lobui_dc_share_06 = "设定当玩家" +lobui_dc_share_07 = "爆炸" +lobui_dc_share_08 = "当玩家断连时 ACU 爆炸。" +lobui_dc_share_09 = "召回" +lobui_dc_share_10 = "过去 2 分钟内未受伤的 ACU 在玩家断连时会被召回。" +lobui_dc_share_11 = "延迟召回" +lobui_dc_share_12 = "断连的 ACU 会共享给盟友 2 分钟,或直到比赛开始 5 分钟后再召回。" +lobui_dc_share_13 = "永久" +lobui_dc_share_14 = "断连的 ACU 会永久共享给盟友。" +lobui_resource_sharing_disabled_help = "默认情况下多余资源会溢出。" +lobui_resource_sharing_disabled_text = "禁用" +lobui_resource_sharing_enabled_help = "默认情况下多余资源会分享给盟友。" +lobui_resource_sharing_enabled_text = "启用" +lobui_resource_sharing_help = "设定多余资源分配给盟友的初始启用/禁用状态。当队伍解锁时,玩家可通过外交菜单切换。" +lobui_resource_sharing_label = "溢出" +map_version = "地图版本" +notify_abnormal = "正在对 " +notify_cancelled = " 已取消" +notify_done = " 完成!" +notify_starting = "开始 " +profiler_0000 = "性能分析器" +profiler_0001 = "概览" +profiler_0002 = "计时器" +profiler_0003 = "标记" +profiler_0004 = "基准测试" +profiler_0005 = "选项" +profiler_0006 = "运行" +profiler_0007 = "基准测试模块" +profiler_0008 = "参数 %d:%s" +profiler_0009 = "%d / %d" +profiler_0010 = "停止" +profiler_0011 = "模块中的基准测试:%s" +profiler_0012 = "等待基准测试数据……" +profiler_0013 = "打印到日志" +profiler_0014 = "将函数字节码打印到日志" +profiler_0015 = "参数:%d" +profiler_0016 = "最大堆栈:%d" +profiler_0017 = "上值:%d" +profiler_0018 = "常量:%d" +profiler_0019 = "从 %s 跳转" +profiler_0020 = "函数" +profiler_0021 = "来源" +profiler_0022 = "作用域" +profiler_0023 = "值" +profiler_0024 = "增长" +profiler_0025 = "摘要" +profiler_0026 = "样本数" +profiler_0027 = "平均值" +profiler_0028 = "标准差" +profiler_0029 = "偏度" +profiler_0030 = "清除统计数据" +profiler_0031 = "无基线数据" +profiler_0032 = "忽略每个样本的" +profiler_0033 = "配对基线数据" +profiler_0034 = "将每个样本除以" +profiler_0035 = "基线数据比率" +profiler_0036 = "将数据与基线独立处理并进行比率检验" +profiler_0037 = "搜索" +profiler_0038 = "清除" +profiler_0039 = "名称" +profiler_0040 = "计数" +profiler_0041 = "清除统计数据" +profiler_0042 = "清除该基准测试的所有样本" +properkeyname_0166 = "折角键" +replay_id = "录像 ID" +saveload_QuickLoad = "正在载入快速存档……" +tooltipui0019 = "左键点击以执行运输命令。右键点击以装载至运输机。" +tooltipui0722 = "召回" +tooltipui0723 = "向你的盟友发出信号,表示你已准备从战场召回。" +tooltipui0724 = "已请求召回" +tooltipui0725 = "你的队伍已收到你从战场召回的请求。" +tooltipui0726 = "无法召回" +tooltipui0727 = "在此场景中你不能从战场召回。" +tooltipui0728 = "传送进入后的 5 分钟内不能从战场召回。" +tooltipui0729 = "你的队伍中有 AI 军队不会召回。" +tooltipui0730 = "你最近刚刚发送过召回请求。" +tooltipui0731 = "你的队伍最近刚进行过召回投票。" +tooltipui0732 = "赞同投票" +tooltipui0733 = "投票赞同你的队伍以战败状态从战场召回。" +tooltipui0734 = "反对投票" +tooltipui0735 = "投票反对你的队伍以战败状态从战场召回。" +tooltipui0736 = "[隐藏/显示] 质量制造机面板" +tooltipui0737 = "[隐藏/显示] 投票面板" +tooltipui0750 = "机动工厂" +tooltipui0751 = "选择附带的工厂" +tooltipui0752 = "选择基础单位" +tooltipui0753 = "右键点击以自动部署建造出的单位" +tooltipui1000 = "质量收入" +tooltipui1001 = "每秒由质量制造机产生的质量" +tooltipui1002 = "能源消耗" +tooltipui1003 = "每秒质量制造机消耗的能源" +tooltipui1004 = "活动中的质量制造机" +tooltipui1005 = "活动中的质量制造机数量" +tooltipui1006 = "非活动中的质量制造机" +tooltipui1007 = "非活动中的质量制造机数量" +tooltipui1008 = "所需能源" +tooltipui1009 = "质量制造机正常工作所需的能源量" +tooltipui2000 = "更新日志" +tooltipui2001 = "访问社区制作的所有历史更新日志" +uilobby_0004 = "在线查看" +usersync_0006 = "断连共享" +usersync_0007 = "%s 的" +usersync_0008 = "%s 的" +usersync_0009 = "\n之后共享条件:%s" +uvd_0010 = "伤害:%.7g,溅射:%.3g" +uvd_0011 = "速度:%0.1f,转向:%0.1f" +uvd_0012 = "速度:%.3g,倒车:%.3g,加速度:%.3g,转向:%d" +uvd_0013 = "视野:%d,水下视野:%d,再生:%.3g,容量成本:%.3g" +uvd_0014 = "伤害:%.8g - %.8g,溅射:%.3g - %.3g" +uvd_0015 = "伤害:%.8g x%d,溅射:%.3g" +uvd_0016 = "强化装置:%d" +uvd_0017 = "运输速度降低:%.3g" +uvd_0018 = "直接火力总 DPS:%d" +uvd_0019 = "间接火力总 DPS:%d" +uvd_0020 = "反舰总 DPS:%d" +uvd_0021 = "防空总 DPS:%d" +uvd_ArmorType = "装甲类型:" +uvd_Blips = "雷达回波:%d" +uvd_BuildRate = "建造速率:%0.1f" +uvd_Capacity = "容量:" +uvd_DPS = "(DPS:%d)" +uvd_DamageTaken = "(所受伤害的百分比)" +uvd_Delay = "延迟:%0.1f" +uvd_DockingSlots = "停靠位:%d" +uvd_FireRate = "射速:%0.1f" +uvd_ManualFire = "(手动发射)" +uvd_Radius = "半径:%d" +uvd_Range = "射程:%d - %d" +uvd_RechargeTime = "充能时间:%d" +uvd_RegenRate = "再生速率:%d" +uvd_Reload = "装填:%0.1f" +uvd_RepairRate = "修理速率:%0.1f" +uvd_Scry = "半径:%d,启动消耗:%d 能源,维持:%d 能源" +uvd_StorageSlots = "储存槽位:%d" +uvd_UnitSize = "单位尺寸:%d" +uvd_VisionField = "半径:%d" +uvd_basic = "基础" +uvd_upgrades = "升级" \ No newline at end of file From ec752fd8fd4748568acfc386b159726459f2943b Mon Sep 17 00:00:00 2001 From: haojun0823 Date: Wed, 26 Aug 2026 20:16:48 +0800 Subject: [PATCH 2/2] Add localization comparison tool. --- loc/diff.py | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 loc/diff.py diff --git a/loc/diff.py b/loc/diff.py new file mode 100644 index 0000000000..692b6c073f --- /dev/null +++ b/loc/diff.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Compare two Lua key-value files and generate the set difference of keys, +including the corresponding values from each file. + +Created by HaoJun0823 on 2026-08-26. + +Usage: + python compare_lua_keys_with_values.py file1.lua file2.lua + python compare_lua_keys_with_values.py ID1 ID2 # automatically appends /strings_db.lua + +Output: + only_in_.txt # keys present in file1 but not in file2, with values from file1 + only_in_.txt # keys present in file2 but not in file1, with values from file2 +""" + +import re +import sys +from pathlib import Path + +def resolve_path(arg): + if arg.lower().endswith('.lua'): + return Path(arg) + else: + return Path(arg) / 'strings_db.lua' + +def extract_keys_and_values(filepath): + """Extract all key names and their corresponding values (right-hand side strings) from a .lua file.""" + data = {} + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + # Match lines like KEY = "value" or KEY = 'value' + pattern = re.compile(r'^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(["\'].*?["\'])', re.MULTILINE) + for match in pattern.finditer(content): + key = match.group(1) + value = match.group(2) # preserve quotes + data[key] = value + return data + +def main(): + if len(sys.argv) != 3: + print("Usage:") + print(" python compare_lua_keys_with_values.py ") + print(" python compare_lua_keys_with_values.py ") + sys.exit(1) + + path1 = resolve_path(sys.argv[1]) + path2 = resolve_path(sys.argv[2]) + + if not path1.exists(): + print(f"Error: file {path1} does not exist") + sys.exit(1) + if not path2.exists(): + print(f"Error: file {path2} does not exist") + sys.exit(1) + + print(f"Parsing {path1} ...") + dict1 = extract_keys_and_values(path1) + print(f"Found {len(dict1)} keys") + + print(f"Parsing {path2} ...") + dict2 = extract_keys_and_values(path2) + print(f"Found {len(dict2)} keys") + + keys1 = set(dict1.keys()) + keys2 = set(dict2.keys()) + + only_in_1 = keys1 - keys2 + only_in_2 = keys2 - keys1 + + base1 = Path(sys.argv[1]).stem + base2 = Path(sys.argv[2]).stem + out1 = Path.cwd() / f"only_in_{base1}.txt" + out2 = Path.cwd() / f"only_in_{base2}.txt" + + with open(out1, 'w', encoding='utf-8') as f: + for key in sorted(only_in_1): + f.write(f'{key} = {dict1[key]}\n') + with open(out2, 'w', encoding='utf-8') as f: + for key in sorted(only_in_2): + f.write(f'{key} = {dict2[key]}\n') + + print(f"Keys only in {path1}: {len(only_in_1)} -> saved to {out1}") + print(f"Keys only in {path2}: {len(only_in_2)} -> saved to {out2}") + +if __name__ == "__main__": + main() \ No newline at end of file