Coverage for src / moai_adk / cli / commands / language.py: 0.00%
161 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-20 20:52 +0900
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-20 20:52 +0900
1"""Language management commands for MoAI-ADK.
3Provides commands for language configuration, template processing,
4and multilingual content generation.
5"""
7import json
8from pathlib import Path
10import click
11from rich.console import Console
12from rich.table import Table
14from ...core.claude_integration import ClaudeCLIIntegration
15from ...core.language_config import (
16 LANGUAGE_CONFIG,
17 get_all_supported_codes,
18 get_native_name,
19 get_optimal_model,
20)
21from ...core.template_engine import TemplateEngine
23console = Console()
26@click.group()
27def language():
28 """Language management and multilingual support."""
29 pass
32@language.command()
33@click.option("--json-output", is_flag=True, help="Output as JSON")
34def list(json_output):
35 """List all supported languages."""
36 if json_output:
37 console.print(json.dumps(LANGUAGE_CONFIG, indent=2, ensure_ascii=False))
38 return
40 table = Table(title="Supported Languages")
41 table.add_column("Code", style="cyan", no_wrap=True)
42 table.add_column("English Name", style="green")
43 table.add_column("Native Name", style="yellow")
44 table.add_column("Family", style="blue")
46 for code, info in LANGUAGE_CONFIG.items():
47 table.add_row(code, info["name"], info["native_name"], info["family"])
49 console.print(table)
52@language.command()
53@click.argument("language_code")
54@click.option("--detail", is_flag=True, help="Show detailed information")
55def info(language_code, detail):
56 """Show information about a specific language."""
57 lang_info = LANGUAGE_CONFIG.get(language_code.lower())
59 if not lang_info:
60 console.print(f"[red]Language code '{language_code}' not found.[/red]")
61 console.print(f"Available codes: {', '.join(get_all_supported_codes())}")
62 return
64 console.print("[bold]Language Information:[/bold]")
65 console.print(f"Code: {language_code}")
66 console.print(f"English Name: {lang_info['name']}")
67 console.print(f"Native Name: {lang_info['native_name']}")
68 console.print(f"Family: {lang_info['family']}")
70 if detail:
71 optimal_model = get_optimal_model(language_code)
72 console.print(f"Optimal Claude Model: {optimal_model}")
75@language.command()
76@click.argument("template_path", type=click.Path(exists=True))
77@click.argument("variables_file", type=click.Path(exists=True))
78@click.option("--output", "-o", type=click.Path(), help="Output file path")
79@click.option("--language", "-l", help="Target language code")
80def render_template(template_path, variables_file, output, language):
81 """Render template with variables and language support."""
82 try:
83 # Load variables
84 with open(variables_file, "r", encoding="utf-8") as f:
85 variables = json.load(f)
87 # Add language info if specified
88 if language:
89 variables["CONVERSATION_LANGUAGE"] = language
90 variables["CONVERSATION_LANGUAGE_NAME"] = get_native_name(language)
92 # Render template
93 template_engine = TemplateEngine()
94 template_path_obj = Path(template_path)
95 output_path_obj = Path(output) if output else None
97 rendered = template_engine.render_file(
98 template_path_obj, variables, output_path_obj
99 )
101 if not output:
102 console.print("[bold]Rendered Template:[/bold]")
103 console.print(rendered)
104 else:
105 console.print(f"[green]Template rendered to: {output}[/green]")
107 except Exception as e:
108 console.print(f"[red]Error rendering template: {e}[/red]")
111@language.command()
112@click.argument("base_description")
113@click.option("--target-languages", "-t", help="Comma-separated target language codes")
114@click.option("--output", "-o", type=click.Path(), help="Output JSON file")
115def translate_descriptions(base_description, target_languages, output):
116 """Generate multilingual descriptions using Claude CLI."""
117 try:
118 if target_languages:
119 languages = [lang.strip() for lang in target_languages.split(",")]
120 else:
121 languages = ["en", "ko", "ja", "es", "fr", "de"]
123 claude_integration = ClaudeCLIIntegration()
124 descriptions = claude_integration.generate_multilingual_descriptions(
125 {"base": base_description}, languages
126 )
128 if output:
129 with open(output, "w", encoding="utf-8") as f:
130 json.dump(descriptions, f, indent=2, ensure_ascii=False)
131 console.print(f"[green]Descriptions saved to: {output}[/green]")
132 else:
133 console.print("[bold]Multilingual Descriptions:[/bold]")
134 console.print(json.dumps(descriptions, indent=2, ensure_ascii=False))
136 except Exception as e:
137 console.print(f"[red]Error generating descriptions: {e}[/red]")
140@language.command()
141@click.argument("prompt_template")
142@click.option(
143 "--variables", "-v", type=click.Path(exists=True), help="Variables JSON file"
144)
145@click.option("--language", "-l", help="Target language code")
146@click.option(
147 "--output-format", default="json", help="Output format (text, json, stream-json)"
148)
149@click.option("--dry-run", is_flag=True, help="Show command without executing")
150def execute(prompt_template, variables, language, output_format, dry_run):
151 """Execute Claude CLI with template variables and language support."""
152 try:
153 # Load or create variables
154 template_vars = {}
155 if variables:
156 with open(variables, "r", encoding="utf-8") as f:
157 template_vars = json.load(f)
159 if language:
160 template_vars["CONVERSATION_LANGUAGE"] = language
161 template_vars["CONVERSATION_LANGUAGE_NAME"] = get_native_name(language)
163 # Process template
164 template_engine = TemplateEngine()
165 processed_prompt = template_engine.render_string(prompt_template, template_vars)
167 if dry_run:
168 console.print("[bold]Dry Run - Command that would be executed:[/bold]")
169 console.print(
170 f"claude --print --output-format {output_format} '{processed_prompt}'"
171 )
172 console.print("[bold]Variables used:[/bold]")
173 console.print(json.dumps(template_vars, indent=2, ensure_ascii=False))
174 return
176 # Execute with Claude integration
177 claude_integration = ClaudeCLIIntegration()
178 result = claude_integration.process_template_command(
179 prompt_template, template_vars, print_mode=True, output_format=output_format
180 )
182 if result["success"]:
183 console.print("[green]✓ Command executed successfully[/green]")
184 if output_format == "json" and result["stdout"]:
185 try:
186 output_data = json.loads(result["stdout"])
187 console.print(json.dumps(output_data, indent=2, ensure_ascii=False))
188 except json.JSONDecodeError:
189 console.print(result["stdout"])
190 else:
191 console.print(result["stdout"])
192 else:
193 console.print("[red]✗ Command execution failed[/red]")
194 if "error" in result:
195 console.print(f"Error: {result['error']}")
196 if result["stderr"]:
197 console.print(f"Stderr: {result['stderr']}")
199 except Exception as e:
200 console.print(f"[red]Error executing command: {e}[/red]")
203@language.command()
204@click.argument("config_file", type=click.Path(exists=True))
205@click.option(
206 "--validate-languages", is_flag=True, help="Validate language codes in config"
207)
208def validate_config(config_file, validate_languages):
209 """Validate language configuration in MoAI-ADK config file."""
210 try:
211 with open(config_file, "r", encoding="utf-8") as f:
212 config = json.load(f)
214 console.print(f"[bold]Validating config: {config_file}[/bold]")
216 # Basic structure validation
217 if "language" not in config:
218 console.print("[yellow]⚠ No 'language' section found in config[/yellow]")
219 else:
220 lang_config = config["language"]
221 if not isinstance(lang_config, dict):
222 console.print("[red]✗ 'language' section must be an object[/red]")
223 else:
224 console.print("[green]✓ Language section structure is valid[/green]")
226 # Check conversation_language
227 conv_lang = lang_config.get("conversation_language")
228 if conv_lang:
229 if conv_lang in get_all_supported_codes():
230 console.print(
231 f"[green]✓ conversation_language '{conv_lang}' is supported[/green]"
232 )
233 else:
234 console.print(
235 f"[red]✗ conversation_language '{conv_lang}' is not supported[/red]"
236 )
237 else:
238 console.print(
239 "[yellow]⚠ No conversation_language specified[/yellow]"
240 )
242 # Check conversation_language_name
243 conv_lang_name = lang_config.get("conversation_language_name")
244 if conv_lang_name and conv_lang:
245 expected_name = get_native_name(conv_lang)
246 if conv_lang_name == expected_name:
247 console.print(
248 "[green]✓ conversation_language_name matches[/green]"
249 )
250 else:
251 console.print(
252 f"[yellow]⚠ conversation_language_name '{conv_lang_name}' doesn't match expected '{expected_name}'[/yellow]"
253 )
255 if validate_languages:
256 # Scan entire config for language codes
257 config_str = json.dumps(config)
258 found_codes = []
259 for code in get_all_supported_codes():
260 if code in config_str:
261 found_codes.append(code)
263 if found_codes:
264 console.print(
265 f"[blue]Found language codes in config: {', '.join(found_codes)}[/blue]"
266 )
268 except Exception as e:
269 console.print(f"[red]Error validating config: {e}[/red]")