"""Configuration module for i18n-guardian.""" from pathlib import Path from typing import Any, Dict, List, Optional import yaml class Config: """Configuration for i18n-guardian.""" def __init__( self, path: Optional[str] = None, i18n_library: Optional[str] = None, i18n_functions: Optional[List[str]] = None, exclude_patterns: Optional[List[str]] = None, include_patterns: Optional[List[str]] = None, min_string_length: int = 3, key_style: str = "snake_case", key_prefix: Optional[str] = None, output_format: str = "text", fail_level: str = "error", ) -> None: self.path = path self.i18n_library = i18n_library self.i18n_functions = i18n_functions or [] self.exclude_patterns = exclude_patterns or [] self.include_patterns = include_patterns or ["**/*.py", "**/*.js", "**/*.ts", "**/*.jsx", "**/*.tsx"] self.min_string_length = min_string_length self.key_style = key_style self.key_prefix = key_prefix self.output_format = output_format self.fail_level = fail_level @classmethod def from_dict(cls, data: Dict[str, Any]) -> "Config": """Create Config from dictionary.""" return cls( path=data.get("path"), i18n_library=data.get("i18n_library"), i18n_functions=data.get("i18n_functions"), exclude_patterns=data.get("exclude_patterns"), include_patterns=data.get("include_patterns"), min_string_length=data.get("min_string_length", 3), key_style=data.get("key_style", "snake_case"), key_prefix=data.get("key_prefix"), output_format=data.get("output_format", "text"), fail_level=data.get("fail_level", "error"), ) def to_dict(self) -> Dict[str, Any]: """Convert Config to dictionary.""" return { "path": self.path, "i18n_library": self.i18n_library, "i18n_functions": self.i18n_functions, "exclude_patterns": self.exclude_patterns, "include_patterns": self.include_patterns, "min_string_length": self.min_string_length, "key_style": self.key_style, "key_prefix": self.key_prefix, "output_format": self.output_format, "fail_level": self.fail_level, } class ConfigLoader: """Loader for i18n-guardian configuration.""" DEFAULT_CONFIG_NAME = ".i18n-guardian.yaml" def __init__(self) -> None: self._config: Optional[Config] = None def load( self, config_path: Optional[str], scan_path: str, ) -> Config: """Load configuration from file or use defaults.""" config_data: Dict[str, Any] = {} if config_path: config_file = Path(config_path) else: config_file = Path(scan_path) / self.DEFAULT_CONFIG_NAME if not config_file.exists(): config_file = Path.home() / self.DEFAULT_CONFIG_NAME if config_file.exists(): try: with open(config_file, "r", encoding="utf-8") as f: config_data = yaml.safe_load(f) or {} except yaml.YAMLError as e: raise ValueError(f"Invalid YAML in config file: {e}") if "include_patterns" not in config_data: config_data["include_patterns"] = ["**/*.py", "**/*.js", "**/*.ts", "**/*.jsx", "**/*.tsx"] if "exclude_patterns" not in config_data: config_data["exclude_patterns"] = ["**/node_modules/**", "**/.git/**", "**/venv/**", "**/__pycache__/**"] config_data["path"] = scan_path self._config = Config.from_dict(config_data) return self._config def save(self, config: Config, output_path: str) -> None: """Save configuration to file.""" config_file = Path(output_path) with open(config_file, "w", encoding="utf-8") as f: yaml.dump(config.to_dict(), f, default_flow_style=False, indent=2) def generate_default_config() -> Dict[str, Any]: """Generate default configuration.""" return { "i18n_library": None, "i18n_functions": [], "exclude_patterns": [ "**/node_modules/**", "**/.git/**", "**/venv/**", "**/__pycache__/**", "**/dist/**", "**/build/**", ], "include_patterns": [ "**/*.py", "**/*.js", "**/*.ts", "**/*.jsx", "**/*.tsx", ], "min_string_length": 3, "key_style": "snake_case", "key_prefix": None, "output_format": "text", "fail_level": "error", }