gitversion-rs 0.2.2

Rust port of GitVersion — calculates semantic versions from Git history. Full feature port with a Ratatui TUI.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
_version: 2

# ── 공통/상태 ──────────────────────────────────────────────
status.ready:
  en: Ready
  ko: 준비 완료
  ja: 準備完了
  zh: 就绪
error.generic:
  en: "Error: %{error}"
  ko: "오류: %{error}"
  ja: "エラー: %{error}"
  zh: "错误: %{error}"

# ── main / 계산 ────────────────────────────────────────────
error.git_open:
  en: "Cannot open git repository (run 'git init' and make a commit first)"
  ko: "git 저장소를 열 수 없습니다 (먼저 'git init' 후 커밋이 필요합니다)"
  ja: "gitリポジトリを開けません(先に 'git init' とコミットが必要です)"
  zh: "无法打开 git 仓库(请先执行 'git init' 并提交)"
error.calc_failed:
  en: Version calculation failed
  ko: 버전 계산에 실패했습니다
  ja: バージョン計算に失敗しました
  zh: 版本计算失败
error.dynamic_repo:
  en: Failed to prepare dynamic remote repository
  ko: 동적 원격 저장소 준비에 실패했습니다
  ja: 動的リモートリポジトリの準備に失敗しました
  zh: 准备动态远程仓库失败
error.version_hook_recalc:
  en: Recalculation after applying version hook failed
  ko: version 훅 적용 후 재계산 실패
  ja: versionフック適用後の再計算に失敗しました
  zh: 应用 version 钩子后重新计算失败
error.output_file:
  en: "Failed to create output file: %{path}"
  ko: "출력 파일 생성 실패: %{path}"
  ja: "出力ファイルの作成に失敗: %{path}"
  zh: "创建输出文件失败: %{path}"
log.version_hook_modified:
  en: "version hook modified version to '%{ver}' -> recalculating"
  ko: "version 훅이 버전을 '%{ver}' 로 수정 -> 재계산"
  ja: "versionフックがバージョンを '%{ver}' に変更 -> 再計算"
  zh: "version 钩子将版本修改为 '%{ver}' -> 重新计算"
log.assemblyinfo_updated:
  en: "AssemblyInfo updated: %{path}"
  ko: "AssemblyInfo 갱신: %{path}"
  ja: "AssemblyInfo 更新: %{path}"
  zh: "已更新 AssemblyInfo: %{path}"
log.projectfile_updated:
  en: "Project file updated: %{path}"
  ko: "프로젝트 파일 갱신: %{path}"
  ja: "プロジェクトファイル更新: %{path}"
  zh: "已更新项目文件: %{path}"
log.wix_created:
  en: "Wix version file created: %{path}"
  ko: "Wix 버전 파일 생성: %{path}"
  ja: "Wixバージョンファイル作成: %{path}"
  zh: "已创建 Wix 版本文件: %{path}"
log.package_updated:
  en: "Package manifest updated: %{path}"
  ko: "패키지 매니페스트 갱신: %{path}"
  ja: "パッケージマニフェスト更新: %{path}"
  zh: "已更新包清单: %{path}"
log.agent_detected:
  en: "Detected build agent: %{name}"
  ko: "감지된 빌드에이전트: %{name}"
  ja: "検出されたビルドエージェント: %{name}"
  zh: "检测到构建代理: %{name}"
log.result_written:
  en: "Result written to %{path}"
  ko: "결과를 %{path} 에 기록했습니다"
  ja: "結果を %{path} に書き込みました"
  zh: "结果已写入 %{path}"

# ── git ───────────────────────────────────────────────────
git.repo_not_found:
  en: "Cannot find a git repository: %{path}"
  ko: "git 저장소를 찾을 수 없습니다: %{path}"
  ja: "gitリポジトリが見つかりません: %{path}"
  zh: "找不到 git 仓库: %{path}"
git.head_read:
  en: Cannot read HEAD commit
  ko: HEAD 커밋을 읽을 수 없습니다
  ja: HEADコミットを読めません
  zh: 无法读取 HEAD 提交
git.commit_not_found:
  en: "Commit not found: %{commit}"
  ko: "커밋을 찾을 수 없습니다: %{commit}"
  ja: "コミットが見つかりません: %{commit}"
  zh: "找不到提交: %{commit}"
git.target_commit_not_found:
  en: Target commit not found
  ko: 대상 커밋을 찾을 수 없습니다
  ja: 対象コミットが見つかりません
  zh: 找不到目标提交
git.tag_create_failed:
  en: "Failed to create tag: %{name}"
  ko: "태그 생성 실패: %{name}"
  ja: "タグ作成に失敗: %{name}"
  zh: "创建标签失败: %{name}"
git.branch_create_failed:
  en: "Failed to create branch: %{name}"
  ko: "브랜치 생성 실패: %{name}"
  ja: "ブランチ作成に失敗: %{name}"
  zh: "创建分支失败: %{name}"
git.cache_clear_failed:
  en: "Failed to clear cache: %{path}"
  ko: "캐시 삭제 실패: %{path}"
  ja: "キャッシュ削除に失敗: %{path}"
  zh: "清除缓存失败: %{path}"

# ── exec ──────────────────────────────────────────────────
exec.dry_run:
  en: "[dry-run] skipped: %{cmd}"
  ko: "[dry-run] 실행 생략: %{cmd}"
  ja: "[dry-run] 実行省略: %{cmd}"
  zh: "[dry-run] 跳过执行: %{cmd}"
exec.running:
  en: "Running: %{cmd}"
  ko: "실행: %{cmd}"
  ja: "実行: %{cmd}"
  zh: "执行: %{cmd}"
exec.run_failed:
  en: "Failed to run command: %{cmd}"
  ko: "명령 실행 실패: %{cmd}"
  ja: "コマンド実行に失敗: %{cmd}"
  zh: "运行命令失败: %{cmd}"
exec.cmd_failed:
  en: "Command failed (code %{code}): %{cmd}"
  ko: "명령이 실패했습니다(코드 %{code}): %{cmd}"
  ja: "コマンドが失敗しました(コード %{code}): %{cmd}"
  zh: "命令失败(代码 %{code}): %{cmd}"
exec.hook_failed:
  en: "%{name} hook failed"
  ko: "%{name} 훅 실패"
  ja: "%{name} フック失敗"
  zh: "%{name} 钩子失败"
exec.exec_prepare_failed:
  en: "--exec (prepare) failed"
  ko: "--exec(prepare) 실패"
  ja: "--exec(prepare) 失敗"
  zh: "--exec(prepare) 失败"
exec.running_fail_hook:
  en: "hook failed -> running fail hook"
  ko: "훅 실패 → fail 훅 실행"
  ja: "フック失敗 → fail フック実行"
  zh: "钩子失败 → 运行 fail 钩子"

# ── cache ─────────────────────────────────────────────────
cache.hit:
  en: "Cache hit: %{path}"
  ko: "캐시 적중: %{path}"
  ja: "キャッシュヒット: %{path}"
  zh: "缓存命中: %{path}"
cache.corrupt:
  en: "Cache file corrupted, deleting: %{path}"
  ko: "캐시 파일이 손상되어 삭제합니다: %{path}"
  ja: "キャッシュファイルが破損、削除します: %{path}"
  zh: "缓存文件损坏,删除: %{path}"
cache.write_failed:
  en: "Failed to write cache %{path}: %{error}"
  ko: "캐시 기록 실패 %{path}: %{error}"
  ja: "キャッシュ書き込み失敗 %{path}: %{error}"
  zh: "写入缓存失败 %{path}: %{error}"
cache.serialize_failed:
  en: "Failed to serialize cache: %{error}"
  ko: "캐시 직렬화 실패: %{error}"
  ja: "キャッシュのシリアライズ失敗: %{error}"
  zh: "缓存序列化失败: %{error}"

# ── remote ────────────────────────────────────────────────
remote.branch_required:
  en: "--branch is required when using --url"
  ko: "/url 사용 시 /b(브랜치)가 필요합니다"
  ja: "--url 使用時は --branch が必要です"
  zh: "使用 --url 时需要 --branch"
remote.remove_failed:
  en: "Failed to remove existing clone: %{path}"
  ko: "기존 clone 제거 실패: %{path}"
  ja: "既存cloneの削除に失敗: %{path}"
  zh: "删除已有克隆失败: %{path}"
remote.cloning:
  en: "Cloning remote: %{url} (branch %{branch}) -> %{dest}"
  ko: "원격 저장소 clone: %{url} (브랜치 %{branch}) -> %{dest}"
  ja: "リモートをclone: %{url} (ブランチ %{branch}) -> %{dest}"
  zh: "克隆远程: %{url} (分支 %{branch}) -> %{dest}"
remote.clone_prepare_failed:
  en: "Failed to prepare clone: %{url}"
  ko: "clone 준비 실패: %{url}"
  ja: "cloneの準備に失敗: %{url}"
  zh: "准备克隆失败: %{url}"
remote.set_ref_failed:
  en: Failed to set branch ref
  ko: 브랜치 ref 설정 실패
  ja: ブランチrefの設定に失敗
  zh: 设置分支 ref 失败
remote.fetch_failed:
  en: Remote fetch failed
  ko: 원격 fetch 실패
  ja: リモートfetchに失敗
  zh: 远程 fetch 失败
remote.checkout_failed:
  en: Worktree checkout failed
  ko: 작업 트리 체크아웃 실패
  ja: ワークツリーのチェックアウトに失敗
  zh: 工作树检出失败
remote.open_failed:
  en: Failed to open cloned repository
  ko: clone 된 저장소 열기 실패
  ja: cloneしたリポジトリを開けません
  zh: 打开克隆的仓库失败
remote.head_write_failed:
  en: "Failed to write HEAD: %{path}"
  ko: "HEAD 기록 실패: %{path}"
  ja: "HEADの書き込みに失敗: %{path}"
  zh: "写入 HEAD 失败: %{path}"
remote.head_set:
  en: "Set HEAD to commit %{sha}"
  ko: "HEAD 를 커밋 %{sha} 로 설정"
  ja: "HEADをコミット %{sha} に設定"
  zh: "将 HEAD 设为提交 %{sha}"

# ── config ────────────────────────────────────────────────
config.read_failed:
  en: "Cannot read config file: %{path}"
  ko: "설정 파일을 읽을 수 없습니다: %{path}"
  ja: "設定ファイルを読めません: %{path}"
  zh: "无法读取配置文件: %{path}"
config.yaml_parse_failed:
  en: "Failed to parse config YAML: %{path}"
  ko: "설정 파일 YAML 파싱 실패: %{path}"
  ja: "設定YAMLの解析に失敗: %{path}"
  zh: "解析配置 YAML 失败: %{path}"
config.validate_failed:
  en: "Config validation failed: %{path}"
  ko: "설정 검증 실패: %{path}"
  ja: "設定検証に失敗: %{path}"
  zh: "配置验证失败: %{path}"

# ── file output ───────────────────────────────────────────
file.read_failed:
  en: "Read failed: %{path}"
  ko: "읽기 실패: %{path}"
  ja: "読み込み失敗: %{path}"
  zh: "读取失败: %{path}"
file.xml_update_failed:
  en: "XML update failed: %{path}"
  ko: "XML 갱신 실패: %{path}"
  ja: "XML更新に失敗: %{path}"
  zh: "XML 更新失败: %{path}"
file.xml_parse_error:
  en: "XML parse error: %{error}"
  ko: "XML 파싱 오류: %{error}"
  ja: "XML解析エラー: %{error}"
  zh: "XML 解析错误: %{error}"
file.json_parse_failed:
  en: Failed to parse package.json
  ko: package.json 파싱 실패
  ja: package.json の解析に失敗
  zh: 解析 package.json 失败
file.cargo_parse_failed:
  en: Failed to parse Cargo.toml
  ko: Cargo.toml 파싱 실패
  ja: Cargo.toml の解析に失敗
  zh: 解析 Cargo.toml 失败
file.pyproject_parse_failed:
  en: Failed to parse pyproject.toml
  ko: pyproject.toml 파싱 실패
  ja: pyproject.toml の解析に失敗
  zh: 解析 pyproject.toml 失败

# ── output ────────────────────────────────────────────────
output.unknown_variable:
  en: "Unknown variable '%{name}'. Available: %{known}"
  ko: "알 수 없는 변수 '%{name}'. 사용 가능: %{known}"
  ja: "不明な変数 '%{name}'。利用可能: %{known}"
  zh: "未知变量 '%{name}'。可用: %{known}"
output.unknown_token:
  en: "Unknown variable in format string: %{token}"
  ko: "포맷 문자열에 알 수 없는 변수: %{token}"
  ja: "フォーマット文字列に不明な変数: %{token}"
  zh: "格式字符串中有未知变量: %{token}"

# ── TUI: tabs ─────────────────────────────────────────────
tui.tab.variables: { en: Variables, ko: 변수, ja: 変数, zh: 变量 }
tui.tab.config: { en: Config, ko: 설정, ja: 設定, zh: 配置 }
tui.tab.commits: { en: Commits, ko: 커밋, ja: コミット, zh: 提交 }
tui.tab.branches: { en: Branches, ko: 브랜치, ja: ブランチ, zh: 分支 }
tui.tab.actions: { en: Actions, ko: 액션, ja: アクション, zh: 操作 }

# ── TUI: prompts ──────────────────────────────────────────
tui.prompt.create_tag:
  en: "Create tag on HEAD — enter version (e.g. v1.2.0)"
  ko: "HEAD 에 태그 생성 — 버전 입력(예: v1.2.0)"
  ja: "HEADにタグ作成 — バージョン入力(例: v1.2.0)"
  zh: "在 HEAD 创建标签 — 输入版本(例: v1.2.0)"
tui.prompt.create_branch:
  en: "Create branch on HEAD — enter name"
  ko: "HEAD 에 브랜치 생성 — 이름 입력"
  ja: "HEADにブランチ作成 — 名前入力"
  zh: "在 HEAD 创建分支 — 输入名称"
tui.prompt.set_next_version:
  en: "Set next-version — enter version (e.g. 2.0.0)"
  ko: "next-version 설정 — 버전 입력(예: 2.0.0)"
  ja: "next-version 設定 — バージョン入力(例: 2.0.0)"
  zh: "设置 next-version — 输入版本(例: 2.0.0)"
tui.prompt.dynamic_clone:
  en: "Dynamic clone — enter 'URL branch'"
  ko: "동적 clone — 'URL 브랜치' 입력"
  ja: "動的clone — 'URL ブランチ' 入力"
  zh: "动态克隆 — 输入 'URL 分支'"
tui.prompt.edit_exec_hook:
  en: "Edit exec hook — 'name=command' (name: verify/prepare/publish/success/fail/version, empty command deletes)"
  ko: "exec 훅 편집 — '이름=명령' (이름: verify/prepare/publish/success/fail/version, 빈 명령은 삭제)"
  ja: "exec フック編集 — '名前=コマンド' (名前: verify/prepare/publish/success/fail/version, 空コマンドは削除)"
  zh: "编辑 exec 钩子 — '名称=命令' (名称: verify/prepare/publish/success/fail/version, 空命令则删除)"
tui.prompt.edit_config:
  en: Edit global config
  ko: 전역 설정 편집
  ja: グローバル設定編集
  zh: 编辑全局配置

# ── TUI: hints ────────────────────────────────────────────
tui.hint.increment: { en: None/Major/Minor/Patch/Inherit, ko: None/Major/Minor/Patch/Inherit, ja: None/Major/Minor/Patch/Inherit, zh: None/Major/Minor/Patch/Inherit }
tui.hint.mode: { en: ContinuousDelivery/ContinuousDeployment/ManualDeployment, ko: ContinuousDelivery/ContinuousDeployment/ManualDeployment, ja: ContinuousDelivery/ContinuousDeployment/ManualDeployment, zh: ContinuousDelivery/ContinuousDeployment/ManualDeployment }
tui.hint.semver_format: { en: Strict/Loose, ko: Strict/Loose, ja: Strict/Loose, zh: Strict/Loose }
tui.hint.bool: { en: true/false, ko: true/false, ja: true/false, zh: true/false }
tui.hint.prerelease_label: { en: pre-release label, ko: 프리릴리스 라벨, ja: プレリリースラベル, zh: 预发布标签 }
tui.hint.tag_prefix: { en: "e.g. [vV]?", ko: "예: [vV]?", ja: "例: [vV]?", zh: "例: [vV]?" }
tui.hint.version_example: { en: "e.g. 2.0.0", ko: "예: 2.0.0", ja: "例: 2.0.0", zh: "例: 2.0.0" }
tui.hint.date_example: { en: "e.g. yyyy-MM-dd", ko: "예: yyyy-MM-dd", ja: "例: yyyy-MM-dd", zh: "例: yyyy-MM-dd" }
tui.hint.integer: { en: integer, ko: 정수, ja: 整数, zh: 整数 }
tui.hint.regex: { en: regex, ko: 정규식, ja: 正規表現, zh: 正则表达式 }

# ── TUI: actions ──────────────────────────────────────────
tui.action.create_tag: { en: "Create tag (HEAD)", ko: "태그 생성 (HEAD)", ja: "タグ作成 (HEAD)", zh: "创建标签 (HEAD)" }
tui.action.create_branch: { en: "Create branch (HEAD)", ko: "브랜치 생성 (HEAD)", ja: "ブランチ作成 (HEAD)", zh: "创建分支 (HEAD)" }
tui.action.set_next_version: { en: Set next-version, ko: next-version 설정, ja: next-version 設定, zh: 设置 next-version }
tui.action.edit_exec_hook: { en: Edit exec hook, ko: exec 훅 편집, ja: exec フック編集, zh: 编辑 exec 钩子 }
tui.action.run_exec_hook: { en: "Run exec hooks (prepare etc.)", ko: "exec 훅 실행 (prepare 등)", ja: "exec フック実行 (prepare など)", zh: "运行 exec 钩子 (prepare 等)" }
tui.action.save_config: { en: "Save config (GitVersion.yml)", ko: "설정 저장 (GitVersion.yml)", ja: "設定保存 (GitVersion.yml)", zh: "保存配置 (GitVersion.yml)" }
tui.action.clear_cache: { en: Clear cache, ko: 캐시 삭제, ja: キャッシュ削除, zh: 清除缓存 }
tui.action.dynamic_clone: { en: Dynamic remote clone, ko: 동적 원격 clone, ja: 動的リモートclone, zh: 动态远程克隆 }
tui.action.recompute: { en: Recompute, ko: 재계산, ja: 再計算, zh: 重新计算 }
tui.action.reset_base: { en: Reset to base branch, ko: 기준 브랜치로 초기화, ja: 基準ブランチにリセット, zh: 重置到基准分支 }

# ── TUI: status ───────────────────────────────────────────
tui.status.ready: { en: Ready, ko: 준비 완료, ja: 準備完了, zh: 就绪 }
tui.status.input_cancelled: { en: Input cancelled (empty), ko: 입력 취소(빈 값), ja: 入力取消(空値), zh: 输入取消(空值) }
tui.status.version_hook_applied:
  en: "version hook applied: next-version=%{nv}"
  ko: "version 훅 적용: next-version=%{nv}"
  ja: "version フック適用: next-version=%{nv}"
  zh: "已应用 version 钩子: next-version=%{nv}"
tui.status.recompute_done:
  en: "Recomputed (%{branch})"
  ko: "재계산 완료 (%{branch})"
  ja: "再計算完了 (%{branch})"
  zh: "重新计算完成 (%{branch})"
tui.status.calc_error:
  en: "Calculation error: %{error}"
  ko: "계산 오류: %{error}"
  ja: "計算エラー: %{error}"
  zh: "计算错误: %{error}"
tui.status.copied:
  en: "Copied: %{text}"
  ko: "복사됨: %{text}"
  ja: "コピー: %{text}"
  zh: "已复制: %{text}"
tui.status.clipboard_failed:
  en: "Clipboard failed: %{error}"
  ko: "클립보드 실패: %{error}"
  ja: "クリップボード失敗: %{error}"
  zh: "剪贴板失败: %{error}"
tui.status.tag_created:
  en: "Tag created: %{name}"
  ko: "태그 생성: %{name}"
  ja: "タグ作成: %{name}"
  zh: "创建标签: %{name}"
tui.status.branch_created:
  en: "Branch created: %{name}"
  ko: "브랜치 생성: %{name}"
  ja: "ブランチ作成: %{name}"
  zh: "创建分支: %{name}"
tui.status.next_version_set:
  en: "next-version = %{version}"
  ko: "next-version = %{version}"
  ja: "next-version = %{version}"
  zh: "next-version = %{version}"
tui.status.format_name_cmd:
  en: "Format: name=command"
  ko: "형식: 이름=명령"
  ja: "形式: 名前=コマンド"
  zh: "格式: 名称=命令"
tui.status.hook_unknown_name:
  en: "Unknown hook name: %{name} (verify/prepare/publish/success/fail/version)"
  ko: "알 수 없는 훅 이름: %{name} (verify/prepare/publish/success/fail/version)"
  ja: "不明なフック名: %{name} (verify/prepare/publish/success/fail/version)"
  zh: "未知钩子名称: %{name} (verify/prepare/publish/success/fail/version)"
tui.status.hook_removed:
  en: "exec hook removed: %{name}"
  ko: "exec 훅 삭제: %{name}"
  ja: "exec フック削除: %{name}"
  zh: "删除 exec 钩子: %{name}"
tui.status.hook_set:
  en: "exec hook set: %{name}"
  ko: "exec 훅 설정: %{name}"
  ja: "exec フック設定: %{name}"
  zh: "设置 exec 钩子: %{name}"
tui.status.config_saved_key:
  en: "%{key} = %{value} (saved)"
  ko: "%{key} = %{value} (저장됨)"
  ja: "%{key} = %{value} (保存済み)"
  zh: "%{key} = %{value} (已保存)"
tui.status.url_required: { en: URL is required, ko: URL 이 필요합니다, ja: URLが必要です, zh: 需要 URL }
tui.status.cloning: { en: Cloning..., ko: clone 중..., ja: clone 中..., zh: 克隆中... }
tui.status.clone_done:
  en: "Clone done: %{url}"
  ko: "clone 완료: %{url}"
  ja: "clone 完了: %{url}"
  zh: "克隆完成: %{url}"
tui.status.clone_open_failed:
  en: "Failed to open cloned repo: %{error}"
  ko: "clone 저장소 열기 실패: %{error}"
  ja: "cloneリポジトリを開けません: %{error}"
  zh: "打开克隆仓库失败: %{error}"
tui.status.clone_failed:
  en: "Clone failed: %{error}"
  ko: "clone 실패: %{error}"
  ja: "clone 失敗: %{error}"
  zh: "克隆失败: %{error}"
tui.status.cache_cleared:
  en: "Cache cleared: %{count} files"
  ko: "캐시 삭제: %{count}개 파일"
  ja: "キャッシュ削除: %{count}個のファイル"
  zh: "清除缓存: %{count} 个文件"
tui.status.cache_clear_failed:
  en: "Cache clear failed: %{error}"
  ko: "캐시 삭제 실패: %{error}"
  ja: "キャッシュ削除失敗: %{error}"
  zh: "清除缓存失败: %{error}"
tui.status.reset_base:
  en: "Reset to base branch (%{branch})"
  ko: "기준 브랜치(%{branch})로 초기화"
  ja: "基準ブランチ(%{branch})にリセット"
  zh: "重置到基准分支 (%{branch})"
tui.status.config_saved:
  en: "Config saved: %{path}"
  ko: "설정 저장: %{path}"
  ja: "設定保存: %{path}"
  zh: "配置已保存: %{path}"
tui.status.config_save_failed:
  en: "Config save failed: %{error}"
  ko: "설정 저장 실패: %{error}"
  ja: "設定保存失敗: %{error}"
  zh: "配置保存失败: %{error}"
tui.status.no_exec_hooks:
  en: "No exec hooks configured (add via action 'Edit exec hook')"
  ko: "설정된 exec 훅이 없습니다(액션 'exec 훅 편집'으로 추가)"
  ja: "exec フックが未設定です(アクション 'exec フック編集' で追加)"
  zh: "未配置 exec 钩子(通过操作 '编辑 exec 钩子' 添加)"
tui.status.exec_done: { en: exec hooks done, ko: exec 훅 실행 완료, ja: exec フック実行完了, zh: exec 钩子执行完成 }
tui.status.exec_failed:
  en: "exec hooks failed: %{error}"
  ko: "exec 훅 실패: %{error}"
  ja: "exec フック失敗: %{error}"
  zh: "exec 钩子失败: %{error}"

# ── TUI: panic ────────────────────────────────────────────
tui.panic.unknown: { en: unknown panic, ko: 알 수 없는 패닉, ja: 不明なパニック, zh: 未知 panic }
tui.panic.internal: { en: internal error, ko: 내부 오류, ja: 内部エラー, zh: 内部错误 }
tui.panic.defended:
  en: "Defended internal TUI panic: %{msg}"
  ko: "TUI 내부 패닉을 방어했습니다: %{msg}"
  ja: "TUI内部パニックを防ぎました: %{msg}"
  zh: "已防御 TUI 内部 panic: %{msg}"
tui.panic.exit:
  en: "TUI exited safely due to an internal error: %{msg}"
  ko: "TUI 가 내부 오류로 안전하게 종료되었습니다: %{msg}"
  ja: "TUIが内部エラーで安全に終了しました: %{msg}"
  zh: "TUI 因内部错误已安全退出: %{msg}"

# ── TUI: misc ─────────────────────────────────────────────
tui.exec_run_header: { en: exec hooks run, ko: exec 훅 실행, ja: exec フック実行, zh: 运行 exec 钩子 }
tui.press_enter_return:
  en: "Press [Enter] to return to the TUI..."
  ko: "[Enter] 를 누르면 TUI 로 돌아갑니다..."
  ja: "[Enter] を押すとTUIに戻ります..."
  zh: "按 [Enter] 返回 TUI..."
tui.config_edit_prompt:
  en: "%{key} setting — %{hint}"
  ko: "%{key} 설정 — %{hint}"
  ja: "%{key} 設定 — %{hint}"
  zh: "%{key} 设置 — %{hint}"
tui.header.branch: { en: branch, ko: 브랜치, ja: ブランチ, zh: 分支 }
tui.unset: { en: "(unset)", ko: "(미설정)", ja: "(未設定)", zh: "(未设置)" }
tui.default_paren: { en: "(default)", ko: "(기본)", ja: "(既定)", zh: "(默认)" }
tui.none_paren: { en: "(none)", ko: "(없음)", ja: "(なし)", zh: "(无)" }
tui.col.variable: { en: Variable, ko: 변수, ja: 変数, zh: 变量 }
tui.col.value: { en: Value, ko: , ja: , zh:  }
tui.kv.matched_branch_key: { en: matched branch key, ko: 매칭 브랜치 키, ja: マッチしたブランチキー, zh: 匹配的分支键 }
tui.kv.exec_hooks: { en: exec hooks, ko: exec 훅, ja: exec フック, zh: exec 钩子 }

# ── TUI: titles ───────────────────────────────────────────
tui.title.variables_search:
  en: " Variables  search: %{query}_ "
  ko: " 변수  검색: %{query}_ "
  ja: " 変数  検索: %{query}_ "
  zh: " 变量  搜索: %{query}_ "
tui.title.variables_count:
  en: " Variables (%{count}) "
  ko: " 변수 (%{count}개) "
  ja: " 変数 (%{count}件) "
  zh: " 变量 (%{count}个) "
tui.title.global_config:
  en: "Global config (Enter=edit, saves GitVersion.yml on change)"
  ko: "전역 설정 (Enter=편집, 변경 시 GitVersion.yml 저장)"
  ja: "グローバル設定 (Enter=編集, 変更時 GitVersion.yml 保存)"
  zh: "全局配置 (Enter=编辑, 更改时保存 GitVersion.yml)"
tui.title.effective:
  en: "Effective config — how the above resolves on this branch"
  ko: "유효 설정(effective) — 위 설정이 이 브랜치에 해석된 결과"
  ja: "有効設定(effective) — 上の設定がこのブランチで解決された結果"
  zh: "有效配置(effective) — 上述配置在此分支的解析结果"
tui.title.commits:
  en: " Commits (first-parent, %{count})  ◆=version source "
  ko: " 커밋 (first-parent, %{count}개)  ◆=버전 소스 "
  ja: " コミット (first-parent, %{count}件)  ◆=バージョンソース "
  zh: " 提交 (first-parent, %{count}个)  ◆=版本来源 "
tui.title.branches:
  en: "Branches (Enter=recompute, ●current ○base)"
  ko: "브랜치 (Enter=재계산, ●현재 ○기준)"
  ja: "ブランチ (Enter=再計算, ●現在 ○基準)"
  zh: "分支 (Enter=重新计算, ●当前 ○基准)"
tui.title.actions:
  en: "Actions (Enter=run)"
  ko: "액션 (Enter=실행)"
  ja: "アクション (Enter=実行)"
  zh: "操作 (Enter=运行)"
tui.title.input_modal:
  en: "Input (Enter to confirm, Esc to cancel)"
  ko: "입력 (Enter 확인, Esc 취소)"
  ja: "入力 (Enter 確認, Esc キャンセル)"
  zh: "输入 (Enter 确认, Esc 取消)"

# ── TUI: help footers ─────────────────────────────────────
tui.help.variables:
  en: "[/]search [c]copy value [C]copy JSON [↑↓]move [1-5]tab [q]quit"
  ko: "[/]검색 [c]값복사 [C]JSON복사 [↑↓]이동 [1-5]탭 [q]종료"
  ja: "[/]検索 [c]値コピー [C]JSONコピー [↑↓]移動 [1-5]タブ [q]終了"
  zh: "[/]搜索 [c]复制值 [C]复制JSON [↑↓]移动 [1-5]标签 [q]退出"
tui.help.config:
  en: "[Enter]edit setting(saved) [↑↓]move [1-5]tab [q]quit"
  ko: "[Enter]설정 편집(저장됨) [↑↓]이동 [1-5]탭 [q]종료"
  ja: "[Enter]設定編集(保存済み) [↑↓]移動 [1-5]タブ [q]終了"
  zh: "[Enter]编辑设置(已保存) [↑↓]移动 [1-5]标签 [q]退出"
tui.help.branches:
  en: "[Enter]recompute on branch [↑↓]move [q]quit"
  ko: "[Enter]해당 브랜치로 재계산 [↑↓]이동 [q]종료"
  ja: "[Enter]該当ブランチで再計算 [↑↓]移動 [q]終了"
  zh: "[Enter]在该分支重新计算 [↑↓]移动 [q]退出"
tui.help.actions:
  en: "[Enter]run [↑↓]move [q]quit"
  ko: "[Enter]실행 [↑↓]이동 [q]종료"
  ja: "[Enter]実行 [↑↓]移動 [q]終了"
  zh: "[Enter]运行 [↑↓]移动 [q]退出"
tui.help.default:
  en: "[↑↓]scroll/move [1-5]tab [C]copy JSON [q]quit"
  ko: "[↑↓]스크롤/이동 [1-5]탭 [C]JSON복사 [q]종료"
  ja: "[↑↓]スクロール/移動 [1-5]タブ [C]JSONコピー [q]終了"
  zh: "[↑↓]滚动/移动 [1-5]标签 [C]复制JSON [q]退出"

# ── CLI: about & help (clap, localized_command 가 런타임 주입) ──
cli.about:
  en: Calculate a semantic version from Git history (GitVersion Rust port)
  ko: Git 히스토리로부터 의미론적 버전을 계산합니다 (GitVersion Rust 포트)
  ja: Git履歴からセマンティックバージョンを計算します (GitVersion Rust ポート)
  zh: 从 Git 历史计算语义化版本 (GitVersion Rust 移植版)
cli.help.path:
  en: "Repository path (directory containing `.git`). Defaults to the current directory."
  ko: "저장소 경로(`.git` 포함 디렉터리). 생략 시 현재 디렉터리."
  ja: "リポジトリのパス(`.git` を含むディレクトリ)。省略時は現在のディレクトリ。"
  zh: "仓库路径(包含 `.git` 的目录)。省略时为当前目录。"
cli.help.target_path:
  en: "Same as path but position-independent (upstream `/targetpath`)."
  ko: "path 와 동일하지만 위치 무관(원본 `/targetpath`)."
  ja: "path と同じだが位置非依存(原本 `/targetpath`)。"
  zh: "与 path 相同但与位置无关(原版 `/targetpath`)。"
cli.help.nofetch:
  en: "Disable fetch (no-op: this port does not fetch)."
  ko: "fetch 비활성화(무효과: 본 포트는 fetch 하지 않음)."
  ja: "fetch を無効化(無効果: 本ポートは fetch しない)。"
  zh: "禁用 fetch(无效果:本移植不执行 fetch)。"
cli.help.nonormalize:
  en: "Disable normalization (no-op)."
  ko: "정규화 비활성화(무효과)."
  ja: "正規化を無効化(無効果)。"
  zh: "禁用规范化(无效果)。"
cli.help.nocache:
  en: "Disable disk cache read/write (`<.git>/gitversion_cache`)."
  ko: "디스크 캐시 읽기·쓰기 비활성화(`<.git>/gitversion_cache`)."
  ja: "ディスクキャッシュの読み書きを無効化(`<.git>/gitversion_cache`)。"
  zh: "禁用磁盘缓存读写(`<.git>/gitversion_cache`)。"
cli.help.allowshallow:
  en: "Allow shallow clone (no-op: gix reads shallow repos too)."
  ko: "shallow clone 허용(무효과: gix 가 shallow 도 읽음)."
  ja: "shallow clone を許可(無効果: gix は shallow も読む)。"
  zh: "允许 shallow clone(无效果:gix 也能读取 shallow)。"
cli.help.output:
  en: "Output format (json, dot-env, build-server). May be repeated."
  ko: "출력 형식(json, dot-env, build-server). 여러 번 지정 가능."
  ja: "出力形式(json, dot-env, build-server)。複数指定可。"
  zh: "输出格式(json, dot-env, build-server)。可重复指定。"
cli.help.output_file:
  en: "Output file path (writes the result to a file when set)."
  ko: "출력 파일 경로(지정 시 결과를 파일로 기록)."
  ja: "出力ファイルのパス(指定時は結果をファイルに書き込む)。"
  zh: "输出文件路径(设置时将结果写入文件)。"
cli.help.show_variable:
  en: "Print a single variable only (e.g. -v SemVer)."
  ko: "단일 변수만 출력(예: -v SemVer)."
  ja: "単一の変数のみ出力(例: -v SemVer)。"
  zh: "仅输出单个变量(例: -v SemVer)。"
cli.help.format:
  en: 'Print using a format string (e.g. --format "{Major}.{Minor}").'
  ko: '포맷 문자열로 출력(예: --format "{Major}.{Minor}").'
  ja: 'フォーマット文字列で出力(例: --format "{Major}.{Minor}")。'
  zh: '使用格式字符串输出(例: --format "{Major}.{Minor}")。'
cli.help.config:
  en: Config file path.
  ko: 설정 파일 경로.
  ja: 設定ファイルのパス。
  zh: 配置文件路径。
cli.help.show_config:
  en: Print the effective config as YAML and exit.
  ko: 유효 설정을 YAML 로 출력하고 종료.
  ja: 有効な設定を YAML で出力して終了。
  zh: 以 YAML 输出有效配置并退出。
cli.help.override_config:
  en: "Inline config override (key=value). May be repeated."
  ko: "인라인 설정 오버라이드(key=value). 여러 번 지정 가능."
  ja: "インライン設定オーバーライド(key=value)。複数指定可。"
  zh: "内联配置覆盖(key=value)。可重复指定。"
cli.help.branch:
  en: "Branch to compute for (instead of the current checkout)."
  ko: "계산 대상 브랜치명(현재 체크아웃 대신)."
  ja: "計算対象のブランチ名(現在のチェックアウトの代わり)。"
  zh: "用于计算的分支(替代当前检出)。"
cli.help.lang:
  en: "Output language (ko/en/ja/zh). Falls back to LANG/LC_ALL when omitted."
  ko: "출력 언어(ko/en/ja/zh). 생략 시 LANG/LC_ALL 환경변수 사용."
  ja: "出力言語(ko/en/ja/zh)。省略時は LANG/LC_ALL 環境変数を使用。"
  zh: "输出语言(ko/en/ja/zh)。省略时使用 LANG/LC_ALL 环境变量。"
cli.help.verbosity:
  en: Log verbosity.
  ko: 로그 상세도.
  ja: ログの詳細度。
  zh: 日志详细程度。
cli.help.diag:
  en: "Diagnostic mode (Trace logging)."
  ko: "진단 모드(Trace 로깅)."
  ja: "診断モード(Trace ロギング)。"
  zh: "诊断模式(Trace 日志)。"
cli.help.update_assembly_info:
  en: "Update AssemblyInfo files (recursive search when no file is given)."
  ko: "AssemblyInfo 파일 갱신(파일명 생략 시 재귀 탐색)."
  ja: "AssemblyInfo ファイルを更新(ファイル名省略時は再帰探索)。"
  zh: "更新 AssemblyInfo 文件(未指定文件时递归搜索)。"
cli.help.ensure_assembly_info:
  en: "Create the AssemblyInfo file if missing (with updateassemblyinfo)."
  ko: "AssemblyInfo 파일이 없으면 생성(updateassemblyinfo 와 함께)."
  ja: "AssemblyInfo ファイルが無ければ作成(updateassemblyinfo と併用)。"
  zh: "若 AssemblyInfo 文件不存在则创建(与 updateassemblyinfo 一起)。"
cli.help.update_project_files:
  en: "Update version elements in project files (.csproj etc.; recursive when no file is given)."
  ko: "프로젝트 파일(.csproj 등) 버전 요소 갱신(파일명 생략 시 재귀 탐색)."
  ja: "プロジェクトファイル(.csproj 等)のバージョン要素を更新(ファイル名省略時は再帰探索)。"
  zh: "更新项目文件(.csproj 等)中的版本元素(未指定文件时递归搜索)。"
cli.help.update_wix_version_file:
  en: Create GitVersion_WixVersion.wxi.
  ko: GitVersion_WixVersion.wxi 생성.
  ja: GitVersion_WixVersion.wxi を作成。
  zh: 创建 GitVersion_WixVersion.wxi。
cli.help.update_package_files:
  en: "Update the version in package manifests (package.json/Cargo.toml/pyproject.toml). Recursive search when no file is given."
  ko: "패키지 매니페스트의 version 갱신(package.json/Cargo.toml/pyproject.toml). 파일명 생략 시 재귀 탐색."
  ja: "パッケージマニフェスト(package.json/Cargo.toml/pyproject.toml)の version を更新。ファイル名省略時は再帰探索。"
  zh: "更新包清单(package.json/Cargo.toml/pyproject.toml)中的 version。未指定文件时递归搜索。"
cli.help.url:
  en: "Remote git repository URL (clone then compute when set). Requires `--branch`."
  ko: "원격 git 저장소 URL(지정 시 clone 후 계산). `--branch` 필수."
  ja: "リモート git リポジトリ URL(指定時は clone 後に計算)。`--branch` 必須。"
  zh: "远程 git 仓库 URL(设置时先 clone 再计算)。需要 `--branch`。"
cli.help.username:
  en: "Remote auth username (with `--url`)."
  ko: "원격 인증 사용자명(`--url` 과 함께)."
  ja: "リモート認証のユーザー名(`--url` と併用)。"
  zh: "远程认证用户名(与 `--url` 一起)。"
cli.help.password:
  en: "Remote auth password (with `--url`)."
  ko: "원격 인증 비밀번호(`--url` 과 함께)."
  ja: "リモート認証のパスワード(`--url` と併用)。"
  zh: "远程认证密码(与 `--url` 一起)。"
cli.help.commit:
  en: "Commit ID to inspect (latest on the branch when omitted). With `--url`."
  ko: "확인할 커밋 ID(생략 시 브랜치 최신). `--url` 과 함께."
  ja: "確認するコミット ID(省略時はブランチ最新)。`--url` と併用。"
  zh: "要检查的提交 ID(省略时为分支最新)。与 `--url` 一起。"
cli.help.dynamic_repo_location:
  en: "Dynamic clone location (default: a temp directory)."
  ko: "동적 clone 위치(기본: 임시 디렉터리)."
  ja: "動的 clone の場所(既定: 一時ディレクトリ)。"
  zh: "动态 clone 位置(默认:临时目录)。"
cli.help.exec:
  en: "prepare command to run after computing (version variables exposed as GitVersion_* env and {Var})."
  ko: "계산 후 실행할 prepare 명령(버전 변수가 GitVersion_* 환경변수와 {Var} 로 노출)."
  ja: "計算後に実行する prepare コマンド(バージョン変数を GitVersion_* 環境変数と {Var} で公開)。"
  zh: "计算后运行的 prepare 命令(版本变量以 GitVersion_* 环境变量和 {Var} 暴露)。"
cli.help.exec_version:
  en: "Version-modifying command. Its stdout is applied as next-version and recomputed."
  ko: "버전 수정 명령. 표준출력을 next-version 으로 적용해 재계산한다."
  ja: "バージョン修正コマンド。標準出力を next-version として適用し再計算する。"
  zh: "版本修改命令。其标准输出作为 next-version 应用并重新计算。"
cli.help.dry_run:
  en: Print exec hooks without actually running them.
  ko: exec 훅을 실제 실행하지 않고 출력만 한다.
  ja: exec フックを実際に実行せず出力のみ行う。
  zh: 仅输出 exec 钩子而不实际执行。
cli.help.tui:
  en: Launch the interactive Ratatui TUI.
  ko: 대화형 Ratatui TUI 실행.
  ja: 対話型 Ratatui TUI を起動。
  zh: 启动交互式 Ratatui TUI。
cli.help.help:
  en: Print help
  ko: 도움말 출력
  ja: ヘルプを表示
  zh: 显示帮助
cli.help.version:
  en: Print version
  ko: 버전 출력
  ja: バージョンを表示
  zh: 显示版本
cli.override_invalid:
  en: "Invalid overrideconfig entry (ignored): %{entry}"
  ko: "잘못된 overrideconfig 항목(무시): %{entry}"
  ja: "不正な overrideconfig 項目(無視): %{entry}"
  zh: "无效的 overrideconfig 条目(已忽略): %{entry}"
cli.override_unsupported:
  en: "Unsupported overrideconfig key (ignored): %{key}"
  ko: "지원하지 않는 overrideconfig 키(무시): %{key}"
  ja: "サポートされない overrideconfig キー(無視): %{key}"
  zh: "不支持的 overrideconfig 键(已忽略): %{key}"
cli.help.log_file:
  en: "Write log output to a file (upstream `/l`). Logs append; stdout stays clean."
  ko: "로그 출력을 파일에 기록(원본 `/l`). 로그는 추가되며 stdout 은 깨끗하게 유지."
  ja: "ログ出力をファイルに書き込む(原本 `/l`)。ログは追記され、stdout はクリーンなまま。"
  zh: "将日志输出写入文件(原版 `/l`)。日志为追加,stdout 保持干净。"
error.log_open:
  en: "Cannot open log file: %{path}"
  ko: "로그 파일을 열 수 없습니다: %{path}"
  ja: "ログファイルを開けません: %{path}"
  zh: "无法打开日志文件: %{path}"