diff --git a/__init__.py b/__init__.py index caa78a7..22af111 100644 --- a/__init__.py +++ b/__init__.py @@ -19,14 +19,16 @@ def register(): properties.register() # Order the classes before registration core.register.order_classes() - # Register the UI classes - - # Iterate over the classes to register and register them + # Register the properties core.register.register_properties() + # Register the UI classes for cls in core.register.__bl_ordered_classes: print("registering " + str(cls)) bpy.utils.register_class(cls) + # Load the translations after everything else is registered + functions.translations.load_translations() + def unregister(): print("Unregistering Avatar Toolkit") # Unregister the UI classes diff --git a/core/export_resonite.py b/core/export_resonite.py index 5603773..4cb73fe 100644 --- a/core/export_resonite.py +++ b/core/export_resonite.py @@ -5,13 +5,14 @@ from .common import get_armature from bpy.types import Object, ShapeKey, Mesh, Context, Operator from functools import lru_cache from ..core.register import register_wrap +from ..functions.translations import t @register_wrap class ExportResonite(Operator): bl_idname = 'avatar_toolkit.export_resonite' - bl_label = "Export to Resonite" - bl_description = "Export a GLB with all animations and materials. For animation data see: " + bl_label = t("Export.resonite.label") + bl_description = t("Export.resonite.desc") bl_options = {'REGISTER', 'UNDO'} filepath: bpy.props.StringProperty() diff --git a/core/properties.py b/core/properties.py index 1e4f319..13ef631 100644 --- a/core/properties.py +++ b/core/properties.py @@ -3,13 +3,14 @@ from ..functions.translations import t, get_languages_list, update_ui from ..core.register import register_property from typing import Tuple -def register() -> None: - register_property((bpy.types.Scene, "language", bpy.props.EnumProperty( +def register(): + register_property((bpy.types.Scene, "avatar_toolkit_language", bpy.props.EnumProperty( name=t("Settings.language.label"), description=t("Settings.language.desc"), items=get_languages_list, + default=0, update=update_ui ))) -def unregister() -> None: +def unregister(): pass diff --git a/functions/combine_materials.py b/functions/combine_materials.py index 4eaa93d..58fce78 100644 --- a/functions/combine_materials.py +++ b/functions/combine_materials.py @@ -4,6 +4,7 @@ from typing import List, Tuple, Optional from bpy.types import Material, Operator, Context, Object from ..core.common import clean_material_names from ..core.register import register_wrap +from ..functions.translations import t def textures_match(tex1: bpy.types.ImageTexture, tex2: bpy.types.ImageTexture) -> bool: return tex1.image == tex2.image and tex1.extension == tex2.extension @@ -58,8 +59,8 @@ def report_consolidated(self: Operator, num_combined: int) -> None: @register_wrap class CombineMaterials(Operator): bl_idname = "avatar_toolkit.combine_materials" - bl_label = "Combine Materials" - bl_description = "Combine similar materials to optimize the model" + bl_label = t("Optimization.combinematerials.label") + bl_description = t("Optimization.combinematerials.desc") bl_options = {'REGISTER', 'UNDO'} @classmethod diff --git a/functions/translations.py b/functions/translations.py index 4f84a1d..af928fa 100644 --- a/functions/translations.py +++ b/functions/translations.py @@ -19,10 +19,28 @@ def load_translations() -> None: dictionary = dict() languages = ["auto"] - language: str = bpy.context.preferences.view.language - + # Populate languages list for i in os.listdir(translations_dir): - languages.append(i.split(".")[0]) + lang = i.split(".")[0] + if lang != "auto": + languages.append(lang) + + # Check if the context and scene are available + if hasattr(bpy.context, "scene"): + # Check if the property exists before trying to access it + if hasattr(bpy.context.scene, "avatar_toolkit_language"): + language_index = bpy.context.scene.avatar_toolkit_language + if isinstance(language_index, str): + language_index = int(language_index) + if language_index == 0: # "auto" + language = bpy.context.preferences.view.language + else: + language = languages[language_index] + else: + language = bpy.context.preferences.view.language + else: + # Set a default language if the context or scene is not available + language = "en_US" translation_file: str = os.path.join(translations_dir, language + ".json") if os.path.exists(translation_file): @@ -52,13 +70,23 @@ def t(phrase: str, *args, **kwargs) -> str: return output.format(*args, **kwargs) def get_languages_list(self, context) -> List[Tuple[str, str, str]]: - choices: List[Tuple[str, str, str]] = [] - for language in languages: - choices.append((language, language, language)) - return choices + return [(str(i), lang, f"Use {lang} language") for i, lang in enumerate(languages)] -def update_ui(self, context) -> None: +def refresh_translations(): load_translations() - bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) + # Force a full UI update + for window in bpy.context.window_manager.windows: + for area in window.screen.areas: + area.tag_redraw() +def update_ui(self, context): + refresh_translations() + # Force Blender to redraw all UI elements + for screen in bpy.data.screens: + for area in screen.areas: + area.tag_redraw() + # Update the Scene to trigger a full UI refresh + bpy.context.scene.update_tag() + +# Initial load of translations load_translations() diff --git a/resources/translations/en_US.json b/resources/translations/en_US.json index ed97a90..bb29761 100644 --- a/resources/translations/en_US.json +++ b/resources/translations/en_US.json @@ -2,7 +2,17 @@ "messages": { "Settings.label": "Settings", "Settings.language.label": "Language", - "Settings.language.desc": "Select the language for the addon's UI" + "Settings.language.desc": "Select the language for the addon's UI", + "Export.resonite.label": "Export to Resonite", + "Export.resonite.desc": "Export a GLB with all animations and materials. For animation data see:", + "Optimization.combinematerials.label": "Combine Materials", + "Optimization.combinematerials.desc": "Combine similar materials to optimize the model", + "QuickAccess.label": "Quick Access", + "QuickAcess.importexport.txt": "Import/Export", + "QuickAccess.options": "Quick Access Options", + "QuickAccess.importexport.txt": "Import/Export", + "QuickAccess.import": "Import", + "QuickAccess.export": "Export" } } diff --git a/resources/translations/ja_JP.json b/resources/translations/ja_JP.json index 1c53c39..625f13a 100644 --- a/resources/translations/ja_JP.json +++ b/resources/translations/ja_JP.json @@ -1,8 +1,17 @@ { - "messages": { - "Settings.label": "Settings Ja Test", - "Settings.language.label": "Language Ja Test", - "Settings.language.desc": "Select the language for the addon's UI Ja Test" - } + "messages": { + "Settings.label": "設定", + "Settings.language.label": "言語", + "Settings.language.desc": "アドオンのUI言語を選択してください", + "Export.resonite.label": "Resoniteにエクスポート", + "Export.resonite.desc": "すべてのアニメーションとマテリアルを含むGLBをエクスポートします。アニメーションデータについては以下を参照してください:", + "Optimization.combinematerials.label": "マテリアルを結合", + "Optimization.combinematerials.desc": "類似したマテリアルを結合してモデルを最適化します", + "QuickAccess.label": "クイックアクセス", + "QuickAcess.importexport.txt": "インポート/エクスポート", + "QuickAccess.options": "クイックアクセスオプション", + "QuickAccess.importexport.txt": "インポート/エクスポート", + "QuickAccess.import": "インポート", + "QuickAccess.export": "エクスポート" } - \ No newline at end of file +} diff --git a/ui/quick_access.py b/ui/quick_access.py index 1d93c25..bb1a9b2 100644 --- a/ui/quick_access.py +++ b/ui/quick_access.py @@ -2,13 +2,14 @@ import bpy from ..core.register import register_wrap from .panel import AvatarToolkitPanel from bpy.types import Context +from ..functions.translations import t from ..core.import_pmx import import_pmx from ..core.import_pmd import import_pmd @register_wrap class AvatarToolkitQuickAccessPanel(bpy.types.Panel): - bl_label = "Quick Access" + bl_label = t("QuickAccesslabel") bl_idname = "OBJECT_PT_avatar_toolkit_quick_access" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -17,17 +18,17 @@ class AvatarToolkitQuickAccessPanel(bpy.types.Panel): def draw(self, context: Context): layout = self.layout - layout.label(text="Quick Access Options") - + layout.label(text=t("QuickAccess.options")) + row = layout.row() - row.label(text="Import/Export", icon='IMPORT') + row.label(text=t("QuickAccess.importexport.txt"), icon='IMPORT') layout.separator(factor=0.5) row = layout.row(align=True) row.scale_y = 1.5 - row.operator("avatar_toolkit.import_menu", text="Import") - row.operator("avatar_toolkit.export_menu", text="Export") + row.operator("avatar_toolkit.import_menu", text=t("QuickAccess.import")) + row.operator("avatar_toolkit.export_menu", text=t("QuickAccess.export")) @register_wrap class AVATAR_TOOLKIT_OT_import_menu(bpy.types.Operator): diff --git a/ui/settings.py b/ui/settings.py index bd298ed..4287a9c 100644 --- a/ui/settings.py +++ b/ui/settings.py @@ -14,6 +14,4 @@ class AvatarToolkitSettingsPanel(bpy.types.Panel): def draw(self, context): layout = self.layout - props = context.scene - - layout.prop(props, "language") + layout.prop(context.scene, "avatar_toolkit_language", text=t("Settings.language.label"))