Skip to content

Commit b1f85f0

Browse files
author
Joongheon Park
committed
feat: enhance CLI and scaffold templates with language support
- Added language options for scaffolded projects, allowing users to specify language for documentation (English/Korean). - Updated CLI options to include language selection for both acts and casts. - Introduced language normalization and selection functions to streamline user experience. - Enhanced README and template files to reflect new language features and usage instructions. - Removed outdated README files and improved structure for clarity and maintainability.
1 parent 9df5ec0 commit b1f85f0

15 files changed

Lines changed: 359 additions & 249 deletions

File tree

act_operator/act_operator/cli.py

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@
3939
None,
4040
"--cast-name",
4141
"-c",
42-
help="Display name of the initial Cast",
42+
help="Display name of the initial Cast Graph",
43+
)
44+
LANG_OPTION = typer.Option(
45+
None,
46+
"--lang",
47+
"-l",
48+
help="Language for scaffolded docs (en|kr)",
4349
)
4450

4551
CAST_ACT_PATH_OPTION = typer.Option(
@@ -58,6 +64,12 @@
5864
"-c",
5965
help="Display name of the Cast to add",
6066
)
67+
NEW_CAST_LANG_OPTION = typer.Option(
68+
"en",
69+
"--lang",
70+
"-l",
71+
help="Language for scaffolded cast docs (en|kr)",
72+
)
6173

6274

6375
def _resolve_path(path_option: Path | None) -> tuple[Path, bool]:
@@ -83,11 +95,54 @@ def _resolve_name(prompt_message: str, value: str | None) -> str:
8395
console.print("[red]A value is required.[/red]")
8496

8597

98+
def _normalize_lang(value: str | None) -> str:
99+
if not value:
100+
return "en"
101+
val = value.strip().lower()
102+
if val in ("en", "kr"):
103+
return val
104+
console.print("[red]Unsupported language: '{val}'. Please use 'en' or 'kr'.[/red]")
105+
raise typer.Exit(code=1)
106+
107+
108+
def _select_language_menu() -> str:
109+
console.print(
110+
"🌐 Choose template language - This option sets the language for the entire scaffolded template content.\n"
111+
"1. English (EN)\n"
112+
"2. 한국어 (KR)"
113+
)
114+
options = {1: "en", 2: "kr"}
115+
while True:
116+
choice: int = typer.prompt(
117+
"Enter the number of your language choice (default is 1)",
118+
default=1,
119+
type=int,
120+
)
121+
if choice in options:
122+
return options[choice]
123+
console.print("[red]❌ Invalid choice. Please try again.[/red]")
124+
125+
126+
def _resolve_language(language: str | None) -> str:
127+
if language in ("en", "kr"):
128+
if language == "en":
129+
return "English"
130+
elif language == "kr":
131+
return "한국어"
132+
if language is None or not language.strip():
133+
return _select_language_menu()
134+
console.print(
135+
f"[red]Unsupported language: '{language}'. Please use 'en' or 'kr'.[/red]"
136+
)
137+
raise typer.Exit(code=1)
138+
139+
86140
def _generate_project(
87141
*,
88142
path: Path | None,
89143
act_name: str | None,
90144
cast_name: str | None,
145+
language: str | None,
91146
) -> None:
92147
target_dir, path_was_custom = _resolve_path(path)
93148

@@ -104,6 +159,7 @@ def _generate_project(
104159

105160
act_raw = _resolve_name("🚀 Please enter a name for the new Act", act_name)
106161
cast_raw = _resolve_name("🌟 Please enter a name for the first Cast", cast_name)
162+
lang = _resolve_language(language)
107163

108164
try:
109165
act = build_name_variants(act_raw)
@@ -133,6 +189,7 @@ def _generate_project(
133189
# 캐스트 디렉터리는 snake_case 사용
134190
"cast_slug": cast.slug,
135191
"cast_snake": cast.snake,
192+
"language": lang,
136193
}
137194

138195
try:
@@ -170,14 +227,15 @@ def _generate_project(
170227
table = Table(show_header=False)
171228
table.add_row("Act", act.title)
172229
table.add_row("Cast", cast.title)
230+
table.add_row("Language", lang)
173231
table.add_row("Location", str(target_dir))
174232
console.print(table)
175233
console.print("[bold green]Act project created successfully![/bold green]")
176234
try:
177-
casts_dir = target_dir / "casts"
178-
if casts_dir.exists():
179-
entries = ", ".join(sorted(p.name for p in casts_dir.iterdir()))
180-
console.print(f"[dim]casts dir entries: {entries}[/dim]")
235+
act_dir = target_dir
236+
if act_dir.exists():
237+
entries = ", ".join(sorted(p.name for p in act_dir.iterdir()))
238+
console.print(f"[dim]act project entries: {entries}[/dim]")
181239
except Exception:
182240
pass
183241

@@ -188,11 +246,12 @@ def root( # type: ignore[override]
188246
path: Path | None = PATH_OPTION,
189247
act_name: str | None = ACT_NAME_OPTION,
190248
cast_name: str | None = CAST_NAME_OPTION,
249+
lang: str | None = LANG_OPTION,
191250
) -> None:
192-
ctx.obj = {"path": path, "act_name": act_name, "cast_name": cast_name}
251+
ctx.obj = {"path": path, "act_name": act_name, "cast_name": cast_name, "lang": lang}
193252
if ctx.invoked_subcommand is not None:
194253
return
195-
_generate_project(path=path, act_name=act_name, cast_name=cast_name)
254+
_generate_project(path=path, act_name=act_name, cast_name=cast_name, language=lang)
196255

197256

198257
@app.command("new")
@@ -201,12 +260,14 @@ def new_command(
201260
path: Path | None = PATH_OPTION,
202261
act_name: str | None = ACT_NAME_OPTION,
203262
cast_name: str | None = CAST_NAME_OPTION,
263+
lang: str | None = LANG_OPTION,
204264
) -> None:
205265
parent = ctx.parent.obj if ctx.parent and ctx.parent.obj else {}
206266
path = path or parent.get("path")
207267
act_name = act_name or parent.get("act_name")
208268
cast_name = cast_name or parent.get("cast_name")
209-
_generate_project(path=path, act_name=act_name, cast_name=cast_name)
269+
lang = lang or parent.get("lang")
270+
_generate_project(path=path, act_name=act_name, cast_name=cast_name, language=lang)
210271

211272

212273
def _ensure_act_project(act_path: Path) -> None:
@@ -229,6 +290,7 @@ def _generate_cast_project(
229290
*,
230291
act_path: Path,
231292
cast_name: str,
293+
language: str,
232294
) -> None:
233295
act_variants = build_name_variants(act_path.name)
234296
casts_dir = act_path / "casts"
@@ -255,7 +317,7 @@ def _generate_cast_project(
255317
"act_snake": act_variants.snake,
256318
"cast_name": cast_variants.title,
257319
"cast_snake": cast_variants.snake,
258-
"cast_snake": cast_variants.snake,
320+
"language": _normalize_lang(language),
259321
},
260322
)
261323

@@ -284,12 +346,13 @@ def _generate_cast_project(
284346
def cast_command(
285347
act_path: Path = CAST_ACT_PATH_OPTION,
286348
cast_name: str | None = NEW_CAST_NAME_OPTION,
349+
lang: str = NEW_CAST_LANG_OPTION,
287350
) -> None:
288351
act_path = act_path.resolve()
289352
_ensure_act_project(act_path)
290353

291354
cast_raw = _resolve_name("🌟 Please enter a name for the new Cast", cast_name)
292-
_generate_cast_project(act_path=act_path, cast_name=cast_raw)
355+
_generate_cast_project(act_path=act_path, cast_name=cast_raw, language=lang)
293356

294357

295358
def main() -> None:

act_operator/act_operator/scaffold/cookiecutter.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
"act_snake": "act_name",
66
"cast_name": "Cast Name",
77
"cast_slug": "cast-name",
8-
"cast_snake": "cast_name"
8+
"cast_snake": "cast_name",
9+
"language": "en"
910
}

act_operator/act_operator/scaffold/{{ cookiecutter.project_dir }}/README.md

Lines changed: 0 additions & 117 deletions
This file was deleted.

0 commit comments

Comments
 (0)