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 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 @@ 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 @@ def step(self, message: str = "") -> None: 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') + +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) -# 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) + 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 identifier_lower(choice): 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') - - -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 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 +_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 get_objects() -> bpy.types.BlendData: + """Get all objects in the current Blender scene""" + return bpy.data.objects + +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 ..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 @@ 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ ) 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 @@ def execute(self, context: Context) -> Set[str]: 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 @@ def execute(self, context: Context) -> Set[str]: 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 @@ def execute(self, context: Context) -> Set[str]: 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 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 @@ 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def restore_bone_positions(self, armature) -> bool: 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 @@ def find_eye_vertex_groups(mesh_name: str) -> Tuple[str, str]: 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 @@ def validate_setup(context, mesh_name: str) -> Tuple[bool, str]: 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def clear_cache(cls): 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 @@ def execute(self, context): 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 @@ def execute(self, context): 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 @@ def poll(cls, context: Context) -> bool: 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 @@ ) 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 @@ def end_preview(cls, mesh: Object) -> None: 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 @@ ) 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 @@ def draw(self, context: Context) -> None: 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 @@ def draw_armature_tools(self, layout: UILayout, context: Context) -> None: 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 @@ def draw_armature_tools(self, layout: UILayout, context: Context) -> None: # 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 @@ def draw_mesh_tools(self, layout: UILayout, context: Context) -> None: # 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 @@ 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 @@ def draw(self, context: Context) -> None: 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 @@ def draw_av3_setup(self, context: Context, layout: UILayout) -> None: 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 @@ def draw_creation_mode(self, context: Context, layout: UILayout) -> None: 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 @@ def draw_creation_mode(self, context: Context, layout: UILayout) -> None: 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 @@ def draw_creation_mode(self, context: Context, layout: UILayout) -> None: 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 @@ def draw_testing_mode(self, context: Context, layout: UILayout) -> None: 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 @@ def draw(self, context: Context) -> None: # 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 @@ def draw(self, context: Context) -> None: 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')