From 7853581e1f714ba64a135d931377c20010cdb396 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Mon, 2 Feb 2026 17:20:01 +0000 Subject: [PATCH] Add config module --- i18n_guardian/config/__init__.py | 140 +++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 i18n_guardian/config/__init__.py diff --git a/i18n_guardian/config/__init__.py b/i18n_guardian/config/__init__.py new file mode 100644 index 0000000..af22719 --- /dev/null +++ b/i18n_guardian/config/__init__.py @@ -0,0 +1,140 @@ +"""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", + }