migrate to gitea
This commit is contained in:
173
xml_processor.py
Normal file
173
xml_processor.py
Normal file
@@ -0,0 +1,173 @@
|
||||
"""
|
||||
XML file processor for Android resources
|
||||
"""
|
||||
|
||||
import os
|
||||
from lxml import etree
|
||||
from typing import Dict, Tuple, List, Union
|
||||
from models import TranslationItem
|
||||
from config import Config
|
||||
|
||||
|
||||
class XMLProcessor:
|
||||
"""XML file processor for Android resources"""
|
||||
|
||||
def __init__(self, config: Config):
|
||||
self.config = config
|
||||
self.parser = etree.XMLParser(remove_blank_text=False, strip_cdata=False)
|
||||
|
||||
def load_xml_file(self, file_path: str) -> etree.Element:
|
||||
"""Load and parse XML file"""
|
||||
try:
|
||||
tree = etree.parse(file_path, self.parser)
|
||||
return tree.getroot()
|
||||
except Exception as e:
|
||||
print(f"Error loading XML file {file_path}: {e}")
|
||||
return None
|
||||
|
||||
def save_xml_file(self, root: etree.Element, file_path: str):
|
||||
"""Save XML file with formatting"""
|
||||
try:
|
||||
# Ensure proper formatting for the root element
|
||||
if root.text is None:
|
||||
root.text = "\n "
|
||||
if root.tail is None:
|
||||
root.tail = "\n"
|
||||
|
||||
# Ensure all children have proper tails for formatting
|
||||
for i, child in enumerate(root):
|
||||
if child.tail is None or child.tail.strip() == "":
|
||||
child.tail = "\n "
|
||||
|
||||
# Make sure the last child ends with proper indentation
|
||||
if len(root) > 0:
|
||||
last_child = root[-1]
|
||||
if not last_child.tail.endswith("\n"):
|
||||
last_child.tail = "\n"
|
||||
|
||||
# Create backup if enabled
|
||||
if self.config.output_config.get('create_backups', True):
|
||||
backup_path = file_path + self.config.output_config.get('backup_suffix', '.backup')
|
||||
if os.path.exists(file_path):
|
||||
backup_tree = etree.ElementTree(root)
|
||||
backup_tree.write(backup_path,
|
||||
encoding='utf-8',
|
||||
xml_declaration=True,
|
||||
pretty_print=True)
|
||||
|
||||
# Save the modified file with pretty printing
|
||||
tree = etree.ElementTree(root)
|
||||
tree.write(file_path, encoding='utf-8', xml_declaration=True, pretty_print=True)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error saving XML file {file_path}: {e}")
|
||||
|
||||
def extract_strings(self, root: etree.Element) -> Dict[str, TranslationItem]:
|
||||
"""Extract strings and string-arrays from XML root element"""
|
||||
strings = {}
|
||||
|
||||
for element in root:
|
||||
if element.tag == 'string':
|
||||
name = element.get('name')
|
||||
value = element.text or ''
|
||||
|
||||
# Skip strings marked as non-translatable
|
||||
translatable = element.get('translatable', 'true')
|
||||
if translatable.lower() == 'false':
|
||||
continue
|
||||
|
||||
# Handle CDATA and special characters
|
||||
if isinstance(value, str):
|
||||
value = value.strip()
|
||||
|
||||
# Get comment if exists
|
||||
comment = None
|
||||
if element.tail and element.tail.strip():
|
||||
comment = element.tail.strip()
|
||||
|
||||
strings[name] = TranslationItem(name=name, value=value, comment=comment, item_type='string')
|
||||
|
||||
elif element.tag == 'string-array':
|
||||
name = element.get('name')
|
||||
|
||||
# Skip arrays marked as non-translatable
|
||||
translatable = element.get('translatable', 'true')
|
||||
if translatable.lower() == 'false':
|
||||
continue
|
||||
|
||||
# Extract all items from the string-array
|
||||
items = []
|
||||
for item in element:
|
||||
if item.tag == 'item':
|
||||
item_value = item.text or ''
|
||||
if isinstance(item_value, str):
|
||||
item_value = item_value.strip()
|
||||
items.append(item_value)
|
||||
|
||||
# Get comment if exists
|
||||
comment = None
|
||||
if element.tail and element.tail.strip():
|
||||
comment = element.tail.strip()
|
||||
|
||||
# Store with combined value for display
|
||||
combined_value = " | ".join(items) if items else ""
|
||||
strings[name] = TranslationItem(
|
||||
name=name,
|
||||
value=combined_value,
|
||||
comment=comment,
|
||||
item_type='string-array',
|
||||
items=items
|
||||
)
|
||||
|
||||
elif element.tag == 'plurals':
|
||||
# Handle plurals - for now, skip or handle separately
|
||||
name = element.get('name')
|
||||
strings[name] = TranslationItem(name=name, value=f"<{element.tag}>", comment="Complex type", item_type='plurals')
|
||||
|
||||
return strings
|
||||
|
||||
def add_missing_strings(self, target_root: etree.Element, missing_strings: List[Tuple]):
|
||||
"""Add missing strings and string-arrays to target XML"""
|
||||
for item_data in missing_strings:
|
||||
if len(item_data) == 4:
|
||||
# Extended format: (name, value, item_type, items)
|
||||
name, value, item_type, items = item_data
|
||||
else:
|
||||
# Regular string: (name, value)
|
||||
name, value = item_data[0], item_data[1]
|
||||
item_type = 'string'
|
||||
items = []
|
||||
|
||||
if item_type == 'string-array':
|
||||
# Check if string-array already exists
|
||||
existing = target_root.find(f".//string-array[@name='{name}']")
|
||||
if existing is None:
|
||||
# Create new string-array element
|
||||
new_array = etree.SubElement(target_root, 'string-array', name=name)
|
||||
|
||||
# Add items to the array
|
||||
for i, item_value in enumerate(items):
|
||||
item_elem = etree.SubElement(new_array, 'item')
|
||||
item_elem.text = item_value
|
||||
# Add proper indentation between items
|
||||
item_elem.tail = "\n "
|
||||
|
||||
# Add proper tail for the array element itself
|
||||
new_array.tail = "\n "
|
||||
|
||||
else:
|
||||
# Regular string
|
||||
existing = target_root.find(f".//string[@name='{name}']")
|
||||
if existing is None:
|
||||
# Create new string element with proper indentation
|
||||
new_string = etree.SubElement(target_root, 'string', name=name)
|
||||
new_string.text = value
|
||||
|
||||
# Add proper indentation and newlines
|
||||
new_string.tail = "\n "
|
||||
|
||||
# Ensure the last element has proper closing
|
||||
if len(target_root) > 0:
|
||||
last_child = target_root[-1]
|
||||
if last_child.tail and not last_child.tail.endswith("\n"):
|
||||
last_child.tail += "\n"
|
||||
Reference in New Issue
Block a user