96 lines
3.1 KiB
Python
96 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
|
|
"""Build the static mod-playerbots ruRU SQL update from a reviewed TSV file."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import csv
|
|
import re
|
|
from collections import Counter
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
INPUT = ROOT / "playerbots-phrases-ru-reviewed.tsv"
|
|
OUTPUT = (
|
|
ROOT
|
|
/ "modules/mod-playerbots/data/sql/playerbots/updates/"
|
|
/ "2026_07_30_00_ai_playerbot_russian_texts.sql"
|
|
)
|
|
EXPECTED_FIELDS = ("id", "key", "original_en", "translation_ru")
|
|
PLACEHOLDER_RE = re.compile(r"%[A-Za-z_][A-Za-z0-9_]*|<[^>]+>")
|
|
|
|
|
|
def sql_quote(value: str) -> str:
|
|
return "'" + value.replace("\\", "\\\\").replace("'", "\\'") + "'"
|
|
|
|
|
|
def load_rows() -> list[dict[str, str]]:
|
|
with INPUT.open(encoding="utf-8-sig", newline="") as input_file:
|
|
reader = csv.DictReader(input_file, delimiter="\t")
|
|
if tuple(reader.fieldnames or ()) != EXPECTED_FIELDS:
|
|
raise RuntimeError(
|
|
f"Unexpected TSV columns: {reader.fieldnames}; "
|
|
f"expected {EXPECTED_FIELDS}"
|
|
)
|
|
rows = list(reader)
|
|
|
|
if not rows:
|
|
raise RuntimeError(f"No translations found in {INPUT}")
|
|
|
|
seen_ids: set[int] = set()
|
|
for line_number, row in enumerate(rows, start=2):
|
|
try:
|
|
row_id = int(row["id"])
|
|
except ValueError as error:
|
|
raise RuntimeError(
|
|
f"{INPUT}:{line_number}: invalid id {row['id']!r}"
|
|
) from error
|
|
|
|
if row_id in seen_ids:
|
|
raise RuntimeError(f"{INPUT}:{line_number}: duplicate id {row_id}")
|
|
seen_ids.add(row_id)
|
|
|
|
if not row["key"]:
|
|
raise RuntimeError(f"{INPUT}:{line_number}: empty key")
|
|
if not row["translation_ru"].strip():
|
|
raise RuntimeError(f"{INPUT}:{line_number}: empty translation")
|
|
|
|
source_placeholders = Counter(PLACEHOLDER_RE.findall(row["original_en"]))
|
|
target_placeholders = Counter(PLACEHOLDER_RE.findall(row["translation_ru"]))
|
|
if source_placeholders != target_placeholders:
|
|
raise RuntimeError(
|
|
f"{INPUT}:{line_number}: placeholder mismatch: "
|
|
f"{source_placeholders} != {target_placeholders}"
|
|
)
|
|
|
|
return rows
|
|
|
|
|
|
def write_sql(rows: list[dict[str, str]]) -> None:
|
|
lines = [
|
|
"-- MoonWell static Russian localization for mod-playerbots.",
|
|
f"-- Generated from {INPUT.name}; edit the TSV and rebuild, not this file.",
|
|
"-- Placeholder names and counts are validated; their order may differ in Russian.",
|
|
"SET NAMES utf8mb4;",
|
|
"",
|
|
"START TRANSACTION;",
|
|
]
|
|
for row in rows:
|
|
lines.append(
|
|
"UPDATE `ai_playerbot_texts` "
|
|
f"SET `text_loc8`={sql_quote(row['translation_ru'])} "
|
|
f"WHERE `id`={int(row['id'])} AND `name`={sql_quote(row['key'])};"
|
|
)
|
|
lines.extend(["COMMIT;", ""])
|
|
OUTPUT.write_text("\n".join(lines), encoding="utf-8")
|
|
print(f"Wrote {len(rows)} reviewed translations to {OUTPUT}")
|
|
|
|
|
|
def main() -> None:
|
|
write_sql(load_rows())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|