From 74e6f22d86681803af74f6b359daaab2a3c3cda2 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Fri, 23 Aug 2024 23:28:44 -0700 Subject: [PATCH 1/9] Ensure the languages dict property is at least always defined --- MCprep_addon/conf.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/MCprep_addon/conf.py b/MCprep_addon/conf.py index b8cc5a95..ff4a62c4 100644 --- a/MCprep_addon/conf.py +++ b/MCprep_addon/conf.py @@ -143,14 +143,15 @@ def __init__(self): # i18n using Python's gettext module # # This only runs if translations.py does not exist + self.languages: dict[str, gettext.NullTranslations] = {} try: if not self.translations.exists(): - self.languages: dict[str, gettext.NullTranslations] = {} for language in self.languages_folder.iterdir(): - self.languages[language.name] = gettext.translation("mcprep", - self.languages_folder, - fallback=True, - languages=[language.name]) + self.languages[language.name] = gettext.translation( + "mcprep", + self.languages_folder, + fallback=True, + languages=[language.name]) self.use_direct_i18n = True self.log("Loaded direct i18n!") From 982d02906fb5706fba487d1e62fc9fb4e4d08482 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Fri, 23 Aug 2024 23:29:24 -0700 Subject: [PATCH 2/9] Other style cleanup of the conf style for pep8 --- MCprep_addon/conf.py | 81 ++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/MCprep_addon/conf.py b/MCprep_addon/conf.py index ff4a62c4..2b3a9151 100644 --- a/MCprep_addon/conf.py +++ b/MCprep_addon/conf.py @@ -27,6 +27,7 @@ import bpy from bpy.utils.previews import ImagePreviewCollection +import bpy.utils.previews # ----------------------------------------------------------------------------- @@ -57,20 +58,13 @@ class Engine(enum.Enum): Skin = Tuple[str, Path] Entity = Tuple[str, str, str] -# Represents an unknown location -# for MCprepError. Given a global +# Represents an unknown location +# for MCprepError. Given a global # constant to make it easier to use # and check for UNKNOWN_LOCATION = (-1, "UNKNOWN LOCATION") DEBUG_MODE = False -# check if custom preview icons available -try: - import bpy.utils.previews -except: - print("MCprep: No custom icons in this blender instance") - pass - # ----------------------------------------------------------------------------- # ADDON GLOBAL VARIABLES AND INITIAL SETTINGS @@ -81,11 +75,14 @@ class MCprepEnv: def __init__(self): self.data = None self.json_data: Optional[Dict] = None - self.json_path: Path = Path(os.path.dirname(__file__), "MCprep_resources", "mcprep_data.json") - self.json_path_update: Path = Path(os.path.dirname(__file__), "MCprep_resources", "mcprep_data_update.json") + self.json_path: Path = Path( + os.path.dirname(__file__), "MCprep_resources", "mcprep_data.json") + self.json_path_update: Path = Path( + os.path.dirname(__file__), "MCprep_resources", "mcprep_data_update.json") self.dev_file: Path = Path(os.path.dirname(__file__), "mcprep_dev.txt") - self.languages_folder: Path = Path(os.path.dirname(__file__), "MCprep_resources", "Languages") + self.languages_folder: Path = Path( + os.path.dirname(__file__), "MCprep_resources", "Languages") self.translations: Path = Path(os.path.dirname(__file__), "translations.py") self.last_check_for_updated = 0 @@ -137,7 +134,7 @@ def __init__(self): # that no reading has occurred. If lib not found, will update to []. # If ever changing the resource pack, should also reset to None. self.material_sync_cache: List = [] - + # Whether we use PO files directly or use the converted form self.use_direct_i18n = False # i18n using Python's gettext module @@ -159,7 +156,6 @@ def __init__(self): self.languages = {} self.log("Exception occured while loading translations!") - # This allows us to translate strings on the fly def _(self, msg: str) -> str: if not self.use_direct_i18n: @@ -258,14 +254,14 @@ def current_line_and_file(self) -> Tuple[int, str]: MCprepError. This function can not return an MCprepError value as doing - so would be more complicated for the caller. As such, if - this fails, we return values -1 and "UNKNOWN LOCATION" to - indicate that we do not know the line number or file path + so would be more complicated for the caller. As such, if + this fails, we return values -1 and "UNKNOWN LOCATION" to + indicate that we do not know the line number or file path the error occured on. Returns: - - If success: Tuple[int, str] representing the current - line and file path + - If success: Tuple[int, str] representing the current + line and file path - If fail: (-1, "UNKNOWN LOCATION") """ @@ -274,10 +270,10 @@ def current_line_and_file(self) -> Tuple[int, str]: cur_frame = inspect.currentframe() if not cur_frame: return UNKNOWN_LOCATION - + # Get the previous frame since the # current frame is made for this function, - # not the function/code that called + # not the function/code that called # this function prev_frame = cur_frame.f_back if not prev_frame: @@ -286,50 +282,45 @@ def current_line_and_file(self) -> Tuple[int, str]: frame_info = inspect.getframeinfo(prev_frame) return frame_info.lineno, frame_info.filename + @dataclass class MCprepError(object): """ - Object that is returned when + Object that is returned when an error occurs. This is meant - to give more information to the - caller so that a better error + to give more information to the + caller so that a better error message can be made Attributes ------------ err_type: BaseException - The error type; uses standard + The error type; uses standard Python exceptions - + line: int - Line the exception object was - created on. The preferred method - to do this is to use currentframe - and getframeinfo from the inspect + Line the exception object was + created on. The preferred method + to do this is to use currentframe + and getframeinfo from the inspect module file: str Path of file the exception object - was created in. The preferred way + was created in. The preferred way to get this is __file__ msg: Optional[str] - Optional message to display for an - exception. Use this if the exception + Optional message to display for an + exception. Use this if the exception type may not be so clear cut """ err_type: BaseException - line: int + line: int file: str msg: Optional[str] = None -# Requires Extension support and building with the proper wheels -if DEBUG_MODE and bpy.app.version >= (4, 2, 0): - import debugpy - debugpy.listen(("localhost", 5678)) - -env = MCprepEnv() def updater_select_link_function(self, tag): """Indicates what zip file to use for updating from a tag structure. @@ -348,6 +339,16 @@ def updater_select_link_function(self, tag): # GLOBAL REGISTRATOR INIT # ----------------------------------------------------------------------------- + +# Requires Extension support and building with the proper wheels +if DEBUG_MODE and bpy.app.version >= (4, 2, 0): + import debugpy + debugpy.listen(("localhost", 5678)) + + +env = MCprepEnv() + + def register(): global env if not env.json_data: From f0dae228094a98e32c904ea5dcc7c01c52e98cc3 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Sat, 24 Aug 2024 10:47:43 -0700 Subject: [PATCH 3/9] Correct indentation of translation loading mechanism --- MCprep_addon/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MCprep_addon/conf.py b/MCprep_addon/conf.py index 2b3a9151..7b2663de 100644 --- a/MCprep_addon/conf.py +++ b/MCprep_addon/conf.py @@ -149,8 +149,8 @@ def __init__(self): self.languages_folder, fallback=True, languages=[language.name]) - self.use_direct_i18n = True - self.log("Loaded direct i18n!") + self.use_direct_i18n = True + self.log("Loaded direct i18n!") except Exception: self.languages = {} From 4946d6a6f1ae634d71155650217ca622fc33c927 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Sat, 24 Aug 2024 17:09:47 -0700 Subject: [PATCH 4/9] Break down test runner timings and add translation step --- run_tests.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/run_tests.py b/run_tests.py index 2ca36091..2d3f7f3e 100644 --- a/run_tests.py +++ b/run_tests.py @@ -41,7 +41,7 @@ import time -COMPILE_CMD = ["bab", "-b", "dev"] +COMPILE_CMD = ["bab", "-b", "dev", "translate"] DATA_CMD = ["python", "mcprep_data_refresh.py", "-auto"] # TODO, include in build DCC_EXES = "blender_execs.txt" TEST_RUNNER = os.path.join("test_files", "test_runner.py") @@ -60,6 +60,7 @@ def __str__(self): def main(): + t0 = time.time() args = get_args() # Read arguments @@ -69,12 +70,21 @@ def main(): return # Compile the addon + if args.version: + # Just install into the only blender version we'll test anyways + COMPILE_CMD.extend(["-v", args.version]) + elif not args.all_execs: + # Just install into the first blender binary listed to match the tests + # TODO: get Blender version from the binary path at blender_execs[0] + # default_v = x + # COMPILE_CMD.extend(["-v", default_v]) + pass res = subprocess.check_output(COMPILE_CMD) print("Compile output:", res.decode("utf-8")) reset_test_file() # Loop over all binaries and run tests. - t0 = time.time() + t1 = time.time() any_failures = False for ind, binary in enumerate(blender_execs): run_all = args.all_execs is True @@ -104,15 +114,17 @@ def main(): if child.returncode != 0: any_failures = True - t1 = time.time() + t2 = time.time() # Especially ensure tracker files are removed after tests complete. remove_tracker_files() output_results() - round_s = round(t1 - t0) + compile_time = t1 - t0 + test_time = t2 - t1 exit_code = 1 if any_failures else 0 - print(f"tests took {round_s}s to run, ending with code {exit_code}") + print(f"Compiled in {compile_time:.1f}s, tests ran in {test_time:.1f}s") + print(f"Finished in {compile_time + test_time:.1f}s with code {exit_code}") sys.exit(exit_code) From b72a7a38bb79ae70ebffb464751344182ac4cfe6 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Sat, 24 Aug 2024 17:35:48 -0700 Subject: [PATCH 5/9] Adding translations test and some debug prints for troubleshooting Test is NOT yet passing/working, might need some peer assistance --- MCprep_addon/conf.py | 18 ++++++++--- test_files/addon_test.py | 66 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/MCprep_addon/conf.py b/MCprep_addon/conf.py index 7b2663de..39ee7c82 100644 --- a/MCprep_addon/conf.py +++ b/MCprep_addon/conf.py @@ -141,23 +141,31 @@ def __init__(self): # # This only runs if translations.py does not exist self.languages: dict[str, gettext.NullTranslations] = {} + self._load_translations() + + def _load_translations(self, prefix="") -> None: + """Loads in mo file translation maps""" try: if not self.translations.exists(): + print(prefix, "No translations.py, running in location: ", __file__, " with ", self.languages_folder) for language in self.languages_folder.iterdir(): + print(prefix, "In langdir:", language.name) self.languages[language.name] = gettext.translation( "mcprep", - self.languages_folder, + localedir=self.languages_folder, fallback=True, languages=[language.name]) + print(prefix, "Loaded: ", language.name) self.use_direct_i18n = True self.log("Loaded direct i18n!") - - except Exception: + except Exception as e: self.languages = {} - self.log("Exception occured while loading translations!") + self.log(f"Exception occured while loading translations! {e}") + print(prefix, "Exception", e) + #raise e - # This allows us to translate strings on the fly def _(self, msg: str) -> str: + """Allows us to translate strings on the fly""" if not self.use_direct_i18n: return msg if bpy.context.preferences.view.language in self.languages: diff --git a/test_files/addon_test.py b/test_files/addon_test.py index 60ab2bf2..49b038fd 100644 --- a/test_files/addon_test.py +++ b/test_files/addon_test.py @@ -16,14 +16,23 @@ # # ##### END GPL LICENSE BLOCK ##### +from pathlib import Path +import os import unittest import bpy +from MCprep_addon import conf + class AddonTest(unittest.TestCase): """Create addon level tests, and ensures enabled for later tests.""" + @staticmethod + def addon_path() -> Path: + scripts = bpy.utils.user_resource("SCRIPTS") + return Path(scripts, "addons", "MCprep_addon") + def test_enable(self): """Ensure the addon can be directly enabled.""" bpy.ops.preferences.addon_enable(module="MCprep_addon") @@ -33,6 +42,63 @@ def test_disable_enable(self): bpy.ops.preferences.addon_disable(module="MCprep_addon") bpy.ops.preferences.addon_enable(module="MCprep_addon") + def test_translations(self): + """Safely ensures translations are working fine still. + + Something go wrong, blender stuck in another language? Run in console: + bpy.context.preferences.view.language = "en_US" + """ + init_lang = bpy.context.preferences.view.language + try: + self._test_translation() + except Exception: + raise + finally: + bpy.context.preferences.view.language = init_lang + + def _test_translation(self): + """Ensure that creating the MCprep environment is error-free.""" + test_env = conf.MCprepEnv() + mcprep_dir = self.addon_path() + lang_folder = mcprep_dir / "MCprep_resources" / "Languages" + test_env.languages_folder = lang_folder + + print("Lang folder", lang_folder) + print("self.translations", test_env.use_direct_i18n) + print("Dir:", list(os.listdir(lang_folder))) + + # Don't assign translations, to force building the map in memory + # translations_py = mcprep_dir / "translations.py" + # test_env.translations = translations_py + + # Force load translations into this instance of MCprepEnv + test_env._load_translations(prefix=">>>\t") + + # TODO: Not working, above load encounters error + self.assertIn( + "en_US", test_env.languages, "Missing default translation key") + self.assertTrue( + test_env.use_direct_i18n, "use_direct_i18n should be True") + + # Magic string evaluations, will break if source po's change + test_translations = [ + ("ru_RU", "Restart blender", "Перезапустите блендер"), + ("zh_HANS", "Texture pack folder", "材质包文件夹"), + ("en_US", "Mob Spawner", "Mob Spawner"), + ] + for lang, src, dst in test_translations: + with self.subTest(lang): + # First ensure the mo files exist + self.assertTrue( + os.path.isfile( + lang_folder / lang / "LC_MESSAGES" / "mcprep.mo"), + f"Missing {lang}'s mo file") + + # TODO: Not working + bpy.context.preferences.view.language = lang + res = test_env._(src) + self.assertEqual(res, dst, f"Unexpected {lang} translation)") + if __name__ == '__main__': unittest.main(exit=False) From 524717e8ba05d8e773dfbcdc42d7b6f447aa7014 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Sat, 24 Aug 2024 18:36:45 -0700 Subject: [PATCH 6/9] Fixed US translation and backported support for zh_CN pre blender 4.0 Likewise made the gitignore a little more strict for what we want --- .gitignore | 9 +- .../Languages/en_US/LC_MESSAGES/mcprep.po | 2 +- .../MCprep_resources/Languages/mcprep.pot | 4 +- .../Languages/zh_CN/LC_MESSAGES/mcprep.po | 596 ++++++++++++++++++ MCprep_addon/conf.py | 7 +- run_tests.py | 4 +- test_files/addon_test.py | 11 +- 7 files changed, 613 insertions(+), 20 deletions(-) create mode 100644 MCprep_addon/MCprep_resources/Languages/zh_CN/LC_MESSAGES/mcprep.po diff --git a/.gitignore b/.gitignore index 063983ea..89b3e625 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,12 @@ venv/ *.sublime-* MCprep_addon/import_bridge/conf MCprep_addon/import_bridge/nbt -MCprep_addon/MCprep_resources/ +MCprep_addon/MCprep_resources/*.blend +MCprep_addon/MCprep_resources/mcprep_data.json +MCprep_addon/MCprep_resources/effects +MCprep_addon/MCprep_resources/resourcepacks +MCprep_addon/MCprep_resources/rigs +MCprep_addon/MCprep_resources/skins +MCprep_addon/MCprep_resources/textures +!MCprep_addon/MCprep_resources/Languages/* MCprep_addon/.vscode diff --git a/MCprep_addon/MCprep_resources/Languages/en_US/LC_MESSAGES/mcprep.po b/MCprep_addon/MCprep_resources/Languages/en_US/LC_MESSAGES/mcprep.po index 81cd45e1..6cac66b6 100644 --- a/MCprep_addon/MCprep_resources/Languages/en_US/LC_MESSAGES/mcprep.po +++ b/MCprep_addon/MCprep_resources/Languages/en_US/LC_MESSAGES/mcprep.po @@ -14,7 +14,7 @@ msgstr "" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: MCprep_addon/mcprep_ui.py:98 diff --git a/MCprep_addon/MCprep_resources/Languages/mcprep.pot b/MCprep_addon/MCprep_resources/Languages/mcprep.pot index 942aff27..e0249fb7 100644 --- a/MCprep_addon/MCprep_resources/Languages/mcprep.pot +++ b/MCprep_addon/MCprep_resources/Languages/mcprep.pot @@ -1,9 +1,9 @@ # msgid "" msgstr "" -"Project-Id-Version: 3.6.1\n" +"Project-Id-Version: 3.6.1.1\n" "Report-Msgid-Bugs-To: https://github.com/Moo-Ack-Productions/MCprep/issues\n" -"POT-Creation-Date: 2024-08-22 21:18-0700\n" +"POT-Creation-Date: 2024-08-24 18:31-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/MCprep_addon/MCprep_resources/Languages/zh_CN/LC_MESSAGES/mcprep.po b/MCprep_addon/MCprep_resources/Languages/zh_CN/LC_MESSAGES/mcprep.po new file mode 100644 index 00000000..5a7a5b14 --- /dev/null +++ b/MCprep_addon/MCprep_resources/Languages/zh_CN/LC_MESSAGES/mcprep.po @@ -0,0 +1,596 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-02-03 22:03-0600\n" +"PO-Revision-Date: 2024-02-03 22:16-0600\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.4.1\n" + +#: MCprep_addon/mcprep_ui.py:98 +msgid "Restart blender" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:100 +msgid "to complete update" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:109 +msgid "Mob Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:111 +msgid "Menu for placing in the shift-A add object menu" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:121 +msgid "Load mobs" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:150 +msgid "Meshswap Objects" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:157 +msgid "No meshswap blocks found!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:179 +msgid "Item Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:185 +msgid "No items found!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:202 +msgid "Effects Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:245 +msgid "Entity Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:252 +msgid "No entities found!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:268 +msgid "Model Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:274 +msgid "No models found!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:314 +msgid "Load spawners" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:516 +msgid "World Importing & Meshswapping" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:520 +msgid "Default Exporter:" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:525 +msgid "jmc2obj executable" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:530 +msgid "Mineways executable" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:535 +msgid "World OBJ Exports Folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:540 +msgid "Meshwap assets" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:546 MCprep_addon/mcprep_ui.py:871 +#: MCprep_addon/mcprep_ui.py:1337 MCprep_addon/mcprep_ui.py:1485 +msgid "MeshSwap file not found" +msgstr "未找到网格变形文件" + +#: MCprep_addon/mcprep_ui.py:550 +msgid "Entity assets" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:556 MCprep_addon/mcprep_ui.py:1435 +msgid "Entity file not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:562 MCprep_addon/mcprep_ui.py:1658 +msgid "Effects folder not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:566 +msgid "Texture / Resource packs" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:570 MCprep_addon/mcprep_ui.py:843 +#: MCprep_addon/mcprep_ui.py:1651 +msgid "Texture pack folder" +msgstr "材质包文件夹" + +#: MCprep_addon/mcprep_ui.py:575 +msgid "Install to folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:579 +msgid "Open texture pack folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:584 +msgid "Mob spawning" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:588 +msgid "Rig Folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:593 +msgid "Select/install mobs" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:596 +msgid "Install file for mob spawning" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:598 +msgid "Open rig folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:603 MCprep_addon/mcprep_ui.py:675 +msgid "Skin swapping" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:607 +msgid "Skin Folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:612 +msgid "Install skins" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:614 +msgid "Install skin file for swapping" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:616 +msgid "Open skin folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:621 +msgid "Effects" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:625 +msgid "Effect folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:631 +msgid "Open effects folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:643 +msgid "Using MCprep in experimental mode!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:644 +msgid "Early access features and requests for feedback" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:645 +msgid "will be made visible. Thank you for contributing." +msgstr "" + +#: MCprep_addon/mcprep_ui.py:649 +msgid "Unsure on how to use the addon? Check out these resources" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:654 +msgid "MCprep page for instructions and updates" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:662 +msgid "Learn MCprep + Blender, 1-minute tutorials" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:669 +msgid "Import Minecraft worlds" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:672 +msgid "Mob (rig) spawning" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:681 +msgid "jmc2obj/Mineways" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:684 MCprep_addon/mcprep_ui.py:897 +msgid "World Tools" +msgstr "世界工具" + +#: MCprep_addon/mcprep_ui.py:687 +msgid "Tutorial Series" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:695 +msgid "Anonymous user tracking settings" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:704 +msgid "Opt into anonymous usage tracking" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:709 +msgid "Opt OUT of anonymous usage tracking" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:713 +msgid "For info on anonymous usage tracking:" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:716 +msgid "Open the Privacy Policy" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:725 +msgid "World Imports" +msgstr "导入地图" + +#: MCprep_addon/mcprep_ui.py:748 +msgid "World exporter" +msgstr "地图导出工具" + +#: MCprep_addon/mcprep_ui.py:759 MCprep_addon/mcprep_ui.py:787 +msgid "Select exporter!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:769 +msgid "OBJ world import" +msgstr "导入 OBJ 世界" + +#: MCprep_addon/mcprep_ui.py:773 MCprep_addon/mcprep_ui.py:1879 +msgid "MCprep tools" +msgstr "MCprep 工具" + +#: MCprep_addon/mcprep_ui.py:774 +msgid "Prep Materials" +msgstr "准备材质" + +#: MCprep_addon/mcprep_ui.py:781 +msgid "OBJ incompatible with textureswap" +msgstr "OBJ与纹理交换不兼容" + +#: MCprep_addon/mcprep_ui.py:785 +msgid "Mesh Swap" +msgstr "网格变形" + +#: MCprep_addon/mcprep_ui.py:807 +msgid "(UI already improved)" +msgstr "(UI 已经改善)" + +#: MCprep_addon/mcprep_ui.py:810 +msgid "Improve UI" +msgstr "改善 UI" + +#: MCprep_addon/mcprep_ui.py:817 +msgid "Cycles Optimizer" +msgstr "Cycles 优化器" + +#: MCprep_addon/mcprep_ui.py:829 MCprep_addon/mcprep_ui.py:836 +#: MCprep_addon/mcprep_ui.py:1023 MCprep_addon/mcprep_ui.py:1030 +#: MCprep_addon/mcprep_ui.py:1112 MCprep_addon/mcprep_ui.py:1212 +#: MCprep_addon/mcprep_ui.py:1219 MCprep_addon/mcprep_ui.py:1320 +#: MCprep_addon/mcprep_ui.py:1325 MCprep_addon/mcprep_ui.py:1390 +#: MCprep_addon/mcprep_ui.py:1394 MCprep_addon/mcprep_ui.py:1470 +#: MCprep_addon/mcprep_ui.py:1474 MCprep_addon/mcprep_ui.py:1549 +#: MCprep_addon/mcprep_ui.py:1553 MCprep_addon/mcprep_ui.py:1638 +#: MCprep_addon/mcprep_ui.py:1642 +msgid "Advanced" +msgstr "高级" + +#: MCprep_addon/mcprep_ui.py:859 +msgid "Combine Materials" +msgstr "合并材质" + +#: MCprep_addon/mcprep_ui.py:861 +msgid "Combine Images" +msgstr "合并图像" + +#: MCprep_addon/mcprep_ui.py:863 +msgid "Meshswap source:" +msgstr "网格变形源:" + +#: MCprep_addon/mcprep_ui.py:869 +msgid "MeshSwap file must be .blend" +msgstr "网格变形文件必须是.blend格式" + +#: MCprep_addon/mcprep_ui.py:880 +msgid "World Bridge" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:911 +msgid "World settings and lighting" +msgstr "世界设置和光照" + +#: MCprep_addon/mcprep_ui.py:926 +msgid "Time of day" +msgstr "时间" + +#: MCprep_addon/mcprep_ui.py:933 +#, python-brace-format +msgid "{h}:{m}, day {d}" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:942 +msgid "No time controller," +msgstr "没有时间控制器," + +#: MCprep_addon/mcprep_ui.py:943 +msgid "add dynamic MC world." +msgstr "请添加动态MC世界。" + +#: MCprep_addon/mcprep_ui.py:952 +msgid "Skin Swapper" +msgstr "皮肤交换器" + +#: MCprep_addon/mcprep_ui.py:969 +msgid "Select skin" +msgstr "选择皮肤" + +#: MCprep_addon/mcprep_ui.py:986 +msgid "No skins found/loaded" +msgstr "未找到/加载皮肤" + +#: MCprep_addon/mcprep_ui.py:988 MCprep_addon/mcprep_ui.py:993 +msgid "Press to reload" +msgstr "\"按下重新加载" + +#: MCprep_addon/mcprep_ui.py:991 +msgid "Reload skins" +msgstr "重新加载皮肤" + +#: MCprep_addon/mcprep_ui.py:1011 +msgid "No skins found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1013 +msgid "Skin from file" +msgstr "从文件导入皮肤" + +#: MCprep_addon/mcprep_ui.py:1015 +msgid "Skin from username" +msgstr "从用户名导入皮肤" + +#: MCprep_addon/mcprep_ui.py:1036 +msgid "Skin path" +msgstr "皮肤路径" + +#: MCprep_addon/mcprep_ui.py:1050 +msgid "Reload mobs below" +msgstr "重新加载下方的生物" + +#: MCprep_addon/mcprep_ui.py:1054 +msgid "Reload skins above" +msgstr "重新加载上方的皮肤" + +#: MCprep_addon/mcprep_ui.py:1064 +msgid "MCprep materials" +msgstr "MCprep 材质" + +#: MCprep_addon/mcprep_ui.py:1098 +msgid "No materials loaded" +msgstr "未加载材质" + +#: MCprep_addon/mcprep_ui.py:1107 +msgid "Load material" +msgstr "加载材质" + +#: MCprep_addon/mcprep_ui.py:1125 MCprep_addon/mcprep_ui.py:1398 +#: MCprep_addon/mcprep_ui.py:1557 +msgid "Resource pack" +msgstr "资源包" + +#: MCprep_addon/mcprep_ui.py:1141 +msgid "Enter object mode" +msgstr "进入对象模式" + +#: MCprep_addon/mcprep_ui.py:1142 +msgid "to use spawner" +msgstr "以使用生成器" + +#: MCprep_addon/mcprep_ui.py:1151 +msgid "Import pre-rigged mobs & players" +msgstr "导入预设置的生物和玩家" + +#: MCprep_addon/mcprep_ui.py:1170 +msgid "No mobs in category," +msgstr "该类别中没有生物," + +#: MCprep_addon/mcprep_ui.py:1171 +msgid "install a rig below or" +msgstr "安装一个下方的预设或" + +#: MCprep_addon/mcprep_ui.py:1172 +msgid "copy file to folder." +msgstr "将文件复制到文件夹中。" + +#: MCprep_addon/mcprep_ui.py:1178 +msgid "No mobs loaded" +msgstr "未加载生物" + +#: MCprep_addon/mcprep_ui.py:1182 MCprep_addon/mcprep_ui.py:1291 +#: MCprep_addon/mcprep_ui.py:1373 MCprep_addon/mcprep_ui.py:1449 +#: MCprep_addon/mcprep_ui.py:1527 MCprep_addon/mcprep_ui.py:1604 +msgid "Reload assets" +msgstr "重新加载资源" + +#: MCprep_addon/mcprep_ui.py:1226 +msgid "Mob spawner folder" +msgstr "生物生成器文件夹" + +#: MCprep_addon/mcprep_ui.py:1233 +msgid "Open mob folder" +msgstr "打开生物文件夹" + +#: MCprep_addon/mcprep_ui.py:1242 +msgid "Change mob icon" +msgstr "更改生物图标" + +#: MCprep_addon/mcprep_ui.py:1246 +msgid "Reload mobs" +msgstr "重新加载生物" + +#: MCprep_addon/mcprep_ui.py:1254 +msgid "Import pre-made blocks (e.g. lights)" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1268 +msgid "Meshswap file must be a .blend" +msgstr "网格变形文件必须是.blend格式" + +#: MCprep_addon/mcprep_ui.py:1273 MCprep_addon/mcprep_ui.py:1282 +msgid "Reset meshswap path" +msgstr "重置网格变形路径" + +#: MCprep_addon/mcprep_ui.py:1277 +msgid "Meshswap file not found" +msgstr "未找到网格变形文件" + +#: MCprep_addon/mcprep_ui.py:1286 +msgid "No blocks loaded" +msgstr "未加载方块" + +#: MCprep_addon/mcprep_ui.py:1310 +msgid "Place block" +msgstr "放置方块2" + +#: MCprep_addon/mcprep_ui.py:1329 +msgid "Meshswap file" +msgstr "网格变形文件" + +#: MCprep_addon/mcprep_ui.py:1335 MCprep_addon/mcprep_ui.py:1483 +msgid "MeshSwap file must be a .blend" +msgstr "网格变形文件必须是.blend格式" + +#: MCprep_addon/mcprep_ui.py:1348 +msgid "Generate items from textures" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1368 +msgid "No items loaded" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1379 +msgid "Place item" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1412 +msgid "Import pre-rigged entities" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1426 +msgid "Entity file must be a .blend" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1431 MCprep_addon/mcprep_ui.py:1440 +msgid "Reset entity path" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1444 +msgid "No entities loaded" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1461 +msgid "Spawn Entity" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1478 +msgid "Entity file" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1497 +msgid "Generate models from .json files" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1522 +msgid "No models loaded" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1573 +msgid "Load/generate effects" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1599 +msgid "No effects loaded" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1610 +msgid "Add effect" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1646 +msgid "Effects folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1660 +msgid "Effects/collection folder not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1662 +msgid "Effects/geonodes folder not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1664 +msgid "Effects/particle folder not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1672 +msgid "Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1682 +msgid "Click triangle to open" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1691 +msgid "Mob spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1719 +msgid "Block (model) spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1747 +msgid "Item spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1776 +msgid "Effects + weather" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1804 +msgid "Entity spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1832 +msgid "Meshswap spawner" +msgstr "" diff --git a/MCprep_addon/conf.py b/MCprep_addon/conf.py index 39ee7c82..efc7f872 100644 --- a/MCprep_addon/conf.py +++ b/MCprep_addon/conf.py @@ -143,26 +143,21 @@ def __init__(self): self.languages: dict[str, gettext.NullTranslations] = {} self._load_translations() - def _load_translations(self, prefix="") -> None: + def _load_translations(self) -> None: """Loads in mo file translation maps""" try: if not self.translations.exists(): - print(prefix, "No translations.py, running in location: ", __file__, " with ", self.languages_folder) for language in self.languages_folder.iterdir(): - print(prefix, "In langdir:", language.name) self.languages[language.name] = gettext.translation( "mcprep", localedir=self.languages_folder, fallback=True, languages=[language.name]) - print(prefix, "Loaded: ", language.name) self.use_direct_i18n = True self.log("Loaded direct i18n!") except Exception as e: self.languages = {} self.log(f"Exception occured while loading translations! {e}") - print(prefix, "Exception", e) - #raise e def _(self, msg: str) -> str: """Allows us to translate strings on the fly""" diff --git a/run_tests.py b/run_tests.py index 2d3f7f3e..e1201794 100644 --- a/run_tests.py +++ b/run_tests.py @@ -123,8 +123,8 @@ def main(): compile_time = t1 - t0 test_time = t2 - t1 exit_code = 1 if any_failures else 0 - print(f"Compiled in {compile_time:.1f}s, tests ran in {test_time:.1f}s") - print(f"Finished in {compile_time + test_time:.1f}s with code {exit_code}") + print(f"Compiled in {compile_time:.1f}s + tests ran in {test_time:.1f}s") + print(f"Total of {t2-t0:.1f}s with exit code {exit_code}") sys.exit(exit_code) diff --git a/test_files/addon_test.py b/test_files/addon_test.py index 49b038fd..211f0a2a 100644 --- a/test_files/addon_test.py +++ b/test_files/addon_test.py @@ -63,18 +63,13 @@ def _test_translation(self): lang_folder = mcprep_dir / "MCprep_resources" / "Languages" test_env.languages_folder = lang_folder - print("Lang folder", lang_folder) - print("self.translations", test_env.use_direct_i18n) - print("Dir:", list(os.listdir(lang_folder))) - # Don't assign translations, to force building the map in memory # translations_py = mcprep_dir / "translations.py" # test_env.translations = translations_py # Force load translations into this instance of MCprepEnv - test_env._load_translations(prefix=">>>\t") + test_env._load_translations() - # TODO: Not working, above load encounters error self.assertIn( "en_US", test_env.languages, "Missing default translation key") self.assertTrue( @@ -83,7 +78,8 @@ def _test_translation(self): # Magic string evaluations, will break if source po's change test_translations = [ ("ru_RU", "Restart blender", "Перезапустите блендер"), - ("zh_HANS", "Texture pack folder", "材质包文件夹"), + # Blender 4.0+ only has 'zh_HANS', 'zh_HANT' + ("zh_HANS" if bpy.app.version > (4, 0) else "zh_CN", "Texture pack folder", "材质包文件夹"), ("en_US", "Mob Spawner", "Mob Spawner"), ] for lang, src, dst in test_translations: @@ -94,7 +90,6 @@ def _test_translation(self): lang_folder / lang / "LC_MESSAGES" / "mcprep.mo"), f"Missing {lang}'s mo file") - # TODO: Not working bpy.context.preferences.view.language = lang res = test_env._(src) self.assertEqual(res, dst, f"Unexpected {lang} translation)") From a3ed89b933d1bb95207d159dc67a8f849105d147 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Sat, 24 Aug 2024 22:57:00 -0700 Subject: [PATCH 7/9] Simplified pathing with a resource folder constant --- MCprep_addon/conf.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MCprep_addon/conf.py b/MCprep_addon/conf.py index efc7f872..ea688584 100644 --- a/MCprep_addon/conf.py +++ b/MCprep_addon/conf.py @@ -65,6 +65,8 @@ class Engine(enum.Enum): UNKNOWN_LOCATION = (-1, "UNKNOWN LOCATION") DEBUG_MODE = False +MCPREP_RESOURCES: Path = Path(os.path.dirname(__file__), "MCprep_resources") + # ----------------------------------------------------------------------------- # ADDON GLOBAL VARIABLES AND INITIAL SETTINGS @@ -75,14 +77,12 @@ class MCprepEnv: def __init__(self): self.data = None self.json_data: Optional[Dict] = None - self.json_path: Path = Path( - os.path.dirname(__file__), "MCprep_resources", "mcprep_data.json") + self.json_path: Path = Path(MCPREP_RESOURCES, "mcprep_data.json") self.json_path_update: Path = Path( - os.path.dirname(__file__), "MCprep_resources", "mcprep_data_update.json") + MCPREP_RESOURCES, "mcprep_data_update.json") self.dev_file: Path = Path(os.path.dirname(__file__), "mcprep_dev.txt") - self.languages_folder: Path = Path( - os.path.dirname(__file__), "MCprep_resources", "Languages") + self.languages_folder: Path = Path(MCPREP_RESOURCES, "Languages") self.translations: Path = Path(os.path.dirname(__file__), "translations.py") self.last_check_for_updated = 0 From 2d14fd71e9969cb8f4efe56ed89f511b384c98c7 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Sat, 24 Aug 2024 22:57:54 -0700 Subject: [PATCH 8/9] Adding Blender 4.3 to the explicit list of supported versions --- bpy-build.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/bpy-build.yaml b/bpy-build.yaml index c3f6d68a..60a8551a 100644 --- a/bpy-build.yaml +++ b/bpy-build.yaml @@ -2,6 +2,7 @@ addon_folder: MCprep_addon build_name: MCprep_addon install_versions: + - 4.3 - 4.2 - 4.1 - 4.0 From a685dc127a70f0582104795437c5b6a891af4539 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Sat, 24 Aug 2024 23:14:37 -0700 Subject: [PATCH 9/9] Upversion to v3.6.1.2 with updated POT file timestamp --- MCprep_addon/MCprep_resources/Languages/mcprep.pot | 2 +- MCprep_addon/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MCprep_addon/MCprep_resources/Languages/mcprep.pot b/MCprep_addon/MCprep_resources/Languages/mcprep.pot index e0249fb7..24854515 100644 --- a/MCprep_addon/MCprep_resources/Languages/mcprep.pot +++ b/MCprep_addon/MCprep_resources/Languages/mcprep.pot @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: 3.6.1.1\n" "Report-Msgid-Bugs-To: https://github.com/Moo-Ack-Productions/MCprep/issues\n" -"POT-Creation-Date: 2024-08-24 18:31-0700\n" +"POT-Creation-Date: 2024-08-24 22:58-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/MCprep_addon/__init__.py b/MCprep_addon/__init__.py index 3aee06aa..9e0c4bdb 100755 --- a/MCprep_addon/__init__.py +++ b/MCprep_addon/__init__.py @@ -41,7 +41,7 @@ bl_info = { "name": "MCprep", "category": "Object", - "version": (3, 6, 1, 1), + "version": (3, 6, 1, 2), "blender": (2, 80, 0), "location": "3D window toolshelf > MCprep tab", "description": "Minecraft workflow addon for rendering and animation",