222 lines
4.6 KiB
Python
Executable file
222 lines
4.6 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
import sys
|
|
import re
|
|
import ast
|
|
|
|
|
|
if len(sys.argv) != 3:
|
|
print("Usage: sanitize_po_keep_last.py input.po output.po", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
input_file = sys.argv[1]
|
|
output_file = sys.argv[2]
|
|
|
|
|
|
with open(input_file, "r", encoding="utf-8") as f:
|
|
content = f.read()
|
|
|
|
|
|
def split_entries(text):
|
|
entries = []
|
|
current = []
|
|
|
|
for line in text.splitlines(keepends=True):
|
|
if line.strip() == "":
|
|
if current:
|
|
entries.append("".join(current))
|
|
current = []
|
|
else:
|
|
current.append(line)
|
|
|
|
if current:
|
|
entries.append("".join(current))
|
|
|
|
return entries
|
|
|
|
|
|
def read_po_string(lines, start_index):
|
|
value = ""
|
|
i = start_index
|
|
|
|
first = lines[i].strip()
|
|
|
|
m = re.match(
|
|
r'^(msgctxt|msgid|msgid_plural|msgstr(?:\[[0-9]+\])?)\s+(.*)$',
|
|
first
|
|
)
|
|
|
|
if not m:
|
|
return "", i
|
|
|
|
raw = m.group(2).strip()
|
|
|
|
try:
|
|
value += ast.literal_eval(raw)
|
|
except Exception:
|
|
pass
|
|
|
|
i += 1
|
|
|
|
while i < len(lines):
|
|
s = lines[i].strip()
|
|
|
|
if not s.startswith('"'):
|
|
break
|
|
|
|
try:
|
|
value += ast.literal_eval(s)
|
|
except Exception:
|
|
pass
|
|
|
|
i += 1
|
|
|
|
return value, i - 1
|
|
|
|
|
|
def entry_key(entry):
|
|
lines = entry.splitlines()
|
|
msgctxt = None
|
|
msgid = None
|
|
|
|
i = 0
|
|
|
|
while i < len(lines):
|
|
stripped = lines[i].strip()
|
|
|
|
if stripped.startswith("msgctxt "):
|
|
msgctxt, i = read_po_string(lines, i)
|
|
|
|
elif stripped.startswith("msgid "):
|
|
msgid, i = read_po_string(lines, i)
|
|
break
|
|
|
|
i += 1
|
|
|
|
if msgid is None:
|
|
return None
|
|
|
|
return (msgctxt, msgid)
|
|
|
|
|
|
def po_quote(s):
|
|
return '"' + s.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n") + '"'
|
|
|
|
|
|
def clean_conflict_msgstr(entry):
|
|
"""
|
|
Ripulisce i msgstr sporchi generati da merge gettext tipo:
|
|
|
|
#-#-#-#-# file1.po #-#-#-#-#
|
|
Traduzione vecchia
|
|
#-#-#-#-# file2.po #-#-#-#-#
|
|
Traduzione nuova
|
|
|
|
Tiene solo l'ultima traduzione utile.
|
|
"""
|
|
|
|
if "#-#-#-#-#" not in entry:
|
|
return entry
|
|
|
|
lines = entry.splitlines()
|
|
new_lines = []
|
|
i = 0
|
|
|
|
while i < len(lines):
|
|
stripped = lines[i].strip()
|
|
|
|
if stripped.startswith("msgstr "):
|
|
msgstr_value, end_i = read_po_string(lines, i)
|
|
|
|
if "#-#-#-#-#" in msgstr_value:
|
|
parts = re.split(
|
|
r'#-#-#-#-#.*?#-#-#-#-#\n?',
|
|
msgstr_value,
|
|
flags=re.DOTALL
|
|
)
|
|
|
|
parts = [p.strip() for p in parts if p.strip()]
|
|
chosen = parts[-1] if parts else ""
|
|
|
|
new_lines.append('msgstr ""')
|
|
|
|
if chosen:
|
|
new_lines.append(po_quote(chosen))
|
|
else:
|
|
new_lines.extend(lines[i:end_i + 1])
|
|
|
|
i = end_i + 1
|
|
continue
|
|
|
|
if re.match(r"msgstr\[[0-9]+\]\s+", stripped):
|
|
msgstr_value, end_i = read_po_string(lines, i)
|
|
|
|
if "#-#-#-#-#" in msgstr_value:
|
|
parts = re.split(
|
|
r'#-#-#-#-#.*?#-#-#-#-#\n?',
|
|
msgstr_value,
|
|
flags=re.DOTALL
|
|
)
|
|
|
|
parts = [p.strip() for p in parts if p.strip()]
|
|
chosen = parts[-1] if parts else ""
|
|
|
|
prefix = stripped.split(None, 1)[0]
|
|
new_lines.append(f'{prefix} ""')
|
|
|
|
if chosen:
|
|
new_lines.append(po_quote(chosen))
|
|
else:
|
|
new_lines.extend(lines[i:end_i + 1])
|
|
|
|
i = end_i + 1
|
|
continue
|
|
|
|
new_lines.append(lines[i])
|
|
i += 1
|
|
|
|
return "\n".join(new_lines) + "\n"
|
|
|
|
|
|
entries = split_entries(content)
|
|
|
|
header_entries = []
|
|
normal_entries = []
|
|
|
|
for entry in entries:
|
|
if not entry.strip():
|
|
continue
|
|
|
|
key = entry_key(entry)
|
|
|
|
# Header gettext: msgid ""
|
|
if key == (None, ""):
|
|
header_entries.append(clean_conflict_msgstr(entry))
|
|
continue
|
|
|
|
if key is None:
|
|
header_entries.append(entry)
|
|
continue
|
|
|
|
normal_entries.append((key, clean_conflict_msgstr(entry)))
|
|
|
|
|
|
# Tiene SOLO l'ultima occorrenza per ogni coppia msgctxt/msgid.
|
|
last_by_key = {}
|
|
order = []
|
|
|
|
for key, entry in normal_entries:
|
|
if key not in last_by_key:
|
|
order.append(key)
|
|
|
|
last_by_key[key] = entry
|
|
|
|
|
|
with open(output_file, "w", encoding="utf-8") as f:
|
|
for entry in header_entries:
|
|
f.write(entry.rstrip())
|
|
f.write("\n\n")
|
|
|
|
for key in order:
|
|
f.write(last_by_key[key].rstrip())
|
|
f.write("\n\n")
|