LoafyLemon
5c952fe7da
* Added language switch option (WIP) * Fixed translation generation cache cleanup * Fixed python strings being untranslatable (partially)
212 lines
6.9 KiB
Plaintext
212 lines
6.9 KiB
Plaintext
rpy python 3
|
|
|
|
init python in cli:
|
|
import os
|
|
import collections
|
|
import itertools
|
|
from renpy.translation import quote_unicode
|
|
from renpy.parser import elide_filename
|
|
|
|
tl_file_cache = {}
|
|
|
|
def open_tl_file(fn, mode):
|
|
|
|
if fn in tl_file_cache:
|
|
f = tl_file_cache[fn]
|
|
|
|
if f.mode == mode:
|
|
return f
|
|
|
|
# elif not f.closed:
|
|
# # PY 2 only
|
|
# f.close()
|
|
|
|
if not os.path.exists(fn):
|
|
dn = os.path.dirname(fn)
|
|
|
|
try:
|
|
os.makedirs(dn)
|
|
except Exception:
|
|
pass
|
|
|
|
f = open(fn, mode, encoding="utf-8")
|
|
f.write(u"\ufeff")
|
|
|
|
else:
|
|
f = open(fn, mode, encoding="utf-8")
|
|
|
|
tl_file_cache[fn] = f
|
|
|
|
return f
|
|
|
|
def scan_strings(strings, min_priority=0, max_priority=299, common_only=False):
|
|
|
|
strings.sort(key=lambda s : s.sort_key)
|
|
|
|
rv = [ ]
|
|
seen = set()
|
|
|
|
for s in strings:
|
|
|
|
if s.priority < min_priority:
|
|
continue
|
|
|
|
if s.priority > max_priority:
|
|
continue
|
|
|
|
if common_only and not s.common:
|
|
continue
|
|
|
|
if s.text in seen:
|
|
continue
|
|
|
|
seen.add(s.text)
|
|
rv.append(s)
|
|
|
|
return rv
|
|
|
|
def write_strings(language, strings):
|
|
|
|
stl = renpy.game.script.translator.strings[language]
|
|
stringfiles = collections.defaultdict(list)
|
|
seen = set()
|
|
|
|
nstrings = len(strings)-1
|
|
|
|
for i, s in enumerate(strings):
|
|
n = round(float(i)/(nstrings)*100)
|
|
print("\rGenerating strings for {} ... Total progress:{} % ... Stage 2/2".format(language, n), end="")
|
|
|
|
tlfn = renpy.translation.generation.translation_filename(s)
|
|
|
|
if tlfn is None:
|
|
continue
|
|
|
|
if s.text in seen:
|
|
continue
|
|
|
|
seen.add(s.text)
|
|
|
|
if language == "None" and tlfn == "common.rpy":
|
|
tlfn = "common.rpym"
|
|
|
|
stringfiles[tlfn].append(s)
|
|
|
|
for tlfn, sl in list(stringfiles.items()):
|
|
tlfn = os.path.join(renpy.config.gamedir, renpy.config.tl_directory, language, tlfn)
|
|
|
|
f = open_tl_file(tlfn, mode="w")
|
|
f.write(u"translate {} strings:\n".format(language))
|
|
f.write(u"\n")
|
|
|
|
for s in sl:
|
|
original = s.text
|
|
translation = stl.translate(s.text) # Keeps translated strings
|
|
|
|
f.write(u" # {}:{}\n".format(elide_filename(s.filename), s.line))
|
|
f.write(u" old \"{}\"\n".format(quote_unicode(original)))
|
|
f.write(u" new \"{}\"\n".format(quote_unicode(translation)))
|
|
f.write(u"\n")
|
|
|
|
def retranslate():
|
|
translator = renpy.game.script.translator
|
|
generation = renpy.translation.generation
|
|
scanstrings = renpy.translation.scanstrings
|
|
|
|
parser = renpy.arguments.ArgumentParser()
|
|
parser.add_argument("--rebuild", action="store_true", help="Rebuilds the translation pointers and adds missing entries.")
|
|
parser.add_argument("--empty", action="store_true", help="When combined with rebuild parameter, it will insert an empty string into added entires. Does nothing on its own.")
|
|
parser.add_argument("--clean", action="store_true", help="Removes translation files that are no longer present within the game files.")
|
|
parser.add_argument("--dry", action="store_true", help="Simulates the removal of translation files that are no longer present within the game files.")
|
|
parser.add_argument("--include-mods", action="store_true", help="Include mod files when generating translations.")
|
|
args = parser.parse_args()
|
|
|
|
scripts = generation.translate_list_files()
|
|
|
|
if not args.include_mods:
|
|
mods_dir = os.path.join(renpy.config.gamedir, "mods")
|
|
scripts = [f for f in scripts if not f.startswith(mods_dir)]
|
|
|
|
strings = []
|
|
nscripts = len(scripts)-1
|
|
|
|
for i, filepath in enumerate(scripts):
|
|
n = round(float(i)/(nscripts)*100)
|
|
|
|
for language in translator.languages:
|
|
|
|
print("\rGenerating dialogues for {} ... Total progress:{} % ... Stage 1/2".format(language, n), end="")
|
|
|
|
for _, trans in translator.file_translates[filepath]:
|
|
|
|
trans_new = translator.language_translates.get((trans.identifier, language))
|
|
filter = generation.null_filter
|
|
|
|
if trans_new is None:
|
|
if not args.rebuild:
|
|
continue
|
|
|
|
trans_new = trans
|
|
|
|
if args.empty:
|
|
filter = generation.empty_filter
|
|
|
|
if hasattr(trans, "alternate") and (trans.alternate, language) in translator.language_translates:
|
|
continue
|
|
|
|
fp = os.path.relpath(filepath, renpy.config.gamedir)
|
|
fp = os.path.join(renpy.config.gamedir, renpy.config.tl_directory, language, fp)
|
|
|
|
f = open_tl_file(fp, mode="w")
|
|
|
|
f.write(u"# {}:{}\n".format(trans.filename, trans.linenumber))
|
|
f.write(u"translate {} {}:\n".format(language, trans.identifier.replace(".", "_")))
|
|
f.write(u"\n")
|
|
|
|
for n in trans.block:
|
|
f.write(u" # " + n.get_code() + "\n")
|
|
|
|
for n in trans_new.block:
|
|
f.write(u" " + n.get_code(filter) + "\n")
|
|
|
|
f.write(u"\n")
|
|
|
|
strings.extend(scanstrings.scan_strings(filepath))
|
|
|
|
strings = scan_strings(strings)
|
|
|
|
for language in translator.languages:
|
|
|
|
write_strings(language, strings)
|
|
|
|
if args.clean:
|
|
translations = [f for f in renpy.list_files() if f.startswith(renpy.config.tl_directory) and f.endswith((".rpy", ".rpym"))]
|
|
|
|
for filepath in translations:
|
|
fn = os.path.basename(filepath)
|
|
fp = os.path.relpath(filepath, os.path.join(renpy.config.tl_directory, language))
|
|
fp = os.path.join(renpy.config.gamedir, fp)
|
|
|
|
if fp not in scripts:
|
|
if fn == "common.rpy":
|
|
continue
|
|
|
|
if filepath in tl_file_cache:
|
|
f = tl_file_cache.pop(tl_file_cache)
|
|
f.close()
|
|
|
|
if args.dry:
|
|
print("Removal required: {}".format(filepath))
|
|
else:
|
|
os.unlink(filepath)
|
|
os.unlink(filepath + "c")
|
|
|
|
for f in list(tl_file_cache.values()):
|
|
f.close()
|
|
|
|
tl_file_cache.clear()
|
|
|
|
return False
|
|
|
|
renpy.arguments.register_command("retranslate", retranslate)
|