refactor(i18n): use grammar engine for progress messages
- Replace cli.progress.* keys with i18n.P() dynamic generation
- Remove 7 static progress keys from en_GB.json (building, checking, etc.)
- Add additional core.* intents (format, analyse, link, unlink, fetch, etc.)
- Add grammar helpers: Progress(), ProgressSubject(), ActionResult(), Label()
- Add package-level convenience functions: P(), PS(), L()
- Update commands to use common.prompt.abort instead of cli.confirm.abort
The grammar engine now generates progress messages dynamically:
i18n.P("check") → "Checking..."
i18n.P("fetch") → "Fetching..."
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f85064a954
commit
fc74d4df9c
9 changed files with 259 additions and 29 deletions
|
|
@ -30,7 +30,7 @@ func runCIReleaseInit() error {
|
|||
response, _ := reader.ReadString('\n')
|
||||
response = strings.TrimSpace(strings.ToLower(response))
|
||||
if response != "y" && response != "yes" {
|
||||
fmt.Println(i18n.T("cli.confirm.abort"))
|
||||
fmt.Println(i18n.T("common.prompt.abort"))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ func runCI(registryPath string, branch string, failedOnly bool) error {
|
|||
repoList := reg.List()
|
||||
for i, repo := range repoList {
|
||||
repoFullName := fmt.Sprintf("%s/%s", reg.Org, repo.Name)
|
||||
fmt.Printf("\033[2K\r%s %d/%d %s", dimStyle.Render(i18n.T("cli.progress.checking")), i+1, len(repoList), repo.Name)
|
||||
fmt.Printf("\033[2K\r%s %d/%d %s", dimStyle.Render(i18n.P("check")), i+1, len(repoList), repo.Name)
|
||||
|
||||
runs, err := fetchWorkflowRuns(repoFullName, repo.Name, branch)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ func runIssues(registryPath string, limit int, assignee string) error {
|
|||
repoList := reg.List()
|
||||
for i, repo := range repoList {
|
||||
repoFullName := fmt.Sprintf("%s/%s", reg.Org, repo.Name)
|
||||
fmt.Printf("\033[2K\r%s %d/%d %s", dimStyle.Render(i18n.T("cli.progress.fetching")), i+1, len(repoList), repo.Name)
|
||||
fmt.Printf("\033[2K\r%s %d/%d %s", dimStyle.Render(i18n.P("fetch")), i+1, len(repoList), repo.Name)
|
||||
|
||||
issues, err := fetchIssues(repoFullName, repo.Name, limit, assignee)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ func runReviews(registryPath string, author string, showAll bool) error {
|
|||
repoList := reg.List()
|
||||
for i, repo := range repoList {
|
||||
repoFullName := fmt.Sprintf("%s/%s", reg.Org, repo.Name)
|
||||
fmt.Printf("\033[2K\r%s %d/%d %s", dimStyle.Render(i18n.T("cli.progress.fetching")), i+1, len(repoList), repo.Name)
|
||||
fmt.Printf("\033[2K\r%s %d/%d %s", dimStyle.Render(i18n.P("fetch")), i+1, len(repoList), repo.Name)
|
||||
|
||||
prs, err := fetchPRs(repoFullName, repo.Name, author)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ func runDocsSync(registryPath string, outputDir string, dryRun bool) error {
|
|||
// Confirm
|
||||
fmt.Println()
|
||||
if !confirm(i18n.T("cmd.docs.sync.confirm")) {
|
||||
fmt.Println(i18n.T("cli.confirm.abort"))
|
||||
fmt.Println(i18n.T("common.prompt.abort"))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -492,14 +492,82 @@ func Quote(s string) string {
|
|||
// tmpl := template.New("").Funcs(i18n.TemplateFuncs())
|
||||
func TemplateFuncs() template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"title": Title,
|
||||
"lower": strings.ToLower,
|
||||
"upper": strings.ToUpper,
|
||||
"past": PastTense,
|
||||
"gerund": Gerund,
|
||||
"plural": Pluralize,
|
||||
"title": Title,
|
||||
"lower": strings.ToLower,
|
||||
"upper": strings.ToUpper,
|
||||
"past": PastTense,
|
||||
"gerund": Gerund,
|
||||
"plural": Pluralize,
|
||||
"pluralForm": PluralForm,
|
||||
"article": Article,
|
||||
"quote": Quote,
|
||||
"article": Article,
|
||||
"quote": Quote,
|
||||
}
|
||||
}
|
||||
|
||||
// Progress returns a progress message for a verb.
|
||||
// Generates "Verbing..." form.
|
||||
//
|
||||
// Progress("build") // "Building..."
|
||||
// Progress("check") // "Checking..."
|
||||
// Progress("fetch") // "Fetching..."
|
||||
func Progress(verb string) string {
|
||||
g := Gerund(verb)
|
||||
if g == "" {
|
||||
return ""
|
||||
}
|
||||
return Title(g) + "..."
|
||||
}
|
||||
|
||||
// ProgressSubject returns a progress message with a subject.
|
||||
// Generates "Verbing subject..." form.
|
||||
//
|
||||
// ProgressSubject("build", "project") // "Building project..."
|
||||
// ProgressSubject("check", "config.yaml") // "Checking config.yaml..."
|
||||
func ProgressSubject(verb, subject string) string {
|
||||
g := Gerund(verb)
|
||||
if g == "" {
|
||||
return ""
|
||||
}
|
||||
return Title(g) + " " + subject + "..."
|
||||
}
|
||||
|
||||
// ActionResult returns a result message for a completed action.
|
||||
// Generates "Subject verbed" form.
|
||||
//
|
||||
// ActionResult("delete", "file") // "File deleted"
|
||||
// ActionResult("commit", "changes") // "Changes committed"
|
||||
func ActionResult(verb, subject string) string {
|
||||
p := PastTense(verb)
|
||||
if p == "" || subject == "" {
|
||||
return ""
|
||||
}
|
||||
return Title(subject) + " " + p
|
||||
}
|
||||
|
||||
// ActionFailed returns a failure message for an action.
|
||||
// Generates "Failed to verb subject" form.
|
||||
//
|
||||
// ActionFailed("delete", "file") // "Failed to delete file"
|
||||
// ActionFailed("push", "commits") // "Failed to push commits"
|
||||
func ActionFailed(verb, subject string) string {
|
||||
if verb == "" {
|
||||
return ""
|
||||
}
|
||||
if subject == "" {
|
||||
return "Failed to " + verb
|
||||
}
|
||||
return "Failed to " + verb + " " + subject
|
||||
}
|
||||
|
||||
// Label returns a label with a colon suffix.
|
||||
// Generates "Word:" form with title case.
|
||||
//
|
||||
// Label("status") // "Status:"
|
||||
// Label("version") // "Version:"
|
||||
// Label("app url") // "App Url:"
|
||||
func Label(word string) string {
|
||||
if word == "" {
|
||||
return ""
|
||||
}
|
||||
return Title(word) + ":"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,6 +270,35 @@ func C(intent string, subject *Subject) *Composed {
|
|||
}
|
||||
}
|
||||
|
||||
// --- Grammar convenience functions (package-level) ---
|
||||
// These provide direct access to grammar functions without needing a service instance.
|
||||
|
||||
// P returns a progress message for a verb: "Building...", "Checking..."
|
||||
// Use this instead of T("cli.progress.building") for dynamic progress messages.
|
||||
//
|
||||
// P("build") // "Building..."
|
||||
// P("fetch") // "Fetching..."
|
||||
func P(verb string) string {
|
||||
return Progress(verb)
|
||||
}
|
||||
|
||||
// PS returns a progress message with a subject: "Building project...", "Checking config..."
|
||||
//
|
||||
// PS("build", "project") // "Building project..."
|
||||
// PS("check", "config.yaml") // "Checking config.yaml..."
|
||||
func PS(verb, subject string) string {
|
||||
return ProgressSubject(verb, subject)
|
||||
}
|
||||
|
||||
// L returns a label with colon: "Status:", "Version:"
|
||||
// Use this instead of T("common.label.status") for simple labels.
|
||||
//
|
||||
// L("status") // "Status:"
|
||||
// L("version") // "Version:"
|
||||
func L(word string) string {
|
||||
return Label(word)
|
||||
}
|
||||
|
||||
// _ is the standard gettext-style translation helper.
|
||||
// Alias for T() - use whichever you prefer.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -429,6 +429,140 @@ var coreIntents = map[string]Intent{
|
|||
Success: "Confirmed",
|
||||
Failure: "Cancelled",
|
||||
},
|
||||
|
||||
// --- Additional Actions ---
|
||||
|
||||
"core.sync": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "sync",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Sync {{.Subject}}?",
|
||||
Confirm: "Sync {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} synced",
|
||||
Failure: "Failed to sync {{.Subject}}",
|
||||
},
|
||||
|
||||
"core.boot": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "boot",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Boot {{.Subject}}?",
|
||||
Confirm: "Boot {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} booted",
|
||||
Failure: "Failed to boot {{.Subject}}",
|
||||
},
|
||||
|
||||
"core.format": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "format",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Format {{.Subject}}?",
|
||||
Confirm: "Format {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} formatted",
|
||||
Failure: "Failed to format {{.Subject}}",
|
||||
},
|
||||
|
||||
"core.analyse": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "analyse",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Analyse {{.Subject}}?",
|
||||
Confirm: "Analyse {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} analysed",
|
||||
Failure: "Failed to analyse {{.Subject}}",
|
||||
},
|
||||
|
||||
"core.link": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "link",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Link {{.Subject}}?",
|
||||
Confirm: "Link {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} linked",
|
||||
Failure: "Failed to link {{.Subject}}",
|
||||
},
|
||||
|
||||
"core.unlink": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "unlink",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Unlink {{.Subject}}?",
|
||||
Confirm: "Unlink {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} unlinked",
|
||||
Failure: "Failed to unlink {{.Subject}}",
|
||||
},
|
||||
|
||||
"core.fetch": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "fetch",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Fetch {{.Subject}}?",
|
||||
Confirm: "Fetch {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} fetched",
|
||||
Failure: "Failed to fetch {{.Subject}}",
|
||||
},
|
||||
|
||||
"core.generate": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "generate",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Generate {{.Subject}}?",
|
||||
Confirm: "Generate {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} generated",
|
||||
Failure: "Failed to generate {{.Subject}}",
|
||||
},
|
||||
|
||||
"core.validate": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "validate",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Validate {{.Subject}}?",
|
||||
Confirm: "Validate {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} valid",
|
||||
Failure: "{{.Subject | title}} invalid",
|
||||
},
|
||||
|
||||
"core.check": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "check",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Check {{.Subject}}?",
|
||||
Confirm: "Check {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} OK",
|
||||
Failure: "{{.Subject | title}} failed",
|
||||
},
|
||||
|
||||
"core.scan": {
|
||||
Meta: IntentMeta{
|
||||
Type: "action",
|
||||
Verb: "scan",
|
||||
Default: "yes",
|
||||
},
|
||||
Question: "Scan {{.Subject}}?",
|
||||
Confirm: "Scan {{.Subject}}?",
|
||||
Success: "{{.Subject | title}} scanned",
|
||||
Failure: "Failed to scan {{.Subject}}",
|
||||
},
|
||||
}
|
||||
|
||||
// getIntent retrieves an intent by its key from the core intents.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,20 @@
|
|||
{
|
||||
"common": {
|
||||
"prompt": {
|
||||
"yes": "y",
|
||||
"no": "n",
|
||||
"yes_full": "yes",
|
||||
"no_full": "no",
|
||||
"abort": "Operation aborted",
|
||||
"cancel": "Cancelled",
|
||||
"continue": "Continue?",
|
||||
"proceed": "Proceed?",
|
||||
"confirm": "Are you sure?",
|
||||
"overwrite": "Overwrite?",
|
||||
"delete": "Delete?",
|
||||
"save": "Save?",
|
||||
"discard": "Discard changes?"
|
||||
},
|
||||
"label": {
|
||||
"error": "Error:",
|
||||
"done": "Done:",
|
||||
|
|
@ -87,13 +102,6 @@
|
|||
"aborted": "Aborted",
|
||||
"cancelled": "Cancelled",
|
||||
"completed": "Completed",
|
||||
"confirm": {
|
||||
"abort": "Operation aborted",
|
||||
"continue": "Continue?",
|
||||
"no": "No",
|
||||
"proceed": "Proceed?",
|
||||
"yes": "Yes"
|
||||
},
|
||||
"count": {
|
||||
"commits": {
|
||||
"one": "{{.Count}} commit",
|
||||
|
|
@ -116,15 +124,6 @@
|
|||
"ok": "OK",
|
||||
"pass": "PASS",
|
||||
"pending": "Pending",
|
||||
"progress": {
|
||||
"building": "Building",
|
||||
"checking": "Checking",
|
||||
"deploying": "Deploying",
|
||||
"fetching": "Fetching",
|
||||
"loading": "Loading",
|
||||
"processing": "Processing",
|
||||
"testing": "Testing"
|
||||
},
|
||||
"skip": "Skipped",
|
||||
"success": "Success",
|
||||
"time": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue