codexspec 0.6.3__tar.gz → 0.6.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codexspec-0.6.3 → codexspec-0.6.4}/PKG-INFO +1 -1
- {codexspec-0.6.3 → codexspec-0.6.4}/pyproject.toml +1 -1
- {codexspec-0.6.3 → codexspec-0.6.4}/src/codexspec/__init__.py +51 -5
- {codexspec-0.6.3 → codexspec-0.6.4}/src/codexspec/commands/installer.py +49 -1
- {codexspec-0.6.3 → codexspec-0.6.4}/src/codexspec/i18n.py +18 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/src/codexspec/translator.py +34 -72
- {codexspec-0.6.3 → codexspec-0.6.4}/.gitignore +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/LICENSE +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/README.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/codexspec-icon.svg +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/codexspec-logo-dark.svg +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/codexspec-logo-light.svg +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/scripts/bash/check-i18n-completeness.sh +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/scripts/bash/check-i18n-structure.sh +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/scripts/bash/check-prerequisites.sh +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/scripts/bash/common.sh +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/scripts/bash/create-new-feature.sh +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/scripts/powershell/check-prerequisites.ps1 +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/scripts/powershell/common.ps1 +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/scripts/powershell/create-new-feature.ps1 +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/src/codexspec/commands/__init__.py +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/src/codexspec/idea.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/analyze.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/checklist.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/clarify.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/commit-staged.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/config.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/constitution.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/generate-spec.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/implement-tasks.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/plan-to-tasks.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/pr.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/quick.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/review-code.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/review-plan.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/review-spec.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/review-tasks.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/spec-to-plan.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/specify.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/commands/tasks-to-issues.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/checklist-template.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/constitution-template.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/plan-template-detailed.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/plan-template-simple.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/requirements-template.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/spec-template-detailed.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/spec-template-simple.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/tasks-template-detailed.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/docs/tasks-template-simple.md +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/translations/de.json +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/translations/en.json +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/translations/es.json +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/translations/fr.json +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/translations/ja.json +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/translations/ko.json +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/translations/pt-BR.json +0 -0
- {codexspec-0.6.3 → codexspec-0.6.4}/templates/translations/zh-CN.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codexspec
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.4
|
|
4
4
|
Summary: CodexSpec - A Requirements-First SDD toolkit for Claude Code
|
|
5
5
|
Project-URL: Homepage, https://github.com/Zts0hg/codexspec
|
|
6
6
|
Project-URL: Repository, https://github.com/Zts0hg/codexspec
|
|
@@ -26,9 +26,11 @@ from .commands.installer import (
|
|
|
26
26
|
install_commands_to_subdir,
|
|
27
27
|
migrate_old_commands,
|
|
28
28
|
should_update_commands,
|
|
29
|
+
update_installed_command_frontmatter,
|
|
29
30
|
)
|
|
30
31
|
from .i18n import (
|
|
31
32
|
generate_config_content,
|
|
33
|
+
get_explicit_language_key,
|
|
32
34
|
get_interaction_language,
|
|
33
35
|
get_language_name,
|
|
34
36
|
get_supported_languages,
|
|
@@ -36,7 +38,7 @@ from .i18n import (
|
|
|
36
38
|
normalize_locale,
|
|
37
39
|
update_language_field,
|
|
38
40
|
)
|
|
39
|
-
from .translator import translate
|
|
41
|
+
from .translator import SUPPORTED_LANGUAGES, translate
|
|
40
42
|
|
|
41
43
|
# Version info
|
|
42
44
|
__version__ = "0.6.0"
|
|
@@ -270,6 +272,7 @@ def config(
|
|
|
270
272
|
else:
|
|
271
273
|
console.print("[red]Failed to update language setting[/red]")
|
|
272
274
|
raise typer.Exit(1)
|
|
275
|
+
_rerender_command_frontmatter(config_file)
|
|
273
276
|
return
|
|
274
277
|
|
|
275
278
|
# Handle set commit language
|
|
@@ -348,6 +351,7 @@ def config(
|
|
|
348
351
|
else:
|
|
349
352
|
console.print("[red]Failed to update interaction language setting[/red]")
|
|
350
353
|
raise typer.Exit(1)
|
|
354
|
+
_rerender_command_frontmatter(config_file)
|
|
351
355
|
return
|
|
352
356
|
|
|
353
357
|
# Handle set document language
|
|
@@ -553,21 +557,40 @@ def init(
|
|
|
553
557
|
)
|
|
554
558
|
prompted_base = False
|
|
555
559
|
if base_determinable:
|
|
556
|
-
|
|
560
|
+
# Output base already resolved (or None when only dimension flags were
|
|
561
|
+
# given); no prompt needed to resolve it.
|
|
562
|
+
pass
|
|
557
563
|
elif config_exists:
|
|
558
|
-
|
|
564
|
+
# Existing project: preserve every unspecified key (REQ-007); no prompt.
|
|
565
|
+
pass
|
|
559
566
|
elif sys.stdin.isatty():
|
|
560
567
|
try:
|
|
561
568
|
output_value = normalize_locale(prompt_language_selection())
|
|
562
569
|
prompted_base = True
|
|
563
|
-
normalized_lang = output_value
|
|
564
570
|
except KeyboardInterrupt:
|
|
565
571
|
console.print()
|
|
566
572
|
console.print("[yellow]Selection cancelled, using default language (en)[/yellow]")
|
|
567
573
|
output_value = "en"
|
|
568
|
-
normalized_lang = "en"
|
|
569
574
|
else:
|
|
570
575
|
output_value = "en"
|
|
576
|
+
|
|
577
|
+
# Render/CLI-message language = the effective interaction language for THIS
|
|
578
|
+
# run (frontmatter descriptions are an interaction-language artifact). This is
|
|
579
|
+
# deliberately decoupled from output_value/prompted_base above, which only
|
|
580
|
+
# drive config writing and the first-time prompt. Precedence: explicit
|
|
581
|
+
# --interaction-lang -> explicitly-configured interaction -> --lang (output
|
|
582
|
+
# base) -> explicitly-configured output -> "en". Existing interaction is
|
|
583
|
+
# deliberately stronger than --lang; existing output is only a fallback when
|
|
584
|
+
# this run did not provide a new base.
|
|
585
|
+
if "interaction" in lang_overrides:
|
|
586
|
+
normalized_lang = lang_overrides["interaction"]
|
|
587
|
+
elif config_exists and (explicit_interaction := get_explicit_language_key(config_file, "interaction")) is not None:
|
|
588
|
+
normalized_lang = explicit_interaction
|
|
589
|
+
elif output_value is not None:
|
|
590
|
+
normalized_lang = output_value
|
|
591
|
+
elif config_exists and (explicit_output := get_explicit_language_key(config_file, "output")) is not None:
|
|
592
|
+
normalized_lang = explicit_output
|
|
593
|
+
else:
|
|
571
594
|
normalized_lang = "en"
|
|
572
595
|
|
|
573
596
|
if debug:
|
|
@@ -802,6 +825,29 @@ def init(
|
|
|
802
825
|
console.print(f"[yellow]{translate('cli.init.important_action', normalized_lang)}[/yellow]")
|
|
803
826
|
|
|
804
827
|
|
|
828
|
+
def _rerender_command_frontmatter(config_file: Path) -> None:
|
|
829
|
+
"""Re-render installed command frontmatter in the current interaction language.
|
|
830
|
+
|
|
831
|
+
Called after a ``config`` language change so ``.claude/commands/codexspec/*.md``
|
|
832
|
+
descriptions follow the new interaction language immediately, mirroring what
|
|
833
|
+
``init`` does. No-op when commands are not installed. Languages without a
|
|
834
|
+
pre-translated cache are not re-rendered here (that path would invoke the
|
|
835
|
+
``claude`` CLI once per command); the user is advised to run ``codexspec init``.
|
|
836
|
+
"""
|
|
837
|
+
commands_subdir = Path.cwd() / ".claude" / "commands" / COMMANDS_SUBDIR
|
|
838
|
+
if not commands_subdir.exists():
|
|
839
|
+
return
|
|
840
|
+
language = get_interaction_language(config_file) # re-read AFTER the config write
|
|
841
|
+
if language != "en" and language not in SUPPORTED_LANGUAGES:
|
|
842
|
+
console.print(f"[dim]Run [cyan]codexspec init[/cyan] to update command descriptions for {language}.[/dim]")
|
|
843
|
+
return
|
|
844
|
+
templates_dir = get_templates_dir() / "commands"
|
|
845
|
+
if not templates_dir.exists():
|
|
846
|
+
return
|
|
847
|
+
update_installed_command_frontmatter(commands_subdir, templates_dir, language=language)
|
|
848
|
+
console.print(f"[dim]Updated command descriptions to: {get_language_name(language)}[/dim]")
|
|
849
|
+
|
|
850
|
+
|
|
805
851
|
def _print_command_summary(language: str = "en") -> None:
|
|
806
852
|
"""Print a summary of installed commands grouped by category."""
|
|
807
853
|
metadata = get_commands_metadata()
|
|
@@ -8,7 +8,12 @@ import shutil
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Optional, TypedDict
|
|
10
10
|
|
|
11
|
-
from codexspec.translator import
|
|
11
|
+
from codexspec.translator import (
|
|
12
|
+
apply_translations_to_template,
|
|
13
|
+
extract_frontmatter_fields,
|
|
14
|
+
load_translation_cache,
|
|
15
|
+
translate_template_frontmatter,
|
|
16
|
+
)
|
|
12
17
|
|
|
13
18
|
# Constants
|
|
14
19
|
COMMANDS_SUBDIR = "codexspec" # Subdirectory name for commands
|
|
@@ -348,6 +353,49 @@ def install_commands_to_subdir(
|
|
|
348
353
|
return installed_count
|
|
349
354
|
|
|
350
355
|
|
|
356
|
+
def update_installed_command_frontmatter(
|
|
357
|
+
target_dir: Path,
|
|
358
|
+
templates_dir: Path,
|
|
359
|
+
language: str = "en",
|
|
360
|
+
translations_dir: Optional[Path] = None,
|
|
361
|
+
) -> int:
|
|
362
|
+
"""Update frontmatter translations for already-installed command files.
|
|
363
|
+
|
|
364
|
+
This preserves command bodies and any non-translated frontmatter while
|
|
365
|
+
refreshing the language-specific ``description`` and ``argument-hint`` fields.
|
|
366
|
+
Missing installed commands are intentionally skipped.
|
|
367
|
+
"""
|
|
368
|
+
if not target_dir.exists() or not templates_dir.exists():
|
|
369
|
+
return 0
|
|
370
|
+
|
|
371
|
+
translation_cache = None
|
|
372
|
+
if language != "en":
|
|
373
|
+
translation_cache = load_translation_cache(language, translations_dir)
|
|
374
|
+
|
|
375
|
+
updated_count = 0
|
|
376
|
+
for template_file in templates_dir.glob("*.md"):
|
|
377
|
+
target_path = target_dir / template_file.name
|
|
378
|
+
if not target_path.exists():
|
|
379
|
+
continue
|
|
380
|
+
|
|
381
|
+
template_content = template_file.read_text(encoding="utf-8")
|
|
382
|
+
template_name = template_file.stem
|
|
383
|
+
rendered_template = translate_template_frontmatter(template_content, template_name, language, translation_cache)
|
|
384
|
+
fields = {
|
|
385
|
+
key: value for key, value in extract_frontmatter_fields(rendered_template).items() if value is not None
|
|
386
|
+
}
|
|
387
|
+
if not fields:
|
|
388
|
+
continue
|
|
389
|
+
|
|
390
|
+
current_content = target_path.read_text(encoding="utf-8")
|
|
391
|
+
updated_content = apply_translations_to_template(current_content, fields)
|
|
392
|
+
if updated_content != current_content:
|
|
393
|
+
target_path.write_text(updated_content, encoding="utf-8")
|
|
394
|
+
updated_count += 1
|
|
395
|
+
|
|
396
|
+
return updated_count
|
|
397
|
+
|
|
398
|
+
|
|
351
399
|
def should_update_commands(codexspec_dir: Path) -> bool:
|
|
352
400
|
"""Check if commands need updating (subdirectory already exists).
|
|
353
401
|
|
|
@@ -290,6 +290,24 @@ def _resolve_language(config_file: Path, primary_key: str) -> str:
|
|
|
290
290
|
return "en"
|
|
291
291
|
|
|
292
292
|
|
|
293
|
+
def get_explicit_language_key(config_file: Optional[Path], key: str) -> Optional[str]:
|
|
294
|
+
"""Return one explicitly configured ``language.<key>`` value, if present.
|
|
295
|
+
|
|
296
|
+
This differs from the public language-resolution helpers because it never
|
|
297
|
+
falls back to ``language.output`` or ``"en"``.
|
|
298
|
+
"""
|
|
299
|
+
path = config_file or _default_config_path()
|
|
300
|
+
if not path.exists():
|
|
301
|
+
return None
|
|
302
|
+
try:
|
|
303
|
+
value = _read_language_key(path.read_text(encoding="utf-8"), key)
|
|
304
|
+
if value:
|
|
305
|
+
return normalize_locale(value) or None
|
|
306
|
+
except (OSError, re.error):
|
|
307
|
+
pass
|
|
308
|
+
return None
|
|
309
|
+
|
|
310
|
+
|
|
293
311
|
def _default_config_path() -> Path:
|
|
294
312
|
return Path.cwd() / ".codexspec" / "config.yml"
|
|
295
313
|
|
|
@@ -7,8 +7,6 @@ frontmatter fields (description, argument-hint).
|
|
|
7
7
|
import json
|
|
8
8
|
import logging
|
|
9
9
|
import re
|
|
10
|
-
import shutil
|
|
11
|
-
import subprocess
|
|
12
10
|
from pathlib import Path
|
|
13
11
|
from typing import Optional
|
|
14
12
|
|
|
@@ -336,87 +334,56 @@ def apply_translations_to_template(content: str, translations: dict) -> str:
|
|
|
336
334
|
Returns:
|
|
337
335
|
Template content with translated frontmatter
|
|
338
336
|
"""
|
|
337
|
+
frontmatter_match = re.match(r"^(---\n)(.*?)(\n---(?:\n|$))", content, re.DOTALL)
|
|
338
|
+
if not frontmatter_match:
|
|
339
|
+
return content
|
|
340
|
+
|
|
341
|
+
prefix, frontmatter, suffix = frontmatter_match.groups()
|
|
342
|
+
|
|
339
343
|
# Replace description
|
|
340
344
|
if "description" in translations:
|
|
341
|
-
|
|
345
|
+
frontmatter = re.sub(
|
|
346
|
+
r"^(description:\s*).+$",
|
|
347
|
+
lambda match: f"{match.group(1)}{translations['description']}",
|
|
348
|
+
frontmatter,
|
|
349
|
+
flags=re.MULTILINE,
|
|
350
|
+
)
|
|
342
351
|
|
|
343
352
|
# Replace argument-hint (handle both single-line and multiline)
|
|
344
353
|
if "argument-hint" in translations:
|
|
345
354
|
new_hint = translations["argument-hint"]
|
|
346
355
|
# Check if original hint is multiline (uses |)
|
|
347
|
-
if re.search(r"^argument-hint:\s*\|",
|
|
356
|
+
if re.search(r"^argument-hint:\s*\|", frontmatter, re.MULTILINE):
|
|
348
357
|
# Build new multiline content with proper indentation
|
|
349
358
|
# Only add indentation to non-empty lines
|
|
350
359
|
hint_lines = new_hint.split("\n")
|
|
351
360
|
indented_lines = [(" " + line) if line else "" for line in hint_lines]
|
|
352
361
|
indented_hint = "\n".join(indented_lines)
|
|
353
362
|
# Replace multiline hint - match the entire multiline block (supports empty lines)
|
|
354
|
-
|
|
363
|
+
frontmatter = re.sub(
|
|
355
364
|
r"(argument-hint:\s*\|)\s*\n((?: .+\n?|\s*\n)+)",
|
|
356
|
-
|
|
357
|
-
|
|
365
|
+
lambda match: f"{match.group(1)}\n{indented_hint}\n",
|
|
366
|
+
frontmatter,
|
|
358
367
|
flags=re.MULTILINE,
|
|
359
368
|
)
|
|
360
369
|
else:
|
|
361
370
|
# Replace single-line hint (with or without quotes)
|
|
362
|
-
if re.search(r'^argument-hint:\s*"',
|
|
363
|
-
|
|
371
|
+
if re.search(r'^argument-hint:\s*"', frontmatter, re.MULTILINE):
|
|
372
|
+
frontmatter = re.sub(
|
|
373
|
+
r'^(argument-hint:\s*)"[^"]+"$',
|
|
374
|
+
lambda match: f'{match.group(1)}"{new_hint}"',
|
|
375
|
+
frontmatter,
|
|
376
|
+
flags=re.MULTILINE,
|
|
377
|
+
)
|
|
364
378
|
else:
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
"""Check if Claude CLI is available.
|
|
372
|
-
|
|
373
|
-
Returns:
|
|
374
|
-
True if claude command is available
|
|
375
|
-
"""
|
|
376
|
-
return shutil.which("claude") is not None
|
|
379
|
+
frontmatter = re.sub(
|
|
380
|
+
r"^(argument-hint:\s*).+$",
|
|
381
|
+
lambda match: f"{match.group(1)}{new_hint}",
|
|
382
|
+
frontmatter,
|
|
383
|
+
flags=re.MULTILINE,
|
|
384
|
+
)
|
|
377
385
|
|
|
378
|
-
|
|
379
|
-
def translate_with_claude_cli(
|
|
380
|
-
texts: dict[str, dict[str, str]], target_lang: str, timeout: int = 60
|
|
381
|
-
) -> Optional[dict[str, dict[str, str]]]:
|
|
382
|
-
"""Translate texts using Claude CLI.
|
|
383
|
-
|
|
384
|
-
Args:
|
|
385
|
-
texts: Dictionary of {command_name: {field: text}}
|
|
386
|
-
target_lang: Target language code
|
|
387
|
-
timeout: Timeout in seconds
|
|
388
|
-
|
|
389
|
-
Returns:
|
|
390
|
-
Translated dictionary or None on failure
|
|
391
|
-
"""
|
|
392
|
-
if not check_claude_cli_available():
|
|
393
|
-
return None
|
|
394
|
-
|
|
395
|
-
# Build prompt
|
|
396
|
-
input_json = json.dumps(texts, ensure_ascii=False, indent=2)
|
|
397
|
-
prompt = f"""Translate the following JSON values to {target_lang}.
|
|
398
|
-
Keep all keys unchanged. Return only valid JSON with the same structure.
|
|
399
|
-
Do not translate technical terms like "spec.md", "plan.md", "TDD", etc.
|
|
400
|
-
|
|
401
|
-
{input_json}"""
|
|
402
|
-
|
|
403
|
-
try:
|
|
404
|
-
result = subprocess.run(["claude", "--print", prompt], capture_output=True, text=True, timeout=timeout)
|
|
405
|
-
|
|
406
|
-
if result.returncode != 0:
|
|
407
|
-
return None
|
|
408
|
-
|
|
409
|
-
# Parse JSON from output
|
|
410
|
-
output = result.stdout.strip()
|
|
411
|
-
# Remove potential markdown code blocks
|
|
412
|
-
if output.startswith("```"):
|
|
413
|
-
output = re.sub(r"^```(?:json)?\n?", "", output)
|
|
414
|
-
output = re.sub(r"\n?```$", "", output)
|
|
415
|
-
|
|
416
|
-
return json.loads(output)
|
|
417
|
-
|
|
418
|
-
except (subprocess.TimeoutExpired, json.JSONDecodeError, OSError):
|
|
419
|
-
return None
|
|
386
|
+
return f"{prefix}{frontmatter}{suffix}{content[frontmatter_match.end() :]}"
|
|
420
387
|
|
|
421
388
|
|
|
422
389
|
def translate_template_frontmatter(
|
|
@@ -445,13 +412,8 @@ def translate_template_frontmatter(
|
|
|
445
412
|
if cache and template_name in cache:
|
|
446
413
|
return apply_translations_to_template(template_content, cache[template_name])
|
|
447
414
|
|
|
448
|
-
#
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
translations = translate_with_claude_cli({template_name: fields}, target_lang)
|
|
453
|
-
if translations and template_name in translations:
|
|
454
|
-
return apply_translations_to_template(template_content, translations[template_name])
|
|
455
|
-
|
|
456
|
-
# Return original if all translation attempts fail
|
|
415
|
+
# No cache for this language: keep the original (English) frontmatter.
|
|
416
|
+
# Command templates are translated at runtime by Claude reading config.yml
|
|
417
|
+
# (see the template "Language Preference" section), never via a subprocess
|
|
418
|
+
# at install time.
|
|
457
419
|
return template_content
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|