diff --git a/README.md b/README.md index 12ce092..e2daac7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Avatar Toolkit -## Avatar Toolkit is classed as unstable, if you want to test it and report issues that is fine, however if you are looking for a more stable expiereince please use the Unoffical Cats Blender Plugin unto we release a stable version of Avatar Toolkit, you can find Cats Blender Plugin [HERE](https://github.com/unofficalcats/Cats-Blender-Plugin-Unofficial-)! -#### Avatar Toolkit is in very early Alpha and will contain issues, please ensure you report them! +## Avatar Toolkit is in Alpha, There will be issues, please ensure you report them!. If using a Alpha plugin isn't your fancy you can find Cats Blender Plugin [HERE](https://github.com/unofficalcats/Cats-Blender-Plugin-Unofficial-)! +#### Avatar Toolkit is in Alpha and will contain issues, please ensure you report them! A new modern tool designed to shorten steps needed to import and optimize models into VRChat, Resonite and other similar games. @@ -13,23 +13,32 @@ Need a more stable toolset while Avatar Toolkit is in Alpha? Then please use Ble ## Blender version support policies. -Coming Soon. +You can find them on the wiki here [HERE](https://avatartoolkit.xyz/wiki.html?version=0.1.0#what-is-avatar-toolkits-version-support-policy) ## Features -Coming Soon. +See everything Avatar Toolkit has ot offer [here](https://avatartoolkit.xyz/wiki.html) ## Requirements -While The Avatar Toolkit is in Alpha, we are running on Blender 4.3 Alpha, however no stable releases will happen on Blender 4.x as we are aiming for Blender 5.0 for any type of stable release. -- Blender 4.3 Alpha or above (run as administrator is recommended). -- If you have custom Python installed which Blender might use, you need to have NumPy installed +1) Blender Version +- Blender 4.3 or newer is required +- Blender 4.3 is the current recommended version + + +2) Python Requirements +- If using a custom Python installation with Blender, ensure NumPy is installed +- Default Blender installation includes all required packages + +3) Recommended Setup +- Download Blender directly from https://blender.org +- Use Blender 4.3 for the best experience #### Additional Plugins Requirements. Currently None. ## Installation -Coming Soon +You can find out how to install Avatar Toolkit [here](https://avatartoolkit.xyz/wiki.html?version=0.1.0#how-to-install-avatar-toolkit) ## Help diff --git a/blender_manifest.toml b/blender_manifest.toml index 4a45665..e724648 100644 --- a/blender_manifest.toml +++ b/blender_manifest.toml @@ -3,7 +3,7 @@ schema_version = "1.0.0" id = "avatar_toolkit" -version = "0.1.0" +version = "0.1.1" name = "Avatar Toolkit" tagline = "A modern tool for importing and optimizing models for VRChat, Resonite, and other similar games." maintainer = "Team NekoNeo" diff --git a/core/common.py b/core/common.py index d6696b3..c232856 100644 --- a/core/common.py +++ b/core/common.py @@ -6,10 +6,12 @@ import webbrowser import typing import struct from io import BytesIO +import numpy.typing as npt -from typing import Optional, Tuple, List, Set, Dict, Any, Generator, Callable -from mathutils import Vector -from bpy.types import Context, Object, Modifier, EditBone, Operator +from typing import Optional, Tuple, List, Set, Dict, Any, Generator, Callable, Union, Type +from mathutils import Vector, Matrix +from bpy.types import (Context, Object, Modifier, EditBone, Operator, + VertexGroup, ShapeKey, Bone, Mesh, Armature, PropertyGroup) from functools import lru_cache from bpy.props import PointerProperty, IntProperty, StringProperty from bpy.utils import register_class @@ -20,11 +22,11 @@ from ..core.dictionaries import bone_names class ProgressTracker: """Universal progress tracking for Avatar Toolkit operations""" - def __init__(self, context: Context, total_steps: int, operation_name: str = "Operation"): - self.context = context - self.total = total_steps - self.current = 0 - self.operation_name = operation_name + def __init__(self, context: Context, total_steps: int, operation_name: str = "Operation") -> None: + self.context: Context = context + self.total: int = total_steps + self.current: int = 0 + self.operation_name: str = operation_name self.wm = context.window_manager def step(self, message: str = "") -> None: @@ -35,26 +37,28 @@ class ProgressTracker: self.wm.progress_update(progress * 100) logger.debug(f"{self.operation_name} - {progress:.1%}: {message}") - def __enter__(self): + def __enter__(self) -> 'ProgressTracker': logger.info(f"Starting {self.operation_name}") return self - def __exit__(self, exc_type, exc_val, exc_tb): + def __exit__(self, exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[Any]) -> None: self.wm.progress_end() logger.info(f"Completed {self.operation_name}") -def get_active_armature(context: bpy.types.Context) -> Optional[bpy.types.Object]: +def get_active_armature(context: Context) -> Optional[Object]: """Get the currently selected armature from Avatar Toolkit properties""" - armature_name = context.scene.avatar_toolkit.active_armature + armature_name = str(context.scene.avatar_toolkit.active_armature) if armature_name and armature_name != 'NONE': return bpy.data.objects.get(armature_name) return None -def set_active_armature(context: bpy.types.Context, armature: bpy.types.Object) -> None: +def set_active_armature(context: Context, armature: Object) -> None: """Set the active armature for Avatar Toolkit operations""" context.scene.avatar_toolkit.active_armature = armature -def get_armature_list(self=None, context: bpy.types.Context = None) -> List[Tuple[str, str, str]]: +def get_armature_list(self: Optional[Any] = None, context: Optional[Context] = None) -> List[Tuple[str, str, str]]: """Get list of all armature objects in the scene""" if context is None: context = bpy.context @@ -63,25 +67,21 @@ def get_armature_list(self=None, context: bpy.types.Context = None) -> List[Tupl return [('NONE', t("Armature.validation.no_armature"), '')] return armatures -def validate_armature(armature: bpy.types.Object) -> Tuple[bool, List[str]]: +def validate_armature(armature: Object) -> Tuple[bool, List[str]]: """Enhanced armature validation with multiple validation modes""" validation_mode = bpy.context.scene.avatar_toolkit.validation_mode + messages: List[str] = [] - # Skip validation if mode is NONE if validation_mode == 'NONE': return True, [] - messages = [] - - # Basic checks always run if not NONE if not armature or armature.type != 'ARMATURE' or not armature.data.bones: return False, [t("Armature.validation.basic_check_failed")] - found_bones = {bone.name.lower(): bone for bone in armature.data.bones} + found_bones: Dict[str, Bone] = {bone.name.lower(): bone for bone in armature.data.bones} + essential_bones: Set[str] = {'hips', 'spine', 'chest', 'neck', 'head'} - # Essential bones check (BASIC and STRICT) - essential_bones = {'hips', 'spine', 'chest', 'neck', 'head'} - missing_bones = [] + missing_bones: List[str] = [] for bone in essential_bones: if not any(alt_name in found_bones for alt_name in bone_names[bone]): missing_bones.append(bone) @@ -89,41 +89,38 @@ def validate_armature(armature: bpy.types.Object) -> Tuple[bool, List[str]]: if missing_bones: messages.append(t("Armature.validation.missing_bones", bones=", ".join(missing_bones))) - # Additional checks for STRICT mode only if validation_mode == 'STRICT': - # Hierarchy validation - hierarchy = [('hips', 'spine'), ('spine', 'chest'), ('chest', 'neck'), ('neck', 'head')] + hierarchy: List[Tuple[str, str]] = [ + ('hips', 'spine'), ('spine', 'chest'), + ('chest', 'neck'), ('neck', 'head') + ] for parent, child in hierarchy: if not validate_bone_hierarchy(found_bones, parent, child): - messages.append(t("Armature.validation.invalid_hierarchy", parent=parent, child=child)) + messages.append(t("Armature.validation.invalid_hierarchy", + parent=parent, child=child)) - # Symmetry validation - symmetry_pairs = [('arm', 'l', 'r'), ('leg', 'l', 'r')] + symmetry_pairs: List[Tuple[str, str, str]] = [('arm', 'l', 'r'), ('leg', 'l', 'r')] for base, left, right in symmetry_pairs: if not validate_symmetry(found_bones, base, left, right): messages.append(t("Armature.validation.asymmetric_bones", bone=base)) - # Special handling for hand/wrist symmetry if (not validate_symmetry(found_bones, 'hand', 'l', 'r') and not validate_symmetry(found_bones, 'wrist', 'l', 'r')): messages.append(t("Armature.validation.asymmetric_hand_wrist")) - is_valid = len(messages) == 0 + is_valid: bool = len(messages) == 0 return is_valid, messages -def validate_bone_hierarchy(bones: Dict[str, bpy.types.Bone], parent_name: str, child_name: str) -> bool: +def validate_bone_hierarchy(bones: Dict[str, Bone], parent_name: str, child_name: str) -> bool: """Validate if there is a valid parent-child relationship between bones""" - # Find matching parent and child bones using bone_names dictionary - parent_bone = None - child_bone = None + parent_bone: Optional[Bone] = None + child_bone: Optional[Bone] = None - # Check for parent bone matches for alt_name in bone_names[parent_name]: if alt_name in bones: parent_bone = bones[alt_name] break - # Check for child bone matches for alt_name in bone_names[child_name]: if alt_name in bones: child_bone = bones[alt_name] @@ -132,47 +129,42 @@ def validate_bone_hierarchy(bones: Dict[str, bpy.types.Bone], parent_name: str, if not parent_bone or not child_bone: return False - # Check if child's parent matches parent bone return child_bone.parent == parent_bone -def validate_symmetry(bones: Dict[str, bpy.types.Bone], base: str, left: str, right: str) -> bool: - """ - Validate if matching left and right bones exist for a given base bone name - """ - # Define common naming patterns - left_patterns = [ +def validate_symmetry(bones: Dict[str, Bone], base: str, left: str, right: str) -> bool: + """Validate if matching left and right bones exist for a given base bone name""" + left_patterns: List[str] = [ f"{base}.{left}", f"{base}_{left}", f"{left}_{base}" ] - right_patterns = [ + right_patterns: List[str] = [ f"{base}.{right}", f"{base}_{right}", f"{right}_{base}" ] - # Check if any of the patterns exist in the bones dictionary - left_exists = any(pattern in bones for pattern in left_patterns) - right_exists = any(pattern in bones for pattern in right_patterns) + left_exists: bool = any(pattern in bones for pattern in left_patterns) + right_exists: bool = any(pattern in bones for pattern in right_patterns) return left_exists and right_exists -def auto_select_single_armature(context: bpy.types.Context) -> None: +def auto_select_single_armature(context: Context) -> None: """Automatically select armature if only one exists in scene""" - armatures = get_armature_list(context) + armatures: List[Tuple[str, str, str]] = get_armature_list(context) if len(armatures) == 1 and armatures[0][0] != 'NONE': toolkit = context.scene.avatar_toolkit set_active_armature(context, armatures[0]) def clear_default_objects() -> None: - """Removes default Blender objects (cube, light, camera)""" + """Removes default Blender objects""" default_names: Set[str] = {'Cube', 'Light', 'Camera'} for obj in bpy.data.objects: if obj.name.split('.')[0] in default_names: bpy.data.objects.remove(obj, do_unlink=True) -def get_armature_stats(armature: bpy.types.Object) -> dict: +def get_armature_stats(armature: Object) -> Dict[str, Union[int, bool, str]]: """Get statistics about the armature""" return { 'bone_count': len(armature.data.bones), @@ -183,7 +175,7 @@ def get_armature_stats(armature: bpy.types.Object) -> dict: def get_all_meshes(context: Context) -> List[Object]: """Get all mesh objects parented to the active armature""" - armature = get_active_armature(context) + armature: Optional[Object] = get_active_armature(context) if armature: return [obj for obj in bpy.data.objects if obj.type == 'MESH' and obj.parent == armature] return [] @@ -196,26 +188,26 @@ def validate_mesh_for_pose(mesh_obj: Object) -> Tuple[bool, str]: if not mesh_obj.vertex_groups: return False, t("Mesh.validation.no_vertex_groups") - armature_mods = [mod for mod in mesh_obj.modifiers if mod.type == 'ARMATURE'] + armature_mods: List[Modifier] = [mod for mod in mesh_obj.modifiers if mod.type == 'ARMATURE'] if not armature_mods: return False, t("Mesh.validation.no_armature_modifier") return True, t("Mesh.validation.valid") -def cache_vertex_positions(mesh_obj: Object) -> np.ndarray: +def cache_vertex_positions(mesh_obj: Object) -> npt.NDArray[np.float32]: """Cache vertex positions for a mesh object""" vertices = mesh_obj.data.vertices - positions = np.empty(len(vertices) * 3, dtype=np.float32) + positions: npt.NDArray[np.float32] = np.empty(len(vertices) * 3, dtype=np.float32) vertices.foreach_get('co', positions) return positions.reshape(-1, 3) -def apply_vertex_positions(vertices: Object, positions: np.ndarray) -> None: +def apply_vertex_positions(vertices: Object, positions: npt.NDArray[np.float32]) -> None: """Apply cached vertex positions to mesh in batch""" vertices.foreach_set('co', positions.flatten()) def process_armature_modifiers(mesh_obj: Object) -> List[Dict[str, Any]]: """Process and store armature modifier states""" - modifier_states = [] + modifier_states: List[Dict[str, Any]] = [] for mod in mesh_obj.modifiers: if mod.type == 'ARMATURE': modifier_states.append({ @@ -252,10 +244,10 @@ def apply_pose_as_rest(context: Context, armature_obj: Object, meshes: List[Obje except Exception as e: logger.error(f"Error applying pose as rest: {str(e)}") return False, str(e) - + def apply_armature_to_mesh(armature_obj: Object, mesh_obj: Object) -> None: """Apply armature deformation to mesh""" - armature_mod = mesh_obj.modifiers.new('PoseToRest', 'ARMATURE') + armature_mod: Modifier = mesh_obj.modifiers.new('PoseToRest', 'ARMATURE') armature_mod.object = armature_obj if bpy.app.version >= (3, 5): @@ -269,13 +261,13 @@ def apply_armature_to_mesh(armature_obj: Object, mesh_obj: Object) -> None: def apply_armature_to_mesh_with_shapekeys(armature_obj: Object, mesh_obj: Object, context: Context) -> None: """Apply armature deformation to mesh with shape keys""" - old_active_index = mesh_obj.active_shape_key_index - old_show_only = mesh_obj.show_only_shape_key + old_active_index: int = mesh_obj.active_shape_key_index + old_show_only: bool = mesh_obj.show_only_shape_key mesh_obj.show_only_shape_key = True - shape_keys = mesh_obj.data.shape_keys.key_blocks - vertex_groups = [] - mutes = [] + shape_keys: List[ShapeKey] = mesh_obj.data.shape_keys.key_blocks + vertex_groups: List[str] = [] + mutes: List[bool] = [] for sk in shape_keys: vertex_groups.append(sk.vertex_group) @@ -283,17 +275,17 @@ def apply_armature_to_mesh_with_shapekeys(armature_obj: Object, mesh_obj: Object mutes.append(sk.mute) sk.mute = False - disabled_mods = [] + disabled_mods: List[Modifier] = [] for mod in mesh_obj.modifiers: if mod.show_viewport: mod.show_viewport = False disabled_mods.append(mod) - arm_mod = mesh_obj.modifiers.new('PoseToRest', 'ARMATURE') + arm_mod: Modifier = mesh_obj.modifiers.new('PoseToRest', 'ARMATURE') arm_mod.object = armature_obj - co_length = len(mesh_obj.data.vertices) * 3 - eval_cos = np.empty(co_length, dtype=np.single) + co_length: int = len(mesh_obj.data.vertices) * 3 + eval_cos: npt.NDArray[np.float32] = np.empty(co_length, dtype=np.single) for i, shape_key in enumerate(shape_keys): mesh_obj.active_shape_key_index = i @@ -331,6 +323,11 @@ def validate_meshes(meshes: List[Object]) -> Tuple[bool, str]: def join_mesh_objects(context: Context, meshes: List[Object], progress: Optional[ProgressTracker] = None) -> Optional[Object]: """Combines multiple mesh objects into a single mesh with proper cleanup and UV fixing""" try: + # Store UV maps before joining + uv_maps_data = {} + for mesh in meshes: + uv_maps_data[mesh.name] = {uv.name: uv.data.copy() for uv in mesh.data.uv_layers} + bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') @@ -352,12 +349,17 @@ def join_mesh_objects(context: Context, meshes: List[Object], progress: Optional progress.step(t("Optimization.fixing_uvs")) fix_uv_coordinates(context) - # Return the joined mesh object + # Restore UV maps after joining + joined_mesh = context.active_object + for uv_name, uv_data in uv_maps_data.items(): + for map_name, map_data in uv_data.items(): + if map_name not in joined_mesh.data.uv_layers: + joined_mesh.data.uv_layers.new(name=map_name) + joined_mesh.data.uv_layers[map_name].data.foreach_set("uv", map_data) + return context.active_object - else: - # No objects were selected, return None - return None + return None except Exception as e: logger.error(f"Failed to join meshes: {str(e)}") @@ -374,13 +376,17 @@ def fix_uv_coordinates(context: Context) -> None: bpy.ops.object.mode_set(mode='OBJECT') obj.select_set(True) context.view_layer.objects.active = obj - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - - with context.temp_override(active_object=obj): - bpy.ops.uv.select_all(action='SELECT') - bpy.ops.uv.average_islands_scale() + # Process each UV layer + for uv_layer in obj.data.uv_layers: + obj.data.uv_layers.active = uv_layer + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + + with context.temp_override(active_object=obj): + bpy.ops.uv.select_all(action='SELECT') + bpy.ops.uv.pack_islands(margin=0.001) + bpy.ops.uv.average_islands_scale() logger.debug(f"UV Fix - Successfully processed {obj.name}") @@ -392,13 +398,13 @@ def fix_uv_coordinates(context: Context) -> None: for sel_obj in current_selected: sel_obj.select_set(True) context.view_layer.objects.active = current_active -# This should be at the top level, not indented inside any class or function + def clear_unused_data_blocks() -> int: """Removes all unused data blocks from the current Blender file""" - initial_count = sum(len(getattr(bpy.data, attr)) for attr in dir(bpy.data) + initial_count: int = sum(len(getattr(bpy.data, attr)) for attr in dir(bpy.data) if isinstance(getattr(bpy.data, attr), bpy.types.bpy_prop_collection)) bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True) - final_count = sum(len(getattr(bpy.data, attr)) for attr in dir(bpy.data) + final_count: int = sum(len(getattr(bpy.data, attr)) for attr in dir(bpy.data) if isinstance(getattr(bpy.data, attr), bpy.types.bpy_prop_collection)) return initial_count - final_count @@ -408,8 +414,8 @@ def simplify_bonename(name: str) -> str: def duplicate_bone_chain(bones: List[EditBone]) -> List[EditBone]: """Duplicate a chain of bones while preserving hierarchy""" - new_bones = [] - parent_map = {} + new_bones: List[EditBone] = [] + parent_map: Dict[EditBone, EditBone] = {} for bone in bones: new_bone = duplicate_bone(bone) @@ -429,37 +435,31 @@ def restore_bone_transforms(bone: EditBone, transforms: Dict[str, Any]) -> None: def get_vertex_weights(mesh_obj: Object, group_name: str) -> Dict[int, float]: """Get vertex weights for a specific vertex group""" - weights = {} - group_index = mesh_obj.vertex_groups[group_name].index + weights: Dict[int, float] = {} + group_index: int = mesh_obj.vertex_groups[group_name].index for vertex in mesh_obj.data.vertices: for group in vertex.groups: if group.group == group_index: weights[vertex.index] = group.weight return weights -def transfer_vertex_weights(mesh_obj: Object, - source_name: str, - target_name: str, - threshold: float = 0.01) -> None: +def transfer_vertex_weights(mesh_obj: Object, source_name: str, target_name: str, threshold: float = 0.01) -> None: """Transfer vertex weights from source to target group""" if source_name not in mesh_obj.vertex_groups: return - source_group = mesh_obj.vertex_groups[source_name] - target_group = mesh_obj.vertex_groups.get(target_name) + source_group: VertexGroup = mesh_obj.vertex_groups[source_name] + target_group: Optional[VertexGroup] = mesh_obj.vertex_groups.get(target_name) if not target_group: target_group = mesh_obj.vertex_groups.new(name=target_name) - # Get source weights - weights = get_vertex_weights(mesh_obj, source_name) + weights: Dict[int, float] = get_vertex_weights(mesh_obj, source_name) - # Transfer weights above threshold for vertex_index, weight in weights.items(): if weight > threshold: target_group.add([vertex_index], weight, 'ADD') - # Remove source group mesh_obj.vertex_groups.remove(source_group) def remove_unused_shapekeys(mesh_obj: Object, tolerance: float = 0.001) -> int: @@ -467,35 +467,30 @@ def remove_unused_shapekeys(mesh_obj: Object, tolerance: float = 0.001) -> int: if not mesh_obj.data.shape_keys: return 0 - key_blocks = mesh_obj.data.shape_keys.key_blocks - vertex_count = len(mesh_obj.data.vertices) - removed_count = 0 + key_blocks: List[ShapeKey] = mesh_obj.data.shape_keys.key_blocks + vertex_count: int = len(mesh_obj.data.vertices) + removed_count: int = 0 - # Cache for relative key locations - cache = {} - locations = np.empty(3 * vertex_count, dtype=np.float32) - to_delete = [] + cache: Dict[str, npt.NDArray[np.float32]] = {} + locations: npt.NDArray[np.float32] = np.empty(3 * vertex_count, dtype=np.float32) + to_delete: List[str] = [] for key in key_blocks: if key == key.relative_key: continue - # Get current key locations key.data.foreach_get("co", locations) - # Get or calculate relative key locations if key.relative_key.name not in cache: - rel_locations = np.empty(3 * vertex_count, dtype=np.float32) + rel_locations: npt.NDArray[np.float32] = np.empty(3 * vertex_count, dtype=np.float32) key.relative_key.data.foreach_get("co", rel_locations) cache[key.relative_key.name] = rel_locations - # Compare locations locations -= cache[key.relative_key.name] if (np.abs(locations) < tolerance).all(): - if not any(c in key.name for c in "-=~"): # Skip category markers + if not any(c in key.name for c in "-=~"): to_delete.append(key.name) - # Remove marked shape keys for key_name in to_delete: mesh_obj.shape_key_remove(key_blocks[key_name]) removed_count += 1 @@ -503,20 +498,52 @@ def remove_unused_shapekeys(mesh_obj: Object, tolerance: float = 0.001) -> int: return removed_count def has_shapekeys(mesh_obj: Object) -> bool: + """Check if mesh object has shape keys""" return mesh_obj.data.shape_keys is not None -# Identifier to indicate that an EnumProperty is empty -# This is the default identifier used when a wrapped items function returns an empty list -# This identifier needs to be something that should never normally be used, so as to avoid the possibility of -# conflicting with an enum value that exists. -_empty_enum_identifier = 'Cats_empty_enum_identifier' +def fix_zero_length_bones(armature: Object) -> None: + """Fix zero length bones by setting a minimum length""" + if not armature: + return + + bpy.ops.object.mode_set(mode='EDIT') + for bone in armature.data.edit_bones: + if bone.length < 0.001: + bone.length = 0.001 + bpy.ops.object.mode_set(mode='OBJECT') -# names - The first object will be the first one in the list. So the first one has to be the one that exists in the most models -# no_basis - If this is true the Basis will not be available in the list -def get_shapekeys(context, names, is_mouth, no_basis, return_list): - choices = [] - choices_simple = [] - meshes_list = get_meshes_objects(check=False) +def calculate_bone_orientation(mesh: Object, vertices: List[Any]) -> Tuple[Vector, float]: + """Calculate optimal bone orientation based on mesh geometry""" + if not vertices: + return Vector((0, 0, 0.1)), 0.0 + + coords: List[Vector] = [mesh.data.vertices[v.index].co for v in vertices] + min_co: Vector = Vector(map(min, zip(*coords))) + max_co: Vector = Vector(map(max, zip(*coords))) + dimensions: Vector = max_co - min_co + + roll_angle: float = 0.0 + + return dimensions, roll_angle + +def add_armature_modifier(mesh: Object, armature: Object) -> None: + """Add armature modifier to mesh""" + for mod in mesh.modifiers: + if mod.type == 'ARMATURE': + mesh.modifiers.remove(mod) + + modifier: Modifier = mesh.modifiers.new('Armature', 'ARMATURE') + modifier.object = armature + +def get_shapekeys(context: Context, + names: List[str], + is_mouth: bool, + no_basis: bool, + return_list: bool) -> Union[List[Tuple[str, str, str]], List[str]]: + """Get shape keys based on specified criteria""" + choices: List[Tuple[str, str, str]] = [] + choices_simple: List[str] = [] + meshes_list: List[Object] = get_meshes_objects(check=False) if meshes_list: if is_mouth: @@ -536,15 +563,12 @@ def get_shapekeys(context, names, is_mouth, no_basis, return_list): continue if no_basis and name == 'Basis': continue - # 1. Will be returned by context.scene - # 2. Will be shown in lists - # 3. will be shown in the hover description (below description) choices.append((name, name, name)) choices_simple.append(name) _sort_enum_choices_by_identifier_lower(choices) - choices2 = [] + choices2: List[Tuple[str, str, str]] = [] for name in names: if name in choices_simple and len(choices) > 1 and choices[0][0] != name: continue @@ -553,22 +577,16 @@ def get_shapekeys(context, names, is_mouth, no_basis, return_list): choices2.extend(choices) if return_list: - shape_list = [] + shape_list: List[str] = [] for choice in choices2: shape_list.append(choice[0]) return shape_list return choices2 -# Default sorting for dynamic EnumProperty items -def _sort_enum_choices_by_identifier_lower(choices, in_place=True): - """Sort a list of enum choices (items) by the lowercase of their identifier. - - Sorting is performed in-place by default, but can be changed by setting in_place=False. - - Returns the sorted list of enum choices.""" - - def identifier_lower(choice): +def _sort_enum_choices_by_identifier_lower(choices: List[Tuple[str, str, str]], in_place: bool = True) -> List[Tuple[str, str, str]]: + """Sort a list of enum choices by the lowercase of their identifier""" + def identifier_lower(choice: Tuple[str, str, str]) -> str: return choice[0].lower() if in_place: @@ -577,55 +595,39 @@ def _sort_enum_choices_by_identifier_lower(choices, in_place=True): choices = sorted(choices, key=identifier_lower) return choices -def is_enum_empty(string): - """Returns True only if the tested string is the string that signifies that an EnumProperty is empty. - - Returns False in all other cases.""" +def is_enum_empty(string: str) -> bool: + """Returns True only if the tested string is the empty enum identifier""" return _empty_enum_identifier == string - -# This function isn't needed since you can 'not is_enum_empty(string)', but is included for code clarity and readability -def is_enum_non_empty(string): - """Returns False only if the tested string is not the string that signifies that an EnumProperty is empty. - - Returns True in all other cases.""" +def is_enum_non_empty(string: str) -> bool: + """Returns False only if the tested string is not the empty enum identifier""" return _empty_enum_identifier != string -def fix_zero_length_bones(armature: Object) -> None: - """Fix zero length bones by setting a minimum length""" - if not armature: - return - - bpy.ops.object.mode_set(mode='EDIT') - for bone in armature.data.edit_bones: - if bone.length < 0.001: - bone.length = 0.001 - bpy.ops.object.mode_set(mode='OBJECT') +_empty_enum_identifier: str = 'Cats_empty_enum_identifier' +def get_meshes_objects(check: bool = True) -> List[Object]: + """Get all mesh objects in the scene""" + meshes: List[Object] = [obj for obj in bpy.data.objects if obj.type == 'MESH'] + if check and not meshes: + return [] + return meshes -def calculate_bone_orientation(mesh, vertices): - """Calculate optimal bone orientation based on mesh geometry.""" - - if not vertices: - return Vector((0, 0, 0.1)), 0.0 - - coords = [mesh.data.vertices[v.index].co for v in vertices] - min_co = Vector(map(min, zip(*coords))) - max_co = Vector(map(max, zip(*coords))) - dimensions = max_co - min_co - - roll_angle = 0.0 - - return dimensions, roll_angle +def get_objects() -> bpy.types.BlendData: + """Get all objects in the current Blender scene""" + return bpy.data.objects -def add_armature_modifier(mesh: Object, armature: Object): - """Add armature modifier to mesh.""" - for mod in mesh.modifiers: - if mod.type == 'ARMATURE': - mesh.modifiers.remove(mod) - - modifier = mesh.modifiers.new('Armature', 'ARMATURE') - modifier.object = armature +def duplicate_bone(bone: EditBone) -> EditBone: + """Create a duplicate of the given bone""" + new_bone: EditBone = bone.id_data.edit_bones.new(bone.name + "_copy") + new_bone.head = bone.head.copy() + new_bone.tail = bone.tail.copy() + new_bone.roll = bone.roll + new_bone.use_connect = bone.use_connect + new_bone.use_local_location = bone.use_local_location + new_bone.use_inherit_rotation = bone.use_inherit_rotation + new_bone.use_inherit_scale = bone.use_inherit_scale + new_bone.use_deform = bone.use_deform + return new_bone #Binary tools diff --git a/core/logging_setup.py b/core/logging_setup.py index f921d5d..37aab50 100644 --- a/core/logging_setup.py +++ b/core/logging_setup.py @@ -1,5 +1,6 @@ import logging -from typing import Optional +from typing import Optional, Any +from bpy.types import Context logger = logging.getLogger('avatar_toolkit') @@ -18,7 +19,7 @@ def configure_logging(enabled: bool = False) -> None: handler.setFormatter(formatter) logger.addHandler(handler) -def update_logging_state(self, context) -> None: +def update_logging_state(self: Any, context: Context) -> None: """Update logging state based on user preference""" from .addon_preferences import save_preference enabled = self.enable_logging diff --git a/core/properties.py b/core/properties.py index 1aa4a28..bd12643 100644 --- a/core/properties.py +++ b/core/properties.py @@ -1,5 +1,5 @@ import bpy -from typing import List, Tuple, Optional +from typing import List, Tuple, Optional, Any, Dict, Union, Callable from bpy.types import PropertyGroup, Material, Scene, Object, Context from bpy.props import ( StringProperty, @@ -18,19 +18,21 @@ from .common import get_armature_list, get_active_armature, get_all_meshes from ..functions.visemes import VisemePreview from ..functions.eye_tracking import set_rotation -def update_validation_mode(self, context): +def update_validation_mode(self: PropertyGroup, context: Context) -> None: + """Updates validation mode and saves preference""" logger.info(f"Updating validation mode to: {self.validation_mode}") save_preference("validation_mode", self.validation_mode) -def update_logging_state(self, context): +def update_logging_state(self: PropertyGroup, context: Context) -> None: + """Updates logging state and configures logging""" logger.info(f"Updating logging state to: {self.enable_logging}") save_preference("enable_logging", self.enable_logging) from .logging_setup import configure_logging configure_logging(self.enable_logging) -def update_shape_intensity(self, context): +def update_shape_intensity(self: PropertyGroup, context: Context) -> None: + """Updates shape key intensity and refreshes preview""" if self.viseme_preview_mode: - from ..functions.visemes import VisemePreview VisemePreview.update_preview(context) class AvatarToolkitSceneProperties(PropertyGroup): @@ -133,13 +135,7 @@ class AvatarToolkitSceneProperties(PropertyGroup): description=t("Visemes.preview_mode_desc"), default=False ) - - viseme_preview_selection: StringProperty( - name=t("Visemes.preview_selection"), - description=t("Visemes.preview_selection_desc"), - default="vrc.v_aa" - ) - + mouth_a: StringProperty( name=t("Visemes.mouth_a"), description=t("Visemes.mouth_a_desc") @@ -155,6 +151,11 @@ class AvatarToolkitSceneProperties(PropertyGroup): description=t("Visemes.mouth_ch_desc") ) + viseme_mesh: StringProperty( + name=t("Visemes.mesh_select"), + description=t("Visemes.mesh_select_desc"), + ) + shape_intensity: FloatProperty( name=t("Visemes.shape_intensity"), description=t("Visemes.shape_intensity_desc"), @@ -366,16 +367,6 @@ class AvatarToolkitSceneProperties(PropertyGroup): default=True ) - attach_mesh: StringProperty( - name=t("Tools.attach_mesh_select"), - description=t("Tools.attach_mesh_select_desc") - ) - - attach_bone: StringProperty( - name=t("Tools.attach_bone_select"), - description=t("Tools.attach_bone_select_desc") - ) - def register() -> None: """Register the Avatar Toolkit property group""" logger.info("Registering Avatar Toolkit properties") diff --git a/functions/custom_tools/armature_merging.py b/functions/custom_tools/armature_merging.py index 7164652..437119c 100644 --- a/functions/custom_tools/armature_merging.py +++ b/functions/custom_tools/armature_merging.py @@ -1,7 +1,7 @@ import bpy import numpy as np -from typing import List, Optional, Dict, Set -from bpy.types import Context, Object, Operator +from typing import List, Optional, Dict, Set, Tuple, Any +from bpy.types import Context, Object, Operator, ArmatureModifier, EditBone, VertexGroup, Mesh, ShapeKey from ...core.logging_setup import logger from ...core.translations import t @@ -13,26 +13,27 @@ from ...core.common import ( remove_unused_shapekeys ) -class AvatarToolkit_OT_MergeArmature(Operator): - bl_idname = 'avatar_toolkit.merge_armatures' - bl_label = t('MergeArmature.label') - bl_description = t('MergeArmature.desc') - bl_options = {'REGISTER', 'UNDO'} +class AvatarToolkit_OT_MergeArmature(bpy.types.Operator): + """Operator for merging two armatures together with their associated meshes""" + bl_idname: str = 'avatar_toolkit.merge_armatures' + bl_label: str = t('MergeArmature.label') + bl_description: str = t('MergeArmature.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod - def poll(cls, context): + def poll(cls, context: Context) -> bool: return len(get_all_meshes(context)) > 1 - def execute(self, context): + def execute(self, context: Context) -> Set[str]: try: wm = context.window_manager wm.progress_begin(0, 100) # Get both armatures - base_armature_name = context.scene.merge_armature_into - merge_armature_name = context.scene.merge_armature - base_armature = bpy.data.objects.get(base_armature_name) - merge_armature = bpy.data.objects.get(merge_armature_name) + base_armature_name: str = context.scene.merge_armature_into + merge_armature_name: str = context.scene.merge_armature + base_armature: Optional[Object] = bpy.data.objects.get(base_armature_name) + merge_armature: Optional[Object] = bpy.data.objects.get(merge_armature_name) if not base_armature or not merge_armature: logger.error(f"Armature not found: {merge_armature_name}") @@ -51,15 +52,15 @@ class AvatarToolkit_OT_MergeArmature(Operator): wm.progress_update(80) # Get settings from scene properties - merge_all_bones = context.scene.avatar_toolkit.merge_all_bones - join_meshes = context.scene.avatar_toolkit.join_meshes + merge_all_bones: bool = context.scene.avatar_toolkit.merge_all_bones + join_meshes: bool = context.scene.avatar_toolkit.join_meshes # Merge armatures merge_armatures( base_armature_name, merge_armature_name, mesh_only=False, - merge_all_bones=context.scene.avatar_toolkit.merge_all_bones, + merge_all_bones=merge_all_bones, join_meshes=join_meshes, operator=self ) @@ -76,10 +77,10 @@ class AvatarToolkit_OT_MergeArmature(Operator): self.report({'ERROR'}, str(e)) return {'CANCELLED'} -def delete_rigidbodies_and_joints(armature: Object): - """Delete rigid bodies and joints associated with the armature.""" - to_delete = [] - parent = armature +def delete_rigidbodies_and_joints(armature: Object) -> None: + """Delete rigid bodies and joints associated with an armature""" + to_delete: List[Object] = [] + parent: Object = armature while parent.parent: parent = parent.parent @@ -94,9 +95,9 @@ def delete_rigidbodies_and_joints(armature: Object): bpy.data.objects.remove(obj, do_unlink=True) def validate_parents_and_transforms(merge_armature: Object, base_armature: Object, context: Context) -> bool: - """Validate parents and transformations of armatures before merging.""" - merge_parent = merge_armature.parent - base_parent = base_armature.parent + """Validate parent relationships and transformations of armatures""" + merge_parent: Optional[Object] = merge_armature.parent + base_parent: Optional[Object] = base_armature.parent if merge_parent or base_parent: if context.scene.merge_all_bones: @@ -112,21 +113,21 @@ def validate_parents_and_transforms(merge_armature: Object, base_armature: Objec return True def is_transform_clean(obj: Object) -> bool: - """Check if an object's transforms are at default values.""" + """Check if object transforms are at default values""" for i in range(3): if obj.scale[i] != 1 or obj.location[i] != 0 or obj.rotation_euler[i] != 0: return False return True -def prepare_mesh_vertex_groups(mesh: Object): - """Prepare mesh by assigning all vertices to a new vertex group.""" +def prepare_mesh_vertex_groups(mesh: Object) -> None: + """Initialize mesh vertex groups for merging process""" if mesh.vertex_groups: for vg in mesh.vertex_groups: mesh.vertex_groups.remove(vg) bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') - vg = mesh.vertex_groups.new(name=mesh.name) + vg: VertexGroup = mesh.vertex_groups.new(name=mesh.name) bpy.ops.object.vertex_group_assign() bpy.ops.object.mode_set(mode='OBJECT') @@ -136,14 +137,14 @@ def merge_armatures( mesh_only: bool, merge_all_bones: bool = False, join_meshes: bool = False, - operator=None -): - """Main function to merge two armatures.""" + operator: Optional[Operator] = None +) -> None: + """Main function to merge two armatures with their associated meshes and data""" logger.info(f"Merging armatures: {merge_armature_name} into {base_armature_name}") - tolerance = 0.00008726647 # around 0.005 degrees + tolerance: float = 0.00008726647 # around 0.005 degrees - base_armature = bpy.data.objects.get(base_armature_name) - merge_armature = bpy.data.objects.get(merge_armature_name) + base_armature: Optional[Object] = bpy.data.objects.get(base_armature_name) + merge_armature: Optional[Object] = bpy.data.objects.get(merge_armature_name) if not base_armature or not merge_armature: logger.error(f"Armature not found: {merge_armature_name}") @@ -172,12 +173,12 @@ def merge_armatures( fix_zero_length_bones(merge_armature) # Store original parent relationships - original_parents = {} + original_parents: Dict[str, Optional[str]] = {} for bone in merge_armature.data.bones: original_parents[bone.name] = bone.parent.name if bone.parent else None # Get base bone names - base_bone_names = set(bone.name for bone in base_armature.data.bones) + base_bone_names: Set[str] = {bone.name for bone in base_armature.data.bones} # Switch to edit mode on merge armature and rename bones bpy.context.view_layer.objects.active = merge_armature @@ -206,11 +207,11 @@ def merge_armatures( # Restore parent relationships bpy.ops.object.mode_set(mode='EDIT') for bone in base_armature.data.edit_bones: - base_name = bone.name.replace('.merge', '') + base_name: str = bone.name.replace('.merge', '') if base_name in original_parents: - parent_name = original_parents[base_name] + parent_name: Optional[str] = original_parents[base_name] if parent_name: - parent_bone = base_armature.data.edit_bones.get(parent_name) + parent_bone: Optional[EditBone] = base_armature.data.edit_bones.get(parent_name) if parent_bone: bone.parent = parent_bone @@ -223,7 +224,7 @@ def merge_armatures( # Process vertex groups if not mesh_only if not mesh_only: - meshes = [obj for obj in bpy.data.objects if obj.type == 'MESH' and obj.parent == base_armature] + meshes: List[Object] = [obj for obj in bpy.data.objects if obj.type == 'MESH' and obj.parent == base_armature] process_vertex_groups(meshes) # Remove zero weight vertex groups if enabled @@ -235,9 +236,9 @@ def merge_armatures( # Join meshes if requested if join_meshes: - meshes_to_join = [obj for obj in bpy.data.objects if obj.type == 'MESH' and obj.parent == base_armature] + meshes_to_join: List[Object] = [obj for obj in bpy.data.objects if obj.type == 'MESH' and obj.parent == base_armature] if meshes_to_join: - joined_mesh = join_mesh_objects(bpy.context, meshes_to_join) + joined_mesh: Optional[Object] = join_mesh_objects(bpy.context, meshes_to_join) if joined_mesh: logger.info(f"Joined meshes into {joined_mesh.name}") @@ -250,8 +251,8 @@ def merge_armatures( # Remove any remaining .merge bones bpy.context.view_layer.objects.active = base_armature bpy.ops.object.mode_set(mode='EDIT') - edit_bones = base_armature.data.edit_bones - bones_to_remove = [bone for bone in edit_bones if bone.name.endswith('.merge')] + edit_bones: List[EditBone] = base_armature.data.edit_bones + bones_to_remove: List[EditBone] = [bone for bone in edit_bones if bone.name.endswith('.merge')] for bone in bones_to_remove: edit_bones.remove(bone) bpy.ops.object.mode_set(mode='OBJECT') @@ -259,14 +260,13 @@ def merge_armatures( # Final cleanup clear_unused_data_blocks() - def validate_merge_armature_transforms( base_armature: Object, merge_armature: Object, mesh_merge: Optional[Object], tolerance: float ) -> bool: - """Validate transforms of both armatures and mesh.""" + """Validate transforms of both armatures and mesh""" for i in [0, 1, 2]: if abs(base_armature.scale[i] - merge_armature.scale[i]) > tolerance: return False @@ -280,10 +280,10 @@ def validate_merge_armature_transforms( def adjust_merge_armature_transforms( merge_armature: Object, mesh_merge: Object -): - """Adjust transforms of the merge armature.""" - old_loc = list(merge_armature.location) - old_scale = list(merge_armature.scale) +) -> None: + """Adjust transforms of the merge armature""" + old_loc: List[float] = list(merge_armature.location) + old_scale: List[float] = list(merge_armature.scale) for i in [0, 1, 2]: merge_armature.location[i] = (mesh_merge.location[i] * old_scale[i]) + old_loc[i] @@ -295,25 +295,24 @@ def adjust_merge_armature_transforms( mesh_merge.rotation_euler[i] = 0 mesh_merge.scale[i] = 1 - def detect_bones_to_merge( base_edit_bones: bpy.types.ArmatureEditBones, merge_edit_bones: bpy.types.ArmatureEditBones, tolerance: float, merge_all_bones: bool ) -> List[str]: - """Detect corresponding bones between base and merge armatures using smart detection and position tolerance.""" - bones_to_merge = [] + """Detect corresponding bones between base and merge armatures using smart detection and position tolerance""" + bones_to_merge: List[str] = [] # Cache base bone positions - base_bones_positions = { + base_bones_positions: Dict[str, np.ndarray] = { bone.name: np.array(bone.head) for bone in base_edit_bones } # Smart bone detection for merge_bone in merge_edit_bones: - merge_bone_position = np.array(merge_bone.head) - found_match = False + merge_bone_position: np.ndarray = np.array(merge_bone.head) + found_match: bool = False if merge_all_bones and merge_bone.name in base_bones_positions: # If merging same bones by name @@ -333,17 +332,16 @@ def detect_bones_to_merge( return bones_to_merge - -def process_vertex_groups(meshes: List[Object]): - """Process vertex groups in meshes.""" +def process_vertex_groups(meshes: List[Object]) -> None: + """Process vertex groups in meshes""" for mesh in meshes: - vg_names = {vg.name for vg in mesh.vertex_groups} - merge_vg_names = [vg_name for vg_name in vg_names if vg_name.endswith('.merge')] + vg_names: Set[str] = {vg.name for vg in mesh.vertex_groups} + merge_vg_names: List[str] = [vg_name for vg_name in vg_names if vg_name.endswith('.merge')] for vg_merge_name in merge_vg_names: - base_name = vg_merge_name[:-6] - vg_merge = mesh.vertex_groups.get(vg_merge_name) - vg_base = mesh.vertex_groups.get(base_name) + base_name: str = vg_merge_name[:-6] + vg_merge: Optional[VertexGroup] = mesh.vertex_groups.get(vg_merge_name) + vg_base: Optional[VertexGroup] = mesh.vertex_groups.get(base_name) if vg_merge is None: continue @@ -353,20 +351,20 @@ def process_vertex_groups(meshes: List[Object]): else: vg_merge.name = base_name -def mix_vertex_groups(mesh: Object, vg_from_name: str, vg_to_name: str): - """Mix vertex group weights.""" - vg_from = mesh.vertex_groups.get(vg_from_name) - vg_to = mesh.vertex_groups.get(vg_to_name) +def mix_vertex_groups(mesh: Object, vg_from_name: str, vg_to_name: str) -> None: + """Mix vertex group weights""" + vg_from: Optional[VertexGroup] = mesh.vertex_groups.get(vg_from_name) + vg_to: Optional[VertexGroup] = mesh.vertex_groups.get(vg_to_name) if not vg_from or not vg_to: return - num_vertices = len(mesh.data.vertices) - weights_from = np.zeros(num_vertices) - weights_to = np.zeros(num_vertices) + num_vertices: int = len(mesh.data.vertices) + weights_from: np.ndarray = np.zeros(num_vertices) + weights_to: np.ndarray = np.zeros(num_vertices) - idx_from = vg_from.index - idx_to = vg_to.index + idx_from: int = vg_from.index + idx_to: int = vg_to.index for v in mesh.data.vertices: for g in v.groups: @@ -375,14 +373,14 @@ def mix_vertex_groups(mesh: Object, vg_from_name: str, vg_to_name: str): elif g.group == idx_to: weights_to[v.index] = g.weight - weights_combined = np.clip(weights_from + weights_to, 0.0, 1.0) + weights_combined: np.ndarray = np.clip(weights_from + weights_to, 0.0, 1.0) vg_to.add(range(num_vertices), weights_combined.tolist(), 'REPLACE') mesh.vertex_groups.remove(vg_from) -def remove_unused_vertex_groups(mesh: Object): - """Remove vertex groups with no weights.""" +def remove_unused_vertex_groups(mesh: Object) -> None: + """Remove vertex groups with no weights""" for vg in mesh.vertex_groups: - has_weights = False + has_weights: bool = False for vert in mesh.data.vertices: for group in vert.groups: if group.group == vg.index and group.weight > 0.001: @@ -393,9 +391,9 @@ def remove_unused_vertex_groups(mesh: Object): if not has_weights: mesh.vertex_groups.remove(vg) -def apply_armature_to_mesh(armature: Object, mesh: Object): - """Apply armature deformation to mesh.""" - armature_mod = mesh.modifiers.new('PoseToRest', 'ARMATURE') +def apply_armature_to_mesh(armature: Object, mesh: Object) -> None: + """Apply armature deformation to mesh""" + armature_mod: ArmatureModifier = mesh.modifiers.new('PoseToRest', 'ARMATURE') armature_mod.object = armature if bpy.app.version >= (3, 5): @@ -407,15 +405,15 @@ def apply_armature_to_mesh(armature: Object, mesh: Object): with bpy.context.temp_override(object=mesh): bpy.ops.object.modifier_apply(modifier=armature_mod.name) -def apply_armature_to_mesh_with_shapekeys(armature: Object, mesh: Object, context: Context): - """Apply armature deformation to mesh with shape keys.""" - old_active_index = mesh.active_shape_key_index - old_show_only = mesh.show_only_shape_key +def apply_armature_to_mesh_with_shapekeys(armature: Object, mesh: Object, context: Context) -> None: + """Apply armature deformation to mesh with shape keys""" + old_active_index: int = mesh.active_shape_key_index + old_show_only: bool = mesh.show_only_shape_key mesh.show_only_shape_key = True - shape_keys = mesh.data.shape_keys.key_blocks - vertex_groups = [] - mutes = [] + shape_keys: List[ShapeKey] = mesh.data.shape_keys.key_blocks + vertex_groups: List[str] = [] + mutes: List[bool] = [] for sk in shape_keys: vertex_groups.append(sk.vertex_group) @@ -423,23 +421,23 @@ def apply_armature_to_mesh_with_shapekeys(armature: Object, mesh: Object, contex mutes.append(sk.mute) sk.mute = False - disabled_mods = [] + disabled_mods: List[Any] = [] for mod in mesh.modifiers: if mod.show_viewport: mod.show_viewport = False disabled_mods.append(mod) - arm_mod = mesh.modifiers.new('PoseToRest', 'ARMATURE') + arm_mod: ArmatureModifier = mesh.modifiers.new('PoseToRest', 'ARMATURE') arm_mod.object = armature - co_length = len(mesh.data.vertices) * 3 - eval_cos = np.empty(co_length, dtype=np.single) + co_length: int = len(mesh.data.vertices) * 3 + eval_cos: np.ndarray = np.empty(co_length, dtype=np.single) for i, shape_key in enumerate(shape_keys): mesh.active_shape_key_index = i depsgraph = context.evaluated_depsgraph_get() - eval_mesh = mesh.evaluated_get(depsgraph) + eval_mesh: Mesh = mesh.evaluated_get(depsgraph) eval_mesh.data.vertices.foreach_get('co', eval_cos) shape_key.data.foreach_set('co', eval_cos) diff --git a/functions/custom_tools/mesh_attachment.py b/functions/custom_tools/mesh_attachment.py index 560521f..613e5b9 100644 --- a/functions/custom_tools/mesh_attachment.py +++ b/functions/custom_tools/mesh_attachment.py @@ -1,7 +1,7 @@ import bpy -from bpy.types import Operator, Context, Object +from bpy.types import Operator, Context, Object, ArmatureModifier, VertexGroup from mathutils import Vector -from typing import Set, Optional +from typing import Set, Optional, List, Any from ...core.logging_setup import logger from ...core.translations import t @@ -15,28 +15,34 @@ from ...core.common import ( ) class AvatarToolkit_OT_AttachMesh(Operator): - """Attach a mesh to an armature bone with automatic weight setup""" - bl_idname = "avatar_toolkit.attach_mesh" - bl_label = t("AttachMesh.label") - bl_description = t("AttachMesh.desc") - bl_options = {'REGISTER', 'UNDO'} + """Operator to attach a mesh to an armature bone with automatic weight setup""" + bl_idname: str = "avatar_toolkit.attach_mesh" + bl_label: str = t("AttachMesh.label") + bl_description: str = t("AttachMesh.desc") + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context: Context) -> bool: - armature = get_active_armature(context) - return armature is not None and context.mode == 'OBJECT' and len(get_all_meshes(context)) > 0 + """Check if operator can be executed""" + armature: Optional[Object] = get_active_armature(context) + if not armature: + return False + is_valid, _ = validate_armature(armature) + return is_valid def execute(self, context: Context) -> Set[str]: try: logger.info("Starting mesh attachment process") - mesh_name = context.scene.avatar_toolkit.attach_mesh - armature = get_active_armature(context) - attach_bone_name = context.scene.avatar_toolkit.attach_bone - mesh = bpy.data.objects.get(mesh_name) + mesh_name: str = context.scene.avatar_toolkit.attach_mesh + armature: Object = get_active_armature(context) + attach_bone_name: str = context.scene.avatar_toolkit.attach_bone + mesh: Optional[Object] = bpy.data.objects.get(mesh_name) with ProgressTracker(context, 10, "Attaching Mesh") as progress: # Validation steps + is_valid: bool + error_msg: str is_valid, error_msg = validate_mesh_transforms(mesh) if not is_valid: raise ValueError(error_msg) @@ -63,7 +69,7 @@ class AvatarToolkit_OT_AttachMesh(Operator): bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') - vg = mesh.vertex_groups.new(name=mesh_name) + vg: VertexGroup = mesh.vertex_groups.new(name=mesh_name) bpy.ops.object.vertex_group_assign() bpy.ops.object.mode_set(mode='OBJECT') progress.step(t("AttachMesh.setup_weights")) @@ -83,12 +89,14 @@ class AvatarToolkit_OT_AttachMesh(Operator): progress.step(t("AttachMesh.create_bone")) # Calculate bone placement - verts_in_group = [v for v in mesh.data.vertices + verts_in_group: List[Any] = [v for v in mesh.data.vertices for g in v.groups if g.group == vg.index] + dimensions: Vector + roll_angle: float dimensions, roll_angle = calculate_bone_orientation(mesh, verts_in_group) # Set bone position and orientation - center = Vector((0, 0, 0)) + center: Vector = Vector((0, 0, 0)) for v in verts_in_group: center += mesh.data.vertices[v.index].co center /= len(verts_in_group) @@ -111,20 +119,20 @@ class AvatarToolkit_OT_AttachMesh(Operator): self.report({'ERROR'}, str(e)) return {'CANCELLED'} -def validate_mesh_transforms(mesh): - """Validate mesh transforms are suitable for attaching.""" +def validate_mesh_transforms(mesh: Optional[Object]) -> tuple[bool, str]: + """Validate mesh transforms are suitable for attaching""" if not mesh: return False, "Mesh not found" # Check for non-uniform scale - scale = mesh.scale + scale: Vector = mesh.scale if abs(scale[0] - scale[1]) > 0.001 or abs(scale[1] - scale[2]) > 0.001: return False, "Mesh has non-uniform scale. Please apply scale (Ctrl+A)" return True, "" -def validate_mesh_name(armature, mesh_name): - """Validate mesh name doesn't conflict with existing bones.""" +def validate_mesh_name(armature: Object, mesh_name: str) -> tuple[bool, str]: + """Validate mesh name doesn't conflict with existing bones""" if mesh_name in armature.data.bones: return False, f"Bone named '{mesh_name}' already exists in armature" - return True, "" \ No newline at end of file + return True, "" diff --git a/functions/eye_tracking.py b/functions/eye_tracking.py index 0f1169d..6219ac7 100644 --- a/functions/eye_tracking.py +++ b/functions/eye_tracking.py @@ -5,8 +5,8 @@ import math import bmesh import mathutils import json -from bpy.types import Operator, Object, Context -from typing import Optional, Dict, Tuple, Set +from bpy.types import Operator, Object, Context, UILayout, WindowManager, Event, ShapeKey, EditBone, PoseBone +from typing import Optional, Dict, Tuple, Set, List, Any, Union, ClassVar from collections import OrderedDict from random import random from itertools import chain @@ -24,19 +24,19 @@ from ..core.common import ( apply_vertex_positions ) -VALID_EYE_NAMES = { +VALID_EYE_NAMES: Dict[str, List[str]] = { 'left': ['LeftEye', 'Eye_L', 'eye_L', 'eye.L', 'EyeLeft', 'left_eye', 'l_eye'], 'right': ['RightEye', 'Eye_R', 'eye_R', 'eye.R', 'EyeRight', 'right_eye', 'r_eye'] } class CreateEyesAV3Button(bpy.types.Operator): - """Create eye tracking setup for VRChat Avatar 3.0""" - bl_idname = 'avatar_toolkit.create_eye_tracking_av3' - bl_label = t('EyeTracking.create.av3.label') - bl_description = t('EyeTracking.create.av3.desc') - bl_options = {'REGISTER', 'UNDO'} + """Creates eye tracking setup compatible with VRChat Avatar 3.0 system""" + bl_idname: str = 'avatar_toolkit.create_eye_tracking_av3' + bl_label: str = t('EyeTracking.create.av3.label') + bl_description: str = t('EyeTracking.create.av3.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} - mesh = None + mesh: Optional[Object] = None @classmethod def poll(cls, context): @@ -109,13 +109,13 @@ class CreateEyesAV3Button(bpy.types.Operator): return {'CANCELLED'} class CreateEyesSDK2Button(bpy.types.Operator): - """Create eye tracking setup for VRChat SDK2""" - bl_idname = 'avatar_toolkit.create_eye_tracking_sdk2' - bl_label = t('EyeTracking.create.sdk2.label') - bl_description = t('EyeTracking.create.sdk2.desc') - bl_options = {'REGISTER', 'UNDO'} + """Creates eye tracking setup compatible with VRChat SDK2 system""" + bl_idname: str = 'avatar_toolkit.create_eye_tracking_sdk2' + bl_label: str = t('EyeTracking.create.sdk2.label') + bl_description: str = t('EyeTracking.create.sdk2.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} - mesh = None + mesh: Optional[Object] = None @classmethod def poll(cls, context): @@ -201,8 +201,9 @@ class CreateEyesSDK2Button(bpy.types.Operator): return {'CANCELLED'} class EyeTrackingBackup: - def __init__(self): - self.backup_path = os.path.join(bpy.app.tempdir, "eye_tracking_backup.json") + """Manages backup and restoration of eye bone positions""" + def __init__(self) -> None: + self.backup_path: str = os.path.join(bpy.app.tempdir, "eye_tracking_backup.json") self.bone_positions: Dict[str, Dict[str, Tuple[float, float, float]]] = {} def store_bone_positions(self, armature) -> bool: @@ -247,8 +248,10 @@ class EyeTrackingBackup: return False class EyeTrackingValidator: + """Validates eye tracking setup requirements and configurations""" @staticmethod - def find_eye_vertex_groups(mesh_name: str) -> Tuple[str, str]: + def find_eye_vertex_groups(mesh_name: str) -> Tuple[Optional[str], Optional[str]]: + """Locates left and right eye vertex groups in mesh""" mesh = bpy.data.objects.get(mesh_name) if not mesh: return None, None @@ -265,7 +268,8 @@ class EyeTrackingValidator: return left_group, right_group @staticmethod - def validate_setup(context, mesh_name: str) -> Tuple[bool, str]: + def validate_setup(context: Context, mesh_name: str) -> Tuple[bool, str]: + """Validates complete eye tracking setup configuration""" armature = get_active_armature(context) if not armature: return False, t('EyeTracking.validation.noArmature') @@ -299,10 +303,11 @@ class EyeTrackingValidator: return True, t('EyeTracking.validation.success') class StartTestingButton(bpy.types.Operator): - bl_idname = 'avatar_toolkit.start_eye_testing' - bl_label = t('EyeTracking.testing.start.label') - bl_description = t('EyeTracking.testing.start.desc') - bl_options = {'REGISTER', 'UNDO'} + """Initiates eye tracking testing mode""" + bl_idname: str = 'avatar_toolkit.start_eye_testing' + bl_label: str = t('EyeTracking.testing.start.label') + bl_description: str = t('EyeTracking.testing.start.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): @@ -351,10 +356,11 @@ class StartTestingButton(bpy.types.Operator): return {'FINISHED'} class StopTestingButton(bpy.types.Operator): - bl_idname = 'avatar_toolkit.stop_eye_testing' - bl_label = t('EyeTracking.testing.stop.label') - bl_description = t('EyeTracking.testing.stop.desc') - bl_options = {'REGISTER', 'UNDO'} + """Terminates eye tracking testing mode""" + bl_idname: str = 'avatar_toolkit.stop_eye_testing' + bl_label: str = t('EyeTracking.testing.stop.label') + bl_description: str = t('EyeTracking.testing.stop.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} def execute(self, context): global eye_left, eye_right, eye_left_data, eye_right_data, eye_left_rot, eye_right_rot @@ -392,6 +398,7 @@ class StopTestingButton(bpy.types.Operator): return {'FINISHED'} def set_rotation(self, context): + """Updates eye bone rotations based on current settings""" global eye_left, eye_right, eye_left_rot, eye_right_rot toolkit = context.scene.avatar_toolkit @@ -414,10 +421,11 @@ def set_rotation(self, context): return None class ResetRotationButton(bpy.types.Operator): - bl_idname = 'avatar_toolkit.reset_eye_rotation' - bl_label = t('EyeTracking.reset.label') - bl_description = t('EyeTracking.reset.desc') - bl_options = {'REGISTER', 'UNDO'} + """Resets eye bone rotations to default values""" + bl_idname: str = 'avatar_toolkit.reset_eye_rotation' + bl_label: str = t('EyeTracking.reset.label') + bl_description: str = t('EyeTracking.reset.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): @@ -445,10 +453,11 @@ class ResetRotationButton(bpy.types.Operator): return {'FINISHED'} class AdjustEyesButton(bpy.types.Operator): - bl_idname = 'avatar_toolkit.adjust_eyes' - bl_label = t('EyeTracking.adjust.label') - bl_description = t('EyeTracking.adjust.desc') - bl_options = {'REGISTER', 'UNDO'} + """Adjusts eye bone positions and orientations""" + bl_idname: str = 'avatar_toolkit.adjust_eyes' + bl_label: str = t('EyeTracking.adjust.label') + bl_description: str = t('EyeTracking.adjust.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): @@ -494,10 +503,11 @@ class AdjustEyesButton(bpy.types.Operator): return {'FINISHED'} class StartIrisHeightButton(bpy.types.Operator): - bl_idname = 'avatar_toolkit.adjust_iris_height' - bl_label = t('EyeTracking.iris.label') - bl_description = t('EyeTracking.iris.desc') - bl_options = {'REGISTER', 'UNDO'} + """Adjusts iris height for eye meshes""" + bl_idname: str = 'avatar_toolkit.adjust_iris_height' + bl_label: str = t('EyeTracking.iris.label') + bl_description: str = t('EyeTracking.iris.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): @@ -536,10 +546,11 @@ class StartIrisHeightButton(bpy.types.Operator): return {'FINISHED'} class TestBlinking(bpy.types.Operator): - bl_idname = 'avatar_toolkit.test_blinking' - bl_label = t('EyeTracking.blink.test.label') - bl_description = t('EyeTracking.blink.test.desc') - bl_options = {'REGISTER', 'UNDO'} + """Tests eye blinking animations""" + bl_idname: str = 'avatar_toolkit.test_blinking' + bl_label: str = t('EyeTracking.blink.test.label') + bl_description: str = t('EyeTracking.blink.test.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): @@ -559,10 +570,11 @@ class TestBlinking(bpy.types.Operator): return {'FINISHED'} class TestLowerlid(bpy.types.Operator): - bl_idname = 'avatar_toolkit.test_lowerlid' - bl_label = t('EyeTracking.lowerlid.test.label') - bl_description = t('EyeTracking.lowerlid.test.desc') - bl_options = {'REGISTER', 'UNDO'} + """Tests lower eyelid movements""" + bl_idname: str = 'avatar_toolkit.test_lowerlid' + bl_label: str = t('EyeTracking.lowerlid.test.label') + bl_description: str = t('EyeTracking.lowerlid.test.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): @@ -584,10 +596,11 @@ class TestLowerlid(bpy.types.Operator): return {'FINISHED'} class ResetBlinkTest(bpy.types.Operator): - bl_idname = 'avatar_toolkit.reset_blink_test' - bl_label = t('EyeTracking.blink.reset.label') - bl_description = t('EyeTracking.blink.reset.desc') - bl_options = {'REGISTER', 'UNDO'} + """Resets all eye blinking test values""" + bl_idname: str = 'avatar_toolkit.reset_blink_test' + bl_label: str = t('EyeTracking.blink.reset.label') + bl_description: str = t('EyeTracking.blink.reset.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} def execute(self, context): toolkit = context.scene.avatar_toolkit @@ -601,7 +614,8 @@ class ResetBlinkTest(bpy.types.Operator): return {'FINISHED'} -def fix_eye_position(context, old_eye, new_eye, head, right_side): +def fix_eye_position(context: Context, old_eye: Union[EditBone, PoseBone], new_eye: EditBone, head: Optional[EditBone], right_side: bool) -> None: + """Adjusts eye bone positions and orientations for proper tracking""" toolkit = context.scene.avatar_toolkit scale = -toolkit.eye_distance + 1 mesh = bpy.data.objects[toolkit.mesh_name_eye] @@ -637,8 +651,8 @@ def fix_eye_position(context, old_eye, new_eye, head, right_side): new_eye.tail[y_cord] = new_eye.head[y_cord] new_eye.tail[z_cord] = new_eye.head[z_cord] + 0.1 -def repair_shapekeys(mesh_name, vertex_group): - """Fix VRC shape keys by slightly adjusting vertex positions""" +def repair_shapekeys(mesh_name: str, vertex_group: str) -> None: + """Repairs VRChat shape keys by adjusting vertex positions""" armature = get_active_armature(bpy.context) mesh = bpy.data.objects[mesh_name] mesh.select_set(True) @@ -696,10 +710,12 @@ def repair_shapekeys(mesh_name, vertex_group): logger.warning('Shape key repair failed, using random method') repair_shapekeys_mouth(mesh_name) -def randBoolNumber(): +def randBoolNumber() -> int: + """Generates random boolean value as integer""" return -1 if random() < 0.5 else 1 -def repair_shapekeys_mouth(mesh_name): +def repair_shapekeys_mouth(mesh_name: str) -> None: + """Repairs mouth-related shape keys using fallback method""" mesh = bpy.data.objects[mesh_name] mesh.select_set(True) bpy.context.view_layer.objects.active = mesh @@ -730,12 +746,12 @@ def repair_shapekeys_mouth(mesh_name): if not moved: logger.error('Random shape key repair failed') -def get_bone_orientations(): - """Get bone orientation axes""" +def get_bone_orientations() -> Tuple[int, int, int]: + """Returns standardized bone orientation axes""" return (0, 1, 2) # x, y, z coordinates -def find_center_vector_of_vertex_group(mesh, group_name): - """Calculate center position of vertex group""" +def find_center_vector_of_vertex_group(mesh: Object, group_name: str) -> Union[mathutils.Vector, bool]: + """Calculates center position of vertex group""" group = mesh.vertex_groups.get(group_name) if not group: return False @@ -751,8 +767,8 @@ def find_center_vector_of_vertex_group(mesh, group_name): return sum((v for v in vertices), mathutils.Vector()) / len(vertices) -def vertex_group_exists(mesh_obj, group_name): - """Check if vertex group exists and has weights""" +def vertex_group_exists(mesh_obj: Object, group_name: str) -> bool: + """Verifies existence and validity of vertex group""" if not mesh_obj or group_name not in mesh_obj.vertex_groups: return False @@ -763,8 +779,8 @@ def vertex_group_exists(mesh_obj, group_name): return True return False -def copy_vertex_group(self, vertex_group, rename_to): - """Copy vertex group with new name""" +def copy_vertex_group(self: Any, vertex_group: str, rename_to: str) -> None: + """Creates copy of vertex group with new name""" vertex_group_index = 0 # Select and make mesh active bpy.ops.object.mode_set(mode='OBJECT') @@ -781,8 +797,8 @@ def copy_vertex_group(self, vertex_group, rename_to): vertex_group_index += 1 -def copy_shape_key(self, context, from_shape, new_names, new_index): - """Copy shape key with new name""" +def copy_shape_key(self: Any, context: Context, from_shape: str, new_names: List[str], new_index: int) -> str: + """Creates copy of shape key with new name""" blinking = not context.scene.avatar_toolkit.disable_eye_blinking new_name = new_names[new_index - 1] @@ -847,11 +863,11 @@ class VertexGroupCache: cls._cache.clear() class RotateEyeBonesForAv3Button(Operator): - """Reorient eye bones for proper VRChat eye tracking""" - bl_idname = "avatar_toolkit.rotate_eye_bones" - bl_label = t("EyeTracking.rotate.label") - bl_description = t("EyeTracking.rotate.desc") - bl_options = {'REGISTER', 'UNDO'} + """Reorients eye bones for VRChat Avatar 3.0 compatibility""" + bl_idname: str = "avatar_toolkit.rotate_eye_bones" + bl_label: str = t("EyeTracking.rotate.label") + bl_description: str = t("EyeTracking.rotate.desc") + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): @@ -874,11 +890,11 @@ class RotateEyeBonesForAv3Button(Operator): return {'FINISHED'} class ResetEyeTrackingButton(Operator): - """Reset all eye tracking settings and state""" - bl_idname = 'avatar_toolkit.reset_eye_tracking' - bl_label = t('EyeTracking.reset.label') - bl_description = t('EyeTracking.reset.desc') - bl_options = {'REGISTER', 'UNDO'} + """Resets all eye tracking settings to default values""" + bl_idname: str = 'avatar_toolkit.reset_eye_tracking' + bl_label: str = t('EyeTracking.reset.label') + bl_description: str = t('EyeTracking.reset.desc') + bl_options: Set[str] = {'REGISTER', 'UNDO'} def execute(self, context): global eye_left, eye_right, eye_left_data, eye_right_data, eye_left_rot, eye_right_rot @@ -888,7 +904,7 @@ class ResetEyeTrackingButton(Operator): return {'FINISHED'} def validate_weights(mesh_obj: Object, vertex_group: str) -> bool: - """Validate vertex group weights""" + """Validates vertex group weight assignments""" group = mesh_obj.vertex_groups.get(vertex_group) if not group: return False @@ -899,8 +915,8 @@ def validate_weights(mesh_obj: Object, vertex_group: str) -> bool: return True return False -def get_eye_bone_names(armature: Object) -> Dict[str, str]: - """Get standardized eye bone names""" +def get_eye_bone_names(armature: Object) -> Dict[str, Optional[str]]: + """Retrieves standardized eye bone names from armature""" eye_bones = {'left': None, 'right': None} for bone in armature.data.bones: @@ -912,7 +928,7 @@ def get_eye_bone_names(armature: Object) -> Dict[str, str]: return eye_bones def stop_testing(context: Context) -> None: - """Stop eye tracking testing mode""" + """Stops eye tracking testing mode and resets all values""" global eye_left, eye_right, eye_left_data, eye_right_data, eye_left_rot, eye_right_rot if not all([eye_left, eye_right, eye_left_data, eye_right_data, eye_left_rot, eye_right_rot]): diff --git a/functions/optimization/materials_tools.py b/functions/optimization/materials_tools.py index 2741105..d4f1607 100644 --- a/functions/optimization/materials_tools.py +++ b/functions/optimization/materials_tools.py @@ -27,6 +27,11 @@ def consolidate_nodes(node1: ShaderNodeTexImage, node2: ShaderNodeTexImage) -> N """Transfer properties from one texture node to another to ensure consistency""" node2.color_space = node1.color_space node2.coordinates = node1.coordinates + # Add UV map synchronization + if node1.texture_mapping and node2.texture_mapping: + node2.texture_mapping.vector_type = node1.texture_mapping.vector_type + if hasattr(node1, "uv_map") and hasattr(node2, "uv_map"): + node2.uv_map = node1.uv_map def consolidate_textures(node_tree1: NodeTree, node_tree2: NodeTree) -> None: """Synchronize texture nodes between two material node trees""" @@ -81,6 +86,9 @@ class AvatarToolkit_OT_CombineMaterials(Operator): @classmethod def poll(cls, context: Context) -> bool: """Check if the operator can be executed""" + if context.mode != 'OBJECT': + return False + armature = get_active_armature(context) if not armature: return False diff --git a/functions/tools/bone_tools.py b/functions/tools/bone_tools.py index 68e395e..e90ceaf 100644 --- a/functions/tools/bone_tools.py +++ b/functions/tools/bone_tools.py @@ -134,6 +134,10 @@ class AvatarToolKit_OT_DeleteBoneConstraints(Operator): def execute(self, context: Context) -> set[str]: """Execute the constraint removal operation""" + + # Make sure we are in Object mode first or it will error + bpy.ops.object.mode_set(mode='OBJECT') + armature = get_active_armature(context) # Select armature and make it active before changing mode diff --git a/functions/visemes.py b/functions/visemes.py index f6ac3b5..301ab4d 100644 --- a/functions/visemes.py +++ b/functions/visemes.py @@ -1,9 +1,8 @@ -# MIT License # This code was taken from Cats Blender Plugin Unoffical, some of this code is by the original developers, however was improved by myself. # Didn't think it was necessary to re-make something that works well. import bpy -from typing import Dict, List, Optional, Tuple, Any, Set +from typing import Dict, List, Optional, Tuple, Any, Set, Union from bpy.types import Operator, Context, Object, ShapeKey from collections import OrderedDict from ..core.logging_setup import logger @@ -16,22 +15,24 @@ from ..core.common import ( ) class VisemeCache: - """Caches generated viseme shape data""" - _cache: Dict = {} + """Manages caching of generated viseme shape data for performance optimization""" + _cache: Dict[Tuple[str, Tuple[Tuple]], List] = {} @classmethod - def get_cached_shape(cls, key: str, mix_data: List) -> Optional[List]: + def get_cached_shape(cls, key: str, mix_data: List[List[Union[str, float]]]) -> Optional[List]: + """Retrieves cached shape data for a given viseme key and mix configuration""" cache_key = (key, tuple(tuple(x) for x in mix_data)) return cls._cache.get(cache_key) @classmethod - def cache_shape(cls, key: str, mix_data: List, shape_data: List) -> None: + def cache_shape(cls, key: str, mix_data: List[List[Union[str, float]]], shape_data: List) -> None: + """Stores shape data in cache for future retrieval""" cache_key = (key, tuple(tuple(x) for x in mix_data)) cls._cache[cache_key] = shape_data class VisemePreview: - """Handles viseme preview functionality""" - _preview_data: Dict = {} + """Controls real-time preview functionality for viseme shapes""" + _preview_data: Dict[str, float] = {} _active: bool = False _preview_shapes: Optional[OrderedDict] = None @@ -117,13 +118,18 @@ class VisemePreview: cls._preview_shapes = None class ATOOLKIT_OT_preview_visemes(Operator): - bl_idname = "avatar_toolkit.preview_visemes" - bl_label = t("Visemes.preview_label") - bl_description = t("Visemes.preview_desc") - bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + """Operator for previewing viseme shapes in real-time""" + bl_idname: str = "avatar_toolkit.preview_visemes" + bl_label: str = t("Visemes.preview_label") + bl_description: str = t("Visemes.preview_desc") + bl_options: Set[str] = {'REGISTER', 'UNDO', 'INTERNAL'} @classmethod def poll(cls, context: Context) -> bool: + # Check if we're in object mode first + if context.mode != 'OBJECT': + return False + armature = get_active_armature(context) if not armature: return False @@ -165,10 +171,11 @@ def validate_deformation(mesh, mix_data): return max_deform < (mesh_size * 0.4) class ATOOLKIT_OT_create_visemes(Operator): - bl_idname = "avatar_toolkit.create_visemes" - bl_label = t("Visemes.create_label") - bl_description = t("Visemes.create_desc") - bl_options = {'REGISTER', 'UNDO'} + """Operator for generating VRChat-compatible viseme shape keys""" + bl_idname: str = "avatar_toolkit.create_visemes" + bl_label: str = t("Visemes.create_label") + bl_description: str = t("Visemes.create_desc") + bl_options: Set[str] = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context: Context) -> bool: diff --git a/resources/translations/en_US.json b/resources/translations/en_US.json index dd82000..dc60653 100644 --- a/resources/translations/en_US.json +++ b/resources/translations/en_US.json @@ -1,7 +1,7 @@ { "authors": ["Avatar Toolkit Team"], "messages": { - "AvatarToolkit.label": "Avatar Toolkit (Alpha 0.1.0)", + "AvatarToolkit.label": "Avatar Toolkit (Alpha 0.1.1)", "AvatarToolkit.desc1": "Avatar Toolkit is in Early Access there", "AvatarToolkit.desc2": "will be issues, if you find any issues,", "AvatarToolkit.desc3": "please report it on our Github.", @@ -231,6 +231,8 @@ "Visemes.error.no_shapekeys": "Mesh has no shape keys", "Visemes.error.select_shapekeys": "Please select shape keys for A, O and CH", "Visemes.success": "Visemes created successfully", + "Visemes.mesh_select": "Select Mesh", + "Visemes.mesh_select_desc": "Select the mesh to create visemes on", "EyeTracking.label": "Eye Tracking", "EyeTracking.setup": "Eye Tracking Setup", @@ -314,6 +316,8 @@ "EyeTracking.type.av3_desc": "VRChat Avatar 3.0 eye tracking setup", "EyeTracking.type.sdk2": "SDK2 (Legacy)", "EyeTracking.type.sdk2_desc": "VRChat SDK2 eye tracking setup", + "EyeTracking.adjust.label": "Adjust Eye Position", + "EyeTracking.adjust.desc": "Adjust the position of eye bones based on vertex groups", "CustomPanel.label": "Custom Avatar Tools", "CustomPanel.merge_mode": "Merge Mode", @@ -396,8 +400,9 @@ "Language.auto": "Automatic", "Language.en_US": "English", "Language.ja_JP": "Japanese", + "Language.ko_KR": "Korean", "Language.changed.title": "Language Changed", "Language.changed.success": "Language changed successfully!", "Language.changed.restart": "Some UI elements may require restarting Blender" } -} +} \ No newline at end of file diff --git a/resources/translations/ja_JP.json b/resources/translations/ja_JP.json index 57dc4c2..2a7f445 100644 --- a/resources/translations/ja_JP.json +++ b/resources/translations/ja_JP.json @@ -1,298 +1,408 @@ { "authors": ["Avatar Toolkit Team"], "messages": { - "AutoVisemeButton.desc": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใซๅŸบใฅใ„ใฆ่‡ชๅ‹•็š„ใซใƒ“ใ‚ปใƒ ใ‚’ไฝœๆˆ", - "AutoVisemeButton.error.noShapekeys": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", - "AutoVisemeButton.error.selectShapekeys": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", - "AutoVisemeButton.label": "ใƒ“ใ‚ปใƒ ใ‚’ไฝœๆˆ", - "AutoVisemeButton.success": "ใƒ“ใ‚ปใƒ ใฎไฝœๆˆใซๆˆๅŠŸใ—ใพใ—ใŸ", - "AvatarToolkit.label": "Avatar Toolkit (ใ‚ขใƒซใƒ•ใ‚ก็‰ˆ)", - "AvatarToolkit.desc1": "Avatar Toolkitใฏๆ—ฉๆœŸใ‚ขใ‚ฏใ‚ปใ‚นๆฎต้šŽใงใ™", - "AvatarToolkit.desc2": "ๅ•้กŒใŒ็™บ็”Ÿใ™ใ‚‹ๅฏ่ƒฝๆ€งใŒใ‚ใ‚Šใพใ™ใ€‚", - "AvatarToolkit.desc3": "ๅ•้กŒใ‚’่ฆ‹ใคใ‘ใŸๅ ดๅˆใฏGithubใงๅ ฑๅ‘Šใ—ใฆใใ ใ•ใ„ใ€‚", - "Export.resonite.desc": "ใ‚ขใƒ‹ใƒกใƒผใ‚ทใƒงใƒณใจใƒžใƒ†ใƒชใ‚ขใƒซใ‚’ๅซใ‚€GLBใ‚’ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆใ€‚ใ‚ขใƒ‹ใƒกใƒผใ‚ทใƒงใƒณใƒ‡ใƒผใ‚ฟใซใคใ„ใฆใฏ๏ผš", - "Export.resonite.label": "Resoniteใซใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", - "Importer.export_resonite.desc": "GLTFใจใ—ใฆResoniteใซใ‚จใ‚ฏใ‚นใƒใƒผใƒˆใ€‚Blenderใงใƒขใƒ‡ใƒซใฎใ‚นใ‚ฑใƒผใƒซใ‚’็ขบ่ชใ—ใ€Resoniteใงใฏใƒกใƒผใƒˆใƒซๅ˜ไฝใงใ‚คใƒณใƒใƒผใƒˆใ—ใฆใใ ใ•ใ„ใ€‚", - "Importer.export_resonite.label": "Resoniteใซใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", - "Importer.export_vrchat.desc": "VRChatใซใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ๏ผˆChilloutVRใงใ‚‚ๅ‹•ไฝœใ™ใ‚‹ๅฏ่ƒฝๆ€งใ‚ใ‚Š๏ผ‰ใ€‚Catsใฎใ‚จใ‚ฏใ‚นใƒใƒผใƒˆใซไผผใฆใ„ใพใ™ใ€‚", - "Importer.export_vrchat.label": "VRChatใซใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", - "Importer.mmd_anim_importer.desc": "MMDใ‚ขใƒ‹ใƒกใƒผใ‚ทใƒงใƒณ๏ผˆ.vmd๏ผ‰ใ‚’ใ‚คใƒณใƒใƒผใƒˆ", - "Importer.mmd_anim_importer.label": "MMDใ‚ขใƒ‹ใƒกใƒผใ‚ทใƒงใƒณ", - "Importing.importer_search_term": "https://search.brave.com/search?q=blender+{extension}+importer+addon&source=web", - "Importing.need_importer": "{extension}ใ‚ฟใ‚คใƒ—ใซๅฟ…่ฆใชใ‚คใƒณใƒใƒผใ‚ฟใƒผใŒใ‚ใ‚Šใพใ›ใ‚“๏ผใ‚คใƒณใƒใƒผใ‚ฟใƒผๆคœ็ดข็”จใซใ‚ฆใ‚งใƒ–ใƒ–ใƒฉใ‚ฆใ‚ถใ‚’้–‹ใใพใ™...", - "Language.auto": "่‡ชๅ‹•", - "Language.en_US": "English", - "Language.ja_JP": "ๆ—ฅๆœฌ่ชž", - "Optimization.applying_transforms": "ใƒˆใƒฉใƒณใ‚นใƒ•ใ‚ฉใƒผใƒ ใ‚’้ฉ็”จไธญ...", - "Optimization.cleaning_material_names": "ใƒžใƒ†ใƒชใ‚ขใƒซๅใ‚’ๆ•ด็†ไธญ...", - "Optimization.cleaning_material_slots": "ใƒžใƒ†ใƒชใ‚ขใƒซใ‚นใƒญใƒƒใƒˆใ‚’ๆ•ด็†ไธญ...", - "Optimization.clearing_unused_data": "ๆœชไฝฟ็”จใƒ‡ใƒผใ‚ฟใ‚’ๅ‰Š้™คไธญ...", - "Optimization.materials_optimization_report": "ใƒžใƒ†ใƒชใ‚ขใƒซๆœ€้ฉๅŒ–ๅฎŒไบ†๏ผš{num_combined}ๅ€‹ใฎใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตๅˆใ€{num_cleaned_slots}ๅ€‹ใฎใƒžใƒ†ใƒชใ‚ขใƒซใ‚นใƒญใƒƒใƒˆใ‚’ๆ•ด็†ใ€{num_cleaned_names}ๅ€‹ใฎใƒžใƒ†ใƒชใ‚ขใƒซๅใ‚’ๆ•ด็†ใ€{num_removed_data_blocks}ๅ€‹ใฎๆœชไฝฟ็”จใƒ‡ใƒผใ‚ฟใƒ–ใƒญใƒƒใ‚ฏใ‚’ๅ‰Š้™คใ—ใพใ—ใŸ", - "Optimization.combine_materials.desc": "ๆ็”ปใ‚ณใƒผใƒซใ‚’ๆธ›ใ‚‰ใ—ใƒ‘ใƒ•ใ‚ฉใƒผใƒžใƒณใ‚นใ‚’ๅ‘ไธŠใ•ใ›ใ‚‹ใŸใ‚ใ€้กžไผผใ—ใŸใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตๅˆ", - "Optimization.combine_materials.label": "ใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตๅˆ", - "Optimization.consolidating_materials": "ใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตฑๅˆไธญ...", - "Optimization.finalizing": "ๆœ€็ต‚ๅ‡ฆ็†ไธญ...", - "Optimization.fixing_uv_coordinates": "UVๅบงๆจ™ใ‚’ไฟฎๆญฃไธญ...", - "Optimization.join_all_meshes.desc": "ๆ็”ปใ‚ณใƒผใƒซใ‚’ๆธ›ใ‚‰ใ™ใŸใ‚ใ€ใ™ในใฆใฎใƒกใƒƒใ‚ทใƒฅใ‚’1ใคใฎใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใซ็ตๅˆ", - "Optimization.join_all_meshes.label": "ใ™ในใฆใฎใƒกใƒƒใ‚ทใƒฅใ‚’็ตๅˆ", - "Optimization.join_error": "ใƒกใƒƒใ‚ทใƒฅ็ตๅˆไธญใซใ‚จใƒฉใƒผใŒ็™บ็”Ÿ", - "Optimization.join_operation_failed": "็ตๅˆๆ“ไฝœใซๅคฑๆ•—ใ—ใพใ—ใŸ", - "Optimization.join_selected_meshes.desc": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใฎใฟใ‚’1ใคใฎใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใซ็ตๅˆ", - "Optimization.join_selected_meshes.label": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใ‚’็ตๅˆ", - "Optimization.joinmeshes.label": "ใƒกใƒƒใ‚ทใƒฅใฎ็ตๅˆ๏ผš", - "Optimization.joining_meshes": "ใƒกใƒƒใ‚ทใƒฅใ‚’็ตๅˆไธญ...", - "Optimization.label": "ๆœ€้ฉๅŒ–", - "Optimization.material_attribute_mismatch": "ใƒžใƒ†ใƒชใ‚ขใƒซ{material_name}ใฎๅฑžๆ€งใŒไธ€่‡ดใ—ใพใ›ใ‚“ใ€‚ใ‚นใ‚ญใƒƒใƒ—ใ—ใพใ™", - "Optimization.materials_combined": "{num_combined}ๅ€‹ใฎใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตๅˆใ—ใพใ—ใŸ", - "Optimization.meshes_joined": "ใƒกใƒƒใ‚ทใƒฅใฎ็ตๅˆใซๆˆๅŠŸใ—ใพใ—ใŸ", - "Optimization.no_armature_selected": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", - "Optimization.no_mesh_selected": "ใƒกใƒƒใ‚ทใƒฅใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", - "Optimization.no_meshes_found": "้ธๆŠžใ—ใŸใ‚ขใƒผใƒžใƒใƒฅใ‚ขใซใƒกใƒƒใ‚ทใƒฅใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", - "Optimization.options.label": "ๆœ€้ฉๅŒ–๏ผš", - "Optimization.preparing_meshes": "ใƒกใƒƒใ‚ทใƒฅใ‚’ๆบ–ๅ‚™ไธญ...", - "Optimization.processing_mesh_no_shapekeys": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใฎใชใ„ใƒกใƒƒใ‚ทใƒฅใ€Œ{mesh_name}ใ€ใ‚’ๅ‡ฆ็†ไธญ", - "Optimization.processing_shapekey": "ใƒกใƒƒใ‚ทใƒฅใ€Œ{mesh_name}ใ€ใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ€Œ{shapekeyname}ใ€ใ‚’ๅ‡ฆ็†ไธญ", - "Optimization.remove_doubles_completed": "้‡่ค‡้ ‚็‚นใฎๅ‰Š้™คใŒๅฎŒไบ†ใ—ใพใ—ใŸ", - "Optimization.remove_doubles_safely.desc": "ๅฃใฎๅฝข็Šถใชใฉใฎ้‡่ฆใช็‰นๅพดใ‚’ไฟๆŒใ—ใชใŒใ‚‰้‡่ค‡้ ‚็‚นใ‚’ๅ‰Š้™คใ—ใพใ™ใ€‚\n็ด ๆ—ฉใ„่งฃๆฑบ็ญ–ใงใ™ใŒใ€ๅ‹•ใ้ ‚็‚นใฏ็ตๅˆใ—ใพใ›ใ‚“ใ€‚", - "Optimization.remove_doubles_safely.label": "ๅฎ‰ๅ…จใซ้‡่ค‡้ ‚็‚นใ‚’ๅ‰Š้™ค", - "Optimization.remove_doubles_safely_advanced.label": "้ซ˜ๅบฆใชๅฎ‰ๅ…จ้‡่ค‡้ ‚็‚นๅ‰Š้™ค", - "Optimization.remove_doubles_safely_advanced.desc": "ๅฃใฎๅฝข็Šถใชใฉใฎ้‡่ฆใช็‰นๅพดใ‚’ไฟๆŒใ—ใชใŒใ‚‰้‡่ค‡้ ‚็‚นใ‚’ๅ‰Š้™คใ—ใพใ™ใ€‚\nๅŸบๆœฌ็‰ˆใจ็•ฐใชใ‚Šใ€ๅ‹•ใ้ ‚็‚นใ‚‚็ตๅˆใ—ใพใ™ใŒใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใฏไฟๆŒใ—ใพใ™ใ€‚\nไพ‹๏ผšๅ”‡ใ‚’้–‰ใ˜ใ‚‹ใ“ใจใฏใ‚ใ‚Šใพใ›ใ‚“ใŒใ€ๅ”‡ใ‚’ๆง‹ๆˆใ™ใ‚‹ๅˆ†ๅ‰ฒใ•ใ‚ŒใŸใƒใƒชใ‚ดใƒณใฏไฟฎๆญฃใ—ใพใ™ใ€‚", - "UVTools.align_uv_to_target.warning.too_much": "ใ‚จใƒฉใƒผ๏ผ้ธๆŠžใŒๅคšใ™ใŽใพใ™ใ€‚2ใคใฎใ‚จใƒƒใ‚ธใ‚’้ธๆŠžใ—ใฆใ„ใพใ™ใ‹๏ผŸ", - "UVTools.align_uv_to_target.warning.need_a_line": "ๅ„้ธๆŠžใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใซUVใƒใ‚คใƒณใƒˆใฎ1่กŒใŒๅฟ…่ฆใงใ™ใ€‚ใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใ€Œ{obj}ใ€ใŒใ“ใฎ่ฆไปถใ‚’ๆบ€ใŸใ—ใฆใ„ใพใ›ใ‚“๏ผ", - "avatar_toolkit.align_uv_edges_to_target.label": "UVใ‚จใƒƒใ‚ธใ‚’ใ‚ฟใƒผใ‚ฒใƒƒใƒˆใซๅˆใ‚ใ›ใ‚‹", - "avatar_toolkit.align_uv_edges_to_target.desc": "้ธๆŠžใ•ใ‚ŒใŸๅ„ใƒกใƒƒใ‚ทใƒฅใฎUVใƒใ‚คใƒณใƒˆใฎ็ทšใ‚’ใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–ใƒกใƒƒใ‚ทใƒฅใฎ้ธๆŠžใ•ใ‚ŒใŸUVใƒใ‚คใƒณใƒˆใฎ็ทšใซๅˆใ‚ใ›ใพใ™ใ€‚\nใ‚ใ‚‹ใƒขใƒ‡ใƒซใฎใƒ†ใ‚ฏใ‚นใƒใƒฃใ‚’ๅˆฅใฎใƒขใƒ‡ใƒซใซ้ฉ็”จใ™ใ‚‹้š›ใซไพฟๅˆฉใงใ™ใ€‚\n2Dใ‚ซใƒผใ‚ฝใƒซใ‹ใ‚‰ใฎ่ท้›ขใ‚’ไฝฟ็”จใ—ใฆๅ„ใƒกใƒƒใ‚ทใƒฅใฎUVใƒใ‚คใƒณใƒˆใฎ็ทšใฎ้–‹ๅง‹็‚นใ‚’่ญ˜ๅˆฅใ—ใพใ™ใ€‚", - "Quick_Access.selected_armature.label": "้ธๆŠžใ•ใ‚ŒใŸใ‚ขใƒผใƒžใƒใƒฅใ‚ข", - "Quick_Access.selected_armature.desc": "Avatar Toolkitใฎๆ“ไฝœๅฏพ่ฑกใจใชใ‚‹็พๅœจใฎใ€Œใ‚ฟใƒผใ‚ฒใƒƒใƒˆใ€ใ‚ขใƒผใƒžใƒใƒฅใ‚ข", - "Quick_Access.export": "ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", - "Quick_Access.export_fbx.desc": "ใƒขใƒ‡ใƒซใ‚’FBXใจใ—ใฆใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", - "Quick_Access.export_fbx.label": "FBXใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", - "Quick_Access.export_menu.desc": "ใ‚ตใƒใƒผใƒˆใ•ใ‚Œใฆใ„ใ‚‹ๅฝขๅผใซใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", - "Quick_Access.export_menu.label": "ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆใƒกใƒ‹ใƒฅใƒผ", - "Quick_Access.import": "ใ‚คใƒณใƒใƒผใƒˆ", - "Quick_Access.import_export.label": "ใ‚คใƒณใƒใƒผใƒˆ/ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ๏ผš", - "Quick_Access.import_menu.desc": "ใƒขใƒ‡ใƒซใ‚’ใ‚คใƒณใƒใƒผใƒˆ", - "Quick_Access.import_menu.label": "ใ‚คใƒณใƒใƒผใƒˆใƒกใƒ‹ใƒฅใƒผ", - "Quick_Access.import_pmd": "PMDใ‚คใƒณใƒใƒผใƒˆ", - "Quick_Access.import_pmd.desc": "MMD PMDใƒขใƒ‡ใƒซใ‚’ใ‚คใƒณใƒใƒผใƒˆ", - "Quick_Access.import_pmx": "PMXใ‚คใƒณใƒใƒผใƒˆ", - "Quick_Access.import_pmx.desc": "MMD PMXใƒขใƒ‡ใƒซใ‚’ใ‚คใƒณใƒใƒผใƒˆ", - "Quick_Access.import_success": "ใƒขใƒ‡ใƒซใฎใ‚คใƒณใƒใƒผใƒˆใซๆˆๅŠŸใ—ใพใ—ใŸ", - "Quick_Access.label": "ใ‚ฏใ‚คใƒƒใ‚ฏใ‚ขใ‚ฏใ‚ปใ‚น", - "Quick_Access.options": "ใ‚ฏใ‚คใƒƒใ‚ฏใ‚ขใ‚ฏใ‚ปใ‚น๏ผš", - "Quick_Access.select_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’้ธๆŠž๏ผš", - "Quick_Access.apply_armature_failed": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใฎ็ตๅˆๆฎต้šŽใงใƒใƒผใ‚บใ‚’ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใซ้ฉ็”จใงใใพใ›ใ‚“ใงใ—ใŸ๏ผ", - "Quick_Access.apply_pose_as_rest.desc": "็พๅœจใฎใƒใƒผใ‚บใ‚’ใƒ‡ใƒ•ใ‚ฉใƒซใƒˆใฎไผ‘ๆญขใƒใƒผใ‚บใซใ—ใพใ™ใ€‚", - "Quick_Access.stop_pose_mode.desc": "ใƒใƒผใ‚บใƒขใƒผใƒ‰ใ‚’็ต‚ไบ†ใ—ใ€ใƒใƒผใ‚บใƒขใƒผใƒ‰ใฎๅ…จใฆใฎ่กจ็คบใƒœใƒผใƒณใฎใƒใƒผใ‚บใ‚’ใ‚ฏใƒชใ‚ขใ—ใพใ™ใ€‚", - "Quick_Access.apply_pose_as_rest.label": "ใƒใƒผใ‚บใ‚’ไผ‘ๆญขใƒใƒผใ‚บใจใ—ใฆ้ฉ็”จ", - "Quick_Access.apply_pose_as_shapekey.desc": "็พๅœจใฎใƒใƒผใ‚บใ‚’ๅพŒใงๆœ‰ๅŠนๅŒ–ใงใใ‚‹ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใจใ—ใฆไฝœๆˆใ—ใพใ™ใ€‚\n้กŽใฎ้–‹้–‰ไฝ็ฝฎใ‚’้ก”ใฎๅ‹•ใใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใจใ—ใฆ้ฉ็”จใ™ใ‚‹้š›ใซไพฟๅˆฉใงใ™ใ€‚", - "Quick_Access.apply_pose_as_shapekey.label": "ใƒใƒผใ‚บใ‚’ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใจใ—ใฆ้ฉ็”จ", - "Quick_Access.stop_pose_mode.label": "ใƒใƒผใ‚บใƒขใƒผใƒ‰ใ‚’็ต‚ไบ†", - "Quick_Access.start_pose_mode.desc": "Avatar Toolkitใฎใ‚ฟใƒผใ‚ฒใƒƒใƒˆใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎใƒใƒผใ‚บใƒขใƒผใƒ‰ใ‚’้–‹ๅง‹ใ—ใพใ™ใ€‚", - "Quick_Access.start_pose_mode.label": "ใƒใƒผใ‚บใƒขใƒผใƒ‰ใ‚’้–‹ๅง‹", - "Quick_Access.select_export.label": "ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆๆ–นๆณ•ใ‚’้ธๆŠž", - "Quick_Access.select_export_resonite.label": "Resonite", - "Settings.label": "่จญๅฎš", - "Settings.language.desc": "ใ‚ขใƒ‰ใ‚ชใƒณใฎUI่จ€่ชžใ‚’้ธๆŠž", - "Settings.language.label": "่จ€่ชž๏ผš", - "Settings.translation_restart_popup.description": "็ฟป่จณใฎๆ›ดๆ–ฐใซใคใ„ใฆ", - "Settings.translation_restart_popup.label": "็ฟป่จณใฎๆ›ดๆ–ฐ", - "Settings.translation_restart_popup.message1": "ไธ€้ƒจใฎ็ฟป่จณใฏBlenderใ‚’ๅ†่ตทๅ‹•ใ™ใ‚‹ใพใง", - "Settings.translation_restart_popup.message2": "้ฉ็”จใ•ใ‚Œใชใ„ๅ ดๅˆใŒใ‚ใ‚Šใพใ™ใ€‚", - "TextureAtlas.atlas_completed": "ใƒ†ใ‚ฏใ‚นใƒใƒฃใ‚ขใƒˆใƒฉใ‚นใฎไฝœๆˆใŒๅฎŒไบ†ใ—ใพใ—ใŸ", - "TextureAtlas.atlas_error": "ใƒ†ใ‚ฏใ‚นใƒใƒฃใ‚ขใƒˆใƒฉใ‚นใฎไฝœๆˆไธญใซใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸ", - "TextureAtlas.atlas_materials": "ใƒžใƒ†ใƒชใ‚ขใƒซใ‚’ใ‚ขใƒˆใƒฉใ‚นๅŒ–", - "TextureAtlas.atlas_materials_desc": "ใƒขใƒ‡ใƒซใ‚’ๆœ€้ฉๅŒ–ใ™ใ‚‹ใŸใ‚ใซใƒžใƒ†ใƒชใ‚ขใƒซใ‚’ใ‚ขใƒˆใƒฉใ‚นๅŒ–", - "TextureAtlas.label": "ใƒ†ใ‚ฏใ‚นใƒใƒฃใ‚ขใƒˆใƒฉใ‚น", - "TextureAtlas.loaded_list": "ใƒ†ใ‚ฏใ‚นใƒใƒฃใ‚ขใƒˆใƒฉใ‚นใƒžใƒ†ใƒชใ‚ขใƒซใƒชใ‚นใƒˆใ‚’่ชญใฟ่พผใฟใพใ—ใŸ", - "TextureAtlas.material_list_label": "ใƒ†ใ‚ฏใ‚นใƒใƒฃใ‚ขใƒˆใƒฉใ‚นใƒžใƒ†ใƒชใ‚ขใƒซใƒชใ‚นใƒˆใฎใƒžใƒ†ใƒชใ‚ขใƒซ", - "TextureAtlas.reload_list": "ใƒ†ใ‚ฏใ‚นใƒใƒฃใ‚ขใƒˆใƒฉใ‚นใƒžใƒ†ใƒชใ‚ขใƒซใƒชใ‚นใƒˆใ‚’ๅ†่ชญใฟ่พผใฟ", - "Tools.bones_translated_success": "ใ™ในใฆใฎใƒœใƒผใƒณใ‚’ๆญฃๅธธใซใƒ’ใƒฅใƒผใƒžใƒŽใ‚คใƒ‰ๅใซๅค‰ๆ›ใ—ใพใ—ใŸ", - "Tools.bones_translated_with_fails": "{translate_bone_fails}ๅ€‹ใฎใƒœใƒผใƒณใ‚’ใƒ’ใƒฅใƒผใƒžใƒŽใ‚คใƒ‰ๅใซๅค‰ๆ›ใงใใพใ›ใ‚“ใงใ—ใŸใ€‚ๅๅ‰ใซใ€Œใ€ใ‚’่ฟฝๅŠ ใ—ใพใ™ใ€‚", - "Tools.convert_to_resonite.desc": "ใƒขใƒ‡ใƒซใฎใƒœใƒผใƒณๅใ‚’Resoniteไบ’ๆ›ใฎๅๅ‰ใซๅค‰ๆ›", - "Tools.convert_to_resonite.label": "Resoniteใซๅค‰ๆ›", - "Tools.create_digitigrade_legs.desc": "้ธๆŠžใ—ใŸใƒœใƒผใƒณใƒใ‚งใƒผใƒณใ‹ใ‚‰็ฃ่„šใ‚’ไฝœๆˆ", - "Tools.create_digitigrade_legs.label": "็ฃ่„šใ‚’ไฝœๆˆ", - "Tools.digitigrade_legs.error.bone_format": "ใƒœใƒผใƒณใฎๅฝขๅผใŒๆญฃใ—ใใ‚ใ‚Šใพใ›ใ‚“๏ผ4ใคใฎ้€ฃ็ถšใ—ใŸใƒœใƒผใƒณใฎใƒใ‚งใƒผใƒณใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„๏ผ", - "Tools.digitigrade_legs.success": "็ฃ่„šใฎไฝœๆˆใซๆˆๅŠŸใ—ใพใ—ใŸ", - "Tools.import_any_model.desc": "FBXใ€SMDใ€DMXใ€GLTFใ€PMDใ€PMXใชใฉใ€ใ‚ตใƒใƒผใƒˆใ•ใ‚Œใฆใ„ใ‚‹ใƒขใƒ‡ใƒซใ‚’ใ‚คใƒณใƒใƒผใƒˆ", - "Tools.import_any_model.label": "ใƒขใƒ‡ใƒซใ‚’ใ‚คใƒณใƒใƒผใƒˆ", - "Tools.label": "ใƒ„ใƒผใƒซ", - "Tools.no_armature_selected": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", - "Tools.select_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", - "Tools.tools_title.label": "ใƒ„ใƒผใƒซ๏ผš", - "Tools.separate_by.label": "ๅˆ†้›ขๆ–นๆณ•๏ผš", - "Tools.separate_by_materials.label": "ใƒžใƒ†ใƒชใ‚ขใƒซใงๅˆ†้›ข", - "Tools.separate_by_materials.desc": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใ‚’ใƒžใƒ†ใƒชใ‚ขใƒซใงๅˆ†้›ข", - "Tools.separate_by_materials.success": "ใƒกใƒƒใ‚ทใƒฅใ‚’ใƒžใƒ†ใƒชใ‚ขใƒซใงๅˆ†้›ขใ—ใพใ—ใŸ", - "Tools.separate_by_loose_parts.label": "ๅˆ†้›ขใƒ‘ใƒผใƒ„ใงๅˆ†้›ข", - "Tools.separate_by_loose_parts.desc": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใ‚’ๅˆ†้›ขใƒ‘ใƒผใƒ„ใงๅˆ†้›ข", - "Tools.separate_by_loose_parts.success": "ใƒกใƒƒใ‚ทใƒฅใ‚’ๅˆ†้›ขใƒ‘ใƒผใƒ„ใงๅˆ†้›ขใ—ใพใ—ใŸ", - "Tools.apply_transforms.label": "ใƒˆใƒฉใƒณใ‚นใƒ•ใ‚ฉใƒผใƒ ใ‚’้ฉ็”จ", - "Tools.apply_transforms.desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใจใใฎใƒกใƒƒใ‚ทใƒฅใซไฝ็ฝฎใ€ๅ›ž่ปขใ€ใ‚นใ‚ฑใƒผใƒซใ‚’้ฉ็”จ", - "Tools.apply_transforms.invalid_armature": "็„กๅŠนใชใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ™", - "Tools.apply_transforms.success": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใจใƒกใƒƒใ‚ทใƒฅใซใƒˆใƒฉใƒณใ‚นใƒ•ใ‚ฉใƒผใƒ ใ‚’้ฉ็”จใ—ใพใ—ใŸ", - "Tools.remove_unused_shapekeys.label": "ๆœชไฝฟ็”จใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ๅ‰Š้™ค", - "Tools.remove_unused_shapekeys.tolerance.desc": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ไฟๆŒใ™ใ‚‹ๆœ€ๅฐใฎ้ ‚็‚น็งปๅ‹•้‡\n๏ผˆไปปๆ„ใฎๅบงๆจ™ใงใฎไฝ็ฝฎ๏ผ‰", - "Tools.remove_unused_shapekeys.desc": "ไฝ•ใ‚‚ๅ‹•ใ‹ใ•ใชใ„ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ๅ‰Š้™คใ—ใพใ™ใ€‚\nใ‚ซใƒ†ใ‚ดใƒชใƒผใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใฏๅ‰Š้™คใ—ใพใ›ใ‚“ใ€‚\n๏ผˆไพ‹๏ผšๅๅ‰ใซใ€Œ~ใ€ใ€Œ-ใ€ใ€Œ=ใ€ใ‚’ๅซใ‚€ใ‚‚ใฎ๏ผ‰", - "Tools.remove_unused_shapekeys.tolerance.label": "ไฝ็ฝฎใฎ่จฑๅฎนๅ€ค", - "Tools.apply_shape_key.label": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ใƒ™ใƒผใ‚นใซ้ฉ็”จ", - "Tools.apply_shape_key.desc": "้ธๆŠžใ—ใŸใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ใƒ™ใƒผใ‚นใซ้ฉ็”จใ—ใ€ใƒ‡ใƒ•ใ‚ฉใƒซใƒˆใงใ‚ชใƒณใซใ—ใพใ™ใ€‚", - "Tools.apply_shape_key.error": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใŒไฝ•ใ‚‰ใ‹ใฎ็†็”ฑใงใƒžใƒผใ‚ธใ•ใ‚Œใพใ›ใ‚“ใงใ—ใŸ๏ผ", - "Tools.remove_zero_weight_bones.success": "ใ‚ฆใ‚งใ‚คใƒˆใฎใชใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™คใ—ใพใ—ใŸ", - "Tools.remove_zero_weight_bones.label": "ใ‚ฆใ‚งใ‚คใƒˆใฎใชใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™ค", - "Tools.remove_zero_weight_bones.desc": "้–พๅ€คไปฅไธ‹ใฎใ‚ฆใ‚งใ‚คใƒˆใ‚’ๆŒใคใƒœใƒผใƒณใ‚’ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‹ใ‚‰ๅ‰Š้™คใ—ใพใ™ใ€‚", - "Tools.merge_bones_to_active.delete_old.desc": "ใƒžใƒผใ‚ธๆ™‚ใซๅคใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™คใ—ใพใ™ใ€‚", - "Tools.merge_bones_to_active.delete_old.label": "ๅคใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™ค", - "Tools.merge_bones_to_active.desc": "้ธๆŠžใ—ใŸใƒœใƒผใƒณใ‚’ใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–ใชใƒœใƒผใƒณ๏ผˆ้’ใพใŸใฏๆฉ™่‰ฒใง้ธๆŠž๏ผ‰ใซใƒžใƒผใ‚ธใ—ใพใ™ใ€‚", - "Tools.merge_bones_to_active.label": "ใƒœใƒผใƒณใ‚’ใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–ใชใ‚‚ใฎใซใƒžใƒผใ‚ธ", - "Tools.merge_bones_to_parents.delete_old.desc": "ใƒžใƒผใ‚ธๆ™‚ใซๅคใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™คใ—ใพใ™ใ€‚", - "Tools.merge_bones_to_parents.delete_old.label": "ๅคใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™ค", - "Tools.merge_bones_to_parents.desc": "้ธๆŠžใ—ใŸๅ„ใƒœใƒผใƒณใ‚’ใใ‚Œใžใ‚Œใฎ่ฆชใƒœใƒผใƒณใซใƒžใƒผใ‚ธใ—ใพใ™ใ€‚", - "Tools.merge_bones_to_parents.label": "ใƒœใƒผใƒณใ‚’ๅ€‹ๅˆฅใฎ่ฆชใซใƒžใƒผใ‚ธ", - "Tools.remove_zero_weight_bones.threshold.label": "ใ‚ฆใ‚งใ‚คใƒˆใฎ้–พๅ€ค", - "Tools.remove_zero_weight_bones.threshold.desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขไธ‹ใฎใƒกใƒƒใ‚ทใƒฅใฎใฉใฎ้ƒจๅˆ†ใซใ‚‚ใ“ใฎ้–พๅ€คไปฅไธŠใฎใ‚ฆใ‚งใ‚คใƒˆใŒใชใ„ใƒœใƒผใƒณใฏๅ‰Š้™คใ•ใ‚Œใพใ™", - "Tools.connect_bones.label": "ใƒœใƒผใƒณใ‚’ๆŽฅ็ถš", - "Tools.bone_tools.label": "ใƒœใƒผใƒณใƒ„ใƒผใƒซ", - "Tools.additional_tools.label": "่ฟฝๅŠ ใƒ„ใƒผใƒซ", - "Tools.merge_twist_bones.label": "ใƒ„ใ‚คใ‚นใƒˆใƒœใƒผใƒณใ‚’ใƒžใƒผใ‚ธ", - "Tools.merge_twist_bones.desc": "ใƒ„ใ‚คใ‚นใƒˆใƒœใƒผใƒณใ‚’่ฆชใƒœใƒผใƒณใซใƒžใƒผใ‚ธ", - "Tools.connect_bones.desc": "ใƒœใƒผใƒณใ‚’ใใ‚Œใžใ‚ŒใฎๅญใƒœใƒผใƒณใจๆŽฅ็ถš", - "Tools.connect_bones.invalid_armature": "็„กๅŠนใชใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ™", - "Tools.connect_bones.min_distance.label": "ๆœ€ๅฐ่ท้›ข", - "Tools.connect_bones.min_distance.desc": "ใƒœใƒผใƒณใ‚’ๆŽฅ็ถšใ™ใ‚‹ๆœ€ๅฐ่ท้›ข", - "Tools.connect_bones.success": "{bones_connected}ๅ€‹ใฎใƒœใƒผใƒณใ‚’ๆŽฅ็ถšใ—ใพใ—ใŸ", - "Tools.delete_bone_constraints.label": "ใƒœใƒผใƒณใฎๅˆถ็ด„ใ‚’ๅ‰Š้™ค", - "Tools.delete_bone_constraints.desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎใƒœใƒผใƒณใ‹ใ‚‰ๅ…จใฆใฎๅˆถ็ด„ใ‚’ๅ‰Š้™ค", - "Tools.delete_bone_constraints.invalid_armature": "็„กๅŠนใชใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ™", - "Tools.delete_bone_constraints.success": "ใƒœใƒผใƒณใ‹ใ‚‰{constraints_removed}ๅ€‹ใฎๅˆถ็ด„ใ‚’ๅ‰Š้™คใ—ใพใ—ใŸ", - "Tools.convert_rigify_to_unity.label": "Rigifyใ‚’Unityใซๅค‰ๆ›", - "Tools.convert_rigify_to_unity.desc": "Rigifyใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’Unityใงไฝฟ็”จใงใใ‚‹ใ‚ˆใ†ใซๆบ–ๅ‚™", - "Tools.convert_rigify_to_unity.success": "Rigifyใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’Unity็”จใซๅค‰ๆ›ใ—ใพใ—ใŸ", - "VisemePanel.create_visemes": "ใƒ“ใ‚ปใƒ ใ‚’ไฝœๆˆ", - "VisemePanel.creating_viseme": "ใƒ“ใ‚ปใƒ ใ‚’ไฝœๆˆไธญ๏ผš{viseme_name}", - "VisemePanel.creating_viseme_detail": "ใƒ“ใ‚ปใƒ ใ‚’ไฝœๆˆไธญ๏ผš{viseme_name}", - "VisemePanel.creating_visemes": "ใƒ“ใ‚ปใƒ ใ‚’ไฝœๆˆไธญ...", - "VisemePanel.error.noArmature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", - "VisemePanel.error.noMesh": "ใƒกใƒƒใ‚ทใƒฅใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", - "VisemePanel.error.noShapekeys": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใซใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใŒใ‚ใ‚Šใพใ›ใ‚“", - "VisemePanel.error.selectMesh": "ใƒ“ใ‚ปใƒ ใ‚’ไฝœๆˆใ™ใ‚‹ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", - "VisemePanel.info.selectMesh": "ใƒ“ใ‚ปใƒ ใ‚’ไฝœๆˆใ™ใ‚‹ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", - "VisemePanel.label": "ใƒ“ใ‚ปใƒ ", - "VisemePanel.mixing_shape": "ใ‚ทใ‚งใ‚คใƒ—ใ‚’ๆททๅˆไธญ๏ผš{shape_name} ๅ€ค๏ผš{value}", - "VisemePanel.mouth_a.desc": "'A'ใฎๅฃใฎๅฝขใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ", - "VisemePanel.mouth_a.label": "ๅฃ A", - "VisemePanel.mouth_ch.desc": "'CH'ใฎๅฃใฎๅฝขใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ", - "VisemePanel.mouth_ch.label": "ๅฃ CH", - "VisemePanel.mouth_o.desc": "'O'ใฎๅฃใฎๅฝขใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ", - "VisemePanel.mouth_o.label": "ๅฃ O", - "VisemePanel.removing_existing_viseme": "ๆ—ขๅญ˜ใฎใƒ“ใ‚ปใƒ ใ‚’ๅ‰Š้™คไธญ๏ผš{viseme_name}", - "VisemePanel.removing_existing_visemes": "ๆ—ขๅญ˜ใฎใƒ“ใ‚ปใƒ ใ‚’ๅ‰Š้™คไธญ...", - "VisemePanel.select_mesh": "ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠž", - "VisemePanel.selected_mesh.label": "้ธๆŠžใ•ใ‚ŒใŸใƒกใƒƒใ‚ทใƒฅ", - "VisemePanel.selected_mesh.desc": "ใƒ“ใ‚ปใƒ ๆ“ไฝœ็”จใซ็พๅœจ้ธๆŠžใ•ใ‚Œใฆใ„ใ‚‹ใƒกใƒƒใ‚ทใƒฅ", - "VisemePanel.selected_shapes": "้ธๆŠžใ•ใ‚ŒใŸใ‚ทใ‚งใ‚คใƒ—๏ผšA={shape_a}, O={shape_o}, CH={shape_ch}", - "VisemePanel.shape_intensity": "ใ‚ทใ‚งใ‚คใƒ—ใฎๅผทๅบฆ", - "VisemePanel.shape_intensity_desc": "ใƒ“ใ‚ปใƒ ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใฎๅผทๅบฆ", - "VisemePanel.sorting_shapekeys": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ไธฆในๆ›ฟใˆไธญ...", - "VisemePanel.start_viseme_creation": "ใƒ“ใ‚ปใƒ ไฝœๆˆใ‚’้–‹ๅง‹...", - "VisemePanel.viseme_created_successfully": "ใƒ“ใ‚ปใƒ {viseme_name}ใฎไฝœๆˆใซๆˆๅŠŸใ—ใพใ—ใŸ", - "VisemePanel.viseme_creation_completed": "ใƒ“ใ‚ปใƒ ไฝœๆˆใŒๅฎŒไบ†ใ—ใพใ—ใŸใ€‚", - "MergeArmatures.select_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", - "MergeArmatures.title.label": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎใƒžใƒผใ‚ธ๏ผš", - "MergeArmatures.label": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’ใƒžใƒผใ‚ธ", - "MergeArmatures.selected_armature.label": "ใƒžใƒผใ‚ธๅ…ƒใฎใ‚ขใƒผใƒžใƒใƒฅใ‚ข", - "MergeArmatures.selected_armature.desc": "Avatar Toolkitใฎใ‚ฟใƒผใ‚ฒใƒƒใƒˆใ‚ขใƒผใƒžใƒใƒฅใ‚ขใซใƒžใƒผใ‚ธใ•ใ‚Œใ‚‹ใ‚ขใƒผใƒžใƒใƒฅใ‚ข", - "MergeArmatures.target_armature.label": "ใƒžใƒผใ‚ธๅ…ˆใฎใ‚ขใƒผใƒžใƒใƒฅใ‚ข", - "MergeArmatures.target_armature.desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎใƒžใƒผใ‚ธๅ…ˆใจใชใ‚‹ใ‚ฟใƒผใ‚ฒใƒƒใƒˆใ‚ขใƒผใƒžใƒใƒฅใ‚ข", - "MergeArmature.merge_armatures.label": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’ใƒžใƒผใ‚ธ", - "MergeArmature.merge_armatures.desc": "{selected_armature_label}ใ‚’Avatar Toolkitใฎใ‚ฟใƒผใ‚ฒใƒƒใƒˆใ‚ขใƒผใƒžใƒใƒฅใ‚ขใซใƒžใƒผใ‚ธ", - "MergeArmature.merge_armatures.align_bones.label": "ใƒœใƒผใƒณใ‚’ๆ•ดๅˆ—", - "MergeArmature.merge_armatures.align_bones.desc": "ใƒžใƒผใ‚ธๅ‰ใซใ‚ฝใƒผใ‚นใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎใƒœใƒผใƒณใ‚’ใ‚ฟใƒผใ‚ฒใƒƒใƒˆใ‚ขใƒผใƒžใƒใƒฅใ‚ขใซๅˆใ‚ใ›ใฆ\nใƒœใƒผใƒณใ‚’ไผธ็ธฎใ•ใ›ใพใ™ใ€‚", - "MergeArmature.merge_armatures.apply_transforms.label": "ใƒˆใƒฉใƒณใ‚นใƒ•ใ‚ฉใƒผใƒ ใ‚’้ฉ็”จ", - "MergeArmature.merge_armatures.apply_transforms.desc": "ใƒžใƒผใ‚ธๅ‰ใซใ‚ขใƒผใƒžใƒใƒฅใ‚ขใจใใฎใƒกใƒƒใ‚ทใƒฅใซใƒˆใƒฉใƒณใ‚นใƒ•ใ‚ฉใƒผใƒ ใ‚’้ฉ็”จใ—ใพใ™ใ€‚", - "MMDOptions.optimize_armature.label": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’ๆœ€้ฉๅŒ–", - "MMDOptions.optimize_armature.desc": "ใƒœใƒผใƒณใฎใƒญใƒผใƒซใฎไฟฎๆญฃใ€ใƒœใƒผใƒณใฎๆ•ดๅˆ—ใ€ใƒœใƒผใƒณใฎๆŽฅ็ถšใชใฉใงใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’ๆœ€้ฉๅŒ–", - "MMDOptions.fixing_bone_rolls": "ใƒœใƒผใƒณใฎใƒญใƒผใƒซใ‚’ไฟฎๆญฃไธญ", - "MMDOptions.aligning_bones": "ใƒœใƒผใƒณใ‚’ๆ•ดๅˆ—ไธญ", - "MMDOptions.connecting_bones": "ใƒœใƒผใƒณใ‚’ๆŽฅ็ถšไธญ", - "MMDOptions.deleting_bone_constraints": "ใƒœใƒผใƒณใฎๅˆถ็ด„ใ‚’ๅ‰Š้™คไธญ", - "MMDOptions.merging_bones_to_parents": "ใƒœใƒผใƒณใ‚’่ฆชใซใƒžใƒผใ‚ธไธญ", - "MMDOptions.reordering_bones": "ใƒœใƒผใƒณใ‚’ไธฆในๆ›ฟใˆไธญ", - "MMDOptions.fixing_armature_names": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขๅใ‚’ไฟฎๆญฃไธญ", - "MMDOptions.renaming_bones": "ใƒœใƒผใƒณๅใ‚’ๅค‰ๆ›ดไธญ", - "MMDOptions.armature_optimization_complete": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎๆœ€้ฉๅŒ–ใŒๅฎŒไบ†ใ—ใพใ—ใŸ", - "MMDOptions.convert_materials.label": "ใƒžใƒ†ใƒชใ‚ขใƒซใ‚’ๅค‰ๆ›", - "MMDOptions.convert_materials.desc": "ใƒžใƒ†ใƒชใ‚ขใƒซใ‚’Principled BSDFใ‚ทใ‚งใƒผใƒ€ใƒผใ‚’ไฝฟ็”จใ™ใ‚‹ใ‚ˆใ†ใซๅค‰ๆ›ใ—ใ€MMDใจVRMใ‚ทใ‚งใƒผใƒ€ใƒผใ‚’ไฟฎๆญฃ", - "MMDOptions.converting_materials": "{name}ใฎใƒžใƒ†ใƒชใ‚ขใƒซใ‚’ๅค‰ๆ›ไธญ", - "MMDOptions.title": "MMDใ‚ชใƒ—ใ‚ทใƒงใƒณ", - "MMDOptions.no_armature_selected": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", - "MMDOptions.label": "MMDใ‚ชใƒ—ใ‚ทใƒงใƒณ", - "MMDOptions.cleanup_mesh.label": "ใƒกใƒƒใ‚ทใƒฅใฎใ‚ฏใƒชใƒผใƒณใ‚ขใƒƒใƒ—", - "MMDOptions.cleanup_mesh.desc": "็ฉบใฎใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใ€ๆœชไฝฟ็”จใฎ้ ‚็‚นใ‚ฐใƒซใƒผใƒ—ใ€ๆœชไฝฟ็”จใฎ้ ‚็‚นใ€็ฉบใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ๅ‰Š้™คใ—ใฆใƒกใƒƒใ‚ทใƒฅใ‚’ใ‚ฏใƒชใƒผใƒณใ‚ขใƒƒใƒ—", - "MMDOptions.removing_empty_objects": "็ฉบใฎใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใ‚’ๅ‰Š้™คไธญ", - "MMDOptions.removing_unused_vertex_groups": "ๆœชไฝฟ็”จใฎ้ ‚็‚นใ‚ฐใƒซใƒผใƒ—ใ‚’ๅ‰Š้™คไธญ", - "MMDOptions.removing_unused_vertices": "ๆœชไฝฟ็”จใฎ้ ‚็‚นใ‚’ๅ‰Š้™คไธญ", - "MMDOptions.removing_empty_shape_keys": "็ฉบใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ๅ‰Š้™คไธญ", - "MMDOptions.optimize_weights.label": "ใ‚ฆใ‚งใ‚คใƒˆใ‚’ๆœ€้ฉๅŒ–", - "MMDOptions.optimize_weights.desc": "้ ‚็‚นใ‚ใŸใ‚Šใฎใ‚ฆใ‚งใ‚คใƒˆๆ•ฐใ‚’ๅˆถ้™ใ—ใฆใ‚ฆใ‚งใ‚คใƒˆใ‚’ๆœ€้ฉๅŒ–", - "MMDOptions.max_weights.label": "ๆœ€ๅคงใ‚ฆใ‚งใ‚คใƒˆๆ•ฐ", - "MMDOptions.max_weights.desc": "้ ‚็‚นใ‚ใŸใ‚Šใฎๆœ€ๅคงใ‚ฆใ‚งใ‚คใƒˆๆ•ฐ", - "MMDOptions.merging_weights": "ใ‚ฆใ‚งใ‚คใƒˆใ‚’็ตๅˆไธญ", - "MMDOptions.removing_zero_weight_bones": "ใ‚ฆใ‚งใ‚คใƒˆใฎใชใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™คไธญ", - "MMDOptions.limiting_vertex_weights": "้ ‚็‚นใ‚ฆใ‚งใ‚คใƒˆใ‚’ๅˆถ้™ไธญ", - "MMDOptions.weight_optimization_complete": "ใ‚ฆใ‚งใ‚คใƒˆใฎๆœ€้ฉๅŒ–ใŒๅฎŒไบ†ใ—ใพใ—ใŸ", + "AvatarToolkit.label": "ใ‚ขใƒใ‚ฟใƒผใƒ„ใƒผใƒซใ‚ญใƒƒใƒˆ (Alpha 0.1.1)", + "AvatarToolkit.desc1": "ใ‚ขใƒใ‚ฟใƒผใƒ„ใƒผใƒซใ‚ญใƒƒใƒˆใฏๆ—ฉๆœŸใ‚ขใ‚ฏใ‚ปใ‚นไธญใง", + "AvatarToolkit.desc2": "ๅ•้กŒใŒ็™บ็”Ÿใ™ใ‚‹ๅฏ่ƒฝๆ€งใŒใ‚ใ‚Šใพใ™ใ€‚ๅ•้กŒใ‚’่ฆ‹ใคใ‘ใŸๅ ดๅˆใฏใ€", + "AvatarToolkit.desc3": "GitHubใงๅ ฑๅ‘Šใ—ใฆใใ ใ•ใ„ใ€‚", + "Updater.label": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใ‚ฟใƒผ", "Updater.CheckForUpdateButton.label": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใ‚’็ขบ่ช", "Updater.CheckForUpdateButton.label_alt": "ๅˆฉ็”จๅฏ่ƒฝใชใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใฏใ‚ใ‚Šใพใ›ใ‚“", "Updater.UpdateToLatestButton.label": "{name}ใซใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆ", "Updater.UpdateToSelectedButton.label": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆ", - "Updater.currentVersion": "็พๅœจใฎใƒใƒผใ‚ธใƒงใƒณ๏ผš{name}", + "Updater.currentVersion": "็พๅœจใฎใƒใƒผใ‚ธใƒงใƒณ: {name}", + "Updater.selectVersion": "ใƒใƒผใ‚ธใƒงใƒณใ‚’้ธๆŠž", "Updater.CheckForUpdateButton.desc": "ๅˆฉ็”จๅฏ่ƒฝใชใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใ‚’็ขบ่ช", "UpdateToLatestButton.desc": "ๆœ€ๆ–ฐใƒใƒผใ‚ธใƒงใƒณใซใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆ", "UpdateNotificationPopup.label": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆ้€š็Ÿฅ", - "UpdateNotificationPopup.desc": "ๅˆฉ็”จๅฏ่ƒฝใชใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใซใคใ„ใฆใฎ้€š็Ÿฅ", - "UpdateNotificationPopup.newUpdate": "ๆ–ฐใ—ใ„ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใŒๅˆฉ็”จๅฏ่ƒฝ๏ผš{version}", + "UpdateNotificationPopup.desc": "ๅˆฉ็”จๅฏ่ƒฝใชใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใฎ้€š็Ÿฅ", + "UpdateNotificationPopup.newUpdate": "ๆ–ฐใ—ใ„ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใŒๅˆฉ็”จๅฏ่ƒฝ: {version}", "RestartBlenderPopup.label": "Blenderใ‚’ๅ†่ตทๅ‹•", "RestartBlenderPopup.desc": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใ‚’ๅฎŒไบ†ใ™ใ‚‹ใŸใ‚ใซBlenderใ‚’ๅ†่ตทๅ‹•", - "RestartBlenderPopup.message": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใŒๆˆๅŠŸใ—ใพใ—ใŸ๏ผBlenderใ‚’ๅ†่ตทๅ‹•ใ—ใฆใใ ใ•ใ„ใ€‚", + "RestartBlenderPopup.message": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆๆˆๅŠŸ๏ผBlenderใ‚’ๅ†่ตทๅ‹•ใ—ใฆใใ ใ•ใ„ใ€‚", "check_for_update.cantCheck": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใ‚’็ขบ่ชใงใใพใ›ใ‚“", "download_file.cantConnect": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใ‚ตใƒผใƒใƒผใซๆŽฅ็ถšใงใใพใ›ใ‚“", "download_file.cantFindZip": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใƒ•ใ‚กใ‚คใƒซใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", - "download_file.cantFindAvatarToolkit": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใƒ‘ใƒƒใ‚ฑใƒผใ‚ธๅ†…ใซAvatar Toolkitใƒ•ใ‚กใ‚คใƒซใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", - "CreditsSupport.label": "ใ‚ฏใƒฌใ‚ธใƒƒใƒˆ๏ผ†ใ‚ตใƒใƒผใƒˆ", - "CreditsSupport.credits_title": "ใ‚ฏใƒฌใ‚ธใƒƒใƒˆ", - "CreditsSupport.credits_text1": "Avatar Toolkitใฏไปฅไธ‹ใฎNeonekoใƒใƒผใƒ ใซใ‚ˆใฃใฆไฝœๆˆใ•ใ‚Œใพใ—ใŸ๏ผš", - "CreditsSupport.credits_text2": "YusarinaใจOnan989", - "CreditsSupport.credits_text3": "ไธ€้ƒจใฎใ‚ณใƒผใƒ‰ใฏCats Blender Pluginใ‚’ๅ‚่€ƒใซใ—ใฆใ„ใพใ™ใ€‚", - "CreditsSupport.credits_text4": "ๅ…ƒใฎใƒ—ใƒฉใ‚ฐใ‚คใƒณใฎ่ฒข็Œฎ่€…ใซๆ„Ÿ่ฌใ—ใพใ™ใ€‚", - "CreditsSupport.support_text1": "็งใŸใกใฎๆดปๅ‹•ใ‚’ๆ”ฏๆดใ—ใŸใ„ๅ ดๅˆใฏใ€", - "CreditsSupport.support_text2": "pally.ggใƒšใƒผใ‚ธใงๅฏ„ไป˜/ๆŠ•ใ’้ŠญใŒใงใใพใ™ใ€‚", - "CreditsSupport.support_title": "ใ‚ตใƒใƒผใƒˆใ™ใ‚‹", - "CreditsSupport.support_button": "ใ‚ตใƒใƒผใƒˆใ™ใ‚‹", - "CreditsSupport.help_title": "ใƒ˜ใƒซใƒ—ใŒๅฟ…่ฆใงใ™ใ‹๏ผŸ", - "CreditsSupport.help_text1": "ใพใšใฏWikiใ‚’ใ”็ขบ่ชใใ ใ•ใ„ใ€‚ใ•ใ‚‰ใชใ‚‹ใ‚ตใƒใƒผใƒˆใ‚’", - "CreditsSupport.help_text2": "ๆฑ‚ใ‚ใ‚‹ๅ‰ใซWikiใ‚’่ชญใ‚€ใ“ใจใ‚’ๅผทใใŠๅ‹งใ‚ใ—ใพใ™ใ€‚", - "CreditsSupport.wiki_button": "Wiki", - "CreditsSupport.discord_button": "Discordใซๅ‚ๅŠ ", - "TextureAtlas.include_in_atlas": "ใ‚ขใƒˆใƒฉใ‚นใซๅซใ‚ใ‚‹", - "TextureAtlas.include_in_atlas_desc": "ใ“ใฎใƒžใƒ†ใƒชใ‚ขใƒซใ‚’ใƒ†ใ‚ฏใ‚นใƒใƒฃใ‚ขใƒˆใƒฉใ‚นใซๅซใ‚ใ‚‹", + "download_file.cantFindAvatarToolkit": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใƒ‘ใƒƒใ‚ฑใƒผใ‚ธใซAvatarToolkitใƒ•ใ‚กใ‚คใƒซใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + + "QuickAccess.label": "ใ‚ฏใ‚คใƒƒใ‚ฏใ‚ขใ‚ฏใ‚ปใ‚น", + "QuickAccess.select_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’้ธๆŠž", + "QuickAccess.valid_armature": "ๆœ‰ๅŠนใชใ‚ขใƒผใƒžใƒใƒฅใ‚ข", + "QuickAccess.bones_count": "ใƒœใƒผใƒณๆ•ฐ: {count}", + "QuickAccess.pose_bones_available": "ใƒใƒผใ‚บใƒœใƒผใƒณ: ๅˆฉ็”จๅฏ่ƒฝ", + "QuickAccess.pose_controls": "ใƒใƒผใ‚บใ‚ณใƒณใƒˆใƒญใƒผใƒซ", + "QuickAccess.import_export": "ใ‚คใƒณใƒใƒผใƒˆ/ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", + "QuickAccess.import": "ใ‚คใƒณใƒใƒผใƒˆ", + "QuickAccess.export": "ใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", + "QuickAccess.export_fbx": "FBXใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", + "QuickAccess.export_resonite": "Resoniteใซใ‚จใ‚ฏใ‚นใƒใƒผใƒˆ", + "QuickAccess.start_pose_mode.label": "ใƒใƒผใ‚บใƒขใƒผใƒ‰้–‹ๅง‹", + "QuickAccess.start_pose_mode.desc": "้ธๆŠžใ—ใŸใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎใƒใƒผใ‚บใƒขใƒผใƒ‰ใซๅ…ฅใ‚‹", + "QuickAccess.stop_pose_mode.label": "ใƒใƒผใ‚บใƒขใƒผใƒ‰็ต‚ไบ†", + "QuickAccess.stop_pose_mode.desc": "ใƒใƒผใ‚บใƒขใƒผใƒ‰ใ‚’็ต‚ไบ†ใ—ใ€ๅค‰ๅฝขใ‚’ใ‚ฏใƒชใ‚ข", + "QuickAccess.apply_pose_as_shapekey.label": "ใƒใƒผใ‚บใ‚’ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใจใ—ใฆ้ฉ็”จ", + "QuickAccess.apply_pose_as_shapekey.desc": "็พๅœจใฎใƒใƒผใ‚บใ‹ใ‚‰ๆ–ฐใ—ใ„ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ไฝœๆˆ", + "QuickAccess.apply_pose_as_rest.label": "ใƒใƒผใ‚บใ‚’ๅˆๆœŸไฝ็ฝฎใจใ—ใฆ้ฉ็”จ", + "QuickAccess.apply_pose_as_rest.desc": "็พๅœจใฎใƒใƒผใ‚บใ‚’ๅˆๆœŸไฝ็ฝฎใจใ—ใฆ้ฉ็”จ", + "QuickAccess.apply_armature_failed": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎไฟฎๆญฃใฎ้ฉ็”จใซๅคฑๆ•—ใ—ใพใ—ใŸ", + "QuickAccess.validation_basic_warning": "ๅŸบๆœฌ็š„ใชๆคœ่จผใฎใฟๆœ‰ๅŠน", + "QuickAccess.validation_basic_details": "ๅŸบๆœฌ็š„ใชใƒœใƒผใƒณๆง‹้€ ใฎใฟๆคœ่จผใ—ใฆใ„ใพใ™", + "QuickAccess.validation_none_warning": "ๆคœ่จผ็„กๅŠน", + "QuickAccess.validation_none_details": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎๆคœ่จผใฏ่กŒใ‚ใ‚Œใฆใ„ใพใ›ใ‚“", + + "PoseMode.error.start": "ใƒใƒผใ‚บใƒขใƒผใƒ‰ใฎ้–‹ๅง‹ใซๅคฑๆ•—: {error}", + "PoseMode.error.stop": "ใƒใƒผใ‚บใƒขใƒผใƒ‰ใฎ็ต‚ไบ†ใซๅคฑๆ•—: {error}", + "PoseMode.error.shapekey": "ใƒใƒผใ‚บใ‚’ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใจใ—ใฆ้ฉ็”จใซๅคฑๆ•—: {error}", + "PoseMode.error.rest_pose": "ใƒใƒผใ‚บใ‚’ๅˆๆœŸไฝ็ฝฎใจใ—ใฆ้ฉ็”จใซๅคฑๆ•—: {error}", + "PoseMode.shapekey.name": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผๅ", + "PoseMode.shapekey.description": "ๆ–ฐใ—ใ„ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใฎๅๅ‰", + "PoseMode.shapekey.default": "ใƒใƒผใ‚บ_ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ", + "PoseMode.skipped_meshes": "ไธ€้ƒจใฎใƒกใƒƒใ‚ทใƒฅใŒใ‚นใ‚ญใƒƒใƒ—ใ•ใ‚Œใพใ—ใŸ:\n{message}", + "PoseMode.basis": "ๅŸบๆบ–", + + "Armature.validation.no_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", + "Armature.validation.not_armature": "้ธๆŠžใ•ใ‚ŒใŸใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใฏใ‚ขใƒผใƒžใƒใƒฅใ‚ขใงใฏใ‚ใ‚Šใพใ›ใ‚“", + "Armature.validation.no_bones": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใซใƒœใƒผใƒณใŒใ‚ใ‚Šใพใ›ใ‚“", + "Armature.validation.basic_check_failed": "ๅŸบๆœฌ็š„ใชใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎๆคœ่จผใซๅคฑๆ•—ใ—ใพใ—ใŸ", + "Armature.validation.missing_bones": "ๅฟ…้ ˆใƒœใƒผใƒณใŒไธ่ถณ: {bones}", + "Armature.validation.invalid_hierarchy": "{parent}ใจ{child}ใฎ้–“ใฎใƒœใƒผใƒณ้šŽๅฑคใŒ็„กๅŠนใงใ™", + "Armature.validation.asymmetric_bones": "{bone}ใฎๅฏพ็งฐใƒœใƒผใƒณใŒไธ่ถณใ—ใฆใ„ใพใ™", + "Armature.validation.asymmetric_hand_wrist": "ๆ‰‹้ฆ–/ๆ‰‹ใฎใƒœใƒผใƒณใฎๅฏพ็งฐๆ€งใŒไธ่ถณใ—ใฆใ„ใพใ™", + + "Mesh.validation.no_data": "ใƒกใƒƒใ‚ทใƒฅใƒ‡ใƒผใ‚ฟใŒใ‚ใ‚Šใพใ›ใ‚“", + "Mesh.validation.no_vertex_groups": "้ ‚็‚นใ‚ฐใƒซใƒผใƒ—ใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "Mesh.validation.no_armature_modifier": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใƒขใƒ‡ใ‚ฃใƒ•ใ‚กใ‚คใ‚ขใŒใ‚ใ‚Šใพใ›ใ‚“", + "Mesh.validation.valid": "ใƒใƒผใ‚บๆ“ไฝœใซๆœ‰ๅŠนใชใƒกใƒƒใ‚ทใƒฅใงใ™", + + "Operation.pose_applied": "ใƒใƒผใ‚บใŒๆญฃๅธธใซ้ฉ็”จใ•ใ‚Œใพใ—ใŸ", + "Scene.avatar_toolkit_updater_version_list.name": "ใƒใƒผใ‚ธใƒงใƒณใƒชใ‚นใƒˆ", - "Scene.avatar_toolkit_updater_version_list.description": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆๅฏ่ƒฝใชใƒใƒผใ‚ธใƒงใƒณใฎใƒชใ‚นใƒˆ", - "TextureAtlas.albedo": "ใ‚ขใƒซใƒ™ใƒ‰", - "TextureAtlas.normal": "ๆณ•็ทš", - "TextureAtlas.emission": "็™บๅ…‰", - "TextureAtlas.ambient_occlusion": "ใ‚ขใƒณใƒ“ใ‚จใƒณใƒˆใ‚ชใ‚ฏใƒซใƒผใ‚ธใƒงใƒณ", - "TextureAtlas.height": "ใƒใ‚คใƒˆ", - "TextureAtlas.roughness": "ใƒฉใƒ•ใƒใ‚น", - "TextureAtlas.error.label": "ใ‚จใƒฉใƒผ", - "TextureAtlas.none.label": "ใชใ—", - "TextureAtlas.no_nodes_error.desc": "ใ“ใฎใƒžใƒ†ใƒชใ‚ขใƒซใฏใƒŽใƒผใƒ‰ใ‚’ไฝฟ็”จใ—ใฆใ„ใพใ›ใ‚“๏ผ", - "TextureAtlas.no_images_error.desc": "ใ“ใฎใƒžใƒ†ใƒชใ‚ขใƒซใซใฏ็”ปๅƒใŒใ‚ใ‚Šใพใ›ใ‚“๏ผ", - "TextureAtlas.texture_use_atlas.desc": "{name}ใƒžใƒƒใƒ—ใ‚ขใƒˆใƒฉใ‚นใซไฝฟ็”จใ™ใ‚‹ใƒ†ใ‚ฏใ‚นใƒใƒฃ", - "TextureAtlas.no_materials_selected": "ใ‚ขใƒˆใƒฉใ‚น็”จใฎใƒžใƒ†ใƒชใ‚ขใƒซใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", - "Optimization.select_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", - "CheckForUpdateButton.label": "ใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใ‚’็ขบ่ช", - "CheckForUpdateButton.desc": "ๅˆฉ็”จๅฏ่ƒฝใชใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆใ‚’็ขบ่ช", - "UpdateToLatestButton.label": "ๆœ€ๆ–ฐใƒใƒผใ‚ธใƒงใƒณใซใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆ" + "Scene.avatar_toolkit_updater_version_list.description": "ๅˆฉ็”จๅฏ่ƒฝใชใƒใƒผใ‚ธใƒงใƒณใฎใƒชใ‚นใƒˆ", + + "Optimization.label": "ๆœ€้ฉๅŒ–", + "Optimization.materials_title": "ใƒžใƒ†ใƒชใ‚ขใƒซ", + "Optimization.cleanup_title": "ใƒกใƒƒใ‚ทใƒฅใ‚ฏใƒชใƒผใƒณใ‚ขใƒƒใƒ—", + "Optimization.join_meshes_title": "ใƒกใƒƒใ‚ทใƒฅ็ตๅˆ", + "Optimization.combine_materials": "ใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตๅˆ", + "Optimization.combine_materials_desc": "้กžไผผใ—ใŸใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตๅˆใ—ใฆใƒ‰ใƒญใƒผใ‚ณใƒผใƒซใ‚’ๆธ›ใ‚‰ใ™", + "Optimization.remove_doubles": "้‡่ค‡้ ‚็‚นใ‚’ๅ‰Š้™ค", + "Optimization.remove_doubles_desc": "้‡่ค‡ใ—ใŸ้ ‚็‚นใ‚’ๅ‰Š้™ค", + "Optimization.remove_doubles_advanced": "้ซ˜ๅบฆใช่จญๅฎš", + "Optimization.remove_doubles_advanced_desc": "้ซ˜ๅบฆใชใ‚ชใƒ—ใ‚ทใƒงใƒณใง้‡่ค‡้ ‚็‚นใ‚’ๅ‰Š้™ค", + "Optimization.join_all_meshes": "ใ™ในใฆ็ตๅˆ", + "Optimization.join_all_meshes_desc": "ใ‚ทใƒผใƒณๅ†…ใฎใ™ในใฆใฎใƒกใƒƒใ‚ทใƒฅใ‚’็ตๅˆ", + "Optimization.join_selected_meshes": "้ธๆŠžใ‚’็ตๅˆ", + "Optimization.join_selected_meshes_desc": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใฎใฟใ‚’็ตๅˆ", + "Optimization.no_meshes": "ๆœ€้ฉๅŒ–ใ™ใ‚‹ใƒกใƒƒใ‚ทใƒฅใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "Optimization.materials_combined": "{combined}ๅ€‹ใฎใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตๅˆใ—ใ€{cleaned}ๅ€‹ใฎใ‚นใƒญใƒƒใƒˆใ‚’ใ‚ฏใƒชใƒผใƒณใ‚ขใƒƒใƒ—ใ—ใ€{removed}ๅ€‹ใฎๆœชไฝฟ็”จใƒ‡ใƒผใ‚ฟใƒ–ใƒญใƒƒใ‚ฏใ‚’ๅ‰Š้™คใ—ใพใ—ใŸ", + "Optimization.error.combine_materials": "ใƒžใƒ†ใƒชใ‚ขใƒซใฎ็ตๅˆใซๅคฑๆ•—: {error}", + "Optimization.materials_total": "ๅˆ่จˆใƒžใƒ†ใƒชใ‚ขใƒซๆ•ฐ: {count}", + "Optimization.materials_duplicates": "้‡่ค‡ใฎๅฏ่ƒฝๆ€ง: {count}", + "Optimization.no_materials": "ใƒกใƒƒใ‚ทใƒฅใซใƒžใƒ†ใƒชใ‚ขใƒซใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "Optimization.error.consolidation": "ใƒžใƒ†ใƒชใ‚ขใƒซใฎ็ตฑๅˆใซๅคฑๆ•—ใ—ใพใ—ใŸใ€‚ใ‚ณใƒณใ‚ฝใƒผใƒซใง่ฉณ็ดฐใ‚’็ขบ่ชใ—ใฆใใ ใ•ใ„", + "Optimization.combining_materials": "้กžไผผใ—ใŸใƒžใƒ†ใƒชใ‚ขใƒซใ‚’็ตๅˆไธญ...", + "Optimization.cleaning_slots": "ใƒžใƒ†ใƒชใ‚ขใƒซใ‚นใƒญใƒƒใƒˆใ‚’ใ‚ฏใƒชใƒผใƒ‹ใƒณใ‚ฐไธญ...", + "Optimization.removing_unused": "ๆœชไฝฟ็”จใฎใƒžใƒ†ใƒชใ‚ขใƒซใ‚’ๅ‰Š้™คไธญ...", + "Optimization.selecting_meshes": "ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠžไธญ...", + "Optimization.joining_meshes": "ใƒกใƒƒใ‚ทใƒฅใ‚’็ตๅˆไธญ...", + "Optimization.applying_transforms": "ๅค‰ๅฝขใ‚’้ฉ็”จไธญ...", + "Optimization.fixing_uvs": "UVๅบงๆจ™ใ‚’ไฟฎๆญฃไธญ...", + "Optimization.finalizing": "ๅฎŒไบ†ๅ‡ฆ็†ไธญ...", + "Optimization.meshes_joined": "ใ™ในใฆใฎใƒกใƒƒใ‚ทใƒฅใŒๆญฃๅธธใซ็ตๅˆใ•ใ‚Œใพใ—ใŸ", + "Optimization.selected_meshes_joined": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใŒๆญฃๅธธใซ็ตๅˆใ•ใ‚Œใพใ—ใŸ", + "Optimization.no_mesh_selected": "ใƒกใƒƒใ‚ทใƒฅใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", + "Optimization.select_at_least_two": "ๅฐ‘ใชใใจใ‚‚2ใคใฎใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", + "Optimization.error.join_meshes": "ใƒกใƒƒใ‚ทใƒฅใฎ็ตๅˆใซๅคฑๆ•—: {error}", + "Optimization.error.join_selected": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใฎ็ตๅˆใซๅคฑๆ•—: {error}", + "Optimization.merge_distance": "็ตๅˆ่ท้›ข", + "Optimization.merge_distance_desc": "้ ‚็‚นใ‚’็ตๅˆใ™ใ‚‹่ท้›ขใฎ้–พๅ€ค", + "Optimization.remove_doubles_warning": "ใ“ใฎๅ‡ฆ็†ใซใฏๆ™‚้–“ใŒใ‹ใ‹ใ‚‹ๅ ดๅˆใŒใ‚ใ‚Šใพใ™", + "Optimization.remove_doubles_wait": "ใ“ใฎๆ“ไฝœไธญใ€Blenderใฏๅฟœ็ญ”ใ—ใชใ„ใ‚ˆใ†ใซ่ฆ‹ใˆใ‚‹ๅ ดๅˆใŒใ‚ใ‚Šใพใ™", + "Optimization.error.remove_doubles": "้‡่ค‡้ ‚็‚นใฎๅ‰Š้™คใซๅคฑๆ•—: {error}", + "Optimization.no_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", + "Optimization.processing_mesh": "ใƒกใƒƒใ‚ทใƒฅๅ‡ฆ็†ไธญ: {name}", + "Optimization.processing_shapekey": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผๅ‡ฆ็†ไธญ: {name}", + "Optimization.remove_doubles_completed": "้‡่ค‡้ ‚็‚นใฎๅ‰Š้™คใŒๆญฃๅธธใซๅฎŒไบ†ใ—ใพใ—ใŸ", + + "Tools.label": "ใƒ„ใƒผใƒซ", + "Tools.general_title": "ไธ€่ˆฌใƒ„ใƒผใƒซ", + "Tools.convert_resonite": "Resoniteใซๅค‰ๆ›", + "Tools.convert_resonite_desc": "Resonite็”จใซใƒขใƒ‡ใƒซใ‚’ๅค‰ๆ›", + "Tools.convert_resonite.operation": "Resoniteใซๅค‰ๆ›ไธญ", + "Tools.separate_title": "ๅˆ†้›ขใƒ„ใƒผใƒซ", + "Tools.separate_materials": "ใƒžใƒ†ใƒชใ‚ขใƒซใงๅˆ†้›ข", + "Tools.separate_materials_desc": "ใƒžใƒ†ใƒชใ‚ขใƒซใ”ใจใซใƒกใƒƒใ‚ทใƒฅใ‚’ๅˆ†้›ข", + "Tools.separate_loose": "ๅˆ†้›ขใƒ‘ใƒผใƒ„", + "Tools.separate_loose_desc": "ใƒกใƒƒใ‚ทใƒฅใ‚’ๅˆ†้›ขใƒ‘ใƒผใƒ„ใซๅˆ†ๅ‰ฒ", + "Tools.separate_materials_success": "ใƒกใƒƒใ‚ทใƒฅใ‚’ใƒžใƒ†ใƒชใ‚ขใƒซใ”ใจใซๆญฃๅธธใซๅˆ†้›ขใ—ใพใ—ใŸ", + "Tools.separate_loose_success": "ใƒกใƒƒใ‚ทใƒฅใ‚’ๅˆ†้›ขใƒ‘ใƒผใƒ„ใซๆญฃๅธธใซๅˆ†ๅ‰ฒใ—ใพใ—ใŸ", + "Tools.bone_title": "ใƒœใƒผใƒณใƒ„ใƒผใƒซ", + "Tools.create_digitigrade": "ใƒ‡ใ‚ธใ‚ฟใ‚คใ‚ฐใƒฌใƒผใƒ‰่„šใ‚’ไฝœๆˆ", + "Tools.create_digitigrade_desc": "่„šใ‚’ใƒ‡ใ‚ธใ‚ฟใ‚คใ‚ฐใƒฌใƒผใƒ‰่จญๅฎšใซๅค‰ๆ›", + "Tools.digitigrade": "ใƒ‡ใ‚ธใ‚ฟใ‚คใ‚ฐใƒฌใƒผใƒ‰่„šใ‚’ไฝœๆˆ", + "Tools.digitigrade_desc": "้ธๆŠžใ—ใŸ่„šใฎใƒœใƒผใƒณใ‚’ใƒ‡ใ‚ธใ‚ฟใ‚คใ‚ฐใƒฌใƒผใƒ‰่จญๅฎšใซๅค‰ๆ›", + "Tools.digitigrade_error": "ใƒ‡ใ‚ธใ‚ฟใ‚คใ‚ฐใƒฌใƒผใƒ‰่„šใฎไฝœๆˆใซๅคฑๆ•—: {error}", + "Tools.digitigrade_success": "ใƒ‡ใ‚ธใ‚ฟใ‚คใ‚ฐใƒฌใƒผใƒ‰่„šใฎ่จญๅฎšใŒๆญฃๅธธใซไฝœๆˆใ•ใ‚Œใพใ—ใŸ", + "Tools.processing_leg": "่„šใฎใƒœใƒผใƒณๅ‡ฆ็†ไธญ: {bone}", + "Tools.merge_twist_bones": "ใƒ„ใ‚คใ‚นใƒˆใƒœใƒผใƒณใ‚’ไฟๆŒ", + "Tools.merge_twist_bones_desc": "ใƒใ‚งใƒƒใ‚ฏใ™ใ‚‹ใจใ€้‡ใฟใŒ0ใงใ‚‚ใƒ„ใ‚คใ‚นใƒˆใƒœใƒผใƒณใ‚’ไฟๆŒใ—ใพใ™", + "Tools.clean_weights": "้‡ใฟใชใ—ใƒœใƒผใƒณใ‚’ๅ‰Š้™ค", + "Tools.clean_weights_desc": "้ ‚็‚นใฎ้‡ใฟใŒใชใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™ค", + "Tools.clean_constraints": "ใƒœใƒผใƒณใฎใ‚ณใƒณใ‚นใƒˆใƒฌใ‚คใƒณใƒˆใ‚’ๅ‰Š้™ค", + "Tools.clean_constraints_desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‹ใ‚‰ใ™ในใฆใฎใƒœใƒผใƒณใ‚ณใƒณใ‚นใƒˆใƒฌใ‚คใƒณใƒˆใ‚’ๅ‰Š้™ค", + "Tools.clean_constraints_success": "{count}ๅ€‹ใฎใƒœใƒผใƒณใ‚ณใƒณใ‚นใƒˆใƒฌใ‚คใƒณใƒˆใ‚’ๅ‰Š้™คใ—ใพใ—ใŸ", + "Tools.processing_bone_constraints": "ใƒœใƒผใƒณใฎใ‚ณใƒณใ‚นใƒˆใƒฌใ‚คใƒณใƒˆๅ‰Š้™คไธญ: {bone}", + "Tools.clean_weights_success": "{count}ๅ€‹ใฎ้‡ใฟใชใ—ใƒœใƒผใƒณใ‚’ๅ‰Š้™คใ—ใพใ—ใŸ", + "Tools.clean_weights_threshold": "้‡ใฟใฎ้–พๅ€ค", + "Tools.clean_weights_threshold_desc": "ใƒœใƒผใƒณใซ้‡ใฟใŒใ‚ใ‚‹ใจๅˆคๆ–ญใ™ใ‚‹ๆœ€ๅฐๅ€ค", + "Tools.merge_title": "็ตๅˆใƒ„ใƒผใƒซ", + "Tools.merge_to_active": "ใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–ใซ็ตๅˆ", + "Tools.merge_to_active_desc": "้ธๆŠžใ—ใŸใƒœใƒผใƒณใ‚’ใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–ใชใƒœใƒผใƒณใซ็ตๅˆ", + "Tools.merge_to_parent": "่ฆชใซ็ตๅˆ", + "Tools.merge_to_parent_desc": "ใƒœใƒผใƒณใ‚’ใใ‚Œใžใ‚Œใฎ่ฆชใƒœใƒผใƒณใซ็ตๅˆ", + "Tools.connect_bones": "ใƒœใƒผใƒณใ‚’ๆŽฅ็ถš", + "Tools.connect_bones_desc": "ใƒใ‚งใƒผใƒณๅ†…ใฎๆœชๆŽฅ็ถšใฎใƒœใƒผใƒณใ‚’ๆŽฅ็ถš", + "Tools.additional_title": "่ฟฝๅŠ ใƒ„ใƒผใƒซ", + "Tools.apply_transforms": "ๅค‰ๅฝขใ‚’้ฉ็”จ", + "Tools.apply_transforms_desc": "ใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใฎใ™ในใฆใฎๅค‰ๅฝขใ‚’้ฉ็”จ", + "Tools.clean_shapekeys": "ๆœชไฝฟ็”จใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ๅ‰Š้™ค", + "Tools.clean_shapekeys_desc": "ใƒกใƒƒใ‚ทใƒฅใ‹ใ‚‰ๆœชไฝฟ็”จใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ๅ‰Š้™ค", + "Tools.bones_translated_success": "ใ™ในใฆใฎใƒœใƒผใƒณใŒๆญฃๅธธใซๅค‰ๆ›ใ•ใ‚Œใพใ—ใŸ", + "Tools.bones_translated_with_fails": "ๅค‰ๆ›ๅฎŒไบ†๏ผˆ{translate_bone_fails}ๅ€‹ใฎใƒœใƒผใƒณใฏๆœชๅค‰ๆ›๏ผ‰", + "Tools.storing_transforms": "ใƒœใƒผใƒณใฎๅค‰ๅฝขใ‚’ไฟๅญ˜ไธญ...", + "Tools.analyzing_weights": "้ ‚็‚นใฎ้‡ใฟใ‚’ๅˆ†ๆžไธญ...", + "Tools.removing_bones": "้‡ใฟใฎใชใ„ใƒœใƒผใƒณใ‚’ๅ‰Š้™คไธญ...", + "Tools.verifying_hierarchy": "ใƒœใƒผใƒณ้šŽๅฑคใ‚’ๆคœ่จผไธญ...", + "Tools.connect_bones_min_distance": "ๆœ€ๅฐ่ท้›ข", + "Tools.connect_bones_min_distance_desc": "ใƒœใƒผใƒณใ‚’ๆŽฅ็ถšใ™ใ‚‹ๆœ€ๅฐ่ท้›ข", + "Tools.connect_bones_success": "{count}ๅ€‹ใฎใƒœใƒผใƒณใ‚’ๆŽฅ็ถšใ—ใพใ—ใŸ", + "Tools.merge_weights_threshold": "้‡ใฟ่ปข้€้–พๅ€ค", + "Tools.merge_weights_threshold_desc": "ใƒœใƒผใƒณ็ตๅˆๆ™‚ใซ่ปข้€ใ™ใ‚‹ๆœ€ๅฐ้‡ใฟๅ€ค", + "Tools.no_bones_selected": "็ตๅˆใ™ใ‚‹ใƒœใƒผใƒณใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", + "Tools.no_bones_with_parent": "่ฆชใ‚’ๆŒใค้ธๆŠžใƒœใƒผใƒณใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "Tools.merge_to_active_success": "{count}ๅ€‹ใฎใƒœใƒผใƒณใ‚’ใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–ใƒœใƒผใƒณใซๆญฃๅธธใซ็ตๅˆใ—ใพใ—ใŸ", + "Tools.merge_to_parent_success": "{count}ๅ€‹ใฎใƒœใƒผใƒณใ‚’่ฆชใƒœใƒผใƒณใซๆญฃๅธธใซ็ตๅˆใ—ใพใ—ใŸ", + "Tools.transforms_applied": "ๅค‰ๅฝขใŒๆญฃๅธธใซ้ฉ็”จใ•ใ‚Œใพใ—ใŸ", + "Tools.shapekey_tolerance": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใฎ่จฑๅฎนๅ€ค", + "Tools.shapekey_tolerance_desc": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ไฝฟ็”จๆธˆใฟใจๅˆคๆ–ญใ™ใ‚‹ๆœ€ๅฐๅทฎๅˆ†", + "Tools.shapekeys_removed": "{count}ๅ€‹ใฎๆœชไฝฟ็”จใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ๅ‰Š้™คใ—ใพใ—ใŸ", + + "MMD.label": "MMDใƒ„ใƒผใƒซ", + "MMD.bone_standardization": "ใƒœใƒผใƒณๆจ™ๆบ–ๅŒ–", + "MMD.weight_processing": "ใ‚ฆใ‚งใ‚คใƒˆๅ‡ฆ็†", + "MMD.hierarchy": "ใƒœใƒผใƒณ้šŽๅฑค", + "MMD.cleanup": "ใ‚ฏใƒชใƒผใƒณใ‚ขใƒƒใƒ—", + "MMD.no_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", + "MMD.no_meshes": "ใƒกใƒƒใ‚ทใƒฅใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "MMD.validation.rigify_unsupported": "Rigifyใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฏใ‚ตใƒใƒผใƒˆใ•ใ‚Œใฆใ„ใพใ›ใ‚“", + "MMD.validation.multi_user_mesh": "่ค‡ๆ•ฐใƒฆใƒผใ‚ถใƒผใƒกใƒƒใ‚ทใƒฅใŒๆคœๅ‡บใ•ใ‚Œใพใ—ใŸ: {mesh}", + "MMD.bones_standardized": "ใƒœใƒผใƒณใŒๆญฃๅธธใซๆจ™ๆบ–ๅŒ–ใ•ใ‚Œใพใ—ใŸ", + "MMD.weights_processed": "ใ‚ฆใ‚งใ‚คใƒˆใŒๆญฃๅธธใซๅ‡ฆ็†ใ•ใ‚Œใพใ—ใŸ", + "MMD.hierarchy_fixed": "ใƒœใƒผใƒณ้šŽๅฑคใŒๆญฃๅธธใซไฟฎๆญฃใ•ใ‚Œใพใ—ใŸ", + "MMD.hierarchy_validation_warning": "ไธ€้ƒจใฎ้šŽๅฑค้–ขไฟ‚ใ‚’ๆคœ่จผใงใใพใ›ใ‚“ใงใ—ใŸ", + "MMD.cleanup_completed": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎใ‚ฏใƒชใƒผใƒณใ‚ขใƒƒใƒ—ใŒๅฎŒไบ†ใ—ใพใ—ใŸ", + "MMD.process_twist_bones": "ใƒ„ใ‚คใ‚นใƒˆใƒœใƒผใƒณใ‚’ๅ‡ฆ็†", + "MMD.process_twist_bones_desc": "ใƒ„ใ‚คใ‚นใƒˆใƒœใƒผใƒณใฎ้‡ใฟใ‚’่ฆชใƒœใƒผใƒณใซ่ปข้€", + "MMD.connect_bones": "ใƒœใƒผใƒณใ‚’ๆŽฅ็ถš", + "MMD.connect_bones_desc": "้ฉๅˆ‡ใชๅ ดๆ‰€ใงใƒœใƒผใƒณใƒใ‚งใƒผใƒณใ‚’ๆŽฅ็ถš", + + "Visemes.panel_label": "ใƒ“ใ‚ปใƒผใƒ ", + "Visemes.shape_selection": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ้ธๆŠž", + "Visemes.controls": "ใƒ“ใ‚ปใƒผใƒ ใ‚ณใƒณใƒˆใƒญใƒผใƒซ", + "Visemes.no_shapekeys": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใฎใ‚ใ‚‹ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", + "Visemes.mouth_a": "Aๅฝข็Šถ", + "Visemes.mouth_a_desc": "'A'้Ÿณใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ", + "Visemes.mouth_o": "Oๅฝข็Šถ", + "Visemes.mouth_o_desc": "'O'้Ÿณใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ", + "Visemes.mouth_ch": "CHๅฝข็Šถ", + "Visemes.mouth_ch_desc": "'CH'้Ÿณใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ", + "Visemes.shape_intensity": "ๅฝข็Šถใฎๅผทๅบฆ", + "Visemes.shape_intensity_desc": "ใƒ“ใ‚ปใƒผใƒ ๅฝข็Šถใฎๅผทๅบฆไน—ๆ•ฐ", + "Visemes.start_preview": "ใƒ—ใƒฌใƒ“ใƒฅใƒผ้–‹ๅง‹", + "Visemes.stop_preview": "ใƒ—ใƒฌใƒ“ใƒฅใƒผๅœๆญข", + "Visemes.preview_mode_desc": "ใƒ“ใ‚ปใƒผใƒ ใƒ—ใƒฌใƒ“ใƒฅใƒผใƒขใƒผใƒ‰ใฎๅˆ‡ใ‚Šๆ›ฟใˆ", + "Visemes.preview_selection": "ใƒ—ใƒฌใƒ“ใƒฅใƒผ้ธๆŠž", + "Visemes.preview_selection_desc": "ใƒ—ใƒฌใƒ“ใƒฅใƒผใ™ใ‚‹ใƒ“ใ‚ปใƒผใƒ ใ‚’้ธๆŠž", + "Visemes.preview_label": "ใƒ“ใ‚ปใƒผใƒ ใƒ—ใƒฌใƒ“ใƒฅใƒผ", + "Visemes.preview_desc": "ใƒ“ใƒฅใƒผใƒใƒผใƒˆใงใƒ“ใ‚ปใƒผใƒ ๅฝข็Šถใ‚’ใƒ—ใƒฌใƒ“ใƒฅใƒผ", + "Visemes.create_label": "ใƒ“ใ‚ปใƒผใƒ ใ‚’ไฝœๆˆ", + "Visemes.create_desc": "VRCใƒ“ใ‚ปใƒผใƒ ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ไฝœๆˆ", + "Visemes.error.no_shapekeys": "ใƒกใƒƒใ‚ทใƒฅใซใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใŒใ‚ใ‚Šใพใ›ใ‚“", + "Visemes.error.select_shapekeys": "Aใ€Oใ€CHใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", + "Visemes.success": "ใƒ“ใ‚ปใƒผใƒ ใŒๆญฃๅธธใซไฝœๆˆใ•ใ‚Œใพใ—ใŸ", + "Visemes.mesh_select": "ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠž", + "Visemes.mesh_select_desc": "ใƒ“ใ‚ปใƒผใƒ ใ‚’ไฝœๆˆใ™ใ‚‹ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠž", + + "EyeTracking.label": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ", + "EyeTracking.setup": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ่จญๅฎš", + "EyeTracking.mesh_select": "ใƒกใƒƒใ‚ทใƒฅ้ธๆŠž", + "EyeTracking.bones": "ใƒœใƒผใƒณ้ธๆŠž", + "EyeTracking.head_bone": "้ ญ้ƒจใƒœใƒผใƒณ", + "EyeTracking.eye_left": "ๅทฆ็›ฎใƒœใƒผใƒณ", + "EyeTracking.eye_right": "ๅณ็›ฎใƒœใƒผใƒณ", + "EyeTracking.shapekeys": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ้ธๆŠž", + "EyeTracking.options": "ใ‚ชใƒ—ใ‚ทใƒงใƒณ", + "EyeTracking.rotation": "็›ฎใฎๅ›ž่ปข", + "EyeTracking.rotation.x": "ๅž‚็›ดๅ›ž่ปข", + "EyeTracking.rotation.y": "ๆฐดๅนณๅ›ž่ปข", + "EyeTracking.adjust": "็›ฎใฎ่ชฟๆ•ด", + "EyeTracking.blinking": "ใพใฐใŸใใ‚ณใƒณใƒˆใƒญใƒผใƒซ", + "EyeTracking.no_shapekeys": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใซใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "EyeTracking.no_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", + "EyeTracking.no_mesh": "ใƒกใƒƒใ‚ทใƒฅใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "EyeTracking.create.label": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใ‚’ไฝœๆˆ", + "EyeTracking.create.desc": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใฎใƒœใƒผใƒณใจใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’่จญๅฎš", + "EyeTracking.testing.start.label": "ใƒ†ใ‚นใƒˆ้–‹ๅง‹", + "EyeTracking.testing.start.desc": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใƒ†ใ‚นใƒˆใƒขใƒผใƒ‰ใ‚’้–‹ๅง‹", + "EyeTracking.testing.stop.label": "ใƒ†ใ‚นใƒˆๅœๆญข", + "EyeTracking.testing.stop.desc": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใƒ†ใ‚นใƒˆใƒขใƒผใƒ‰ใ‚’็ต‚ไบ†", + "EyeTracking.reset.label": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใ‚’ใƒชใ‚ปใƒƒใƒˆ", + "EyeTracking.reset.desc": "ใ™ในใฆใฎใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ่จญๅฎšใ‚’ใƒชใ‚ปใƒƒใƒˆ", + "EyeTracking.rotate.label": "็›ฎใฎใƒœใƒผใƒณใ‚’ๅ›ž่ปข", + "EyeTracking.rotate.desc": "VRChatไบ’ๆ›ๆ€งใฎใŸใ‚ใซ็›ฎใฎใƒœใƒผใƒณใ‚’ๅ›ž่ปข", + "EyeTracking.iris.label": "่™นๅฝฉใฎ้ซ˜ใ•ใ‚’่ชฟๆ•ด", + "EyeTracking.iris.desc": "่™นๅฝฉใฎ้ ‚็‚นใฎ้ซ˜ใ•ใ‚’่ชฟๆ•ด", + "EyeTracking.blink.test.label": "ใพใฐใŸใใƒ†ใ‚นใƒˆ", + "EyeTracking.blink.test.desc": "ใพใฐใŸใใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ใƒ†ใ‚นใƒˆ", + "EyeTracking.lowerlid.test.label": "ไธ‹ใพใถใŸใƒ†ใ‚นใƒˆ", + "EyeTracking.lowerlid.test.desc": "ไธ‹ใพใถใŸใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ใƒ†ใ‚นใƒˆ", + "EyeTracking.blink.reset.label": "ใพใฐใŸใใƒ†ใ‚นใƒˆใ‚’ใƒชใ‚ปใƒƒใƒˆ", + "EyeTracking.blink.reset.desc": "ใพใฐใŸใใƒ†ใ‚นใƒˆใฎๅ€คใ‚’ใƒชใ‚ปใƒƒใƒˆ", + "EyeTracking.validation.noArmature": "ใ‚ทใƒผใƒณใซใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "EyeTracking.validation.noMesh": "ใƒกใƒƒใ‚ทใƒฅ'{mesh}'ใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "EyeTracking.validation.noShapekeys": "้ธๆŠžใ—ใŸใƒกใƒƒใ‚ทใƒฅใซใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใŒใ‚ใ‚Šใพใ›ใ‚“", + "EyeTracking.validation.leftEye": "ๅทฆ็›ฎ", + "EyeTracking.validation.rightEye": "ๅณ็›ฎ", + "EyeTracking.validation.missingGroups": "ไธ่ถณใ—ใฆใ„ใ‚‹้ ‚็‚นใ‚ฐใƒซใƒผใƒ—: {groups}", + "EyeTracking.validation.missingBones": "ๅฟ…่ฆใชใƒœใƒผใƒณใŒไธ่ถณ: {bones}", + "EyeTracking.validation.success": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ่จญๅฎšใŒๆญฃๅธธใซๆคœ่จผใ•ใ‚Œใพใ—ใŸ", + "EyeTracking.error.noMesh": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ็”จใฎใƒกใƒƒใ‚ทใƒฅใŒ้ธๆŠžใ•ใ‚Œใฆใ„ใพใ›ใ‚“", + "EyeTracking.error.noVertexGroup": "ใƒœใƒผใƒณ็”จใฎ้ ‚็‚นใ‚ฐใƒซใƒผใƒ—ใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“: {bone}", + "EyeTracking.error.noShapeSelected": "ๅฟ…่ฆใชใ™ในใฆใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", + "EyeTracking.success": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ่จญๅฎšใŒๆญฃๅธธใซๅฎŒไบ†ใ—ใพใ—ใŸ", + "EyeTracking.mode_select": "ใƒขใƒผใƒ‰้ธๆŠž", + "EyeTracking.mesh_setup": "ใƒกใƒƒใ‚ทใƒฅ่จญๅฎš", + "EyeTracking.bone_setup": "ใƒœใƒผใƒณ่จญๅฎš", + "EyeTracking.shapekey_setup": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผ่จญๅฎš", + "EyeTracking.testing": "ใƒ†ใ‚นใƒˆใƒขใƒผใƒ‰", + "EyeTracking.rotation_controls": "็›ฎใฎๅ›ž่ปขใ‚ณใƒณใƒˆใƒญใƒผใƒซ", + "EyeTracking.adjustments": "็›ฎใฎ่ชฟๆ•ด", + "EyeTracking.blink_testing": "ใพใฐใŸใใƒ†ใ‚นใƒˆ", + "EyeTracking.wink_left": "ๅทฆ็›ฎใฎใ‚ฆใ‚ฃใƒณใ‚ฏ", + "EyeTracking.wink_right": "ๅณ็›ฎใฎใ‚ฆใ‚ฃใƒณใ‚ฏ", + "EyeTracking.lowerlid_left": "ๅทฆไธ‹ใพใถใŸ", + "EyeTracking.lowerlid_right": "ๅณไธ‹ใพใถใŸ", + "EyeTracking.mode.creation": "ไฝœๆˆใƒขใƒผใƒ‰", + "EyeTracking.mode.testing": "ใƒ†ใ‚นใƒˆใƒขใƒผใƒ‰", + "EyeTracking.disable_blinking": "ใพใฐใŸใใ‚’็„กๅŠนๅŒ–", + "EyeTracking.disable_movement": "็›ฎใฎๅ‹•ใใ‚’็„กๅŠนๅŒ–", + "EyeTracking.distance": "็›ฎใฎ่ท้›ข", + "EyeTracking.distance_desc": "็›ฎใฎ้–“ใฎ่ท้›ขใ‚’่ชฟๆ•ด", + "EyeTracking.mode": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใƒขใƒผใƒ‰", + "EyeTracking.mesh_name": "ใƒกใƒƒใ‚ทใƒฅ", + "EyeTracking.mesh_name_desc": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ็”จใฎใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠž", + "EyeTracking.head_bone_desc": "้ ญ้ƒจใƒœใƒผใƒณใ‚’้ธๆŠž", + "EyeTracking.eye_left_desc": "ๅทฆ็›ฎใฎใƒœใƒผใƒณใ‚’้ธๆŠž", + "EyeTracking.eye_right_desc": "ๅณ็›ฎใฎใƒœใƒผใƒณใ‚’้ธๆŠž", + "EyeTracking.type": "ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใ‚ฟใ‚คใƒ—", + "EyeTracking.type_desc": "ไฝœๆˆใ™ใ‚‹ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ่จญๅฎšใฎใ‚ฟใ‚คใƒ—ใ‚’้ธๆŠž", + "EyeTracking.create.av3.label": "AV3ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใ‚’ไฝœๆˆ", + "EyeTracking.create.av3.desc": "VRChat Avatar 3.0็”จใฎใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใ‚’่จญๅฎš", + "EyeTracking.create.sdk2.label": "SDK2ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใ‚’ไฝœๆˆ", + "EyeTracking.create.sdk2.desc": "VRChat SDK2็”จใฎใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐใ‚’่จญๅฎš", + "EyeTracking.sdk_version": "SDKใƒใƒผใ‚ธใƒงใƒณ", + "EyeTracking.type.av3": "Avatar 3.0", + "EyeTracking.type.av3_desc": "VRChat Avatar 3.0ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ่จญๅฎš", + "EyeTracking.type.sdk2": "SDK2๏ผˆใƒฌใ‚ฌใ‚ทใƒผ๏ผ‰", + "EyeTracking.type.sdk2_desc": "VRChat SDK2ใ‚ขใ‚คใƒˆใƒฉใƒƒใ‚ญใƒณใ‚ฐ่จญๅฎš", + "EyeTracking.adjust.label": "็›ฎใฎไฝ็ฝฎใ‚’่ชฟๆ•ด", + "EyeTracking.adjust.desc": "้ ‚็‚นใ‚ฐใƒซใƒผใƒ—ใซๅŸบใฅใ„ใฆ็›ฎใฎใƒœใƒผใƒณใฎไฝ็ฝฎใ‚’่ชฟๆ•ด", + + "CustomPanel.label": "ใ‚ซใ‚นใ‚ฟใƒ ใ‚ขใƒใ‚ฟใƒผใƒ„ใƒผใƒซ", + "CustomPanel.merge_mode": "็ตๅˆใƒขใƒผใƒ‰", + "CustomPanel.mesh_selection": "ใƒกใƒƒใ‚ทใƒฅ้ธๆŠž", + "CustomPanel.select_mesh": "ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠž", + "CustomPanel.select_bone": "ใƒœใƒผใƒณใ‚’้ธๆŠž", + "CustomPanel.select_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’้ธๆŠž", + "CustomPanel.mode.armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ข", + "CustomPanel.mode.armature_desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’็ตๅˆ", + "CustomPanel.mode.mesh": "ใƒกใƒƒใ‚ทใƒฅ", + "CustomPanel.mode.mesh_desc": "ใƒกใƒƒใ‚ทใƒฅใ‚’ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใซๆŽฅ็ถš", + + "AttachMesh.label": "ใƒกใƒƒใ‚ทใƒฅใ‚’ๆŽฅ็ถš", + "AttachMesh.desc": "่‡ชๅ‹•ใ‚ฆใ‚งใ‚คใƒˆ่จญๅฎšใงใƒกใƒƒใ‚ทใƒฅใ‚’ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใƒœใƒผใƒณใซๆŽฅ็ถš", + "AttachMesh.search_desc": "ๆŽฅ็ถšใ™ใ‚‹ใƒกใƒƒใ‚ทใƒฅใ‚’ๆคœ็ดข", + "AttachMesh.select": "ๆŽฅ็ถšใ™ใ‚‹ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠž", + "AttachMesh.select_desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใซๆŽฅ็ถšใ™ใ‚‹ใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠž", + "AttachMesh.success": "ใƒกใƒƒใ‚ทใƒฅใŒๆญฃๅธธใซๆŽฅ็ถšใ•ใ‚Œใพใ—ใŸ", + "AttachMesh.warn_no_armature": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใจใƒกใƒƒใ‚ทใƒฅใ‚’้ธๆŠžใ—ใฆใใ ใ•ใ„", + "AttachMesh.validate_transforms": "ใƒกใƒƒใ‚ทใƒฅใฎๅค‰ๅฝขใ‚’ๆคœ่จผไธญ", + "AttachMesh.validate_name": "ใƒกใƒƒใ‚ทใƒฅๅใ‚’ๆคœ่จผไธญ", + "AttachMesh.parent_mesh": "ใƒกใƒƒใ‚ทใƒฅใ‚’ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎๅญใซ่จญๅฎšไธญ", + "AttachMesh.setup_weights": "้ ‚็‚นใ‚ฆใ‚งใ‚คใƒˆใ‚’่จญๅฎšไธญ", + "AttachMesh.create_bone": "ๆŽฅ็ถš็”จใƒœใƒผใƒณใ‚’ไฝœๆˆไธญ", + "AttachMesh.position_bone": "ใƒœใƒผใƒณใ‚’้…็ฝฎไธญ", + "AttachMesh.add_modifier": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใƒขใƒ‡ใ‚ฃใƒ•ใ‚กใ‚คใ‚ขใ‚’่ฟฝๅŠ ไธญ", + "AttachMesh.error.bone_not_found": "ๆŽฅ็ถšใƒœใƒผใƒณ'{bone}'ใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "AttachMesh.error.mesh_not_found": "ใƒกใƒƒใ‚ทใƒฅใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "AttachMesh.error.non_uniform_scale": "ใƒกใƒƒใ‚ทใƒฅใซไธๅ‡ไธ€ใชใ‚นใ‚ฑใƒผใƒซใŒใ‚ใ‚Šใพใ™ใ€‚ใ‚นใ‚ฑใƒผใƒซใ‚’้ฉ็”จใ—ใฆใใ ใ•ใ„", + "AttachBone.search_desc": "ๅฏพ่ฑกใฎใƒœใƒผใƒณใ‚’ๆคœ็ดข", + "AttachBone.select": "ๅฏพ่ฑกใฎใƒœใƒผใƒณใ‚’้ธๆŠž", + "AttachBone.select_desc": "ใƒกใƒƒใ‚ทใƒฅใ‚’ๆŽฅ็ถšใ™ใ‚‹ใƒœใƒผใƒณใ‚’้ธๆŠž", + + "MergeArmature.label": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎ็ตๅˆ", + "MergeArmature.desc": "2ใคใฎใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’็ตๅˆ", + "MergeArmature.options": "็ตๅˆใ‚ชใƒ—ใ‚ทใƒงใƒณ", + "MergeArmature.warn_two": "็ตๅˆใซใฏๅฐ‘ใชใใจใ‚‚2ใคใฎใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒๅฟ…่ฆใงใ™", + "MergeArmature.into": "็ตๅˆๅ…ˆ", + "MergeArmature.into_desc": "็ตๅˆๅ…ˆใฎใ‚ฟใƒผใ‚ฒใƒƒใƒˆใ‚ขใƒผใƒžใƒใƒฅใ‚ข", + "MergeArmature.into_search_desc": "็ตๅˆๅ…ˆใฎใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’ๆคœ็ดข", + "MergeArmature.from": "็ตๅˆๅ…ƒ", + "MergeArmature.from_desc": "็ตๅˆๅ…ƒใฎใ‚ฝใƒผใ‚นใ‚ขใƒผใƒžใƒใƒฅใ‚ข", + "MergeArmature.from_search_desc": "็ตๅˆๅ…ƒใฎใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’ๆคœ็ดข", + "MergeArmature.error.not_found": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ข'{name}'ใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“", + "MergeArmature.error.transforms_not_aligned": "ใ“ใฎใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’็ตๅˆใ™ใ‚‹ใซใฏๅค‰ๅฝขใ‚’้ฉ็”จใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ๆ‰‹ๅ‹•ใง่กŒใ†ใ‹ใ€ๅค‰ๅฝข้ฉ็”จใฎใƒใ‚งใƒƒใ‚ฏใƒžใƒผใ‚ฏใ‚’ไฝฟ็”จใ—ใฆใใ ใ•ใ„", + "MergeArmature.error.check_transforms": "่ฆชใฎๅค‰ๅฝขใ‚’็ขบ่ชใ—ใฆใใ ใ•ใ„", + "MergeArmature.error.fix_parents": "่ฆชๅญ้–ขไฟ‚ใ‚’ไฟฎๆญฃใ—ใฆใใ ใ•ใ„", + "MergeArmature.progress.removing_rigidbodies": "ๅ‰›ไฝ“ใจใ‚ธใƒงใ‚คใƒณใƒˆใ‚’ๅ‰Š้™คไธญ", + "MergeArmature.progress.validating": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’ๆคœ่จผไธญ", + "MergeArmature.progress.merging": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใ‚’็ตๅˆไธญ", + "MergeArmature.success": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใŒๆญฃๅธธใซ็ตๅˆใ•ใ‚Œใพใ—ใŸ", + "MergeArmature.merge_all": "ๅŒๅใƒœใƒผใƒณใ‚’็ตๅˆ", + "MergeArmature.merge_all_desc": "ๅๅ‰ใŒไธ€่‡ดใ™ใ‚‹ใƒœใƒผใƒณใ‚’็ตๅˆ", + "MergeArmature.apply_transforms": "ๅค‰ๅฝขใ‚’้ฉ็”จ", + "MergeArmature.apply_transforms_desc": "็ตๅˆๅ‰ใซใ™ในใฆใฎๅค‰ๅฝขใ‚’้ฉ็”จ", + "MergeArmature.join_meshes": "ใƒกใƒƒใ‚ทใƒฅใ‚’็ตๅˆ", + "MergeArmature.join_meshes_desc": "็ตๅˆๅพŒใซใƒกใƒƒใ‚ทใƒฅใ‚’็ตๅˆ", + "MergeArmature.remove_zero_weights": "้‡ใฟใชใ—ใ‚’ๅ‰Š้™ค", + "MergeArmature.remove_zero_weights_desc": "้‡ใฟใฎใชใ„้ ‚็‚นใ‚ฐใƒซใƒผใƒ—ใ‚’ๅ‰Š้™ค", + "MergeArmature.cleanup_shape_keys": "ใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ใ‚ฏใƒชใƒผใƒณ", + "MergeArmature.cleanup_shape_keys_desc": "ๆœชไฝฟ็”จใฎใ‚ทใ‚งใ‚คใƒ—ใ‚ญใƒผใ‚’ๅ‰Š้™ค", + + "Settings.label": "่จญๅฎš", + "Settings.language": "่จ€่ชž", + "Settings.language_desc": "ใ‚คใƒณใ‚ฟใƒผใƒ•ใ‚งใƒผใ‚น่จ€่ชžใ‚’้ธๆŠž", + "Settings.validation_mode": "ๆคœ่จผใƒขใƒผใƒ‰", + "Settings.validation_mode_desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎๆคœ่จผใฎๅŽณๅฏ†ใ•ใ‚’้ธๆŠž", + "Settings.validation_mode.strict": "ๅŽณๅฏ†", + "Settings.validation_mode.strict_desc": "ใƒœใƒผใƒณ้šŽๅฑคใจๅฏพ็งฐๆ€งใ‚’ๅซใ‚€ๅฎŒๅ…จใชๆคœ่จผ", + "Settings.validation_mode.basic": "ๅŸบๆœฌ", + "Settings.validation_mode.basic_desc": "ๅฟ…้ ˆใƒœใƒผใƒณใฎใฟใƒใ‚งใƒƒใ‚ฏ", + "Settings.validation_mode.none": "ใชใ—", + "Settings.validation_mode.none_desc": "ใ‚ขใƒผใƒžใƒใƒฅใ‚ขใฎๆคœ่จผใ‚’่กŒใ‚ใชใ„", + "Settings.debug": "ใƒ‡ใƒใƒƒใ‚ฐ่จญๅฎš", + "Settings.logging": "ใƒญใ‚ฐ่จ˜้Œฒ", + "Settings.enable_logging": "ใƒ‡ใƒใƒƒใ‚ฐใƒญใ‚ฐใ‚’ๆœ‰ๅŠนๅŒ–", + "Settings.enable_logging_desc": "ใƒˆใƒฉใƒ–ใƒซใ‚ทใƒฅใƒผใƒ†ใ‚ฃใƒณใ‚ฐ็”จใฎ่ฉณ็ดฐใƒญใ‚ฐใ‚’ๆœ‰ๅŠนๅŒ–", + "Settings.logging_enabled": "ใƒ‡ใƒใƒƒใ‚ฐใƒญใ‚ฐใŒๆœ‰ๅŠนใซใชใ‚Šใพใ—ใŸ", + "Settings.logging_disabled": "ใƒ‡ใƒใƒƒใ‚ฐใƒญใ‚ฐใŒ็„กๅŠนใซใชใ‚Šใพใ—ใŸ", + "Language.auto": "่‡ชๅ‹•", + "Language.en_US": "่‹ฑ่ชž", + "Language.ja_JP": "ๆ—ฅๆœฌ่ชž", + "Language.ko_KR": "้Ÿ“ๅ›ฝ่ชž", + "Language.changed.title": "่จ€่ชžใŒๅค‰ๆ›ดใ•ใ‚Œใพใ—ใŸ", + "Language.changed.success": "่จ€่ชžใŒๆญฃๅธธใซๅค‰ๆ›ดใ•ใ‚Œใพใ—ใŸ๏ผ", + "Language.changed.restart": "ไธ€้ƒจใฎUI่ฆ็ด ใฎๆ›ดๆ–ฐใซใฏBlenderใฎๅ†่ตทๅ‹•ใŒๅฟ…่ฆใชๅ ดๅˆใŒใ‚ใ‚Šใพใ™" } } \ No newline at end of file diff --git a/resources/translations/ko_KR.json b/resources/translations/ko_KR.json new file mode 100644 index 0000000..28ce1ed --- /dev/null +++ b/resources/translations/ko_KR.json @@ -0,0 +1,408 @@ +{ + "authors": ["Avatar Toolkit Team"], + "messages": { + "AvatarToolkit.label": "์•„๋ฐ”ํƒ€ ํˆดํ‚ท (์•ŒํŒŒ 0.1.1)", + "AvatarToolkit.desc1": "์•„๋ฐ”ํƒ€ ํˆดํ‚ท์€ ์ดˆ๊ธฐ ์•ก์„ธ์Šค ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค", + "AvatarToolkit.desc2": "๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•˜์‹œ๋ฉด", + "AvatarToolkit.desc3": "Github์— ๋ณด๊ณ ํ•ด ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.", + + "Updater.label": "์—…๋ฐ์ดํ„ฐ", + "Updater.CheckForUpdateButton.label": "์—…๋ฐ์ดํŠธ ํ™•์ธ", + "Updater.CheckForUpdateButton.label_alt": "์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—…๋ฐ์ดํŠธ ์—†์Œ", + "Updater.UpdateToLatestButton.label": "{name}์œผ๋กœ ์—…๋ฐ์ดํŠธ", + "Updater.UpdateToSelectedButton.label": "์—…๋ฐ์ดํŠธ", + "Updater.currentVersion": "ํ˜„์žฌ ๋ฒ„์ „: {name}", + "Updater.selectVersion": "๋ฒ„์ „ ์„ ํƒ", + "Updater.CheckForUpdateButton.desc": "์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—…๋ฐ์ดํŠธ ํ™•์ธ", + "UpdateToLatestButton.desc": "์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์—…๋ฐ์ดํŠธ", + "UpdateNotificationPopup.label": "์—…๋ฐ์ดํŠธ ์•Œ๋ฆผ", + "UpdateNotificationPopup.desc": "์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—…๋ฐ์ดํŠธ ์•Œ๋ฆผ", + "UpdateNotificationPopup.newUpdate": "์ƒˆ ์—…๋ฐ์ดํŠธ ์‚ฌ์šฉ ๊ฐ€๋Šฅ: {version}", + "RestartBlenderPopup.label": "๋ธ”๋ Œ๋” ์žฌ์‹œ์ž‘", + "RestartBlenderPopup.desc": "์—…๋ฐ์ดํŠธ๋ฅผ ์™„๋ฃŒํ•˜๋ ค๋ฉด ๋ธ”๋ Œ๋”๋ฅผ ์žฌ์‹œ์ž‘ํ•˜์„ธ์š”", + "RestartBlenderPopup.message": "์—…๋ฐ์ดํŠธ ์„ฑ๊ณต! ๋ธ”๋ Œ๋”๋ฅผ ์žฌ์‹œ์ž‘ํ•ด ์ฃผ์„ธ์š”.", + "check_for_update.cantCheck": "์—…๋ฐ์ดํŠธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค", + "download_file.cantConnect": "์—…๋ฐ์ดํŠธ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค", + "download_file.cantFindZip": "์—…๋ฐ์ดํŠธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค", + "download_file.cantFindAvatarToolkit": "์—…๋ฐ์ดํŠธ ํŒจํ‚ค์ง€์—์„œ ์•„๋ฐ”ํƒ€ ํˆดํ‚ท ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค", + + "QuickAccess.label": "๋น ๋ฅธ ์ ‘๊ทผ", + "QuickAccess.select_armature": "์•„๋งˆ์ถ”์–ด ์„ ํƒ", + "QuickAccess.valid_armature": "์œ ํšจํ•œ ์•„๋งˆ์ถ”์–ด", + "QuickAccess.bones_count": "๋ณธ: {count}๊ฐœ", + "QuickAccess.pose_bones_available": "ํฌ์ฆˆ ๋ณธ: ์‚ฌ์šฉ ๊ฐ€๋Šฅ", + "QuickAccess.pose_controls": "ํฌ์ฆˆ ์ปจํŠธ๋กค", + "QuickAccess.import_export": "๊ฐ€์ ธ์˜ค๊ธฐ/๋‚ด๋ณด๋‚ด๊ธฐ", + "QuickAccess.import": "๊ฐ€์ ธ์˜ค๊ธฐ", + "QuickAccess.export": "๋‚ด๋ณด๋‚ด๊ธฐ", + "QuickAccess.export_fbx": "FBX ๋‚ด๋ณด๋‚ด๊ธฐ", + "QuickAccess.export_resonite": "Resonite๋กœ ๋‚ด๋ณด๋‚ด๊ธฐ", + "QuickAccess.start_pose_mode.label": "ํฌ์ฆˆ ๋ชจ๋“œ ์‹œ์ž‘", + "QuickAccess.start_pose_mode.desc": "์„ ํƒํ•œ ์•„๋งˆ์ถ”์–ด์˜ ํฌ์ฆˆ ๋ชจ๋“œ ์ง„์ž…", + "QuickAccess.stop_pose_mode.label": "ํฌ์ฆˆ ๋ชจ๋“œ ์ข…๋ฃŒ", + "QuickAccess.stop_pose_mode.desc": "ํฌ์ฆˆ ๋ชจ๋“œ ์ข…๋ฃŒ ๋ฐ ๋ณ€ํ˜• ์ดˆ๊ธฐํ™”", + "QuickAccess.apply_pose_as_shapekey.label": "ํฌ์ฆˆ๋ฅผ ์‰์ดํ”„ ํ‚ค๋กœ ์ ์šฉ", + "QuickAccess.apply_pose_as_shapekey.desc": "ํ˜„์žฌ ํฌ์ฆˆ๋กœ ์ƒˆ ์‰์ดํ”„ ํ‚ค ์ƒ์„ฑ", + "QuickAccess.apply_pose_as_rest.label": "ํฌ์ฆˆ๋ฅผ ๊ธฐ๋ณธ ์ž์„ธ๋กœ ์ ์šฉ", + "QuickAccess.apply_pose_as_rest.desc": "ํ˜„์žฌ ํฌ์ฆˆ๋ฅผ ๊ธฐ๋ณธ ์ž์„ธ๋กœ ์ ์šฉ", + "QuickAccess.apply_armature_failed": "์•„๋งˆ์ถ”์–ด ์ˆ˜์ • ์ ์šฉ ์‹คํŒจ", + "QuickAccess.validation_basic_warning": "์ œํ•œ๋œ ๊ฒ€์ฆ ํ™œ์„ฑํ™”๋จ", + "QuickAccess.validation_basic_details": "ํ•„์ˆ˜ ๋ณธ ๊ตฌ์กฐ๋งŒ ๊ฒ€์ฆ๋จ", + "QuickAccess.validation_none_warning": "๊ฒ€์ฆ ๋น„ํ™œ์„ฑํ™”๋จ", + "QuickAccess.validation_none_details": "์•„๋งˆ์ถ”์–ด ๊ฒ€์ฆ์ด ์ˆ˜ํ–‰๋˜์ง€ ์•Š์Œ", + + "PoseMode.error.start": "ํฌ์ฆˆ ๋ชจ๋“œ ์‹œ์ž‘ ์‹คํŒจ: {error}", + "PoseMode.error.stop": "ํฌ์ฆˆ ๋ชจ๋“œ ์ข…๋ฃŒ ์‹คํŒจ: {error}", + "PoseMode.error.shapekey": "ํฌ์ฆˆ๋ฅผ ์‰์ดํ”„ ํ‚ค๋กœ ์ ์šฉ ์‹คํŒจ: {error}", + "PoseMode.error.rest_pose": "ํฌ์ฆˆ๋ฅผ ๊ธฐ๋ณธ ์ž์„ธ๋กœ ์ ์šฉ ์‹คํŒจ: {error}", + "PoseMode.shapekey.name": "์‰์ดํ”„ ํ‚ค ์ด๋ฆ„", + "PoseMode.shapekey.description": "์ƒˆ ์‰์ดํ”„ ํ‚ค์˜ ์ด๋ฆ„", + "PoseMode.shapekey.default": "ํฌ์ฆˆ_์‰์ดํ”„ํ‚ค", + "PoseMode.skipped_meshes": "์ผ๋ถ€ ๋ฉ”์‹œ๊ฐ€ ๊ฑด๋„ˆ๋›ฐ์–ด์ง:\n{message}", + "PoseMode.basis": "๊ธฐ๋ณธ", + + "Armature.validation.no_armature": "์„ ํƒ๋œ ์•„๋งˆ์ถ”์–ด ์—†์Œ", + "Armature.validation.not_armature": "์„ ํƒ๋œ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์•„๋งˆ์ถ”์–ด๊ฐ€ ์•„๋‹˜", + "Armature.validation.no_bones": "์•„๋งˆ์ถ”์–ด์— ๋ณธ์ด ์—†์Œ", + "Armature.validation.basic_check_failed": "๊ธฐ๋ณธ ์•„๋งˆ์ถ”์–ด ๊ฒ€์ฆ ์‹คํŒจ", + "Armature.validation.missing_bones": "ํ•„์ˆ˜ ๋ณธ ๋ˆ„๋ฝ: {bones}", + "Armature.validation.invalid_hierarchy": "{parent}์™€ {child} ์‚ฌ์ด์˜ ์ž˜๋ชป๋œ ๋ณธ ๊ณ„์ธต ๊ตฌ์กฐ", + "Armature.validation.asymmetric_bones": "{bone}์˜ ๋Œ€์นญ ๋ณธ ๋ˆ„๋ฝ", + "Armature.validation.asymmetric_hand_wrist": "์†/์†๋ชฉ์˜ ๋Œ€์นญ ๋ณธ ๋ˆ„๋ฝ", + + "Mesh.validation.no_data": "๋ฉ”์‹œ ๋ฐ์ดํ„ฐ ์—†์Œ", + "Mesh.validation.no_vertex_groups": "๋ฒ„ํ…์Šค ๊ทธ๋ฃน ์—†์Œ", + "Mesh.validation.no_armature_modifier": "์•„๋งˆ์ถ”์–ด ๋ชจ๋””ํŒŒ์ด์–ด ์—†์Œ", + "Mesh.validation.valid": "ํฌ์ฆˆ ์ž‘์—…์— ์œ ํšจํ•œ ๋ฉ”์‹œ", + + "Operation.pose_applied": "ํฌ์ฆˆ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ ์šฉ๋จ", + + "Scene.avatar_toolkit_updater_version_list.name": "๋ฒ„์ „ ๋ชฉ๋ก", + "Scene.avatar_toolkit_updater_version_list.description": "์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฒ„์ „ ๋ชฉ๋ก", + + "Optimization.label": "์ตœ์ ํ™”", + "Optimization.materials_title": "์žฌ์งˆ", + "Optimization.cleanup_title": "๋ฉ”์‹œ ์ •๋ฆฌ", + "Optimization.join_meshes_title": "๋ฉ”์‹œ ๊ฒฐํ•ฉ", + "Optimization.combine_materials": "์žฌ์งˆ ๊ฒฐํ•ฉ", + "Optimization.combine_materials_desc": "๋“œ๋กœ์šฐ ์ฝœ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ์œ ์‚ฌํ•œ ์žฌ์งˆ ๊ฒฐํ•ฉ", + "Optimization.remove_doubles": "์ค‘๋ณต ์ œ๊ฑฐ", + "Optimization.remove_doubles_desc": "์ค‘๋ณต๋œ ๋ฒ„ํ…์Šค ์ œ๊ฑฐ", + "Optimization.remove_doubles_advanced": "๊ณ ๊ธ‰", + "Optimization.remove_doubles_advanced_desc": "๊ณ ๊ธ‰ ์˜ต์…˜์œผ๋กœ ์ค‘๋ณต ๋ฒ„ํ…์Šค ์ œ๊ฑฐ", + "Optimization.join_all_meshes": "์ „์ฒด ๊ฒฐํ•ฉ", + "Optimization.join_all_meshes_desc": "์”ฌ์˜ ๋ชจ๋“  ๋ฉ”์‹œ ๊ฒฐํ•ฉ", + "Optimization.join_selected_meshes": "์„ ํƒ ๊ฒฐํ•ฉ", + "Optimization.join_selected_meshes_desc": "์„ ํƒ๋œ ๋ฉ”์‹œ๋งŒ ๊ฒฐํ•ฉ", + "Optimization.no_meshes": "์ตœ์ ํ™”ํ•  ๋ฉ”์‹œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "Optimization.materials_combined": "{combined}๊ฐœ์˜ ์žฌ์งˆ ๊ฒฐํ•ฉ, {cleaned}๊ฐœ์˜ ์Šฌ๋กฏ ์ •๋ฆฌ, {removed}๊ฐœ์˜ ๋ฏธ์‚ฌ์šฉ ๋ฐ์ดํ„ฐ ๋ธ”๋ก ์ œ๊ฑฐ๋จ", + "Optimization.error.combine_materials": "์žฌ์งˆ ๊ฒฐํ•ฉ ์‹คํŒจ: {error}", + "Optimization.materials_total": "์ „์ฒด ์žฌ์งˆ: {count}๊ฐœ", + "Optimization.materials_duplicates": "์ž ์žฌ์  ์ค‘๋ณต: {count}๊ฐœ", + "Optimization.no_materials": "๋ฉ”์‹œ์—์„œ ์žฌ์งˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "Optimization.error.consolidation": "์žฌ์งˆ ํ†ตํ•ฉ ์‹คํŒจ. ์ฝ˜์†”์—์„œ ์„ธ๋ถ€ ์ •๋ณด ํ™•์ธ", + "Optimization.combining_materials": "์œ ์‚ฌํ•œ ์žฌ์งˆ ๊ฒฐํ•ฉ ์ค‘...", + "Optimization.cleaning_slots": "์žฌ์งˆ ์Šฌ๋กฏ ์ •๋ฆฌ ์ค‘...", + "Optimization.removing_unused": "๋ฏธ์‚ฌ์šฉ ์žฌ์งˆ ์ œ๊ฑฐ ์ค‘...", + "Optimization.selecting_meshes": "๋ฉ”์‹œ ์„ ํƒ ์ค‘...", + "Optimization.joining_meshes": "๋ฉ”์‹œ ๊ฒฐํ•ฉ ์ค‘...", + "Optimization.applying_transforms": "๋ณ€ํ˜• ์ ์šฉ ์ค‘...", + "Optimization.fixing_uvs": "UV ์ขŒํ‘œ ์ˆ˜์ • ์ค‘...", + "Optimization.finalizing": "๋งˆ๋ฌด๋ฆฌ ์ค‘...", + "Optimization.meshes_joined": "๋ชจ๋“  ๋ฉ”์‹œ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฒฐํ•ฉ๋จ", + "Optimization.selected_meshes_joined": "์„ ํƒ๋œ ๋ฉ”์‹œ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฒฐํ•ฉ๋จ", + "Optimization.no_mesh_selected": "์„ ํƒ๋œ ๋ฉ”์‹œ ์—†์Œ", + "Optimization.select_at_least_two": "์ตœ์†Œ ๋‘ ๊ฐœ์˜ ๋ฉ”์‹œ๋ฅผ ์„ ํƒํ•˜์„ธ์š”", + "Optimization.error.join_meshes": "๋ฉ”์‹œ ๊ฒฐํ•ฉ ์‹คํŒจ: {error}", + "Optimization.error.join_selected": "์„ ํƒ๋œ ๋ฉ”์‹œ ๊ฒฐํ•ฉ ์‹คํŒจ: {error}", + "Optimization.merge_distance": "๋ณ‘ํ•ฉ ๊ฑฐ๋ฆฌ", + "Optimization.merge_distance_desc": "๋ฒ„ํ…์Šค๋ฅผ ๋ณ‘ํ•ฉํ•  ๊ฑฐ๋ฆฌ", + "Optimization.remove_doubles_warning": "์ด ๊ณผ์ •์€ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค", + "Optimization.remove_doubles_wait": "์ด ์ž‘์—… ์ค‘์—๋Š” ๋ธ”๋ Œ๋”๊ฐ€ ์‘๋‹ตํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค", + "Optimization.error.remove_doubles": "์ค‘๋ณต ์ œ๊ฑฐ ์‹คํŒจ: {error}", + "Optimization.no_armature": "์„ ํƒ๋œ ์•„๋งˆ์ถ”์–ด ์—†์Œ", + "Optimization.processing_mesh": "๋ฉ”์‹œ ์ฒ˜๋ฆฌ ์ค‘: {name}", + "Optimization.processing_shapekey": "์‰์ดํ”„ ํ‚ค ์ฒ˜๋ฆฌ ์ค‘: {name}", + "Optimization.remove_doubles_completed": "์ค‘๋ณต ์ œ๊ฑฐ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋จ", + + "Tools.label": "๋„๊ตฌ", + "Tools.general_title": "์ผ๋ฐ˜ ๋„๊ตฌ", + "Tools.convert_resonite": "Resonite๋กœ ๋ณ€ํ™˜", + "Tools.convert_resonite_desc": "Resonite์—์„œ ์‚ฌ์šฉํ•  ๋ชจ๋ธ ๋ณ€ํ™˜", + "Tools.convert_resonite.operation": "Resonite๋กœ ๋ณ€ํ™˜ ์ค‘", + "Tools.separate_title": "๋ถ„๋ฆฌ ๋„๊ตฌ", + "Tools.separate_materials": "์žฌ์งˆ๋ณ„", + "Tools.separate_materials_desc": "์žฌ์งˆ๋ณ„๋กœ ๋ฉ”์‹œ ๋ถ„๋ฆฌ", + "Tools.separate_loose": "๋ถ„๋ฆฌ๋œ ๋ถ€๋ถ„", + "Tools.separate_loose_desc": "๋ถ„๋ฆฌ๋œ ๋ถ€๋ถ„์œผ๋กœ ๋ฉ”์‹œ ๋ถ„๋ฆฌ", + "Tools.separate_materials_success": "๋ฉ”์‹œ๊ฐ€ ์žฌ์งˆ๋ณ„๋กœ ์„ฑ๊ณต์ ์œผ๋กœ ๋ถ„๋ฆฌ๋จ", + "Tools.separate_loose_success": "๋ฉ”์‹œ๊ฐ€ ๋ถ„๋ฆฌ๋œ ๋ถ€๋ถ„์œผ๋กœ ์„ฑ๊ณต์ ์œผ๋กœ ๋ถ„๋ฆฌ๋จ", + "Tools.bone_title": "๋ณธ ๋„๊ตฌ", + "Tools.create_digitigrade": "๋””์ง€ํ‹ฐ๊ทธ๋ ˆ์ด๋“œ ๋‹ค๋ฆฌ ์ƒ์„ฑ", + "Tools.create_digitigrade_desc": "๋‹ค๋ฆฌ๋ฅผ ๋””์ง€ํ‹ฐ๊ทธ๋ ˆ์ด๋“œ ์„ค์ •์œผ๋กœ ๋ณ€ํ™˜", + "Tools.digitigrade": "๋””์ง€ํ‹ฐ๊ทธ๋ ˆ์ด๋“œ ๋‹ค๋ฆฌ ์ƒ์„ฑ", + "Tools.digitigrade_desc": "์„ ํƒ๋œ ๋‹ค๋ฆฌ ๋ณธ์„ ๋””์ง€ํ‹ฐ๊ทธ๋ ˆ์ด๋“œ ์„ค์ •์œผ๋กœ ๋ณ€ํ™˜", + "Tools.digitigrade_error": "๋””์ง€ํ‹ฐ๊ทธ๋ ˆ์ด๋“œ ๋‹ค๋ฆฌ ์ƒ์„ฑ ์‹คํŒจ: {error}", + "Tools.digitigrade_success": "๋””์ง€ํ‹ฐ๊ทธ๋ ˆ์ด๋“œ ๋‹ค๋ฆฌ ์„ค์ • ์ƒ์„ฑ ์„ฑ๊ณต", + "Tools.processing_leg": "๋‹ค๋ฆฌ ๋ณธ ์ฒ˜๋ฆฌ ์ค‘: {bone}", + "Tools.merge_twist_bones": "ํŠธ์œ„์ŠคํŠธ ๋ณธ ์œ ์ง€", + "Tools.merge_twist_bones_desc": "์ฒดํฌํ•˜๋ฉด ๊ฐ€์ค‘์น˜๊ฐ€ 0์ด์–ด๋„ ํŠธ์œ„์ŠคํŠธ ๋ณธ ์œ ์ง€", + "Tools.clean_weights": "0 ๊ฐ€์ค‘์น˜ ๋ณธ ์ œ๊ฑฐ", + "Tools.clean_weights_desc": "๋ฒ„ํ…์Šค ๊ฐ€์ค‘์น˜๊ฐ€ ์—†๋Š” ๋ณธ ์ œ๊ฑฐ", + "Tools.clean_constraints": "๋ณธ ์ œ์•ฝ ์กฐ๊ฑด ์‚ญ์ œ", + "Tools.clean_constraints_desc": "์•„๋งˆ์ถ”์–ด์—์„œ ๋ชจ๋“  ๋ณธ ์ œ์•ฝ ์กฐ๊ฑด ์ œ๊ฑฐ", + "Tools.clean_constraints_success": "{count}๊ฐœ์˜ ๋ณธ ์ œ์•ฝ ์กฐ๊ฑด ์ œ๊ฑฐ๋จ", + "Tools.processing_bone_constraints": "๋ณธ์˜ ์ œ์•ฝ ์กฐ๊ฑด ์ œ๊ฑฐ ์ค‘: {bone}", + "Tools.clean_weights_success": "{count}๊ฐœ์˜ 0 ๊ฐ€์ค‘์น˜ ๋ณธ ์ œ๊ฑฐ๋จ", + "Tools.clean_weights_threshold": "๊ฐ€์ค‘์น˜ ์ž„๊ณ„๊ฐ’", + "Tools.clean_weights_threshold_desc": "๋ณธ์ด ๊ฐ€์ค‘์น˜๋ฅผ ๊ฐ€์ง„ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•  ์ตœ์†Œ๊ฐ’", + "Tools.merge_title": "๋ณ‘ํ•ฉ ๋„๊ตฌ", + "Tools.merge_to_active": "ํ™œ์„ฑ ๋ณธ์œผ๋กœ ๋ณ‘ํ•ฉ", + "Tools.merge_to_active_desc": "์„ ํƒ๋œ ๋ณธ์„ ํ™œ์„ฑ ๋ณธ์œผ๋กœ ๋ณ‘ํ•ฉ", + "Tools.merge_to_parent": "๋ถ€๋ชจ๋กœ ๋ณ‘ํ•ฉ", + "Tools.merge_to_parent_desc": "๋ณธ์„ ๊ฐ๊ฐ์˜ ๋ถ€๋ชจ๋กœ ๋ณ‘ํ•ฉ", + "Tools.connect_bones": "๋ณธ ์—ฐ๊ฒฐ", + "Tools.connect_bones_desc": "์ฒด์ธ์—์„œ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์€ ๋ณธ ์—ฐ๊ฒฐ", + "Tools.additional_title": "์ถ”๊ฐ€ ๋„๊ตฌ", + "Tools.apply_transforms": "๋ณ€ํ˜• ์ ์šฉ", + "Tools.apply_transforms_desc": "์˜ค๋ธŒ์ ํŠธ์— ๋ชจ๋“  ๋ณ€ํ˜• ์ ์šฉ", + "Tools.clean_shapekeys": "๋ฏธ์‚ฌ์šฉ ์‰์ดํ”„ํ‚ค ์ œ๊ฑฐ", + "Tools.clean_shapekeys_desc": "๋ฉ”์‹œ์—์„œ ๋ฏธ์‚ฌ์šฉ ์‰์ดํ”„ ํ‚ค ์ œ๊ฑฐ", + "Tools.bones_translated_success": "๋ชจ๋“  ๋ณธ์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ€ํ™˜๋จ", + "Tools.bones_translated_with_fails": "๋ณ€ํ™˜ ์™„๋ฃŒ๋จ (๋ณ€ํ™˜๋˜์ง€ ์•Š์€ ๋ณธ {translate_bone_fails}๊ฐœ)", + "Tools.storing_transforms": "๋ณธ ๋ณ€ํ˜• ์ €์žฅ ์ค‘...", + "Tools.analyzing_weights": "๋ฒ„ํ…์Šค ๊ฐ€์ค‘์น˜ ๋ถ„์„ ์ค‘...", + "Tools.removing_bones": "๊ฐ€์ค‘์น˜ ์—†๋Š” ๋ณธ ์ œ๊ฑฐ ์ค‘...", + "Tools.verifying_hierarchy": "๋ณธ ๊ณ„์ธต ๊ตฌ์กฐ ํ™•์ธ ์ค‘...", + "Tools.connect_bones_min_distance": "์ตœ์†Œ ๊ฑฐ๋ฆฌ", + "Tools.connect_bones_min_distance_desc": "๋ณธ ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•  ์ตœ์†Œ ๊ฑฐ๋ฆฌ", + "Tools.connect_bones_success": "{count}๊ฐœ์˜ ๋ณธ ์—ฐ๊ฒฐ๋จ", + "Tools.merge_weights_threshold": "๊ฐ€์ค‘์น˜ ์ „์†ก ์ž„๊ณ„๊ฐ’", + "Tools.merge_weights_threshold_desc": "๋ณธ ๋ณ‘ํ•ฉ ์‹œ ์ „์†กํ•  ์ตœ์†Œ ๊ฐ€์ค‘์น˜ ๊ฐ’", + "Tools.no_bones_selected": "๋ณ‘ํ•ฉํ•  ๋ณธ์ด ์„ ํƒ๋˜์ง€ ์•Š์Œ", + "Tools.no_bones_with_parent": "๋ถ€๋ชจ๊ฐ€ ์žˆ๋Š” ์„ ํƒ๋œ ๋ณธ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "Tools.merge_to_active_success": "{count}๊ฐœ์˜ ๋ณธ์„ ํ™œ์„ฑ ๋ณธ์œผ๋กœ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ‘ํ•ฉํ•จ", + "Tools.merge_to_parent_success": "{count}๊ฐœ์˜ ๋ณธ์„ ๋ถ€๋ชจ๋กœ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ‘ํ•ฉํ•จ", + "Tools.transforms_applied": "๋ณ€ํ˜•์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ ์šฉ๋จ", + "Tools.shapekey_tolerance": "์‰์ดํ”„ ํ‚ค ํ—ˆ์šฉ ์˜ค์ฐจ", + "Tools.shapekey_tolerance_desc": "์‰์ดํ”„ ํ‚ค๋ฅผ ์‚ฌ์šฉ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•  ์ตœ์†Œ ์ฐจ์ด", + "Tools.shapekeys_removed": "{count}๊ฐœ์˜ ๋ฏธ์‚ฌ์šฉ ์‰์ดํ”„ ํ‚ค ์ œ๊ฑฐ๋จ", + + "MMD.label": "MMD ๋„๊ตฌ", + "MMD.bone_standardization": "๋ณธ ํ‘œ์ค€ํ™”", + "MMD.weight_processing": "๊ฐ€์ค‘์น˜ ์ฒ˜๋ฆฌ", + "MMD.hierarchy": "๋ณธ ๊ณ„์ธต ๊ตฌ์กฐ", + "MMD.cleanup": "์ •๋ฆฌ", + "MMD.no_armature": "์„ ํƒ๋œ ์•„๋งˆ์ถ”์–ด ์—†์Œ", + "MMD.no_meshes": "๋ฉ”์‹œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "MMD.validation.rigify_unsupported": "Rigify ์•„๋งˆ์ถ”์–ด๋Š” ์ง€์›๋˜์ง€ ์•Š์Œ", + "MMD.validation.multi_user_mesh": "๋‹ค์ค‘ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ ๊ฐ์ง€๋จ: {mesh}", + "MMD.bones_standardized": "๋ณธ์ด ์„ฑ๊ณต์ ์œผ๋กœ ํ‘œ์ค€ํ™”๋จ", + "MMD.weights_processed": "๊ฐ€์ค‘์น˜๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋จ", + "MMD.hierarchy_fixed": "๋ณธ ๊ณ„์ธต ๊ตฌ์กฐ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜์ •๋จ", + "MMD.hierarchy_validation_warning": "์ผ๋ถ€ ๊ณ„์ธต ๊ด€๊ณ„๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์—†์Œ", + "MMD.cleanup_completed": "์•„๋งˆ์ถ”์–ด ์ •๋ฆฌ ์™„๋ฃŒ", + "MMD.process_twist_bones": "ํŠธ์œ„์ŠคํŠธ ๋ณธ ์ฒ˜๋ฆฌ", + "MMD.process_twist_bones_desc": "ํŠธ์œ„์ŠคํŠธ ๋ณธ์˜ ๊ฐ€์ค‘์น˜๋ฅผ ๋ถ€๋ชจ ๋ณธ์œผ๋กœ ์ „์†ก", + "MMD.connect_bones": "๋ณธ ์—ฐ๊ฒฐ", + "MMD.connect_bones_desc": "์ ์ ˆํ•œ ๊ฒฝ์šฐ ์ฒด์ธ์˜ ๋ณธ ์—ฐ๊ฒฐ", + + "Visemes.panel_label": "๋น„์…ˆ", + "Visemes.shape_selection": "์‰์ดํ”„ ํ‚ค ์„ ํƒ", + "Visemes.controls": "๋น„์…ˆ ์ปจํŠธ๋กค", + "Visemes.no_shapekeys": "์‰์ดํ”„ ํ‚ค๊ฐ€ ์žˆ๋Š” ๋ฉ”์‹œ ์„ ํƒ", + "Visemes.mouth_a": "A ๋ชจ์–‘", + "Visemes.mouth_a_desc": "'A' ์†Œ๋ฆฌ๋ฅผ ์œ„ํ•œ ์‰์ดํ”„ ํ‚ค", + "Visemes.mouth_o": "O ๋ชจ์–‘", + "Visemes.mouth_o_desc": "'O' ์†Œ๋ฆฌ๋ฅผ ์œ„ํ•œ ์‰์ดํ”„ ํ‚ค", + "Visemes.mouth_ch": "CH ๋ชจ์–‘", + "Visemes.mouth_ch_desc": "'CH' ์†Œ๋ฆฌ๋ฅผ ์œ„ํ•œ ์‰์ดํ”„ ํ‚ค", + "Visemes.shape_intensity": "์‰์ดํ”„ ๊ฐ•๋„", + "Visemes.shape_intensity_desc": "๋น„์…ˆ ์‰์ดํ”„์˜ ๊ฐ•๋„ ๋ฐฐ์œจ", + "Visemes.start_preview": "๋ฏธ๋ฆฌ๋ณด๊ธฐ ์‹œ์ž‘", + "Visemes.stop_preview": "๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ค‘์ง€", + "Visemes.preview_mode_desc": "๋น„์…ˆ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชจ๋“œ ์ „ํ™˜", + "Visemes.preview_selection": "๋ฏธ๋ฆฌ๋ณด๊ธฐ ์„ ํƒ", + "Visemes.preview_selection_desc": "๋ฏธ๋ฆฌ๋ณผ ๋น„์…ˆ ์„ ํƒ", + "Visemes.preview_label": "๋น„์…ˆ ๋ฏธ๋ฆฌ๋ณด๊ธฐ", + "Visemes.preview_desc": "๋ทฐํฌํŠธ์—์„œ ๋น„์…ˆ ์‰์ดํ”„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ", + "Visemes.create_label": "๋น„์…ˆ ์ƒ์„ฑ", + "Visemes.create_desc": "VRC ๋น„์…ˆ ์‰์ดํ”„ ํ‚ค ์ƒ์„ฑ", + "Visemes.error.no_shapekeys": "๋ฉ”์‹œ์— ์‰์ดํ”„ ํ‚ค๊ฐ€ ์—†์Œ", + "Visemes.error.select_shapekeys": "A, O, CH ์‰์ดํ”„ ํ‚ค๋ฅผ ์„ ํƒํ•˜์„ธ์š”", + "Visemes.success": "๋น„์…ˆ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋จ", + "Visemes.mesh_select": "๋ฉ”์‹œ ์„ ํƒ", + "Visemes.mesh_select_desc": "๋น„์…ˆ์„ ์ƒ์„ฑํ•  ๋ฉ”์‹œ ์„ ํƒ", + + "EyeTracking.label": "์‹œ์„  ์ถ”์ ", + "EyeTracking.setup": "์‹œ์„  ์ถ”์  ์„ค์ •", + "EyeTracking.mesh_select": "๋ฉ”์‹œ ์„ ํƒ", + "EyeTracking.bones": "๋ณธ ์„ ํƒ", + "EyeTracking.head_bone": "๋จธ๋ฆฌ ๋ณธ", + "EyeTracking.eye_left": "์™ผ์ชฝ ๋ˆˆ ๋ณธ", + "EyeTracking.eye_right": "์˜ค๋ฅธ์ชฝ ๋ˆˆ ๋ณธ", + "EyeTracking.shapekeys": "์‰์ดํ”„ ํ‚ค ์„ ํƒ", + "EyeTracking.options": "์˜ต์…˜", + "EyeTracking.rotation": "๋ˆˆ ํšŒ์ „", + "EyeTracking.rotation.x": "์ˆ˜์ง ํšŒ์ „", + "EyeTracking.rotation.y": "์ˆ˜ํ‰ ํšŒ์ „", + "EyeTracking.adjust": "๋ˆˆ ์กฐ์ •", + "EyeTracking.blinking": "๊นœ๋นก์ž„ ์ปจํŠธ๋กค", + "EyeTracking.no_shapekeys": "์„ ํƒ๋œ ๋ฉ”์‹œ์—์„œ ์‰์ดํ”„ ํ‚ค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "EyeTracking.no_armature": "์„ ํƒ๋œ ์•„๋งˆ์ถ”์–ด ์—†์Œ", + "EyeTracking.no_mesh": "๋ฉ”์‹œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "EyeTracking.create.label": "์‹œ์„  ์ถ”์  ์ƒ์„ฑ", + "EyeTracking.create.desc": "์‹œ์„  ์ถ”์  ๋ณธ๊ณผ ์‰์ดํ”„ ํ‚ค ์„ค์ •", + "EyeTracking.testing.start.label": "ํ…Œ์ŠคํŠธ ์‹œ์ž‘", + "EyeTracking.testing.start.desc": "์‹œ์„  ์ถ”์  ํ…Œ์ŠคํŠธ ๋ชจ๋“œ ์ง„์ž…", + "EyeTracking.testing.stop.label": "ํ…Œ์ŠคํŠธ ์ค‘์ง€", + "EyeTracking.testing.stop.desc": "์‹œ์„  ์ถ”์  ํ…Œ์ŠคํŠธ ๋ชจ๋“œ ์ข…๋ฃŒ", + "EyeTracking.reset.label": "์‹œ์„  ์ถ”์  ์ดˆ๊ธฐํ™”", + "EyeTracking.reset.desc": "๋ชจ๋“  ์‹œ์„  ์ถ”์  ์„ค์ • ์ดˆ๊ธฐํ™”", + "EyeTracking.rotate.label": "๋ˆˆ ๋ณธ ํšŒ์ „", + "EyeTracking.rotate.desc": "VRChat ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•œ ๋ˆˆ ๋ณธ ํšŒ์ „", + "EyeTracking.iris.label": "ํ™์ฑ„ ๋†’์ด ์กฐ์ •", + "EyeTracking.iris.desc": "ํ™์ฑ„ ๋ฒ„ํ…์Šค์˜ ๋†’์ด ์กฐ์ •", + "EyeTracking.blink.test.label": "๊นœ๋นก์ž„ ํ…Œ์ŠคํŠธ", + "EyeTracking.blink.test.desc": "๋ˆˆ ๊นœ๋นก์ž„ ์‰์ดํ”„ ํ‚ค ํ…Œ์ŠคํŠธ", + "EyeTracking.lowerlid.test.label": "์•„๋ž˜ ๋ˆˆ๊บผํ’€ ํ…Œ์ŠคํŠธ", + "EyeTracking.lowerlid.test.desc": "์•„๋ž˜ ๋ˆˆ๊บผํ’€ ์‰์ดํ”„ ํ‚ค ํ…Œ์ŠคํŠธ", + "EyeTracking.blink.reset.label": "๊นœ๋นก์ž„ ํ…Œ์ŠคํŠธ ์ดˆ๊ธฐํ™”", + "EyeTracking.blink.reset.desc": "๊นœ๋นก์ž„ ํ…Œ์ŠคํŠธ ๊ฐ’ ์ดˆ๊ธฐํ™”", + "EyeTracking.validation.noArmature": "์”ฌ์—์„œ ์•„๋งˆ์ถ”์–ด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "EyeTracking.validation.noMesh": "๋ฉ”์‹œ '{mesh}'๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "EyeTracking.validation.noShapekeys": "์„ ํƒ๋œ ๋ฉ”์‹œ์— ์‰์ดํ”„ ํ‚ค๊ฐ€ ์—†์Œ", + "EyeTracking.validation.leftEye": "์™ผ์ชฝ ๋ˆˆ", + "EyeTracking.validation.rightEye": "์˜ค๋ฅธ์ชฝ ๋ˆˆ", + "EyeTracking.validation.missingGroups": "๋ˆ„๋ฝ๋œ ๋ฒ„ํ…์Šค ๊ทธ๋ฃน: {groups}", + "EyeTracking.validation.missingBones": "ํ•„์š”ํ•œ ๋ณธ ๋ˆ„๋ฝ: {bones}", + "EyeTracking.validation.success": "์‹œ์„  ์ถ”์  ์„ค์ •์ด ์„ฑ๊ณต์ ์œผ๋กœ ๊ฒ€์ฆ๋จ", + "EyeTracking.error.noMesh": "์‹œ์„  ์ถ”์ ์„ ์œ„ํ•œ ๋ฉ”์‹œ๊ฐ€ ์„ ํƒ๋˜์ง€ ์•Š์Œ", + "EyeTracking.error.noVertexGroup": "๋ณธ์„ ์œ„ํ•œ ๋ฒ„ํ…์Šค ๊ทธ๋ฃน์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ: {bone}", + "EyeTracking.error.noShapeSelected": "ํ•„์š”ํ•œ ๋ชจ๋“  ์‰์ดํ”„ ํ‚ค๋ฅผ ์„ ํƒํ•˜์„ธ์š”", + "EyeTracking.success": "์‹œ์„  ์ถ”์  ์„ค์ •์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋จ", + "EyeTracking.mode_select": "๋ชจ๋“œ ์„ ํƒ", + "EyeTracking.mesh_setup": "๋ฉ”์‹œ ์„ค์ •", + "EyeTracking.bone_setup": "๋ณธ ์„ค์ •", + "EyeTracking.shapekey_setup": "์‰์ดํ”„ ํ‚ค ์„ค์ •", + "EyeTracking.testing": "ํ…Œ์ŠคํŠธ ๋ชจ๋“œ", + "EyeTracking.rotation_controls": "๋ˆˆ ํšŒ์ „ ์ปจํŠธ๋กค", + "EyeTracking.adjustments": "๋ˆˆ ์กฐ์ •", + "EyeTracking.blink_testing": "๊นœ๋นก์ž„ ํ…Œ์ŠคํŠธ", + "EyeTracking.wink_left": "์™ผ์ชฝ ์œ™ํฌ", + "EyeTracking.wink_right": "์˜ค๋ฅธ์ชฝ ์œ™ํฌ", + "EyeTracking.lowerlid_left": "์™ผ์ชฝ ์•„๋ž˜ ๋ˆˆ๊บผํ’€", + "EyeTracking.lowerlid_right": "์˜ค๋ฅธ์ชฝ ์•„๋ž˜ ๋ˆˆ๊บผํ’€", + "EyeTracking.mode.creation": "์ƒ์„ฑ ๋ชจ๋“œ", + "EyeTracking.mode.testing": "ํ…Œ์ŠคํŠธ ๋ชจ๋“œ", + "EyeTracking.disable_blinking": "๋ˆˆ ๊นœ๋นก์ž„ ๋น„ํ™œ์„ฑํ™”", + "EyeTracking.disable_movement": "๋ˆˆ ์›€์ง์ž„ ๋น„ํ™œ์„ฑํ™”", + "EyeTracking.distance": "๋ˆˆ ๊ฑฐ๋ฆฌ", + "EyeTracking.distance_desc": "๋ˆˆ ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ ์กฐ์ •", + "EyeTracking.mode": "์‹œ์„  ์ถ”์  ๋ชจ๋“œ", + "EyeTracking.mesh_name": "๋ฉ”์‹œ", + "EyeTracking.mesh_name_desc": "์‹œ์„  ์ถ”์ ์„ ์œ„ํ•œ ๋ฉ”์‹œ ์„ ํƒ", + "EyeTracking.head_bone_desc": "๋จธ๋ฆฌ ๋ณธ ์„ ํƒ", + "EyeTracking.eye_left_desc": "์™ผ์ชฝ ๋ˆˆ ๋ณธ ์„ ํƒ", + "EyeTracking.eye_right_desc": "์˜ค๋ฅธ์ชฝ ๋ˆˆ ๋ณธ ์„ ํƒ", + "EyeTracking.type": "์‹œ์„  ์ถ”์  ์œ ํ˜•", + "EyeTracking.type_desc": "์ƒ์„ฑํ•  ์‹œ์„  ์ถ”์  ์„ค์ • ์œ ํ˜• ์„ ํƒ", + "EyeTracking.create.av3.label": "AV3 ์‹œ์„  ์ถ”์  ์ƒ์„ฑ", + "EyeTracking.create.av3.desc": "VRChat Avatar 3.0์šฉ ์‹œ์„  ์ถ”์  ์„ค์ •", + "EyeTracking.create.sdk2.label": "SDK2 ์‹œ์„  ์ถ”์  ์ƒ์„ฑ", + "EyeTracking.create.sdk2.desc": "VRChat SDK2์šฉ ์‹œ์„  ์ถ”์  ์„ค์ •", + "EyeTracking.sdk_version": "SDK ๋ฒ„์ „", + "EyeTracking.type.av3": "Avatar 3.0", + "EyeTracking.type.av3_desc": "VRChat Avatar 3.0 ์‹œ์„  ์ถ”์  ์„ค์ •", + "EyeTracking.type.sdk2": "SDK2 (๋ ˆ๊ฑฐ์‹œ)", + "EyeTracking.type.sdk2_desc": "VRChat SDK2 ์‹œ์„  ์ถ”์  ์„ค์ •", + "EyeTracking.adjust.label": "๋ˆˆ ์œ„์น˜ ์กฐ์ •", + "EyeTracking.adjust.desc": "๋ฒ„ํ…์Šค ๊ทธ๋ฃน์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ˆˆ ๋ณธ ์œ„์น˜ ์กฐ์ •", + + "CustomPanel.label": "์ปค์Šคํ…€ ์•„๋ฐ”ํƒ€ ๋„๊ตฌ", + "CustomPanel.merge_mode": "๋ณ‘ํ•ฉ ๋ชจ๋“œ", + "CustomPanel.mesh_selection": "๋ฉ”์‹œ ์„ ํƒ", + "CustomPanel.select_mesh": "๋ฉ”์‹œ ์„ ํƒ", + "CustomPanel.select_bone": "๋ณธ ์„ ํƒ", + "CustomPanel.select_armature": "์•„๋งˆ์ถ”์–ด ์„ ํƒ", + "CustomPanel.mode.armature": "์•„๋งˆ์ถ”์–ด", + "CustomPanel.mode.armature_desc": "์•„๋งˆ์ถ”์–ด ํ•จ๊ป˜ ๋ณ‘ํ•ฉ", + "CustomPanel.mode.mesh": "๋ฉ”์‹œ", + "CustomPanel.mode.mesh_desc": "๋ฉ”์‹œ๋ฅผ ์•„๋งˆ์ถ”์–ด์— ๋ถ€์ฐฉ", + + "AttachMesh.label": "๋ฉ”์‹œ ๋ถ€์ฐฉ", + "AttachMesh.desc": "์ž๋™ ๊ฐ€์ค‘์น˜ ์„ค์ •์œผ๋กœ ๋ฉ”์‹œ๋ฅผ ์•„๋งˆ์ถ”์–ด ๋ณธ์— ๋ถ€์ฐฉ", + "AttachMesh.search_desc": "๋ถ€์ฐฉํ•  ๋ฉ”์‹œ ๊ฒ€์ƒ‰", + "AttachMesh.select": "๋ถ€์ฐฉํ•  ๋ฉ”์‹œ ์„ ํƒ", + "AttachMesh.select_desc": "์•„๋งˆ์ถ”์–ด์— ๋ถ€์ฐฉํ•  ๋ฉ”์‹œ ์„ ํƒ", + "AttachMesh.success": "๋ฉ”์‹œ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ถ€์ฐฉ๋จ", + "AttachMesh.warn_no_armature": "๋ถ€์ฐฉํ•  ์•„๋งˆ์ถ”์–ด์™€ ๋ฉ”์‹œ๋ฅผ ์„ ํƒํ•˜์„ธ์š”", + "AttachMesh.validate_transforms": "๋ฉ”์‹œ ๋ณ€ํ˜• ๊ฒ€์ฆ ์ค‘", + "AttachMesh.validate_name": "๋ฉ”์‹œ ์ด๋ฆ„ ๊ฒ€์ฆ ์ค‘", + "AttachMesh.parent_mesh": "๋ฉ”์‹œ๋ฅผ ์•„๋งˆ์ถ”์–ด์— ํŽ˜์–ด๋ŸฐํŒ…", + "AttachMesh.setup_weights": "๋ฒ„ํ…์Šค ๊ฐ€์ค‘์น˜ ์„ค์ • ์ค‘", + "AttachMesh.create_bone": "๋ถ€์ฐฉ ๋ณธ ์ƒ์„ฑ ์ค‘", + "AttachMesh.position_bone": "๋ณธ ์œ„์น˜ ์ง€์ • ์ค‘", + "AttachMesh.add_modifier": "์•„๋งˆ์ถ”์–ด ๋ชจ๋””ํŒŒ์ด์–ด ์ถ”๊ฐ€ ์ค‘", + "AttachMesh.error.bone_not_found": "๋ถ€์ฐฉ ๋ณธ '{bone}'์„(๋ฅผ) ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "AttachMesh.error.mesh_not_found": "๋ฉ”์‹œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "AttachMesh.error.non_uniform_scale": "๋ฉ”์‹œ์— ๋น„๊ท ์ผ ์Šค์ผ€์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์Šค์ผ€์ผ์„ ์ ์šฉํ•˜์„ธ์š”", + "AttachBone.search_desc": "๋Œ€์ƒ ๋ณธ ๊ฒ€์ƒ‰", + "AttachBone.select": "๋Œ€์ƒ ๋ณธ ์„ ํƒ", + "AttachBone.select_desc": "๋ฉ”์‹œ๋ฅผ ๋ถ€์ฐฉํ•  ๋ณธ ์„ ํƒ", + + "MergeArmature.label": "์•„๋งˆ์ถ”์–ด ๋ณ‘ํ•ฉ", + "MergeArmature.desc": "๋‘ ์•„๋งˆ์ถ”์–ด ๋ณ‘ํ•ฉ", + "MergeArmature.options": "๋ณ‘ํ•ฉ ์˜ต์…˜", + "MergeArmature.warn_two": "๋ณ‘ํ•ฉํ•˜๋ ค๋ฉด ์ตœ์†Œ ๋‘ ๊ฐœ์˜ ์•„๋งˆ์ถ”์–ด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค", + "MergeArmature.into": "๋ณ‘ํ•ฉ ๋Œ€์ƒ", + "MergeArmature.into_desc": "๋ณ‘ํ•ฉํ•  ๋Œ€์ƒ ์•„๋งˆ์ถ”์–ด", + "MergeArmature.into_search_desc": "๋Œ€์ƒ ์•„๋งˆ์ถ”์–ด ๊ฒ€์ƒ‰", + "MergeArmature.from": "๋ณ‘ํ•ฉ ์†Œ์Šค", + "MergeArmature.from_desc": "๋ณ‘ํ•ฉํ•  ์†Œ์Šค ์•„๋งˆ์ถ”์–ด", + "MergeArmature.from_search_desc": "์†Œ์Šค ์•„๋งˆ์ถ”์–ด ๊ฒ€์ƒ‰", + "MergeArmature.error.not_found": "์•„๋งˆ์ถ”์–ด '{name}'์„(๋ฅผ) ์ฐพ์„ ์ˆ˜ ์—†์Œ", + "MergeArmature.error.transforms_not_aligned": "์ด ์•„๋งˆ์ถ”์–ด๋ฅผ ๋ณ‘ํ•ฉํ•˜๋ ค๋ฉด ๋ณ€ํ˜•์„ ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜๋™ ๋ฐฉ๋ฒ•์ด๋‚˜ ๋ณ€ํ˜• ์ ์šฉ ์ฒดํฌ๋ฐ•์Šค๋ฅผ ํ†ตํ•ด ์ˆ˜ํ–‰ํ•˜์„ธ์š”", + "MergeArmature.error.check_transforms": "๋ถ€๋ชจ ๋ณ€ํ˜•์„ ํ™•์ธํ•˜์„ธ์š”", + "MergeArmature.error.fix_parents": "๋ถ€๋ชจ ๊ด€๊ณ„๋ฅผ ์ˆ˜์ •ํ•˜์„ธ์š”", + "MergeArmature.progress.removing_rigidbodies": "๊ฐ•์ฒด์™€ ์กฐ์ธํŠธ ์ œ๊ฑฐ ์ค‘", + "MergeArmature.progress.validating": "์•„๋งˆ์ถ”์–ด ๊ฒ€์ฆ ์ค‘", + "MergeArmature.progress.merging": "์•„๋งˆ์ถ”์–ด ๋ณ‘ํ•ฉ ์ค‘", + "MergeArmature.success": "์•„๋งˆ์ถ”์–ด๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ‘ํ•ฉ๋จ", + "MergeArmature.merge_all": "๋™์ผํ•œ ๋ณธ ๋ณ‘ํ•ฉ", + "MergeArmature.merge_all_desc": "์ผ์น˜ํ•˜๋Š” ์ด๋ฆ„์˜ ๋ณธ ๋ณ‘ํ•ฉ", + "MergeArmature.apply_transforms": "๋ณ€ํ˜• ์ ์šฉ", + "MergeArmature.apply_transforms_desc": "๋ณ‘ํ•ฉ ์ „ ๋ชจ๋“  ๋ณ€ํ˜• ์ ์šฉ", + "MergeArmature.join_meshes": "๋ฉ”์‹œ ๊ฒฐํ•ฉ", + "MergeArmature.join_meshes_desc": "๋ณ‘ํ•ฉ ํ›„ ๋ฉ”์‹œ ๊ฒฐํ•ฉ", + "MergeArmature.remove_zero_weights": "0 ๊ฐ€์ค‘์น˜ ์ œ๊ฑฐ", + "MergeArmature.remove_zero_weights_desc": "๊ฐ€์ค‘์น˜๊ฐ€ ์—†๋Š” ๋ฒ„ํ…์Šค ๊ทธ๋ฃน ์ œ๊ฑฐ", + "MergeArmature.cleanup_shape_keys": "์‰์ดํ”„ ํ‚ค ์ •๋ฆฌ", + "MergeArmature.cleanup_shape_keys_desc": "๋ฏธ์‚ฌ์šฉ ์‰์ดํ”„ ํ‚ค ์ œ๊ฑฐ", + + "Settings.label": "์„ค์ •", + "Settings.language": "์–ธ์–ด", + "Settings.language_desc": "์ธํ„ฐํŽ˜์ด์Šค ์–ธ์–ด ์„ ํƒ", + "Settings.validation_mode": "๊ฒ€์ฆ ๋ชจ๋“œ", + "Settings.validation_mode_desc": "์•„๋งˆ์ถ”์–ด ๊ฒ€์ฆ์˜ ์—„๊ฒฉ์„ฑ ์„ ํƒ", + "Settings.validation_mode.strict": "์—„๊ฒฉ", + "Settings.validation_mode.strict_desc": "๋ณธ ๊ณ„์ธต ๊ตฌ์กฐ์™€ ๋Œ€์นญ์„ฑ์„ ํฌํ•จํ•œ ์ „์ฒด ๊ฒ€์ฆ", + "Settings.validation_mode.basic": "๊ธฐ๋ณธ", + "Settings.validation_mode.basic_desc": "ํ•„์ˆ˜ ๋ณธ ํ™•์ธ๋งŒ", + "Settings.validation_mode.none": "์—†์Œ", + "Settings.validation_mode.none_desc": "์•„๋งˆ์ถ”์–ด ๊ฒ€์ฆ ์—†์Œ", + "Settings.debug": "๋””๋ฒ„๊ทธ ์„ค์ •", + "Settings.logging": "๋กœ๊น…", + "Settings.enable_logging": "๋””๋ฒ„๊ทธ ๋กœ๊น… ํ™œ์„ฑํ™”", + "Settings.enable_logging_desc": "๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•œ ์ƒ์„ธ ๋””๋ฒ„๊ทธ ๋กœ๊น… ํ™œ์„ฑํ™”", + "Settings.logging_enabled": "๋””๋ฒ„๊ทธ ๋กœ๊น…์ด ํ™œ์„ฑํ™”๋จ", + "Settings.logging_disabled": "๋””๋ฒ„๊ทธ ๋กœ๊น…์ด ๋น„ํ™œ์„ฑํ™”๋จ", + "Language.auto": "์ž๋™", + "Language.en_US": "์˜์–ด", + "Language.ja_JP": "์ผ๋ณธ์–ด", + "Language.ko_KR": "ํ•œ๊ตญ์–ด", + "Language.changed.title": "์–ธ์–ด ๋ณ€๊ฒฝ๋จ", + "Language.changed.success": "์–ธ์–ด๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ€๊ฒฝ๋จ!", + "Language.changed.restart": "์ผ๋ถ€ UI ์š”์†Œ๋Š” ๋ธ”๋ Œ๋” ์žฌ์‹œ์ž‘์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Œ" + } + } \ No newline at end of file diff --git a/ui/custom_avatar_panel.py b/ui/custom_avatar_panel.py index 9c2c378..1db821f 100644 --- a/ui/custom_avatar_panel.py +++ b/ui/custom_avatar_panel.py @@ -1,6 +1,6 @@ import bpy -from typing import Set -from bpy.types import Panel, Context, UILayout, Operator +from typing import Set, List, Tuple, Any +from bpy.types import Panel, Context, UILayout, Operator, Event, WindowManager from .main_panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME from ..core.translations import t from ..core.common import ( @@ -11,10 +11,11 @@ from ..core.common import ( ) class AvatarToolkit_OT_SearchMergeArmatureInto(Operator): - bl_idname = "avatar_toolkit.search_merge_armature_into" - bl_label = "" - bl_description = t('MergeArmature.into_search_desc') - bl_property = "search_merge_armature_into_enum" + """Search operator for selecting target armature to merge into""" + bl_idname: str = "avatar_toolkit.search_merge_armature_into" + bl_label: str = "" + bl_description: str = t('MergeArmature.into_search_desc') + bl_property: str = "search_merge_armature_into_enum" search_merge_armature_into_enum: bpy.props.EnumProperty( name=t('MergeArmature.into'), @@ -22,19 +23,20 @@ class AvatarToolkit_OT_SearchMergeArmatureInto(Operator): items=get_armature_list ) - def execute(self, context): + def execute(self, context: Context) -> Set[str]: context.scene.avatar_toolkit.merge_armature_into = self.search_merge_armature_into_enum return {'FINISHED'} - def invoke(self, context, event): + def invoke(self, context: Context, event: Event) -> Set[str]: context.window_manager.invoke_search_popup(self) return {'FINISHED'} class AvatarToolkit_OT_SearchMergeArmature(Operator): - bl_idname = "avatar_toolkit.search_merge_armature" - bl_label = "" - bl_description = t('MergeArmature.from_search_desc') - bl_property = "search_merge_armature_enum" + """Search operator for selecting source armature to merge from""" + bl_idname: str = "avatar_toolkit.search_merge_armature" + bl_label: str = "" + bl_description: str = t('MergeArmature.from_search_desc') + bl_property: str = "search_merge_armature_enum" search_merge_armature_enum: bpy.props.EnumProperty( name=t('MergeArmature.from'), @@ -42,44 +44,46 @@ class AvatarToolkit_OT_SearchMergeArmature(Operator): items=get_armature_list ) - def execute(self, context): + def execute(self, context: Context) -> Set[str]: context.scene.avatar_toolkit.merge_armature = self.search_merge_armature_enum return {'FINISHED'} - def invoke(self, context, event): + def invoke(self, context: Context, event: Event) -> Set[str]: context.window_manager.invoke_search_popup(self) return {'FINISHED'} class AvatarToolkit_OT_SearchAttachMesh(Operator): - bl_idname = "avatar_toolkit.search_attach_mesh" - bl_label = "" - bl_description = t('AttachMesh.search_desc') - bl_property = "search_attach_mesh_enum" + """Search operator for selecting mesh to attach to armature""" + bl_idname: str = "avatar_toolkit.search_attach_mesh" + bl_label: str = "" + bl_description: str = t('AttachMesh.search_desc') + bl_property: str = "search_attach_mesh_enum" search_attach_mesh_enum: bpy.props.EnumProperty( name=t('AttachMesh.select'), description=t('AttachMesh.select_desc'), items=lambda self, context: [ - (obj.name, obj.name, "") + (obj.name, obj.name, "") for obj in bpy.data.objects if obj.type == 'MESH' and not any(mod.type == 'ARMATURE' for mod in obj.modifiers) ] ) - def execute(self, context): + def execute(self, context: Context) -> Set[str]: context.scene.avatar_toolkit.attach_mesh = self.search_attach_mesh_enum return {'FINISHED'} - def invoke(self, context, event): + def invoke(self, context: Context, event: Event) -> Set[str]: context.window_manager.invoke_search_popup(self) return {'FINISHED'} class AvatarToolkit_OT_SearchAttachBone(Operator): - bl_idname = "avatar_toolkit.search_attach_bone" - bl_label = "" - bl_description = t('AttachBone.search_desc') - bl_property = "search_attach_bone_enum" + """Search operator for selecting bone to attach mesh to""" + bl_idname: str = "avatar_toolkit.search_attach_bone" + bl_label: str = "" + bl_description: str = t('AttachBone.search_desc') + bl_property: str = "search_attach_bone_enum" search_attach_bone_enum: bpy.props.EnumProperty( name=t('AttachBone.select'), @@ -90,26 +94,27 @@ class AvatarToolkit_OT_SearchAttachBone(Operator): ] if get_active_armature(context) else [] ) - def execute(self, context): + def execute(self, context: Context) -> Set[str]: context.scene.avatar_toolkit.attach_bone = self.search_attach_bone_enum return {'FINISHED'} - def invoke(self, context, event): + def invoke(self, context: Context, event: Event) -> Set[str]: context.window_manager.invoke_search_popup(self) return {'FINISHED'} class AvatarToolKit_PT_CustomPanel(Panel): """Panel containing tools for custom avatar creation and merging""" - bl_label = t('CustomPanel.label') - bl_idname = "VIEW3D_PT_avatar_toolkit_custom" - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = CATEGORY_NAME - bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname - bl_order = 4 - bl_options = {'DEFAULT_CLOSED'} + bl_label: str = t('CustomPanel.label') + bl_idname: str = "VIEW3D_PT_avatar_toolkit_custom" + bl_space_type: str = 'VIEW_3D' + bl_region_type: str = 'UI' + bl_category: str = CATEGORY_NAME + bl_parent_id: str = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname + bl_order: int = 4 + bl_options: Set[str] = {'DEFAULT_CLOSED'} def draw(self, context: Context) -> None: + """Draw the custom avatar panel UI""" layout: UILayout = self.layout toolkit = context.scene.avatar_toolkit @@ -129,6 +134,7 @@ class AvatarToolKit_PT_CustomPanel(Panel): self.draw_mesh_tools(layout, context) def draw_armature_tools(self, layout: UILayout, context: Context) -> None: + """Draw the armature merging tools section""" toolkit = context.scene.avatar_toolkit # Merge Settings Box @@ -148,13 +154,13 @@ class AvatarToolKit_PT_CustomPanel(Panel): col.separator(factor=0.5) # Group related options together - transform_col = col.column(align=True) + transform_col: UILayout = col.column(align=True) transform_col.prop(toolkit, "merge_all_bones") transform_col.prop(toolkit, "apply_transforms") col.separator(factor=0.5) - cleanup_col = col.column(align=True) + cleanup_col: UILayout = col.column(align=True) cleanup_col.prop(toolkit, "join_meshes") cleanup_col.prop(toolkit, "remove_zero_weights") cleanup_col.prop(toolkit, "cleanup_shape_keys") @@ -178,12 +184,13 @@ class AvatarToolKit_PT_CustomPanel(Panel): # Merge button with emphasis merge_box: UILayout = layout.box() - col = merge_box.column(align=True) - row = col.row(align=True) + col: UILayout = merge_box.column(align=True) + row: UILayout = col.row(align=True) row.scale_y = 1.5 row.operator("avatar_toolkit.merge_armatures", icon='ARMATURE_DATA') def draw_mesh_tools(self, layout: UILayout, context: Context) -> None: + """Draw the mesh attachment tools section""" toolkit = context.scene.avatar_toolkit # Mesh Tools Box @@ -220,8 +227,7 @@ class AvatarToolKit_PT_CustomPanel(Panel): # Attach button with emphasis attach_box: UILayout = layout.box() - col = attach_box.column(align=True) - row = col.row(align=True) + col: UILayout = attach_box.column(align=True) + row: UILayout = col.row(align=True) row.scale_y = 1.5 row.operator("avatar_toolkit.attach_mesh", icon='ARMATURE_DATA') - diff --git a/ui/eye_tracking_panel.py b/ui/eye_tracking_panel.py index ffb59fe..1178bc9 100644 --- a/ui/eye_tracking_panel.py +++ b/ui/eye_tracking_panel.py @@ -1,6 +1,6 @@ import bpy from typing import Set -from bpy.types import Panel, Context, UILayout, Operator +from bpy.types import Panel, Context, UILayout, Operator, Event, WindowManager from .main_panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME from ..core.translations import t from ..core.common import get_active_armature, get_all_meshes @@ -20,32 +20,32 @@ from ..functions.eye_tracking import ( class AvatarToolKit_PT_EyeTrackingPanel(Panel): """Panel containing eye tracking setup and testing tools""" - bl_label = t("EyeTracking.label") - bl_idname = "VIEW3D_PT_avatar_toolkit_eye_tracking" - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = CATEGORY_NAME - bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname - bl_order = 6 - bl_options = {'DEFAULT_CLOSED'} + bl_label: str = t("EyeTracking.label") + bl_idname: str = "VIEW3D_PT_avatar_toolkit_eye_tracking" + bl_space_type: str = 'VIEW_3D' + bl_region_type: str = 'UI' + bl_category: str = CATEGORY_NAME + bl_parent_id: str = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname + bl_order: int = 6 + bl_options: Set[str] = {'DEFAULT_CLOSED'} def draw(self, context: Context) -> None: """Draw the eye tracking panel interface""" - layout = self.layout + layout: UILayout = self.layout toolkit = context.scene.avatar_toolkit # SDK Version Selection Box - sdk_box = layout.box() - col = sdk_box.column(align=True) + sdk_box: UILayout = layout.box() + col: UILayout = sdk_box.column(align=True) col.label(text=t("EyeTracking.sdk_version"), icon='PRESET') col.separator(factor=0.5) - row = col.row(align=True) + row: UILayout = col.row(align=True) row.prop(toolkit, "eye_tracking_type", expand=True) if toolkit.eye_tracking_type == 'SDK2': # Mode Selection Box - mode_box = layout.box() - col = mode_box.column(align=True) + mode_box: UILayout = layout.box() + col: UILayout = mode_box.column(align=True) col.label(text=t("EyeTracking.setup"), icon='TOOL_SETTINGS') col.separator(factor=0.5) col.prop(toolkit, "eye_mode", expand=True) @@ -59,11 +59,12 @@ class AvatarToolKit_PT_EyeTrackingPanel(Panel): self.draw_av3_setup(context, layout) def draw_av3_setup(self, context: Context, layout: UILayout) -> None: + """Draw the AV3 eye tracking setup interface""" toolkit = context.scene.avatar_toolkit # Bone Setup Box - bone_box = layout.box() - col = bone_box.column(align=True) + bone_box: UILayout = layout.box() + col: UILayout = bone_box.column(align=True) col.label(text=t("EyeTracking.bone_setup"), icon='BONE_DATA') col.separator(factor=0.5) @@ -76,16 +77,17 @@ class AvatarToolKit_PT_EyeTrackingPanel(Panel): col.label(text=t("EyeTracking.no_armature"), icon='ERROR') # Create Button - row = layout.row(align=True) + row: UILayout = layout.row(align=True) row.scale_y = 1.5 row.operator(CreateEyesAV3Button.bl_idname, icon='PLAY') def draw_creation_mode(self, context: Context, layout: UILayout) -> None: + """Draw the eye tracking creation mode interface""" toolkit = context.scene.avatar_toolkit # Bone Setup Box - bone_box = layout.box() - col = bone_box.column(align=True) + bone_box: UILayout = layout.box() + col: UILayout = bone_box.column(align=True) col.label(text=t("EyeTracking.bone_setup"), icon='BONE_DATA') col.separator(factor=0.5) @@ -98,15 +100,15 @@ class AvatarToolKit_PT_EyeTrackingPanel(Panel): col.label(text=t("EyeTracking.no_armature"), icon='ERROR') # Mesh Setup Box - mesh_box = layout.box() - col = mesh_box.column(align=True) + mesh_box: UILayout = layout.box() + col: UILayout = mesh_box.column(align=True) col.label(text=t("EyeTracking.mesh_setup"), icon='MESH_DATA') col.separator(factor=0.5) col.prop_search(toolkit, "mesh_name_eye", bpy.data, "objects", text="") # Shape Key Setup Box - shape_box = layout.box() - col = shape_box.column(align=True) + shape_box: UILayout = layout.box() + col: UILayout = shape_box.column(align=True) col.label(text=t("EyeTracking.shapekey_setup"), icon='SHAPEKEY_DATA') col.separator(factor=0.5) @@ -120,8 +122,8 @@ class AvatarToolKit_PT_EyeTrackingPanel(Panel): col.label(text=t("EyeTracking.no_shapekeys"), icon='ERROR') # Options Box - options_box = layout.box() - col = options_box.column(align=True) + options_box: UILayout = layout.box() + col: UILayout = options_box.column(align=True) col.label(text=t("EyeTracking.options"), icon='SETTINGS') col.separator(factor=0.5) col.prop(toolkit, "disable_eye_blinking") @@ -130,26 +132,27 @@ class AvatarToolKit_PT_EyeTrackingPanel(Panel): col.prop(toolkit, "eye_distance") # Create Button - row = layout.row(align=True) + row: UILayout = layout.row(align=True) row.scale_y = 1.5 row.operator(CreateEyesSDK2Button.bl_idname, icon='PLAY') def draw_testing_mode(self, context: Context, layout: UILayout) -> None: + """Draw the eye tracking testing mode interface""" toolkit = context.scene.avatar_toolkit if context.mode != 'POSE': # Testing Start Box - test_box = layout.box() - col = test_box.column(align=True) + test_box: UILayout = layout.box() + col: UILayout = test_box.column(align=True) col.label(text=t("EyeTracking.testing"), icon='PLAY') col.separator(factor=0.5) - row = col.row(align=True) + row: UILayout = col.row(align=True) row.scale_y = 1.5 row.operator(StartTestingButton.bl_idname, icon='PLAY') else: # Eye Rotation Box - rotation_box = layout.box() - col = rotation_box.column(align=True) + rotation_box: UILayout = layout.box() + col: UILayout = rotation_box.column(align=True) col.label(text=t("EyeTracking.rotation_controls"), icon='DRIVER_ROTATIONAL_DIFFERENCE') col.separator(factor=0.5) col.prop(toolkit, "eye_rotation_x", text=t("EyeTracking.rotation.x")) @@ -157,31 +160,31 @@ class AvatarToolKit_PT_EyeTrackingPanel(Panel): col.operator(ResetRotationButton.bl_idname, icon='LOOP_BACK') # Eye Adjustment Box - adjust_box = layout.box() - col = adjust_box.column(align=True) + adjust_box: UILayout = layout.box() + col: UILayout = adjust_box.column(align=True) col.label(text=t("EyeTracking.adjustments"), icon='MODIFIER') col.separator(factor=0.5) col.prop(toolkit, "eye_distance") col.operator(AdjustEyesButton.bl_idname, icon='CON_TRACKTO') # Blinking Test Box - blink_box = layout.box() - col = blink_box.column(align=True) + blink_box: UILayout = layout.box() + col: UILayout = blink_box.column(align=True) col.label(text=t("EyeTracking.blink_testing"), icon='HIDE_OFF') col.separator(factor=0.5) - row = col.row(align=True) + row: UILayout = col.row(align=True) row.prop(toolkit, "eye_blink_shape") row.operator(TestBlinking.bl_idname, icon='RESTRICT_VIEW_OFF') - row = col.row(align=True) + row: UILayout = col.row(align=True) row.prop(toolkit, "eye_lowerlid_shape") row.operator(TestLowerlid.bl_idname, icon='RESTRICT_VIEW_OFF') col.operator(ResetBlinkTest.bl_idname, icon='LOOP_BACK') # Stop Testing Button - row = layout.row(align=True) + row: UILayout = layout.row(align=True) row.scale_y = 1.5 row.operator(StopTestingButton.bl_idname, icon='PAUSE') # Reset Button - row = layout.row(align=True) + row: UILayout = layout.row(align=True) row.operator(ResetEyeTrackingButton.bl_idname, icon='FILE_REFRESH') diff --git a/ui/visemes_panel.py b/ui/visemes_panel.py index d79d041..5de266f 100644 --- a/ui/visemes_panel.py +++ b/ui/visemes_panel.py @@ -1,6 +1,8 @@ -from bpy.types import Panel, Context, UILayout +import bpy +from bpy.types import Panel, Context, UILayout, Object, ShapeKey from ..core.translations import t from .main_panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME +from ..core.common import get_active_armature class AvatarToolKit_PT_VisemesPanel(Panel): """Panel containing viseme creation and preview tools""" @@ -11,26 +13,39 @@ class AvatarToolKit_PT_VisemesPanel(Panel): bl_category: str = CATEGORY_NAME bl_parent_id: str = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname bl_order: int = 5 - bl_options = {'DEFAULT_CLOSED'} + bl_options: set[str] = {'DEFAULT_CLOSED'} def draw(self, context: Context) -> None: - """Draw the visemes panel interface""" + """Draw the visemes panel interface with shape key selection and preview controls""" layout: UILayout = self.layout props = context.scene.avatar_toolkit - - # Check for valid mesh with shape keys - if not context.active_object or context.active_object.type != 'MESH' or not context.active_object.data.shape_keys: + + # Mesh Selection Box + mesh_box: UILayout = layout.box() + col: UILayout = mesh_box.column(align=True) + col.label(text=t("Visemes.mesh_select"), icon='OUTLINER_OB_MESH') + col.separator(factor=0.5) + + armature = get_active_armature(context) + if armature: + col.prop_search(props, "viseme_mesh", bpy.data, "objects", text="") + else: + col.label(text=t("Visemes.no_armature"), icon='ERROR') + + # Get selected mesh + mesh_obj = bpy.data.objects.get(props.viseme_mesh) + if not mesh_obj or not mesh_obj.data.shape_keys: layout.label(text=t("Visemes.no_shapekeys")) return - - # Shape Key Selection Box + + # Shape Key Selection Box shape_box: UILayout = layout.box() col: UILayout = shape_box.column(align=True) col.label(text=t("Visemes.shape_selection"), icon='SHAPEKEY_DATA') col.separator(factor=0.5) # Shape key selection with valid data - shape_keys = context.active_object.data.shape_keys + shape_keys: ShapeKey = mesh_obj.data.shape_keys col.prop_search(props, "mouth_a", shape_keys, "key_blocks", text=t("Visemes.mouth_a")) col.prop_search(props, "mouth_o", shape_keys, "key_blocks", text=t("Visemes.mouth_o")) col.prop_search(props, "mouth_ch", shape_keys, "key_blocks", text=t("Visemes.mouth_ch")) @@ -41,7 +56,7 @@ class AvatarToolKit_PT_VisemesPanel(Panel): # Preview Box preview_box: UILayout = layout.box() - col = preview_box.column(align=True) + col: UILayout = preview_box.column(align=True) col.label(text=t("Visemes.preview_label"), icon='HIDE_OFF') col.separator(factor=0.5) @@ -49,12 +64,12 @@ class AvatarToolKit_PT_VisemesPanel(Panel): col.prop(props, "viseme_preview_selection", text="") col.separator() - preview_text = t("Visemes.stop_preview") if props.viseme_preview_mode else t("Visemes.start_preview") + preview_text: str = t("Visemes.stop_preview") if props.viseme_preview_mode else t("Visemes.start_preview") col.operator("avatar_toolkit.preview_visemes", text=preview_text, icon='HIDE_OFF') # Create Box create_box: UILayout = layout.box() - col = create_box.column(align=True) + col: UILayout = create_box.column(align=True) col.label(text=t("Visemes.create_label"), icon='ADD') col.separator(factor=0.5) col.operator("avatar_toolkit.create_visemes", icon='ADD')