Skip to content

Commit 448707e

Browse files
committed
Forbid to use curly brackets in msg translations, ref BGforgeNet/Fallout2_Restoration_Project#336
1 parent 4dfb13d commit 448707e

2 files changed

Lines changed: 49 additions & 25 deletions

File tree

msg2po/core.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"context": "{{{index}}}{{{context}}}{{{value}}}\n",
3232
"female": "separate",
3333
},
34+
"forbidden_characters": ["{", "}"],
3435
},
3536
"sve": {
3637
"pattern": r"(\d+):(.*)",
@@ -41,6 +42,7 @@
4142
"default": "{index}:{value}\n",
4243
"female": "separate",
4344
},
45+
"forbidden_characters": [],
4446
},
4547
"txt": {
4648
"pattern": r"(\d+):(.*)",
@@ -52,6 +54,7 @@
5254
"default": "{index}:{value}\n",
5355
"female": "separate",
5456
},
57+
"forbidden_characters": [],
5558
},
5659
"tra": {
5760
"pattern": r"@(\d+)\s*?=\s*?~([^~]*?)~(?:\s)?(?:\[([^]]*)\])?(?:~([^~]*)~)?",
@@ -65,6 +68,7 @@
6568
"context": "@{index} = ~{value}~ [{context}]\n",
6669
"female": "@{index} = ~{value}~ ~{female}~\n",
6770
},
71+
"forbidden_characters": [],
6872
},
6973
}
7074

@@ -542,6 +546,14 @@ def get_line_format(e, ext: str):
542546
"""
543547
ff = FILE_FORMAT[ext]
544548
line_format = ff["line_format"]
549+
550+
forbidden_characters = ff["forbidden_characters"]
551+
for fc in forbidden_characters:
552+
if fc in e["value"]:
553+
print(f"ERROR: {ext} strings may not contain '{fc}' character")
554+
print(f"\t\tentry: {e}")
555+
raise ValueError("Invalid translation character")
556+
545557
if e["context"] is not None: # entry with context
546558
lfrm = line_format["context"]
547559
elif (
@@ -789,6 +801,7 @@ def __init__(self, filepath: str, is_source: False, encoding=CONFIG.encoding):
789801
self.pattern = self.fformat["pattern"]
790802
self.dotall = self.fformat["dotall"]
791803
self.filepath = filepath
804+
self.forbidden_characters = self.fformat["forbidden_characters"]
792805

793806
try: # comment for all entries in file
794807
self.comment = self.fformat["comment"]
@@ -827,6 +840,12 @@ def __init__(self, filepath: str, is_source: False, encoding=CONFIG.encoding):
827840
entry.occurence = (filepath, str(index))
828841
entry.value = str(line[self.fformat["value"]])
829842

843+
for fc in self.forbidden_characters:
844+
if fc in entry.value:
845+
print(f"ERROR: {fext} strings may not contain '{fc}' character")
846+
print(f"\t\tentry: {entry}")
847+
raise ValueError("Invalid translation character")
848+
830849
# skip invalid '000' entries in MSG files
831850
if fext == "msg" and index == "000":
832851
print(

msg2po/unpoify.py

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
#!/usr/bin/env python3
2-
# coding: utf-8
32

43
import os
54
import argparse
65
import sys
7-
from multiprocessing import Pool
6+
import concurrent.futures
87
from polib import pofile
9-
from functools import partial
108
from msg2po.core import (
119
CONFIG,
1210
LanguageMap,
@@ -37,8 +35,9 @@ def extract_po(pf: str, language_map: LanguageMap):
3735
pf is po file basename
3836
"""
3937
po_path = os.path.join(CONFIG.po_dirname, pf)
40-
print("processing {}".format(po_path))
41-
po = pofile(po_path) # open once
38+
print(f"processing {po_path}")
39+
# Open PO once, it's a heavy op
40+
po = pofile(po_path)
4241
trans_map = translation_entries(po)
4342
female_map = female_entries(po)
4443

@@ -47,38 +46,44 @@ def extract_po(pf: str, language_map: LanguageMap):
4746
for ef in sorted(trans_map):
4847
enc = get_enc(po_path, ef)
4948
ef_extract_path = os.path.join(dst_dir, ef)
50-
print("Extracting {} from {} into {} with encoding {}".format(ef, po_path, ef_extract_path, enc))
49+
print(f"Extracting {ef} from {po_path} into {ef_extract_path} with encoding {enc}")
5150
po2file(po, ef_extract_path, enc, ef, dst_dir=dst_dir, trans_map=trans_map, female_map=female_map)
5251

5352
enc = get_enc(po_path)
54-
print("Extracted {} into {} with encoding {}".format(po_path, dst_dir, enc))
53+
print(f"Extracted {po_path} into {dst_dir} with encoding {enc}")
5554

5655

5756
def main():
5857
po_dir = CONFIG.po_dir
5958
language_map = LanguageMap()
6059

61-
# find PO files
62-
po_files = []
63-
for dir_name, subdir_list, file_list in os.walk(po_dir):
64-
for f in file_list:
65-
if get_ext(f) == "po":
66-
po_files.append(f)
67-
if po_files == []:
68-
print("no PO files found in directory {}".format(po_dir))
60+
# Find PO files
61+
po_files = [f for _, _, files in os.walk(po_dir) for f in files if get_ext(f) == "po"]
62+
63+
if not po_files:
64+
print(f"no PO files found in directory {po_dir}")
6965
sys.exit(1)
7066

7167
with cd(CONFIG.tra_dir):
72-
# extract PO files
73-
pool = Pool()
74-
try:
75-
r = pool.map_async(partial(extract_po, language_map=language_map), po_files)
76-
pool.close()
77-
codes = r.get() # noqa: F841 - need to get results to see if there's an exception
78-
except KeyboardInterrupt:
79-
pool.terminate()
80-
finally:
81-
pool.join()
68+
with concurrent.futures.ProcessPoolExecutor() as executor:
69+
futures = {executor.submit(extract_po, pf, language_map): pf for pf in po_files}
70+
71+
for future in concurrent.futures.as_completed(futures):
72+
pf = futures[future]
73+
try:
74+
future.result()
75+
except ValueError as e:
76+
print(f"ValueError in file {pf}: {e}")
77+
executor.shutdown(wait=False, cancel_futures=True)
78+
sys.exit(1)
79+
except KeyboardInterrupt:
80+
print("Interrupted by user, terminating execution...")
81+
executor.shutdown(wait=False, cancel_futures=True)
82+
sys.exit(1)
83+
except Exception as e:
84+
print(f"Unhandled exception in file {pf}: {e}")
85+
executor.shutdown(wait=False, cancel_futures=True)
86+
sys.exit(1)
8287

8388

8489
if __name__ == "__main__":

0 commit comments

Comments
 (0)