Android项目资源字符串内容多语言对齐工具:

#!/usr/bin/env python3import re
from dataclasses import dataclass, field
from typing import Optional, Dict, List
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox@dataclass
class StringLine:name: Optional[str]raw: strtext: Optional[str] = Noneattrs: Dict[str, str] = field(default_factory=dict)def parse_string_lines(xml_path: Path) -> List[StringLine]:lines = []last_line_empty = Falsestring_tag_pattern = re.compile(r'<string\s+([^>]+)>(.*?)</string>', re.DOTALL)attr_pattern = re.compile(r'(\w+)="(.*?)"')with xml_path.open(encoding='utf-8') as f:for line in f:stripped = line.strip()if not stripped:if not last_line_empty:lines.append(StringLine(name=None, raw="\n"))last_line_empty = Truecontinuelast_line_empty = Falsematch = string_tag_pattern.match(stripped)if match:attr_text, content = match.groups()attrs = dict(attr_pattern.findall(attr_text))name = attrs.get("name")lines.append(StringLine(name=name, raw=line, text=content, attrs=attrs))else:lines.append(StringLine(name=None, raw=line))return linesdef map_string_lines(lines: List[StringLine]) -> Dict[str, StringLine]:return {line.name: line for line in lines if line.name}def align_string_lines(base_lines: List[StringLine], target_lines: List[StringLine]) -> List[StringLine]:target_map = map_string_lines(target_lines)aligned_lines = []for line in base_lines:if line.name:target_line = target_map.pop(line.name, None)aligned_lines.append(target_line if target_line else line)else:aligned_lines.append(line)if target_map:aligned_lines.append(StringLine(name=None, raw="\n"))aligned_lines.append(StringLine(name=None, raw="\n"))aligned_lines.extend(target_map.values())return aligned_linesdef write_aligned_lines(lines: List[StringLine], output_path: Path):with output_path.open('w', encoding='utf-8') as f:# f.write('<resources>\n')for line in lines:f.write(line.raw.rstrip('\n') + '\n')# f.write('</resources>\n')class AlignStringsApp:def __init__(self, root):self.root = rootself.root.title("Android 资源文件多语言字符串对齐工具-WKF")self.root.resizable(False, False)# 计算居中坐标win_width, win_height = 916, 190x = (self.root.winfo_screenwidth() - win_width) // 2y = (self.root.winfo_screenheight() - win_height) // 2self.root.geometry(f"{win_width}x{win_height}+{x}+{y}")self.base_file = Noneself.res_dir = Noneself.output_dir = Nonetk.Label(root, text="基准 strings.xml 文件:").grid(row=0, column=0, sticky="w", padx=(10, 0), pady=(16, 0))self.base_entry = tk.Entry(root, width=100, state="readonly")self.base_entry.grid(row=0, column=1, pady=(16, 0))tk.Button(root, text="选择", width=6, command=self.select_base_file).grid(row=0, column=2, pady=(16, 0))tk.Label(root, text="res 根目录:").grid(row=1, column=0, sticky="w", padx=(10, 0))self.res_entry = tk.Entry(root, width=100, state="readonly")self.res_entry.grid(row=1, column=1)tk.Button(root, text="选择", width=6, command=self.select_res_dir).grid(row=1, column=2)tk.Label(root, text="输出目录:").grid(row=2, column=0, sticky="w", padx=(10, 0))self.out_entry = tk.Entry(root, width=100, state="readonly")self.out_entry.grid(row=2, column=1)tk.Button(root, text="选择", width=6, command=self.select_output_dir).grid(row=2, column=2)self.align_button = tk.Button(root, text="一键对齐", width=16, height=2, command=self.align_strings)self.align_button.grid(row=3, column=1, pady=10)messagebox.showinfo("提示","本工具以选择的xml文件为基准对齐内容,对齐的文件中若不存在则补充基准的内容,若多了则保留在处理后的文件末尾!")def select_base_file(self):path = filedialog.askopenfilename(filetypes=[("XML 文件", "*.xml")])if path:self.base_file = Path(path)self.base_entry.config(state="normal")self.base_entry.delete(0, tk.END)self.base_entry.insert(0, str(self.base_file))self.base_entry.config(state="readonly")def select_res_dir(self):path = filedialog.askdirectory()if path:self.res_dir = Path(path)self.res_entry.config(state="normal")self.res_entry.delete(0, tk.END)self.res_entry.insert(0, str(self.res_dir))self.res_entry.config(state="readonly")def select_output_dir(self):path = filedialog.askdirectory()if path:self.output_dir = Path(path)self.out_entry.config(state="normal")self.out_entry.delete(0, tk.END)self.out_entry.insert(0, str(self.output_dir))self.out_entry.config(state="readonly")def align_strings(self):# 判断是否路径都已选择if not self.base_file or not self.base_file.exists():messagebox.showwarning("警告", "请先选择【基准 strings.xml 文件】")returnif not self.res_dir or not self.res_dir.exists():messagebox.showwarning("警告", "请先选择【res 根目录】")returnif not self.output_dir or not self.output_dir.exists():messagebox.showwarning("警告", "请先选择【输出目录】")returntry:base_lines = parse_string_lines(self.base_file)base_name = self.base_file.namefor xml_path in self.res_dir.rglob(base_name):target_lines = parse_string_lines(xml_path)aligned = align_string_lines(base_lines, target_lines)relative = xml_path.relative_to(self.res_dir)out_path = self.output_dir / relativeout_path.parent.mkdir(parents=True, exist_ok=True)write_aligned_lines(aligned, out_path)messagebox.showinfo("完成", "对齐完成!")except Exception as e:messagebox.showerror("错误", f"对齐失败: {e}")if __name__ == "__main__":window = tk.Tk()app = AlignStringsApp(window)window.mainloop()

 工具运行截图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85508.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85508.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/85508.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

创客匠人分享:知识变现时代的创始人 IP 打造路径

当知识付费市场规模突破千亿&#xff0c;创始人 IP 已成为知识变现的 “流量引擎”。创客匠人结合陈雷教授的实战经验&#xff0c;拆解创始人 IP 从 0 到 1 的打造路径&#xff0c;为内容创业者提供从流量引流到商业变现的全链路思路。 一、破局认知&#xff1a;IP 打造的核心…

【数据分析五:Feature Engineering】特征工程

一、特征工程定义 在数据预处理以后&#xff08;或者数据预处理过程中&#xff09;&#xff0c;如何从数据中提取有效的特征&#xff0c;使这些特征能够尽可能的表达原始数据中的信息&#xff0c;使得后续建立的数据模型能达到更好的效果&#xff0c;就是特征工程所要做的工作…

标杆确立!永洪科技位于IDC报告Data Analytics领域象限排头位!

近日&#xff0c;全球知名市场研究机构IDC发布的《数据管理分析与生成式AI发展趋势及最佳实践》报告&#xff0c;为正处于数字化转型深水区的企业描绘了清晰的技术演进蓝图。在这幅权威绘制的产业图谱中&#xff0c;“Data Analytics”&#xff08;数据分析&#xff09;作为连接…

启动tomcat控制台日志出现乱码

当我们启动tomcat控制台日志出现乱码怎么办&#xff1f; 解决方案&#xff1a; 在tomcat根目录中config文件夹下将log.properties文件中将默认控制台日志输出编码UTF修改成GBK或者GB2312都可以。 java.util.logging.ConsoleHandler.encoding UTF-8 修改为&#xff1a; j…

【橘子的AI | 每日一课】Day4!机器学习 (ML) 基础

机器学习 (ML) 基础介绍 一、机器学习的定义 从广义上来说&#xff0c;机器学习是一种能够赋予机器学习的能力以此让它完成直接编程无法完成的功能的方法。但从实践的意义上来说&#xff0c;机器学习是一种通过利用数据&#xff0c;训练出模型&#xff0c;然后使用模型预测的…

【C语言】药店药品管理系统 -丨完整源码与实现解析

系统概述 这是一个功能完善的药店药品管理系统&#xff0c;使用C语言开发&#xff0c;基于链表数据结构实现。系统提供药品信息的增删改查、排序和持久化存储功能&#xff0c;适用于药店日常药品管理工作。 数据结构设计 #define MAX_NAME_LEN 50 #define MAX_ID_LEN 20 #de…

sass-loader与webpack版本冲突解决方案

#npm i 错误解决记录# 最开始错误 &#xff1a;拉取代码&#xff0c;增加依赖时&#xff0c;报错 问题&#xff1a; 在安装sass-loader10.1.1时&#xff0c;发现与现有的webpack版本有冲突。 当前项目已经安装了webpack4.28.4&#xff08;通过peer dependency requirements f…

常见误区解读之三:超融合只适合外围/轻量业务场景,无法承载数据库等关键业务?

作者&#xff1a;SmartX 金融团队 祝志刚 在前两期“超融合常见误区解读”中&#xff0c;我们分别解读了如何以超融合建云并进行大规模部署。而对于生产业务场景&#xff0c;部分行业用户和业界人士可能还会有这样的认知&#xff1a; “超融合管理简单、成本也低&#xff0c;…

Kafka重平衡机制深度解析:原理、触发条件与应对策略

引言 在Kafka分布式消息系统中&#xff0c;重平衡&#xff08;Rebalance&#xff09;是一个至关重要的机制&#xff0c;它确保消费者组中的各个消费者实例能够公平地分担主题分区的消费任务。然而&#xff0c;重平衡过程也可能带来短暂的消费停顿和性能波动&#xff0c;处理不…

使用 Docker Compose 安装 Milvus(单机版)

1. 创建专用目录并进入 mkdir milvus-standalone && cd milvus-standalone 2. 下载 docker-compose.yml 文件 使用官方提供的配置文件&#xff08;以 Milvus v2.3.3 为例&#xff09;&#xff1a; wget https://github.com/milvus-io/milvus/releases/download/v2.3…

【MySQL篇05】:事务的 ACID 性(数据库原理篇)

文章目录 一、事务的ACID特性二、数据库原理例题与 ACID 特性判断三、拓展&#xff08;undolog 与 redolog&#xff09; 一、事务的ACID特性 综述&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务是不可分割的最小操作单元&#xff0c;要么全部成功&…

crawl4ai 框架的入门讲解和实战指南——基于Python的智能爬虫框架,集成AI(如NLP/OCR)实现自动化数据采集与处理

一、crawl4ai 框架简介 1. 框架定位 核心功能&#xff1a;基于Python的智能爬虫框架&#xff0c;集成AI&#xff08;如NLP/OCR&#xff09;实现自动化数据采集与处理 关键特性&#xff1a; 零配置快速启动&#xff08;自动识别网页结构&#xff09; 内置反反爬机制&#xff…

受够垃圾翻译!CodeBuddy 8 分钟造神器,划词秒翻 + 自动适配所有网页

本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 前言 作为一个天天泡在 GitHub 上扒项目的人&#xff0c;翻译问题简直是我 “挖宝” 路上的头号绊脚石&#xff01;想研究国外大神的优质开源项目&#xff0c;不是被机翻软…

零基础设计模式——总结与进阶 - 2. 反模式

第五部分&#xff1a;总结与进阶 - 2. 反模式 (Anti-Patterns) 在软件开发中&#xff0c;我们追求良好的设计模式以构建健壮、可维护的系统。然而&#xff0c;同样存在一些常见的、导致不良后果的解决方案&#xff0c;这些被称为“反模式”。理解反模式&#xff0c;可以帮助我…

音视频流媒体高级开发-学习路线

原文作者&#xff1a;Linux 原文链接&#xff1a;音视频流媒体高级开发-学习路线 如果你想往音视频方向发展&#xff0c;那么本文一定要认真阅读~ 大家都知道音视频开发薪资高、门槛高、发展空间大&#xff0c;心里蠢蠢欲动&#xff0c;却不知道怎么入门&#xff0c;怎么进阶…

LINUX 通过rsync同步 免密备份

1&#xff0c;增加免密码用户密码 useradd backup echo "5566777" | passwd --stdin backup echo "backup ALL(ALL) ALL" >> /etc/sudoers # 源服务器操作 ssh client_usersource_server ssh-keygen -t rsa # 一路回车 ssh-copy-id serv…

在使用 HTML5 的 <video> 标签嵌入视频时,有时会遇到无法播放 MP4 文件的问题

原因分析&#xff1a; 只能播放声音&#xff0c;却无法播放视频。这通常是由于视频编码格式不兼容导致的。虽然 MP4 是一种常见的视频格式&#xff0c;但它包含多种编码方式&#xff0c;并非所有编码方式都受 HTML5 支持。 解决方案&#xff1a; 确认视频编码格式&#xff1a; …

【bugfix】记一次Spring Boot 配置层级错误导致数据库连接失败

前言&#xff1a;为什么你的数据库配置读不到&#xff1f; 在 Spring Boot 项目中&#xff0c;配置文件的层级&#xff08;prefix&#xff09; 是决定属性能否被正确解析的核心因素。一个看似微小的缩进错误&#xff0c;可能导致整个应用的数据库连接失败、服务启动异常&#…

wpf 队列(Queue)在视觉树迭代查找中的作用分析

文章目录 队列(Queue)在视觉树迭代查找中的作用分析示例代码一、队列的核心作用1. 替代递归的迭代机制2. 实现广度优先搜索(BFS) 二、队列的工作流程1. 初始化阶段2. 处理循环 三、队列操作的详细步骤查找过程分解&#xff1a; 四、为什么使用队列而不是其他数据结构1. 与栈(St…

快手数据开发面试SQL题:取窗口内排名第一和排名倒数第一的作为两个字段输出

目录 问题描述 样例数据表 sales 解决方案 第三步:使用条件聚合将多行合并为单行输出" 步骤1:计算排名的中间结果 中间结果输出: 步骤2:最终查询(处理并列情况) 最终输出结果: 关键点解释: RANK() OVER (PARTITION BY group_id ORDER BY amount DESC):…