# Copyright 2004-2023 Tom Rothamel # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. init python: import re import tempfile if persistent.translate_language is None: persistent.translate_language = "english" if persistent.generate_empty_strings is None: persistent.generate_empty_strings = True if persistent.replace_translations is None: persistent.replace_translations = False if persistent.reverse_languages is None: persistent.reverse_languages = False def CheckLanguage(): return SensitiveIf(re.match(r'^\w+$', persistent.translate_language)) strings_json = None def get_strings_json(): global strings_json if strings_json is not None: return strings_json try: tempdir = os.path.join(config.basedir, "tmp") try: os.makedirs(os.path.join(config.basedir, "tmp")) except Exception: pass write_test = os.path.join(tempdir, "writetest.txt") if os.path.exists(write_test): os.unlink(write_test) with open(write_test, "w"): pass os.unlink(write_test) except Exception: tempdir = tempfile.mkdtemp() strings_json = os.path.join(tempdir, "strings.json") return strings_json screen translate: default tt = Tooltip(None) $ state = AndroidState() frame: style_group "l" style "l_root" window: has vbox label _("Translations: [project.current.display_name!q]") add HALF_SPACER hbox: # Left side. frame: style "l_indent" xmaximum ONEHALF xfill True has vbox frame: style "l_indent" has vbox text _("Language:") add HALF_SPACER frame style "l_indent": input style "l_default": value FieldInputValue(persistent, "translate_language") size 24 color INPUT_COLOR allow interface.TRANSLATE_LETTERS # Left side. frame: style "l_indent" xmaximum ONEHALF xfill True has vbox frame: style "l_indent" has vbox text _("The language to work with. This should only contain lower-case ASCII characters and underscores.") add SPACER hbox: frame: style "l_indent" xmaximum ONEHALF xfill True has vbox add SEPARATOR2 add HALF_SPACER frame: style "l_indent" has vbox textbutton _("Generate Translations"): text_size 24 action [ CheckLanguage(), Jump("generate_translations") ] add HALF_SPACER textbutton _("Generate empty strings for translations") style "l_checkbox" action ToggleField(persistent, "generate_empty_strings") frame: style "l_indent" xmaximum ONEHALF xfill True has vbox add SEPARATOR2 frame: style "l_indent" top_padding 10 has vbox text _("Generates or updates translation files. The files will be placed in game/tl/[persistent.translate_language!q].") add SPACER hbox: frame: style "l_indent" xmaximum ONEHALF xfill True has vbox add SEPARATOR2 add HALF_SPACER frame: style "l_indent" has vbox textbutton _("Extract String Translations"): action [ CheckLanguage(), Jump("extract_strings") ] textbutton _("Merge String Translations"): action [ CheckLanguage(), Jump("merge_strings") ] add HALF_SPACER textbutton _("Replace existing translations") style "l_checkbox" action ToggleField(persistent, "replace_translations") textbutton _("Reverse languages") style "l_checkbox" action ToggleField(persistent, "reverse_languages") add HALF_SPACER textbutton _("Update Default Interface Translations"): action [ Jump("update_renpy_strings") ] frame: style "l_indent" xmaximum ONEHALF xfill True has vbox add SEPARATOR2 frame: style "l_indent" top_padding 10 has vbox text _("The extract command allows you to extract string translations from an existing project into a temporary file.\n\nThe merge command merges extracted translations into another project.") textbutton _("Return") action Jump("front_page") style "l_left_button" label translate: call screen translate # Common code to create the new translations in the current game. label generate_translations_common: python: language = persistent.translate_language args = [ "translate", language ] if language == "rot13": args.append("--rot13") elif language == "piglatin": args.append("--piglatin") elif persistent.generate_empty_strings: args.append("--empty") interface.processing(_("Ren'Py is generating translations....")) project.current.launch(args, wait=True) project.current.update_dump(force=True) return # Code to generate translations by themselves. label generate_translations: call generate_translations_common python: interface.info(_("Ren'Py has finished generating [language] translations.")) jump front_page label extract_strings: python: language = persistent.translate_language args = [ "extract_strings", language, get_strings_json() ] interface.processing(_("Ren'Py is extracting string translations...")) project.current.launch(args, wait=True) interface.info(_("Ren'Py has finished extracting [language] string translations.")) jump front_page label merge_strings: call generate_translations_common python: language = persistent.translate_language args = [ "merge_strings", language, get_strings_json() ] if persistent.replace_translations: args.append("--replace") if persistent.reverse_languages: args.append("--reverse") interface.processing(_("Ren'Py is merging string translations...")) project.current.launch(args, wait=True) interface.info(_("Ren'Py has finished merging [language] string translations.")) jump front_page label update_renpy_strings_common: python: language = _preferences.language interface.processing(_("Updating default interface translations...")) renpy.translation.extract.extract_strings_core(language, get_strings_json()) args = [ "translate", "None", "--common-only", "--strings-only", "--max-priority", "399", "--no-todo" ] project.current.launch(args, wait=True) args = [ "merge_strings", "None", get_strings_json() ] project.current.launch(args, wait=True) return label update_renpy_strings: call update_renpy_strings_common jump front_page screen extract_dialogue: frame: style_group "l" style "l_root" window: has vbox label _("Extract Dialogue: [project.current.display_name!q]") add HALF_SPACER frame: style "l_indent" xfill True has vbox add SEPARATOR2 frame: style "l_indent" has vbox text _("Format:") add HALF_SPACER frame: style "l_indent" has vbox textbutton _("Tab-delimited Spreadsheet (dialogue.tab)") action SetField(persistent, "dialogue_format", "tab") textbutton _("Dialogue Text Only (dialogue.txt)") action SetField(persistent, "dialogue_format", "txt") add SPACER add SEPARATOR2 frame: style "l_indent" has vbox text _("Options:") add HALF_SPACER textbutton _("Strip text tags from the dialogue.") action ToggleField(persistent, "dialogue_notags") style "l_checkbox" textbutton _("Escape quotes and other special characters.") action ToggleField(persistent, "dialogue_escape") style "l_checkbox" textbutton _("Extract all translatable strings, not just dialogue.") action ToggleField(persistent, "dialogue_strings") style "l_checkbox" add SPACER add SEPARATOR2 frame: style "l_indent" has vbox text _("Language (or None for the default language):") input style "l_default": value FieldInputValue(persistent, "extract_language") size 24 color INPUT_COLOR allow interface.TRANSLATE_LETTERS textbutton _("Cancel") action Jump("front_page") style "l_left_button" textbutton _("Continue") action Jump("start_extract_dialogue") style "l_right_button" label extract_dialogue: $persistent.extract_language = persistent.extract_language or "None" call screen extract_dialogue label start_extract_dialogue: python: language = persistent.extract_language args = [ "dialogue", language] if persistent.dialogue_format == "txt": args.append("--text") if persistent.dialogue_strings: args.append("--strings") if persistent.dialogue_notags: args.append("--notags") if persistent.dialogue_escape: args.append("--escape") interface.processing(_("Ren'Py is extracting dialogue....")) project.current.launch(args, wait=True) project.current.update_dump(force=True) interface.info(_("Ren'Py has finished extracting dialogue. The extracted dialogue can be found in dialogue.[persistent.dialogue_format] in the base directory.")) jump front_page