From 47cc2c2888eb031f9b0133a4e7c515be08abad74 Mon Sep 17 00:00:00 2001 From: laurencewannamaker Date: Mon, 6 Jul 2026 06:24:42 +0000 Subject: [PATCH 1/2] =?UTF-8?q?feat(i18n):=2010=20=E4=B8=AA=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E7=BB=84=E6=8E=A5=E5=85=A5=20i18n=20=E5=85=A8?= =?UTF-8?q?=E8=A6=86=E7=9B=96=EF=BC=88145=20=E4=B8=AA=E4=B8=AD=E8=8B=B1?= =?UTF-8?q?=E9=94=AE=EF=BC=9Amilestone/label/member/wiki/pipeline/compare/?= =?UTF-8?q?license/ignore/workflow/health=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- internal/i18n/locales/en-US.json | 145 ++++++++++++++++++++++++++++++ internal/i18n/locales/zh-CN.json | 145 ++++++++++++++++++++++++++++++ shortcuts/compare/compare.go | 29 +++--- shortcuts/health/health.go | 14 ++- shortcuts/ignore/ignore.go | 15 +++- shortcuts/label/label.go | 43 +++++---- shortcuts/license/license.go | 15 +++- shortcuts/member/member.go | 49 +++++----- shortcuts/milestone/milestone.go | 77 +++++++++------- shortcuts/pipeline/pipeline.go | 89 +++++++++--------- shortcuts/register.go | 18 ++-- shortcuts/wiki/wiki.go | 65 ++++++++------ shortcuts/workflow/pr_summary.go | 19 ++-- shortcuts/workflow/repo_report.go | 21 ++--- shortcuts/workflow/workflow.go | 91 ++++++++++--------- 15 files changed, 608 insertions(+), 227 deletions(-) diff --git a/internal/i18n/locales/en-US.json b/internal/i18n/locales/en-US.json index 0739395..3fd3354 100644 --- a/internal/i18n/locales/en-US.json +++ b/internal/i18n/locales/en-US.json @@ -16,6 +16,8 @@ "cmd.ci.restart.short": "Restart a build", "cmd.ci.short": "CI/CD operations", "cmd.ci.stop.short": "Stop a build", + "cmd.compare.files.short": "List changed files between two refs", + "cmd.compare.view.short": "Compare two branches, tags, or commits", "cmd.config.get.short": "Get a configuration value", "cmd.config.init.short": "Initialize configuration file", "cmd.config.list.short": "List all configuration values", @@ -34,6 +36,8 @@ "cmd.dataset.view.short": "View a repository's dataset", "cmd.doctor.long": "Run local diagnostics for gitlink-cli configuration, authentication, repository context and API connectivity.", "cmd.doctor.short": "Diagnose gitlink-cli environment problems", + "cmd.health.fetch.short": "Fetch PR and Issue data into SQLite for health analysis", + "cmd.ignore.list.short": "List available ignore-file templates", "cmd.issue.batch_close.long": "Close filtered issues in bulk.\n\nThis command defaults to dry-run mode and only prints matching issues.\nPass --yes to execute remote close operations. Use restrictive filters and a small limit.\n\nExamples:\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20 --yes", "cmd.issue.batch_close.short": "Close filtered issues in bulk. Defaults to dry-run; pass --yes to execute.", "cmd.issue.batch_label.long": "Add a label to filtered issues in bulk.\n\nThis command defaults to dry-run mode and only prints matching issues.\nPass --yes to execute remote label operations. The current implementation does not fake label writes when the API endpoint is unavailable.\n\nExamples:\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50 --yes", @@ -47,11 +51,41 @@ "cmd.issue.short": "Issue operations", "cmd.issue.update.short": "Update an issue", "cmd.issue.view.short": "View issue details", + "cmd.label.create.short": "Create an issue label", + "cmd.label.delete.short": "Delete an issue label", + "cmd.label.list.short": "List issue labels", + "cmd.label.update.short": "Update an issue label while preserving unspecified fields", + "cmd.license.list.short": "List available licenses", + "cmd.member.accept-invite.short": "Accept a repository invite link", + "cmd.member.add.short": "Add a repository member by user ID", + "cmd.member.batch-add.short": "Add multiple repository members by user IDs or a CSV file", + "cmd.member.invite-info.short": "Show repository invite link information", + "cmd.member.invite-link.short": "Get or create a repository invite link", + "cmd.member.list.short": "List repository members", + "cmd.member.remove.short": "Remove a repository member by user ID", + "cmd.member.role.short": "Change a repository member role", + "cmd.milestone.close.short": "Close a milestone", + "cmd.milestone.create.short": "Create a milestone", + "cmd.milestone.delete.short": "Delete a milestone", + "cmd.milestone.list.short": "List milestones", + "cmd.milestone.reopen.short": "Reopen a milestone", + "cmd.milestone.update.short": "Update a milestone", + "cmd.milestone.view.short": "View milestone details and linked issues", "cmd.org.create.short": "Create an organization", "cmd.org.info.short": "Show organization details", "cmd.org.list.short": "List organizations", "cmd.org.members.short": "List organization members", "cmd.org.short": "Organization operations", + "cmd.pipeline.delete.short": "Delete a pipeline", + "cmd.pipeline.disable.short": "Disable a pipeline workflow", + "cmd.pipeline.enable.short": "Enable a pipeline workflow", + "cmd.pipeline.list.short": "List platform pipelines", + "cmd.pipeline.logs.short": "Query pipeline run logs", + "cmd.pipeline.results.short": "Show pipeline run report results", + "cmd.pipeline.run.short": "Run a pipeline workflow", + "cmd.pipeline.runs.short": "List pipeline run records", + "cmd.pipeline.save-yaml.short": "Save a visual pipeline YAML graph", + "cmd.pipeline.view.short": "Show pipeline details", "cmd.pr.close.short": "Close a pull request", "cmd.pr.comment.short": "Add a comment to a pull request", "cmd.pr.create.short": "Create a pull request", @@ -105,6 +139,15 @@ "cmd.webhook.test.short": "Trigger a test delivery for a webhook", "cmd.webhook.update.short": "Update a repository webhook while preserving unspecified fields when available", "cmd.webhook.view.short": "View webhook details", + "cmd.wiki.create.short": "Create a new wiki page", + "cmd.wiki.delete.short": "Delete a wiki page", + "cmd.wiki.list.short": "List wiki pages", + "cmd.wiki.update.short": "Update an existing wiki page", + "cmd.wiki.view.short": "View a wiki page by page name", + "cmd.workflow.health.short": "Score repository health with local workflow rules", + "cmd.workflow.pr-summary.short": "Generate a read-only pull request review summary", + "cmd.workflow.repo-report.short": "Generate a read-only repository workflow report", + "cmd.workflow.triage.short": "Analyze issues with local workflow triage rules", "error.auth.delete_token_failed": "failed to delete token: {message}", "error.auth.login_failed": "login failed: {message}", "error.auth.store_token_failed": "failed to store token: {message}", @@ -130,6 +173,9 @@ "flag.ci.stage": "Stage number", "flag.ci.step": "Step number", "flag.comment.body": "Comment body", + "flag.compare.base": "Target branch, tag, or commit", + "flag.compare.file": "Filter by file path", + "flag.compare.head": "Source branch, tag, or commit", "flag.dataset.description": "Dataset description", "flag.dataset.dry_run": "Preview the request without writing the dataset", "flag.dataset.dry_run_delete": "Preview the request without deleting the attachment", @@ -146,6 +192,9 @@ "flag.doctor.skip_network": "Skip authenticated API connectivity checks", "flag.dry_run": "Preview the request without creating it", "flag.format": "Output format: json, table, yaml (default: table)", + "flag.health.db": "SQLite database path (default: ~/.agents/skills/gitlink-health/data/gitlink_health.db)", + "flag.health.max_pages": "Maximum pages per query (default: unlimited)", + "flag.ignore.name": "Filter ignore templates by name", "flag.issue.add_label": "Label to add to each matching issue", "flag.issue.assignee": "Assignee login", "flag.issue.assignee_id": "Assignee user ID", @@ -171,13 +220,57 @@ "flag.issue.status_id": "Issue status ID", "flag.issue.tag_ids": "Comma-separated issue tag IDs", "flag.issue.title": "Issue title", + "flag.label.color": "Label color in hex, for example: #1E90FF", + "flag.label.description": "Label description", + "flag.label.id": "Label ID", + "flag.label.keyword": "Filter labels by keyword", + "flag.label.name": "Label name", + "flag.label.only_name": "Return only label id and name: true or false", + "flag.label.sort_by": "Sort field: updated_on, created_on, issues_count", + "flag.label.sort_direction": "Sort direction: asc or desc", "flag.lang": "Display language", + "flag.license.name": "Filter licenses by name", "flag.limit": "Items per page", + "flag.member.apply": "Whether joining by invite requires approval: true or false", + "flag.member.dry_run": "Preview members that would be added without changing them", + "flag.member.from": "Read user IDs from a CSV file. Supports a user_id/id column or first column without header", + "flag.member.role": "Member role: Manager, Developer, or Reporter", + "flag.member.role_2": "Invite role: manager, developer, or reporter", + "flag.member.sign": "Invite link sign", + "flag.member.user_id": "GitLink user ID to add", + "flag.member.user_id_2": "GitLink user ID to update", + "flag.member.user_ids": "Comma-separated GitLink user IDs, for example: 101,102", + "flag.milestone.assigner_id": "Filter issues by assignee ID", + "flag.milestone.author_id": "Filter issues by author ID", + "flag.milestone.category": "Filter by category: opening, closed", + "flag.milestone.category_2": "Filter issues by category: all, opened, closed", + "flag.milestone.description": "Milestone description", + "flag.milestone.due_date": "Due date in YYYY-MM-DD format", + "flag.milestone.id": "Milestone ID", + "flag.milestone.issue_tag_ids": "Comma-separated issue tag IDs", + "flag.milestone.name": "Milestone name", + "flag.milestone.only_name": "Return only milestone id and name: true or false", + "flag.milestone.sort_by": "Sort field: created_on, updated_on, effective_date, issues_count, percent", + "flag.milestone.sort_by_2": "Sort field: issues.created_on, issues.updated_on, issue_priorities.position", + "flag.milestone.sort_direction": "Sort direction: asc or desc", "flag.org.id": "Organization ID", "flag.org.id_or_login": "Organization ID or login", "flag.org.name": "Organization name", "flag.owner": "Repository owner (auto-detected from git remote)", "flag.page": "Page number", + "flag.pipeline.cursor": "Log cursor", + "flag.pipeline.dry_run": "Preview the run request without starting a pipeline", + "flag.pipeline.dry_run_2": "Preview the request without changing pipeline state", + "flag.pipeline.expanded": "Whether the log cursor is expanded", + "flag.pipeline.id": "Pipeline ID", + "flag.pipeline.index": "Run index", + "flag.pipeline.job": "Job index", + "flag.pipeline.owner_id": "Owner user or organization ID", + "flag.pipeline.pipeline_json": "Pipeline graph JSON object or string", + "flag.pipeline.ref": "Branch, tag, or commit SHA", + "flag.pipeline.run_id": "Pipeline run ID", + "flag.pipeline.step": "Log step", + "flag.pipeline.workflow": "Workflow file name", "flag.pr.assignee_id": "Assignee user ID", "flag.pr.base": "Target branch", "flag.pr.body": "PR description", @@ -229,6 +322,58 @@ "flag.webhook.secret_update": "Webhook secret. Pass it again if the server does not return existing secrets.", "flag.webhook.type": "Webhook type: gitea/slack/discord/dingtalk/telegram/msteams/feishu/matrix/jianmu/softbot", "flag.webhook.url": "Webhook target URL", + "flag.wiki.content": "Wiki page content (markdown)", + "flag.wiki.gateway": "Use gateway API endpoint", + "flag.wiki.message": "Commit message", + "flag.wiki.page_name": "Wiki page name (slug)", + "flag.wiki.project_id": "GitLink project ID", + "flag.wiki.title": "Wiki page title", + "flag.workflow.agent_readiness_known": "Whether agent readiness score is known", + "flag.workflow.agent_readiness_score": "Agent readiness score from 0 to 10", + "flag.workflow.author": "Issue author for single-issue local analysis", + "flag.workflow.body": "Issue body for single-issue local analysis", + "flag.workflow.ci_known": "Whether CI status is known", + "flag.workflow.ci_passing": "Whether CI is passing", + "flag.workflow.dry_run": "Preview workflow recommendations without remote writes", + "flag.workflow.from": "Read issue inputs from a JSON file. Supports a single issue, an array, or an object with an issues field", + "flag.workflow.from_2": "Read health input from a JSON file", + "flag.workflow.has_contributing": "Whether CONTRIBUTING exists", + "flag.workflow.has_license": "Whether LICENSE exists", + "flag.workflow.has_readme": "Whether README exists", + "flag.workflow.has_recent_release": "Whether a recent release exists", + "flag.workflow.labels": "Comma-separated labels for single-issue local analysis", + "flag.workflow.lang": "Output language: en or zh-CN", + "flag.workflow.limit": "Maximum issues to analyze", + "flag.workflow.number": "Issue number for single-issue local analysis", + "flag.workflow.open_issues": "Open issue count", + "flag.workflow.open_prs": "Open pull request count", + "flag.workflow.page": "API page number for remote triage", + "flag.workflow.pr_summary.from": "Read PR summary input from a JSON file", + "flag.workflow.pr_summary.include_commits": "Fetch commits in remote mode", + "flag.workflow.pr_summary.include_files": "Fetch changed files in remote mode", + "flag.workflow.pr_summary.lang": "Output language: en or zh-CN", + "flag.workflow.pr_summary.max_commits": "Maximum commits to analyze", + "flag.workflow.pr_summary.max_files": "Maximum changed files to analyze", + "flag.workflow.pr_summary.number": "Pull request number for remote read-only analysis", + "flag.workflow.recent_activity_days": "Days since recent activity", + "flag.workflow.recent_activity_known": "Whether recent activity is known", + "flag.workflow.release_known": "Whether release status is known", + "flag.workflow.repo_report.from": "Read repository report input from a JSON file", + "flag.workflow.repo_report.include_health": "Include repository health summary", + "flag.workflow.repo_report.include_issues": "Include issue triage summary", + "flag.workflow.repo_report.include_prs": "Include pull request summary", + "flag.workflow.repo_report.issue_limit": "Maximum issues to fetch and analyze", + "flag.workflow.repo_report.lang": "Output language: en or zh-CN", + "flag.workflow.repo_report.pr_limit": "Maximum pull requests to fetch and summarize", + "flag.workflow.repo_report.stale_days": "Days before an issue or PR is considered stale", + "flag.workflow.repository": "Repository name, for example owner/repo", + "flag.workflow.since": "Optional remote issue filter for updated time", + "flag.workflow.stale_days": "Days before an issue or PR is considered stale", + "flag.workflow.stale_issues": "Stale issue count", + "flag.workflow.stale_prs": "Stale pull request count", + "flag.workflow.state": "Filter or assign issue state", + "flag.workflow.title": "Issue title for single-issue local analysis", + "flag.workflow.url": "Issue URL for single-issue local analysis", "output.auth.env_hint": " Or set {env} environment variable", "output.auth.login_hint": " Run: gitlink-cli auth login", "output.config.file": "Config file: {path}", diff --git a/internal/i18n/locales/zh-CN.json b/internal/i18n/locales/zh-CN.json index 2e6fc4d..0e0e9ba 100644 --- a/internal/i18n/locales/zh-CN.json +++ b/internal/i18n/locales/zh-CN.json @@ -16,6 +16,8 @@ "cmd.ci.restart.short": "重启构建", "cmd.ci.short": "CI/CD 操作", "cmd.ci.stop.short": "停止构建", + "cmd.compare.files.short": "列出两个引用之间变更的文件", + "cmd.compare.view.short": "比较两个分支、标签或提交", "cmd.config.get.short": "获取配置项", "cmd.config.init.short": "初始化配置文件", "cmd.config.list.short": "列出所有配置项", @@ -34,6 +36,8 @@ "cmd.dataset.view.short": "查看仓库数据集", "cmd.doctor.long": "诊断 gitlink-cli 的配置、认证、仓库上下文和 API 连通性问题。", "cmd.doctor.short": "诊断 gitlink-cli 环境问题", + "cmd.health.fetch.short": "抓取 PR 与 Issue 数据到 SQLite 用于健康度分析", + "cmd.ignore.list.short": "列出可用的 ignore 文件模板", "cmd.issue.batch_close.long": "批量关闭筛选后的议题。\n\n该命令默认处于 dry-run 模式,只打印匹配的议题。\n传入 --yes 后执行远端关闭操作。请使用严格筛选条件和较小 limit。\n\n示例:\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20 --yes", "cmd.issue.batch_close.short": "批量关闭筛选后的议题。默认 dry-run;传入 --yes 后执行。", "cmd.issue.batch_label.long": "给筛选后的议题批量添加标签。\n\n该命令默认处于 dry-run 模式,只打印匹配的议题。\n传入 --yes 后执行远端标签操作。当前实现不会在 API 端点不可用时伪造写入结果。\n\n示例:\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50 --yes", @@ -47,11 +51,41 @@ "cmd.issue.short": "议题操作", "cmd.issue.update.short": "更新议题", "cmd.issue.view.short": "查看议题详情", + "cmd.label.create.short": "创建 issue 标签", + "cmd.label.delete.short": "删除 issue 标签", + "cmd.label.list.short": "列出 issue 标签", + "cmd.label.update.short": "更新 issue 标签(未指定字段保持不变)", + "cmd.license.list.short": "列出可用的开源许可证", + "cmd.member.accept-invite.short": "接受仓库邀请链接", + "cmd.member.add.short": "按用户 ID 添加仓库成员", + "cmd.member.batch-add.short": "按用户 ID 列表或 CSV 文件批量添加仓库成员", + "cmd.member.invite-info.short": "查看仓库邀请链接信息", + "cmd.member.invite-link.short": "获取或创建仓库邀请链接", + "cmd.member.list.short": "列出仓库成员", + "cmd.member.remove.short": "按用户 ID 移除仓库成员", + "cmd.member.role.short": "变更仓库成员角色", + "cmd.milestone.close.short": "关闭里程碑", + "cmd.milestone.create.short": "创建里程碑", + "cmd.milestone.delete.short": "删除里程碑", + "cmd.milestone.list.short": "列出里程碑", + "cmd.milestone.reopen.short": "重新打开里程碑", + "cmd.milestone.update.short": "更新里程碑", + "cmd.milestone.view.short": "查看里程碑详情及关联 issue", "cmd.org.create.short": "创建组织", "cmd.org.info.short": "显示组织详情", "cmd.org.list.short": "列出组织", "cmd.org.members.short": "列出组织成员", "cmd.org.short": "组织操作", + "cmd.pipeline.delete.short": "删除流水线", + "cmd.pipeline.disable.short": "停用流水线工作流", + "cmd.pipeline.enable.short": "启用流水线工作流", + "cmd.pipeline.list.short": "列出平台流水线", + "cmd.pipeline.logs.short": "查询流水线运行日志", + "cmd.pipeline.results.short": "查看流水线运行报告结果", + "cmd.pipeline.run.short": "运行流水线工作流", + "cmd.pipeline.runs.short": "列出流水线运行记录", + "cmd.pipeline.save-yaml.short": "保存可视化流水线 YAML 图", + "cmd.pipeline.view.short": "查看流水线详情", "cmd.pr.close.short": "关闭拉取请求", "cmd.pr.comment.short": "给拉取请求添加评论", "cmd.pr.create.short": "创建拉取请求", @@ -105,6 +139,15 @@ "cmd.webhook.test.short": "触发 Webhook 测试投递", "cmd.webhook.update.short": "更新仓库 Webhook,并在可用时保留未指定字段", "cmd.webhook.view.short": "查看 Webhook 详情", + "cmd.wiki.create.short": "创建 wiki 页面", + "cmd.wiki.delete.short": "删除 wiki 页面", + "cmd.wiki.list.short": "列出 wiki 页面", + "cmd.wiki.update.short": "更新已有 wiki 页面", + "cmd.wiki.view.short": "按页面名查看 wiki 页面", + "cmd.workflow.health.short": "用本地工作流规则为仓库健康度打分", + "cmd.workflow.pr-summary.short": "生成只读的 PR 评审摘要", + "cmd.workflow.repo-report.short": "生成只读的仓库工作流报告", + "cmd.workflow.triage.short": "用本地工作流分诊规则分析 issue", "error.auth.delete_token_failed": "删除 Token 失败:{message}", "error.auth.login_failed": "登录失败:{message}", "error.auth.store_token_failed": "保存 Token 失败:{message}", @@ -130,6 +173,9 @@ "flag.ci.stage": "阶段编号", "flag.ci.step": "步骤编号", "flag.comment.body": "评论内容", + "flag.compare.base": "目标分支、标签或提交", + "flag.compare.file": "按文件路径过滤", + "flag.compare.head": "源分支、标签或提交", "flag.dataset.description": "数据集描述", "flag.dataset.dry_run": "预览请求,不写入数据集", "flag.dataset.dry_run_delete": "预览请求,不删除附件", @@ -146,6 +192,9 @@ "flag.doctor.skip_network": "跳过需要访问 GitLink 的认证连通性检查", "flag.dry_run": "预览请求,不实际创建", "flag.format": "输出格式:json、table、yaml(默认:table)", + "flag.health.db": "SQLite 数据库路径(默认:~/.agents/skills/gitlink-health/data/gitlink_health.db)", + "flag.health.max_pages": "每次查询的最大页数(默认:不限)", + "flag.ignore.name": "按名称过滤 ignore 模板", "flag.issue.add_label": "要添加到每个匹配议题的标签", "flag.issue.assignee": "负责人登录名", "flag.issue.assignee_id": "负责人用户 ID", @@ -171,13 +220,57 @@ "flag.issue.status_id": "议题状态 ID", "flag.issue.tag_ids": "逗号分隔的议题标签 ID", "flag.issue.title": "议题标题", + "flag.label.color": "标签颜色(十六进制),例如:#1E90FF", + "flag.label.description": "标签描述", + "flag.label.id": "标签 ID", + "flag.label.keyword": "按关键词过滤标签", + "flag.label.name": "标签名称", + "flag.label.only_name": "仅返回标签 id 和名称:true 或 false", + "flag.label.sort_by": "排序字段:updated_on、created_on、issues_count", + "flag.label.sort_direction": "排序方向:asc 或 desc", "flag.lang": "显示语言", + "flag.license.name": "按名称过滤许可证", "flag.limit": "每页条目数", + "flag.member.apply": "通过邀请加入是否需要审批:true 或 false", + "flag.member.dry_run": "仅预览将添加的成员,不实际变更", + "flag.member.from": "从 CSV 文件读取用户 ID。支持 user_id/id 列或无表头的第一列", + "flag.member.role": "成员角色:Manager、Developer 或 Reporter", + "flag.member.role_2": "邀请角色:manager、developer 或 reporter", + "flag.member.sign": "邀请链接签名", + "flag.member.user_id": "要添加的 GitLink 用户 ID", + "flag.member.user_id_2": "要更新的 GitLink 用户 ID", + "flag.member.user_ids": "逗号分隔的 GitLink 用户 ID,例如:101,102", + "flag.milestone.assigner_id": "按负责人 ID 过滤 issue", + "flag.milestone.author_id": "按作者 ID 过滤 issue", + "flag.milestone.category": "按类别过滤:opening、closed", + "flag.milestone.category_2": "按类别过滤 issue:all、opened、closed", + "flag.milestone.description": "里程碑描述", + "flag.milestone.due_date": "截止日期(YYYY-MM-DD 格式)", + "flag.milestone.id": "里程碑 ID", + "flag.milestone.issue_tag_ids": "逗号分隔的 issue 标签 ID", + "flag.milestone.name": "里程碑名称", + "flag.milestone.only_name": "仅返回里程碑 id 和名称:true 或 false", + "flag.milestone.sort_by": "排序字段:created_on、updated_on、effective_date、issues_count、percent", + "flag.milestone.sort_by_2": "排序字段:issues.created_on、issues.updated_on、issue_priorities.position", + "flag.milestone.sort_direction": "排序方向:asc 或 desc", "flag.org.id": "组织 ID", "flag.org.id_or_login": "组织 ID 或登录名", "flag.org.name": "组织名称", "flag.owner": "仓库所有者(自动从 git remote 检测)", "flag.page": "页码", + "flag.pipeline.cursor": "日志游标", + "flag.pipeline.dry_run": "仅预览运行请求,不实际启动流水线", + "flag.pipeline.dry_run_2": "仅预览请求,不变更流水线状态", + "flag.pipeline.expanded": "日志游标是否展开", + "flag.pipeline.id": "流水线 ID", + "flag.pipeline.index": "运行序号", + "flag.pipeline.job": "任务序号", + "flag.pipeline.owner_id": "所有者用户或组织 ID", + "flag.pipeline.pipeline_json": "流水线图 JSON 对象或字符串", + "flag.pipeline.ref": "分支、标签或提交 SHA", + "flag.pipeline.run_id": "流水线运行 ID", + "flag.pipeline.step": "日志步骤", + "flag.pipeline.workflow": "工作流文件名", "flag.pr.assignee_id": "指派人用户 ID", "flag.pr.base": "目标分支", "flag.pr.body": "PR 描述", @@ -229,6 +322,58 @@ "flag.webhook.secret_update": "Webhook 密钥。如果服务端不返回已有密钥,请再次传入。", "flag.webhook.type": "Webhook 类型:gitea/slack/discord/dingtalk/telegram/msteams/feishu/matrix/jianmu/softbot", "flag.webhook.url": "Webhook 目标 URL", + "flag.wiki.content": "wiki 页面内容(markdown)", + "flag.wiki.gateway": "使用网关 API 端点", + "flag.wiki.message": "提交说明", + "flag.wiki.page_name": "wiki 页面名(slug)", + "flag.wiki.project_id": "GitLink 项目 ID", + "flag.wiki.title": "wiki 页面标题", + "flag.workflow.agent_readiness_known": "Agent 就绪度得分是否已知", + "flag.workflow.agent_readiness_score": "Agent 就绪度得分(0 到 10)", + "flag.workflow.author": "单 issue 本地分析的 issue 作者", + "flag.workflow.body": "单 issue 本地分析的 issue 正文", + "flag.workflow.ci_known": "CI 状态是否已知", + "flag.workflow.ci_passing": "CI 是否通过", + "flag.workflow.dry_run": "仅预览工作流建议,不做远程写入", + "flag.workflow.from": "从 JSON 文件读取 issue 输入。支持单个 issue、数组或含 issues 字段的对象", + "flag.workflow.from_2": "从 JSON 文件读取健康度输入", + "flag.workflow.has_contributing": "是否存在 CONTRIBUTING", + "flag.workflow.has_license": "是否存在 LICENSE", + "flag.workflow.has_readme": "是否存在 README", + "flag.workflow.has_recent_release": "是否有近期 release", + "flag.workflow.labels": "单 issue 本地分析的逗号分隔标签", + "flag.workflow.lang": "输出语言:en 或 zh-CN", + "flag.workflow.limit": "分析的最大 issue 数", + "flag.workflow.number": "单 issue 本地分析的 issue 编号", + "flag.workflow.open_issues": "打开的 issue 数", + "flag.workflow.open_prs": "打开的 PR 数", + "flag.workflow.page": "远程分诊的 API 页码", + "flag.workflow.pr_summary.from": "从 JSON 文件读取 PR 摘要输入", + "flag.workflow.pr_summary.include_commits": "远程模式下抓取提交", + "flag.workflow.pr_summary.include_files": "远程模式下抓取变更文件", + "flag.workflow.pr_summary.lang": "输出语言:en 或 zh-CN", + "flag.workflow.pr_summary.max_commits": "分析的最大提交数", + "flag.workflow.pr_summary.max_files": "分析的最大变更文件数", + "flag.workflow.pr_summary.number": "远程只读分析的 PR 编号", + "flag.workflow.recent_activity_days": "距最近活动的天数", + "flag.workflow.recent_activity_known": "最近活动是否已知", + "flag.workflow.release_known": "release 状态是否已知", + "flag.workflow.repo_report.from": "从 JSON 文件读取仓库报告输入", + "flag.workflow.repo_report.include_health": "包含仓库健康度摘要", + "flag.workflow.repo_report.include_issues": "包含 issue 分诊摘要", + "flag.workflow.repo_report.include_prs": "包含 PR 摘要", + "flag.workflow.repo_report.issue_limit": "抓取并分析的最大 issue 数", + "flag.workflow.repo_report.lang": "输出语言:en 或 zh-CN", + "flag.workflow.repo_report.pr_limit": "抓取并汇总的最大 PR 数", + "flag.workflow.repo_report.stale_days": "issue 或 PR 视为停滞的天数", + "flag.workflow.repository": "仓库名,例如 owner/repo", + "flag.workflow.since": "可选的远程 issue 更新时间过滤", + "flag.workflow.stale_days": "issue 或 PR 视为停滞的天数", + "flag.workflow.stale_issues": "停滞 issue 数", + "flag.workflow.stale_prs": "停滞 PR 数", + "flag.workflow.state": "过滤或指定 issue 状态", + "flag.workflow.title": "单 issue 本地分析的 issue 标题", + "flag.workflow.url": "单 issue 本地分析的 issue URL", "output.auth.env_hint": " 或设置 {env} 环境变量", "output.auth.login_hint": " 运行:gitlink-cli auth login", "output.config.file": "配置文件:{path}", diff --git a/shortcuts/compare/compare.go b/shortcuts/compare/compare.go index b39937a..5301243 100644 --- a/shortcuts/compare/compare.go +++ b/shortcuts/compare/compare.go @@ -5,17 +5,19 @@ import ( "fmt" "net/url" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "view", - Description: "Compare two branches, tags, or commits", + Description: tr.T("cmd.compare.view.short"), Flags: []common.Flag{ - {Name: "head", Usage: "Source branch, tag, or commit", Required: true}, - {Name: "base", Usage: "Target branch, tag, or commit", Required: true}, + {Name: "head", Usage: tr.T("flag.compare.head"), Required: true}, + {Name: "base", Usage: tr.T("flag.compare.base"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -38,13 +40,13 @@ func Shortcuts() []*common.Shortcut { }, { Name: "files", - Description: "List changed files between two refs", + Description: tr.T("cmd.compare.files.short"), Flags: []common.Flag{ - {Name: "head", Usage: "Source branch, tag, or commit", Required: true}, - {Name: "base", Usage: "Target branch, tag, or commit", Required: true}, - {Name: "file", Short: "f", Usage: "Filter by file path"}, - {Name: "page", Short: "p", Usage: "Page number", Default: "1"}, - {Name: "limit", Short: "l", Usage: "Items per page", Default: "20"}, + {Name: "head", Usage: tr.T("flag.compare.head"), Required: true}, + {Name: "base", Usage: tr.T("flag.compare.base"), Required: true}, + {Name: "file", Short: "f", Usage: tr.T("flag.compare.file")}, + {Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"}, + {Name: "limit", Short: "l", Usage: tr.T("flag.limit"), Default: "20"}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -81,3 +83,10 @@ func comparePath(ctx *common.RuntimeContext, head, base string) string { func encodeRef(ref string) string { return base64.RawURLEncoding.EncodeToString([]byte(ref)) } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/health/health.go b/shortcuts/health/health.go index 04f26d1..6ab9d0e 100644 --- a/shortcuts/health/health.go +++ b/shortcuts/health/health.go @@ -16,13 +16,14 @@ import ( ) func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "fetch", - Description: "Fetch PR and Issue data into SQLite for health analysis", + Description: tr.T("cmd.health.fetch.short"), Flags: []common.Flag{ - {Name: "db", Short: "d", Usage: "SQLite database path (default: ~/.agents/skills/gitlink-health/data/gitlink_health.db)"}, - {Name: "max-pages", Short: "M", Usage: "Maximum pages per query (default: unlimited)"}, + {Name: "db", Short: "d", Usage: tr.T("flag.health.db")}, + {Name: "max-pages", Short: "M", Usage: tr.T("flag.health.max_pages")}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -224,3 +225,10 @@ func fetchIssues(ctx *common.RuntimeContext, db *sql.DB, repoID int, state strin } return nil } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/ignore/ignore.go b/shortcuts/ignore/ignore.go index 9f5e406..ccb44cd 100644 --- a/shortcuts/ignore/ignore.go +++ b/shortcuts/ignore/ignore.go @@ -3,6 +3,7 @@ package ignore import ( "net/url" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) @@ -10,13 +11,14 @@ import ( // // These shortcuts provide access to the GitLink ignore-file registry, // which lists all available .gitignore templates supported by the platform. -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "list", - Description: "List available ignore-file templates", + Description: tr.T("cmd.ignore.list.short"), Flags: []common.Flag{ - {Name: "name", Short: "n", Usage: "Filter ignore templates by name"}, + {Name: "name", Short: "n", Usage: tr.T("flag.ignore.name")}, }, Run: runList, }, @@ -34,3 +36,10 @@ func runList(ctx *common.RuntimeContext) error { } return ctx.Output(env) } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/label/label.go b/shortcuts/label/label.go index 2b6a298..a694c38 100644 --- a/shortcuts/label/label.go +++ b/shortcuts/label/label.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) @@ -22,16 +23,17 @@ var hexColorPattern = regexp.MustCompile(`^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$`) // Issue labels back the issue triage and PR gatekeeping workflows: until now // they could only be managed through the raw API (issue_tags), so these // shortcuts close that gap with first-class create/list/update/delete commands. -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "list", - Description: "List issue labels", + Description: tr.T("cmd.label.list.short"), Flags: []common.Flag{ - {Name: "keyword", Short: "k", Usage: "Filter labels by keyword"}, - {Name: "only-name", Usage: "Return only label id and name: true or false"}, - {Name: "sort-by", Usage: "Sort field: updated_on, created_on, issues_count"}, - {Name: "sort-direction", Usage: "Sort direction: asc or desc"}, + {Name: "keyword", Short: "k", Usage: tr.T("flag.label.keyword")}, + {Name: "only-name", Usage: tr.T("flag.label.only_name")}, + {Name: "sort-by", Usage: tr.T("flag.label.sort_by")}, + {Name: "sort-direction", Usage: tr.T("flag.label.sort_direction")}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -51,30 +53,30 @@ func Shortcuts() []*common.Shortcut { }, { Name: "create", - Description: "Create an issue label", + Description: tr.T("cmd.label.create.short"), Flags: []common.Flag{ - {Name: "name", Short: "n", Usage: "Label name", Required: true}, - {Name: "description", Short: "d", Usage: "Label description"}, - {Name: "color", Short: "c", Usage: "Label color in hex, for example: #1E90FF", Default: defaultLabelColor}, + {Name: "name", Short: "n", Usage: tr.T("flag.label.name"), Required: true}, + {Name: "description", Short: "d", Usage: tr.T("flag.label.description")}, + {Name: "color", Short: "c", Usage: tr.T("flag.label.color"), Default: defaultLabelColor}, }, Run: runCreate, }, { Name: "update", - Description: "Update an issue label while preserving unspecified fields", + Description: tr.T("cmd.label.update.short"), Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Label ID", Required: true}, - {Name: "name", Short: "n", Usage: "Label name"}, - {Name: "description", Short: "d", Usage: "Label description"}, - {Name: "color", Short: "c", Usage: "Label color in hex, for example: #1E90FF"}, + {Name: "id", Short: "i", Usage: tr.T("flag.label.id"), Required: true}, + {Name: "name", Short: "n", Usage: tr.T("flag.label.name")}, + {Name: "description", Short: "d", Usage: tr.T("flag.label.description")}, + {Name: "color", Short: "c", Usage: tr.T("flag.label.color")}, }, Run: runUpdate, }, { Name: "delete", - Description: "Delete an issue label", + Description: tr.T("cmd.label.delete.short"), Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Label ID", Required: true}, + {Name: "id", Short: "i", Usage: tr.T("flag.label.id"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -242,3 +244,10 @@ func firstNonEmpty(values ...string) string { } return "" } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/license/license.go b/shortcuts/license/license.go index b8b7443..ab19034 100644 --- a/shortcuts/license/license.go +++ b/shortcuts/license/license.go @@ -3,6 +3,7 @@ package license import ( "net/url" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) @@ -10,13 +11,14 @@ import ( // // These shortcuts provide access to the GitLink license registry, // which lists all available open-source licenses supported by the platform. -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "list", - Description: "List available licenses", + Description: tr.T("cmd.license.list.short"), Flags: []common.Flag{ - {Name: "name", Short: "n", Usage: "Filter licenses by name"}, + {Name: "name", Short: "n", Usage: tr.T("flag.license.name")}, }, Run: runList, }, @@ -34,3 +36,10 @@ func runList(ctx *common.RuntimeContext) error { } return ctx.Output(env) } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/member/member.go b/shortcuts/member/member.go index 3734da3..a2f8abf 100644 --- a/shortcuts/member/member.go +++ b/shortcuts/member/member.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) @@ -21,11 +22,12 @@ var roleAliases = map[string]string{ } // Shortcuts returns repository member management shortcuts. -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "list", - Description: "List repository members", + Description: tr.T("cmd.member.list.short"), Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { return err @@ -39,9 +41,9 @@ func Shortcuts() []*common.Shortcut { }, { Name: "add", - Description: "Add a repository member by user ID", + Description: tr.T("cmd.member.add.short"), Flags: []common.Flag{ - {Name: "user-id", Short: "u", Usage: "GitLink user ID to add", Required: true}, + {Name: "user-id", Short: "u", Usage: tr.T("flag.member.user_id"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -60,19 +62,19 @@ func Shortcuts() []*common.Shortcut { }, { Name: "batch-add", - Description: "Add multiple repository members by user IDs or a CSV file", + Description: tr.T("cmd.member.batch-add.short"), Flags: []common.Flag{ - {Name: "user-ids", Short: "u", Usage: "Comma-separated GitLink user IDs, for example: 101,102"}, - {Name: "from", Usage: "Read user IDs from a CSV file. Supports a user_id/id column or first column without header"}, - {Name: "dry-run", Usage: "Preview members that would be added without changing them", Bool: true, Default: "false"}, + {Name: "user-ids", Short: "u", Usage: tr.T("flag.member.user_ids")}, + {Name: "from", Usage: tr.T("flag.member.from")}, + {Name: "dry-run", Usage: tr.T("flag.member.dry_run"), Bool: true, Default: "false"}, }, Run: runBatchAdd, }, { Name: "remove", - Description: "Remove a repository member by user ID", + Description: tr.T("cmd.member.remove.short"), Flags: []common.Flag{ - {Name: "user-id", Short: "u", Usage: "GitLink user ID to remove", Required: true}, + {Name: "user-id", Short: "u", Usage: tr.T("flag.member.user_id_2"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -91,10 +93,10 @@ func Shortcuts() []*common.Shortcut { }, { Name: "role", - Description: "Change a repository member role", + Description: tr.T("cmd.member.role.short"), Flags: []common.Flag{ - {Name: "user-id", Short: "u", Usage: "GitLink user ID to update", Required: true}, - {Name: "role", Short: "r", Usage: "Member role: Manager, Developer, or Reporter", Required: true}, + {Name: "user-id", Short: "u", Usage: tr.T("flag.member.user_id_2"), Required: true}, + {Name: "role", Short: "r", Usage: tr.T("flag.member.role"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -120,10 +122,10 @@ func Shortcuts() []*common.Shortcut { }, { Name: "invite-link", - Description: "Get or create a repository invite link", + Description: tr.T("cmd.member.invite-link.short"), Flags: []common.Flag{ - {Name: "role", Short: "r", Usage: "Invite role: manager, developer, or reporter", Default: "developer"}, - {Name: "apply", Usage: "Whether joining by invite requires approval: true or false", Default: "true"}, + {Name: "role", Short: "r", Usage: tr.T("flag.member.role_2"), Default: "developer"}, + {Name: "apply", Usage: tr.T("flag.member.apply"), Default: "true"}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -149,9 +151,9 @@ func Shortcuts() []*common.Shortcut { }, { Name: "invite-info", - Description: "Show repository invite link information", + Description: tr.T("cmd.member.invite-info.short"), Flags: []common.Flag{ - {Name: "sign", Short: "s", Usage: "Invite link sign", Required: true}, + {Name: "sign", Short: "s", Usage: tr.T("flag.member.sign"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -172,9 +174,9 @@ func Shortcuts() []*common.Shortcut { }, { Name: "accept-invite", - Description: "Accept a repository invite link", + Description: tr.T("cmd.member.accept-invite.short"), Flags: []common.Flag{ - {Name: "sign", Short: "s", Usage: "Invite link sign", Required: true}, + {Name: "sign", Short: "s", Usage: tr.T("flag.member.sign"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -390,3 +392,10 @@ func userIDColumn(header []string) int { } return -1 } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/milestone/milestone.go b/shortcuts/milestone/milestone.go index 1ec2b30..9175ca1 100644 --- a/shortcuts/milestone/milestone.go +++ b/shortcuts/milestone/milestone.go @@ -5,22 +5,24 @@ import ( "net/url" "strings" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "list", - Description: "List milestones", + Description: tr.T("cmd.milestone.list.short"), Flags: []common.Flag{ - {Name: "keyword", Short: "k", Usage: "Search keyword"}, - {Name: "category", Short: "c", Usage: "Filter by category: opening, closed"}, - {Name: "only-name", Usage: "Return only milestone id and name: true or false"}, - {Name: "sort-by", Usage: "Sort field: created_on, updated_on, effective_date, issues_count, percent"}, - {Name: "sort-direction", Usage: "Sort direction: asc or desc"}, - {Name: "page", Short: "p", Usage: "Page number", Default: "1"}, - {Name: "limit", Short: "l", Usage: "Items per page", Default: "20"}, + {Name: "keyword", Short: "k", Usage: tr.T("flag.search.keyword")}, + {Name: "category", Short: "c", Usage: tr.T("flag.milestone.category")}, + {Name: "only-name", Usage: tr.T("flag.milestone.only_name")}, + {Name: "sort-by", Usage: tr.T("flag.milestone.sort_by")}, + {Name: "sort-direction", Usage: tr.T("flag.milestone.sort_direction")}, + {Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"}, + {Name: "limit", Short: "l", Usage: tr.T("flag.limit"), Default: "20"}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -43,11 +45,11 @@ func Shortcuts() []*common.Shortcut { }, { Name: "create", - Description: "Create a milestone", + Description: tr.T("cmd.milestone.create.short"), Flags: []common.Flag{ - {Name: "name", Short: "n", Usage: "Milestone name", Required: true}, - {Name: "description", Short: "d", Usage: "Milestone description", Required: true}, - {Name: "due-date", Usage: "Due date in YYYY-MM-DD format", Required: true}, + {Name: "name", Short: "n", Usage: tr.T("flag.milestone.name"), Required: true}, + {Name: "description", Short: "d", Usage: tr.T("flag.milestone.description"), Required: true}, + {Name: "due-date", Usage: tr.T("flag.milestone.due_date"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -66,17 +68,17 @@ func Shortcuts() []*common.Shortcut { }, { Name: "view", - Description: "View milestone details and linked issues", + Description: tr.T("cmd.milestone.view.short"), Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Milestone ID", Required: true}, - {Name: "category", Short: "c", Usage: "Filter issues by category: all, opened, closed"}, - {Name: "author-id", Usage: "Filter issues by author ID"}, - {Name: "assigner-id", Usage: "Filter issues by assignee ID"}, - {Name: "issue-tag-ids", Usage: "Comma-separated issue tag IDs"}, - {Name: "sort-by", Usage: "Sort field: issues.created_on, issues.updated_on, issue_priorities.position"}, - {Name: "sort-direction", Usage: "Sort direction: asc or desc"}, - {Name: "page", Short: "p", Usage: "Page number", Default: "1"}, - {Name: "limit", Short: "l", Usage: "Items per page", Default: "20"}, + {Name: "id", Short: "i", Usage: tr.T("flag.milestone.id"), Required: true}, + {Name: "category", Short: "c", Usage: tr.T("flag.milestone.category_2")}, + {Name: "author-id", Usage: tr.T("flag.milestone.author_id")}, + {Name: "assigner-id", Usage: tr.T("flag.milestone.assigner_id")}, + {Name: "issue-tag-ids", Usage: tr.T("flag.milestone.issue_tag_ids")}, + {Name: "sort-by", Usage: tr.T("flag.milestone.sort_by_2")}, + {Name: "sort-direction", Usage: tr.T("flag.milestone.sort_direction")}, + {Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"}, + {Name: "limit", Short: "l", Usage: tr.T("flag.limit"), Default: "20"}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -104,12 +106,12 @@ func Shortcuts() []*common.Shortcut { }, { Name: "update", - Description: "Update a milestone", + Description: tr.T("cmd.milestone.update.short"), Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Milestone ID", Required: true}, - {Name: "name", Short: "n", Usage: "Milestone name"}, - {Name: "description", Short: "d", Usage: "Milestone description"}, - {Name: "due-date", Usage: "Due date in YYYY-MM-DD format"}, + {Name: "id", Short: "i", Usage: tr.T("flag.milestone.id"), Required: true}, + {Name: "name", Short: "n", Usage: tr.T("flag.milestone.name")}, + {Name: "description", Short: "d", Usage: tr.T("flag.milestone.description")}, + {Name: "due-date", Usage: tr.T("flag.milestone.due_date")}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -132,9 +134,9 @@ func Shortcuts() []*common.Shortcut { }, { Name: "delete", - Description: "Delete a milestone", + Description: tr.T("cmd.milestone.delete.short"), Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Milestone ID", Required: true}, + {Name: "id", Short: "i", Usage: tr.T("flag.milestone.id"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -151,8 +153,8 @@ func Shortcuts() []*common.Shortcut { return ctx.Output(env) }, }, - newStatusShortcut("close", "Close a milestone", "closed"), - newStatusShortcut("reopen", "Reopen a milestone", "open"), + newStatusShortcut(tr, "close", tr.T("cmd.milestone.close.short"), "closed"), + newStatusShortcut(tr, "reopen", tr.T("cmd.milestone.reopen.short"), "open"), } } @@ -194,12 +196,12 @@ func milestonePayload(ctx *common.RuntimeContext, requireAll bool) (map[string]i return payload, nil } -func newStatusShortcut(name, description, status string) *common.Shortcut { +func newStatusShortcut(tr *i18n.Translator, name, description, status string) *common.Shortcut { return &common.Shortcut{ Name: name, Description: description, Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Milestone ID", Required: true}, + {Name: "id", Short: "i", Usage: tr.T("flag.milestone.id"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -237,3 +239,10 @@ func normalizeCSV(value string) string { } return strings.Join(result, ",") } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/pipeline/pipeline.go b/shortcuts/pipeline/pipeline.go index 846f57e..02f64a9 100644 --- a/shortcuts/pipeline/pipeline.go +++ b/shortcuts/pipeline/pipeline.go @@ -7,18 +7,20 @@ import ( "strconv" "strings" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "list", - Description: "List platform pipelines", + Description: tr.T("cmd.pipeline.list.short"), Flags: []common.Flag{ - {Name: "owner-id", Usage: "Owner user or organization ID"}, - {Name: "page", Short: "p", Usage: "Page number", Default: "1"}, - {Name: "limit", Short: "l", Usage: "Items per page", Default: "20"}, + {Name: "owner-id", Usage: tr.T("flag.pipeline.owner_id")}, + {Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"}, + {Name: "limit", Short: "l", Usage: tr.T("flag.limit"), Default: "20"}, }, Run: func(ctx *common.RuntimeContext) error { q := pageLimitQuery(ctx) @@ -32,8 +34,8 @@ func Shortcuts() []*common.Shortcut { }, { Name: "runs", - Description: "List pipeline run records", - Flags: runFilterFlags(), + Description: tr.T("cmd.pipeline.runs.short"), + Flags: runFilterFlags(tr), Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { return err @@ -47,9 +49,9 @@ func Shortcuts() []*common.Shortcut { }, { Name: "run", - Description: "Run a pipeline workflow", - Flags: append(runFilterFlags(), - common.Flag{Name: "dry-run", Usage: "Preview the run request without starting a pipeline", Bool: true, Default: "false"}, + Description: tr.T("cmd.pipeline.run.short"), + Flags: append(runFilterFlags(tr), + common.Flag{Name: "dry-run", Usage: tr.T("flag.pipeline.dry_run"), Bool: true, Default: "false"}, ), Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -76,9 +78,9 @@ func Shortcuts() []*common.Shortcut { }, { Name: "view", - Description: "Show pipeline details", + Description: tr.T("cmd.pipeline.view.short"), Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Pipeline ID", Required: true}, + {Name: "id", Short: "i", Usage: tr.T("flag.pipeline.id"), Required: true}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -97,10 +99,10 @@ func Shortcuts() []*common.Shortcut { }, { Name: "delete", - Description: "Delete a pipeline", + Description: tr.T("cmd.pipeline.delete.short"), Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Pipeline ID", Required: true}, - {Name: "dry-run", Usage: "Preview the delete request without changing pipeline state", Bool: true, Default: "false"}, + {Name: "id", Short: "i", Usage: tr.T("flag.pipeline.id"), Required: true}, + {Name: "dry-run", Usage: tr.T("flag.pipeline.dry_run_2"), Bool: true, Default: "false"}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -129,11 +131,11 @@ func Shortcuts() []*common.Shortcut { }, { Name: "save-yaml", - Description: "Save a visual pipeline YAML graph", + Description: tr.T("cmd.pipeline.save-yaml.short"), Flags: []common.Flag{ - {Name: "id", Short: "i", Usage: "Pipeline ID", Required: true}, - {Name: "pipeline-json", Usage: "Pipeline graph JSON object or string", Required: true}, - {Name: "dry-run", Usage: "Preview the save request without changing pipeline state", Bool: true, Default: "false"}, + {Name: "id", Short: "i", Usage: tr.T("flag.pipeline.id"), Required: true}, + {Name: "pipeline-json", Usage: tr.T("flag.pipeline.pipeline_json"), Required: true}, + {Name: "dry-run", Usage: tr.T("flag.pipeline.dry_run_2"), Bool: true, Default: "false"}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -171,31 +173,31 @@ func Shortcuts() []*common.Shortcut { }, { Name: "enable", - Description: "Enable a pipeline workflow", - Flags: workflowStateFlags(true), + Description: tr.T("cmd.pipeline.enable.short"), + Flags: workflowStateFlags(tr, true), Run: func(ctx *common.RuntimeContext) error { return runWorkflowState(ctx, "enable") }, }, { Name: "disable", - Description: "Disable a pipeline workflow", - Flags: workflowStateFlags(true), + Description: tr.T("cmd.pipeline.disable.short"), + Flags: workflowStateFlags(tr, true), Run: func(ctx *common.RuntimeContext) error { return runWorkflowState(ctx, "disable") }, }, { Name: "logs", - Description: "Query pipeline run logs", + Description: tr.T("cmd.pipeline.logs.short"), Flags: []common.Flag{ - {Name: "run-id", Short: "r", Usage: "Pipeline run ID", Required: true}, - {Name: "id", Short: "i", Usage: "Pipeline ID", Required: true}, - {Name: "index", Usage: "Run index", Required: true}, - {Name: "job", Short: "j", Usage: "Job index", Default: "0"}, - {Name: "cursor", Usage: "Log cursor"}, - {Name: "step", Usage: "Log step", Default: "1"}, - {Name: "expanded", Usage: "Whether the log cursor is expanded", Bool: true, Default: "true"}, + {Name: "run-id", Short: "r", Usage: tr.T("flag.pipeline.run_id"), Required: true}, + {Name: "id", Short: "i", Usage: tr.T("flag.pipeline.id"), Required: true}, + {Name: "index", Usage: tr.T("flag.pipeline.index"), Required: true}, + {Name: "job", Short: "j", Usage: tr.T("flag.pipeline.job"), Default: "0"}, + {Name: "cursor", Usage: tr.T("flag.pipeline.cursor")}, + {Name: "step", Usage: tr.T("flag.pipeline.step"), Default: "1"}, + {Name: "expanded", Usage: tr.T("flag.pipeline.expanded"), Bool: true, Default: "true"}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -244,9 +246,9 @@ func Shortcuts() []*common.Shortcut { }, { Name: "results", - Description: "Show pipeline run report results", + Description: tr.T("cmd.pipeline.results.short"), Flags: []common.Flag{ - {Name: "run-id", Short: "r", Usage: "Pipeline run ID"}, + {Name: "run-id", Short: "r", Usage: tr.T("flag.pipeline.run_id")}, }, Run: func(ctx *common.RuntimeContext) error { if err := ctx.ResolveOwnerRepo(); err != nil { @@ -268,10 +270,10 @@ func pipelineV1RepoPath(ctx *common.RuntimeContext) string { return "/v1" + ctx.RepoPath() } -func runFilterFlags() []common.Flag { +func runFilterFlags(tr *i18n.Translator) []common.Flag { return []common.Flag{ - {Name: "ref", Short: "r", Usage: "Branch, tag, or commit SHA"}, - {Name: "workflow", Short: "w", Usage: "Workflow file name"}, + {Name: "ref", Short: "r", Usage: tr.T("flag.pipeline.ref")}, + {Name: "workflow", Short: "w", Usage: tr.T("flag.pipeline.workflow")}, } } @@ -282,13 +284,13 @@ func runFilterQuery(ctx *common.RuntimeContext) url.Values { return q } -func workflowStateFlags(includeDryRun bool) []common.Flag { +func workflowStateFlags(tr *i18n.Translator, includeDryRun bool) []common.Flag { flags := []common.Flag{ - {Name: "id", Short: "i", Usage: "Pipeline ID", Required: true}, - {Name: "workflow", Short: "w", Usage: "Workflow file name", Required: true}, + {Name: "id", Short: "i", Usage: tr.T("flag.pipeline.id"), Required: true}, + {Name: "workflow", Short: "w", Usage: tr.T("flag.pipeline.workflow"), Required: true}, } if includeDryRun { - flags = append(flags, common.Flag{Name: "dry-run", Usage: "Preview the request without changing pipeline state", Bool: true, Default: "false"}) + flags = append(flags, common.Flag{Name: "dry-run", Usage: tr.T("flag.pipeline.dry_run_2"), Bool: true, Default: "false"}) } return flags } @@ -387,3 +389,10 @@ func requiredNonNegativeIntWithDefault(ctx *common.RuntimeContext, flagName stri } return id, nil } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/register.go b/shortcuts/register.go index 1fedc7e..c34b92e 100644 --- a/shortcuts/register.go +++ b/shortcuts/register.go @@ -38,11 +38,11 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) { groups := map[string][]*common.Shortcut{ "repo": repo.Shortcuts(tr), "issue": issue.Shortcuts(tr), - "label": label.Shortcuts(), - "license": license.Shortcuts(), - "member": member.Shortcuts(), - "milestone": milestone.Shortcuts(), - "pipeline": pipeline.Shortcuts(), + "label": label.Shortcuts(tr), + "license": license.Shortcuts(tr), + "member": member.Shortcuts(tr), + "milestone": milestone.Shortcuts(tr), + "pipeline": pipeline.Shortcuts(tr), "pr": pr.Shortcuts(tr), "profile": profile.Shortcuts(tr), "release": release.Shortcuts(tr), @@ -51,13 +51,13 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) { "user": user.Shortcuts(tr), "search": search.Shortcuts(tr), "ci": ci.Shortcuts(tr), - "compare": compare.Shortcuts(), + "compare": compare.Shortcuts(tr), "dataset": dataset.Shortcuts(tr), "webhook": webhook.Shortcuts(tr), - "wiki": wiki.Shortcuts(), + "wiki": wiki.Shortcuts(tr), "health": health.Shortcuts(tr), - "ignore": ignore.Shortcuts(), - "workflow": workflow.Shortcuts(), + "ignore": ignore.Shortcuts(tr), + "workflow": workflow.Shortcuts(tr), } descriptions := map[string]string{ diff --git a/shortcuts/wiki/wiki.go b/shortcuts/wiki/wiki.go index 539b7a1..261c697 100644 --- a/shortcuts/wiki/wiki.go +++ b/shortcuts/wiki/wiki.go @@ -6,6 +6,7 @@ import ( "net/url" "github.com/gitlink-org/gitlink-cli/internal/config" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) @@ -23,19 +24,20 @@ func switchToGateway(ctx *common.RuntimeContext) error { } // gatewayFlag returns the common --gateway flag definition. -func gatewayFlag() common.Flag { - return common.Flag{Name: "gateway", Short: "g", Usage: "Use gateway API endpoint", Bool: true} +func gatewayFlag(tr *i18n.Translator) common.Flag { + return common.Flag{Name: "gateway", Short: "g", Usage: tr.T("flag.wiki.gateway"), Bool: true} } // Shortcuts returns all wiki shortcuts. -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ { Name: "list", - Description: "List wiki pages", + Description: tr.T("cmd.wiki.list.short"), Flags: []common.Flag{ - {Name: "project-id", Usage: "GitLink project ID", Required: true}, - gatewayFlag(), + {Name: "project-id", Usage: tr.T("flag.wiki.project_id"), Required: true}, + gatewayFlag(tr), }, Run: func(ctx *common.RuntimeContext) error { if ctx.Arg("gateway") == "true" { @@ -59,11 +61,11 @@ func Shortcuts() []*common.Shortcut { }, { Name: "view", - Description: "View a wiki page by page name", + Description: tr.T("cmd.wiki.view.short"), Flags: []common.Flag{ - {Name: "project-id", Usage: "GitLink project ID", Required: true}, - {Name: "page-name", Short: "n", Usage: "Wiki page name (slug)", Required: true}, - gatewayFlag(), + {Name: "project-id", Usage: tr.T("flag.wiki.project_id"), Required: true}, + {Name: "page-name", Short: "n", Usage: tr.T("flag.wiki.page_name"), Required: true}, + gatewayFlag(tr), }, Run: func(ctx *common.RuntimeContext) error { if ctx.Arg("gateway") == "true" { @@ -88,14 +90,14 @@ func Shortcuts() []*common.Shortcut { }, { Name: "create", - Description: "Create a new wiki page", + Description: tr.T("cmd.wiki.create.short"), Flags: []common.Flag{ - {Name: "project-id", Usage: "GitLink project ID", Required: true}, - {Name: "page-name", Short: "n", Usage: "Wiki page name (slug)", Required: true}, - {Name: "title", Short: "t", Usage: "Wiki page title", Required: true}, - {Name: "content", Short: "c", Usage: "Wiki page content (markdown)", Required: true}, - {Name: "message", Short: "m", Usage: "Commit message"}, - gatewayFlag(), + {Name: "project-id", Usage: tr.T("flag.wiki.project_id"), Required: true}, + {Name: "page-name", Short: "n", Usage: tr.T("flag.wiki.page_name"), Required: true}, + {Name: "title", Short: "t", Usage: tr.T("flag.wiki.title"), Required: true}, + {Name: "content", Short: "c", Usage: tr.T("flag.wiki.content"), Required: true}, + {Name: "message", Short: "m", Usage: tr.T("flag.wiki.message")}, + gatewayFlag(tr), }, Run: func(ctx *common.RuntimeContext) error { if ctx.Arg("gateway") == "true" { @@ -125,14 +127,14 @@ func Shortcuts() []*common.Shortcut { }, { Name: "update", - Description: "Update an existing wiki page", + Description: tr.T("cmd.wiki.update.short"), Flags: []common.Flag{ - {Name: "project-id", Usage: "GitLink project ID", Required: true}, - {Name: "page-name", Short: "n", Usage: "Wiki page name (slug)", Required: true}, - {Name: "title", Short: "t", Usage: "Wiki page title", Required: true}, - {Name: "content", Short: "c", Usage: "Wiki page content (markdown)"}, - {Name: "message", Short: "m", Usage: "Commit message"}, - gatewayFlag(), + {Name: "project-id", Usage: tr.T("flag.wiki.project_id"), Required: true}, + {Name: "page-name", Short: "n", Usage: tr.T("flag.wiki.page_name"), Required: true}, + {Name: "title", Short: "t", Usage: tr.T("flag.wiki.title"), Required: true}, + {Name: "content", Short: "c", Usage: tr.T("flag.wiki.content")}, + {Name: "message", Short: "m", Usage: tr.T("flag.wiki.message")}, + gatewayFlag(tr), }, Run: func(ctx *common.RuntimeContext) error { if ctx.Arg("gateway") == "true" { @@ -168,11 +170,11 @@ func Shortcuts() []*common.Shortcut { }, { Name: "delete", - Description: "Delete a wiki page", + Description: tr.T("cmd.wiki.delete.short"), Flags: []common.Flag{ - {Name: "project-id", Usage: "GitLink project ID", Required: true}, - {Name: "page-name", Short: "n", Usage: "Wiki page name (slug)", Required: true}, - gatewayFlag(), + {Name: "project-id", Usage: tr.T("flag.wiki.project_id"), Required: true}, + {Name: "page-name", Short: "n", Usage: tr.T("flag.wiki.page_name"), Required: true}, + gatewayFlag(tr), }, Run: func(ctx *common.RuntimeContext) error { if ctx.Arg("gateway") == "true" { @@ -198,3 +200,10 @@ func Shortcuts() []*common.Shortcut { }, } } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/workflow/pr_summary.go b/shortcuts/workflow/pr_summary.go index 398bf1e..4035610 100644 --- a/shortcuts/workflow/pr_summary.go +++ b/shortcuts/workflow/pr_summary.go @@ -8,6 +8,7 @@ import ( "time" "github.com/gitlink-org/gitlink-cli/cmd/cmdutil" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) @@ -82,18 +83,18 @@ type PRSummaryResult struct { Source string `json:"source"` } -func newPRSummaryShortcut() *common.Shortcut { +func newPRSummaryShortcut(tr *i18n.Translator) *common.Shortcut { return &common.Shortcut{ Name: "pr-summary", - Description: "Generate a read-only pull request review summary", + Description: tr.T("cmd.workflow.pr-summary.short"), Flags: []common.Flag{ - {Name: "from", Usage: "Read PR summary input from a JSON file"}, - {Name: "number", Short: "n", Usage: "Pull request number for remote read-only analysis"}, - {Name: "include-commits", Usage: "Fetch commits in remote mode", Bool: true, Default: "true"}, - {Name: "include-files", Usage: "Fetch changed files in remote mode", Bool: true, Default: "true"}, - {Name: "max-files", Usage: "Maximum changed files to analyze", Default: "100"}, - {Name: "max-commits", Usage: "Maximum commits to analyze", Default: "100"}, - {Name: "lang", Usage: "Output language: en or zh-CN", Default: langEN}, + {Name: "from", Usage: tr.T("flag.workflow.pr_summary.from")}, + {Name: "number", Short: "n", Usage: tr.T("flag.workflow.pr_summary.number")}, + {Name: "include-commits", Usage: tr.T("flag.workflow.pr_summary.include_commits"), Bool: true, Default: "true"}, + {Name: "include-files", Usage: tr.T("flag.workflow.pr_summary.include_files"), Bool: true, Default: "true"}, + {Name: "max-files", Usage: tr.T("flag.workflow.pr_summary.max_files"), Default: "100"}, + {Name: "max-commits", Usage: tr.T("flag.workflow.pr_summary.max_commits"), Default: "100"}, + {Name: "lang", Usage: tr.T("flag.workflow.pr_summary.lang"), Default: langEN}, }, Run: runPRSummary, } diff --git a/shortcuts/workflow/repo_report.go b/shortcuts/workflow/repo_report.go index 4043be6..5cd3b16 100644 --- a/shortcuts/workflow/repo_report.go +++ b/shortcuts/workflow/repo_report.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/gitlink-org/gitlink-cli/cmd/cmdutil" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) @@ -48,19 +49,19 @@ type RepoPRSummary struct { ReviewFocus []string `json:"review_focus"` } -func newRepoReportShortcut() *common.Shortcut { +func newRepoReportShortcut(tr *i18n.Translator) *common.Shortcut { return &common.Shortcut{ Name: "repo-report", - Description: "Generate a read-only repository workflow report", + Description: tr.T("cmd.workflow.repo-report.short"), Flags: []common.Flag{ - {Name: "from", Usage: "Read repository report input from a JSON file"}, - {Name: "issue-limit", Usage: "Maximum issues to fetch and analyze", Default: "20"}, - {Name: "pr-limit", Usage: "Maximum pull requests to fetch and summarize", Default: "10"}, - {Name: "stale-days", Usage: "Days before an issue or PR is considered stale", Default: "30"}, - {Name: "include-issues", Usage: "Include issue triage summary", Bool: true, Default: "true"}, - {Name: "include-prs", Usage: "Include pull request summary", Bool: true, Default: "true"}, - {Name: "include-health", Usage: "Include repository health summary", Bool: true, Default: "true"}, - {Name: "lang", Usage: "Output language: en or zh-CN", Default: langEN}, + {Name: "from", Usage: tr.T("flag.workflow.repo_report.from")}, + {Name: "issue-limit", Usage: tr.T("flag.workflow.repo_report.issue_limit"), Default: "20"}, + {Name: "pr-limit", Usage: tr.T("flag.workflow.repo_report.pr_limit"), Default: "10"}, + {Name: "stale-days", Usage: tr.T("flag.workflow.repo_report.stale_days"), Default: "30"}, + {Name: "include-issues", Usage: tr.T("flag.workflow.repo_report.include_issues"), Bool: true, Default: "true"}, + {Name: "include-prs", Usage: tr.T("flag.workflow.repo_report.include_prs"), Bool: true, Default: "true"}, + {Name: "include-health", Usage: tr.T("flag.workflow.repo_report.include_health"), Bool: true, Default: "true"}, + {Name: "lang", Usage: tr.T("flag.workflow.repo_report.lang"), Default: langEN}, }, Run: runRepoReport, } diff --git a/shortcuts/workflow/workflow.go b/shortcuts/workflow/workflow.go index 4dc69e5..b72f621 100644 --- a/shortcuts/workflow/workflow.go +++ b/shortcuts/workflow/workflow.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) @@ -19,62 +20,63 @@ type TriageReport struct { Results []TriageResult `json:"results"` } -func Shortcuts() []*common.Shortcut { +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ - newTriageShortcut(), - newHealthShortcut(), - newPRSummaryShortcut(), - newRepoReportShortcut(), + newTriageShortcut(tr), + newHealthShortcut(tr), + newPRSummaryShortcut(tr), + newRepoReportShortcut(tr), } } -func newTriageShortcut() *common.Shortcut { +func newTriageShortcut(tr *i18n.Translator) *common.Shortcut { return &common.Shortcut{ Name: "triage", - Description: "Analyze issues with local workflow triage rules", + Description: tr.T("cmd.workflow.triage.short"), Flags: []common.Flag{ - {Name: "from", Usage: "Read issue inputs from a JSON file. Supports a single issue, an array, or an object with an issues field"}, - {Name: "title", Short: "t", Usage: "Issue title for single-issue local analysis"}, - {Name: "body", Short: "b", Usage: "Issue body for single-issue local analysis"}, - {Name: "number", Short: "n", Usage: "Issue number for single-issue local analysis"}, - {Name: "author", Usage: "Issue author for single-issue local analysis"}, - {Name: "url", Usage: "Issue URL for single-issue local analysis"}, - {Name: "labels", Usage: "Comma-separated labels for single-issue local analysis"}, - {Name: "state", Short: "s", Usage: "Filter or assign issue state", Default: "open"}, - {Name: "page", Short: "p", Usage: "API page number for remote triage", Default: "1"}, - {Name: "limit", Short: "l", Usage: "Maximum issues to analyze", Default: "30"}, - {Name: "since", Usage: "Optional remote issue filter for updated time"}, - {Name: "dry-run", Usage: "Preview workflow recommendations without remote writes", Bool: true, Default: "true"}, - {Name: "lang", Usage: "Output language: en or zh-CN", Default: langEN}, + {Name: "from", Usage: tr.T("flag.workflow.from")}, + {Name: "title", Short: "t", Usage: tr.T("flag.workflow.title")}, + {Name: "body", Short: "b", Usage: tr.T("flag.workflow.body")}, + {Name: "number", Short: "n", Usage: tr.T("flag.workflow.number")}, + {Name: "author", Usage: tr.T("flag.workflow.author")}, + {Name: "url", Usage: tr.T("flag.workflow.url")}, + {Name: "labels", Usage: tr.T("flag.workflow.labels")}, + {Name: "state", Short: "s", Usage: tr.T("flag.workflow.state"), Default: "open"}, + {Name: "page", Short: "p", Usage: tr.T("flag.workflow.page"), Default: "1"}, + {Name: "limit", Short: "l", Usage: tr.T("flag.workflow.limit"), Default: "30"}, + {Name: "since", Usage: tr.T("flag.workflow.since")}, + {Name: "dry-run", Usage: tr.T("flag.workflow.dry_run"), Bool: true, Default: "true"}, + {Name: "lang", Usage: tr.T("flag.workflow.lang"), Default: langEN}, }, Run: runTriage, } } -func newHealthShortcut() *common.Shortcut { +func newHealthShortcut(tr *i18n.Translator) *common.Shortcut { return &common.Shortcut{ Name: "health", - Description: "Score repository health with local workflow rules", + Description: tr.T("cmd.workflow.health.short"), Flags: []common.Flag{ - {Name: "from", Usage: "Read health input from a JSON file"}, - {Name: "repository", Usage: "Repository name, for example owner/repo"}, - {Name: "open-issues", Usage: "Open issue count", Default: "0"}, - {Name: "open-prs", Usage: "Open pull request count", Default: "0"}, - {Name: "stale-issues", Usage: "Stale issue count", Default: "0"}, - {Name: "stale-prs", Usage: "Stale pull request count", Default: "0"}, - {Name: "recent-activity-known", Usage: "Whether recent activity is known", Bool: true, Default: "false"}, - {Name: "recent-activity-days", Usage: "Days since recent activity", Default: "0"}, - {Name: "release-known", Usage: "Whether release status is known", Bool: true, Default: "false"}, - {Name: "has-recent-release", Usage: "Whether a recent release exists", Bool: true, Default: "false"}, - {Name: "ci-known", Usage: "Whether CI status is known", Bool: true, Default: "false"}, - {Name: "ci-passing", Usage: "Whether CI is passing", Bool: true, Default: "false"}, - {Name: "has-readme", Usage: "Whether README exists", Bool: true, Default: "false"}, - {Name: "has-license", Usage: "Whether LICENSE exists", Bool: true, Default: "false"}, - {Name: "has-contributing", Usage: "Whether CONTRIBUTING exists", Bool: true, Default: "false"}, - {Name: "agent-readiness-known", Usage: "Whether agent readiness score is known", Bool: true, Default: "false"}, - {Name: "agent-readiness-score", Usage: "Agent readiness score from 0 to 10", Default: "0"}, - {Name: "stale-days", Usage: "Days before an issue or PR is considered stale", Default: "30"}, - {Name: "lang", Usage: "Output language: en or zh-CN", Default: langEN}, + {Name: "from", Usage: tr.T("flag.workflow.from_2")}, + {Name: "repository", Usage: tr.T("flag.workflow.repository")}, + {Name: "open-issues", Usage: tr.T("flag.workflow.open_issues"), Default: "0"}, + {Name: "open-prs", Usage: tr.T("flag.workflow.open_prs"), Default: "0"}, + {Name: "stale-issues", Usage: tr.T("flag.workflow.stale_issues"), Default: "0"}, + {Name: "stale-prs", Usage: tr.T("flag.workflow.stale_prs"), Default: "0"}, + {Name: "recent-activity-known", Usage: tr.T("flag.workflow.recent_activity_known"), Bool: true, Default: "false"}, + {Name: "recent-activity-days", Usage: tr.T("flag.workflow.recent_activity_days"), Default: "0"}, + {Name: "release-known", Usage: tr.T("flag.workflow.release_known"), Bool: true, Default: "false"}, + {Name: "has-recent-release", Usage: tr.T("flag.workflow.has_recent_release"), Bool: true, Default: "false"}, + {Name: "ci-known", Usage: tr.T("flag.workflow.ci_known"), Bool: true, Default: "false"}, + {Name: "ci-passing", Usage: tr.T("flag.workflow.ci_passing"), Bool: true, Default: "false"}, + {Name: "has-readme", Usage: tr.T("flag.workflow.has_readme"), Bool: true, Default: "false"}, + {Name: "has-license", Usage: tr.T("flag.workflow.has_license"), Bool: true, Default: "false"}, + {Name: "has-contributing", Usage: tr.T("flag.workflow.has_contributing"), Bool: true, Default: "false"}, + {Name: "agent-readiness-known", Usage: tr.T("flag.workflow.agent_readiness_known"), Bool: true, Default: "false"}, + {Name: "agent-readiness-score", Usage: tr.T("flag.workflow.agent_readiness_score"), Default: "0"}, + {Name: "stale-days", Usage: tr.T("flag.workflow.stale_days"), Default: "30"}, + {Name: "lang", Usage: tr.T("flag.workflow.lang"), Default: langEN}, }, Run: runHealth, } @@ -384,3 +386,10 @@ func mustParseInt(value string, defaultValue int) int { } return parsed } + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} From 0135cf36e0eb7c3183aace94e8c180cc07fd7d72 Mon Sep 17 00:00:00 2001 From: Taoyouce Date: Tue, 7 Jul 2026 14:16:24 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix(i18n):=20=E5=91=BD=E4=BB=A4=E7=BB=84?= =?UTF-8?q?=E7=BA=A7=20Short=20=E6=8F=8F=E8=BF=B0=E6=8E=A5=E5=85=A5=20i18n?= =?UTF-8?q?=20=E5=B9=B6=E4=BF=AE=E5=A4=8D=20ignore=20=E7=BB=84=20help=20?= =?UTF-8?q?=E6=B3=84=E6=BC=8F=E5=8E=9F=E5=A7=8B=E9=94=AE=20cmd.ignore.shor?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/i18n/locales/en-US.json | 10 ++++++++++ internal/i18n/locales/zh-CN.json | 10 ++++++++++ shortcuts/register.go | 18 +++++++++--------- shortcuts/register_test.go | 4 ++++ 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/internal/i18n/locales/en-US.json b/internal/i18n/locales/en-US.json index 3fd3354..25f5522 100644 --- a/internal/i18n/locales/en-US.json +++ b/internal/i18n/locales/en-US.json @@ -17,6 +17,7 @@ "cmd.ci.short": "CI/CD operations", "cmd.ci.stop.short": "Stop a build", "cmd.compare.files.short": "List changed files between two refs", + "cmd.compare.short": "Compare branches, tags, or commits", "cmd.compare.view.short": "Compare two branches, tags, or commits", "cmd.config.get.short": "Get a configuration value", "cmd.config.init.short": "Initialize configuration file", @@ -37,7 +38,9 @@ "cmd.doctor.long": "Run local diagnostics for gitlink-cli configuration, authentication, repository context and API connectivity.", "cmd.doctor.short": "Diagnose gitlink-cli environment problems", "cmd.health.fetch.short": "Fetch PR and Issue data into SQLite for health analysis", + "cmd.health.short": "Project health data collection", "cmd.ignore.list.short": "List available ignore-file templates", + "cmd.ignore.short": "Ignore file template operations", "cmd.issue.batch_close.long": "Close filtered issues in bulk.\n\nThis command defaults to dry-run mode and only prints matching issues.\nPass --yes to execute remote close operations. Use restrictive filters and a small limit.\n\nExamples:\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20 --yes", "cmd.issue.batch_close.short": "Close filtered issues in bulk. Defaults to dry-run; pass --yes to execute.", "cmd.issue.batch_label.long": "Add a label to filtered issues in bulk.\n\nThis command defaults to dry-run mode and only prints matching issues.\nPass --yes to execute remote label operations. The current implementation does not fake label writes when the API endpoint is unavailable.\n\nExamples:\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50 --yes", @@ -54,8 +57,10 @@ "cmd.label.create.short": "Create an issue label", "cmd.label.delete.short": "Delete an issue label", "cmd.label.list.short": "List issue labels", + "cmd.label.short": "Issue label operations", "cmd.label.update.short": "Update an issue label while preserving unspecified fields", "cmd.license.list.short": "List available licenses", + "cmd.license.short": "License operations", "cmd.member.accept-invite.short": "Accept a repository invite link", "cmd.member.add.short": "Add a repository member by user ID", "cmd.member.batch-add.short": "Add multiple repository members by user IDs or a CSV file", @@ -64,11 +69,13 @@ "cmd.member.list.short": "List repository members", "cmd.member.remove.short": "Remove a repository member by user ID", "cmd.member.role.short": "Change a repository member role", + "cmd.member.short": "Repository member operations", "cmd.milestone.close.short": "Close a milestone", "cmd.milestone.create.short": "Create a milestone", "cmd.milestone.delete.short": "Delete a milestone", "cmd.milestone.list.short": "List milestones", "cmd.milestone.reopen.short": "Reopen a milestone", + "cmd.milestone.short": "Milestone operations", "cmd.milestone.update.short": "Update a milestone", "cmd.milestone.view.short": "View milestone details and linked issues", "cmd.org.create.short": "Create an organization", @@ -85,6 +92,7 @@ "cmd.pipeline.run.short": "Run a pipeline workflow", "cmd.pipeline.runs.short": "List pipeline run records", "cmd.pipeline.save-yaml.short": "Save a visual pipeline YAML graph", + "cmd.pipeline.short": "Pipeline operations", "cmd.pipeline.view.short": "Show pipeline details", "cmd.pr.close.short": "Close a pull request", "cmd.pr.comment.short": "Add a comment to a pull request", @@ -142,11 +150,13 @@ "cmd.wiki.create.short": "Create a new wiki page", "cmd.wiki.delete.short": "Delete a wiki page", "cmd.wiki.list.short": "List wiki pages", + "cmd.wiki.short": "Wiki page management", "cmd.wiki.update.short": "Update an existing wiki page", "cmd.wiki.view.short": "View a wiki page by page name", "cmd.workflow.health.short": "Score repository health with local workflow rules", "cmd.workflow.pr-summary.short": "Generate a read-only pull request review summary", "cmd.workflow.repo-report.short": "Generate a read-only repository workflow report", + "cmd.workflow.short": "AI agent workflow analysis", "cmd.workflow.triage.short": "Analyze issues with local workflow triage rules", "error.auth.delete_token_failed": "failed to delete token: {message}", "error.auth.login_failed": "login failed: {message}", diff --git a/internal/i18n/locales/zh-CN.json b/internal/i18n/locales/zh-CN.json index 0e0e9ba..40657da 100644 --- a/internal/i18n/locales/zh-CN.json +++ b/internal/i18n/locales/zh-CN.json @@ -17,6 +17,7 @@ "cmd.ci.short": "CI/CD 操作", "cmd.ci.stop.short": "停止构建", "cmd.compare.files.short": "列出两个引用之间变更的文件", + "cmd.compare.short": "比较分支、标签或提交", "cmd.compare.view.short": "比较两个分支、标签或提交", "cmd.config.get.short": "获取配置项", "cmd.config.init.short": "初始化配置文件", @@ -37,7 +38,9 @@ "cmd.doctor.long": "诊断 gitlink-cli 的配置、认证、仓库上下文和 API 连通性问题。", "cmd.doctor.short": "诊断 gitlink-cli 环境问题", "cmd.health.fetch.short": "抓取 PR 与 Issue 数据到 SQLite 用于健康度分析", + "cmd.health.short": "项目健康数据采集", "cmd.ignore.list.short": "列出可用的 ignore 文件模板", + "cmd.ignore.short": "忽略文件模板操作", "cmd.issue.batch_close.long": "批量关闭筛选后的议题。\n\n该命令默认处于 dry-run 模式,只打印匹配的议题。\n传入 --yes 后执行远端关闭操作。请使用严格筛选条件和较小 limit。\n\n示例:\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20 --yes", "cmd.issue.batch_close.short": "批量关闭筛选后的议题。默认 dry-run;传入 --yes 后执行。", "cmd.issue.batch_label.long": "给筛选后的议题批量添加标签。\n\n该命令默认处于 dry-run 模式,只打印匹配的议题。\n传入 --yes 后执行远端标签操作。当前实现不会在 API 端点不可用时伪造写入结果。\n\n示例:\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50 --yes", @@ -54,8 +57,10 @@ "cmd.label.create.short": "创建 issue 标签", "cmd.label.delete.short": "删除 issue 标签", "cmd.label.list.short": "列出 issue 标签", + "cmd.label.short": "Issue 标签操作", "cmd.label.update.short": "更新 issue 标签(未指定字段保持不变)", "cmd.license.list.short": "列出可用的开源许可证", + "cmd.license.short": "许可证操作", "cmd.member.accept-invite.short": "接受仓库邀请链接", "cmd.member.add.short": "按用户 ID 添加仓库成员", "cmd.member.batch-add.short": "按用户 ID 列表或 CSV 文件批量添加仓库成员", @@ -64,11 +69,13 @@ "cmd.member.list.short": "列出仓库成员", "cmd.member.remove.short": "按用户 ID 移除仓库成员", "cmd.member.role.short": "变更仓库成员角色", + "cmd.member.short": "仓库成员操作", "cmd.milestone.close.short": "关闭里程碑", "cmd.milestone.create.short": "创建里程碑", "cmd.milestone.delete.short": "删除里程碑", "cmd.milestone.list.short": "列出里程碑", "cmd.milestone.reopen.short": "重新打开里程碑", + "cmd.milestone.short": "里程碑操作", "cmd.milestone.update.short": "更新里程碑", "cmd.milestone.view.short": "查看里程碑详情及关联 issue", "cmd.org.create.short": "创建组织", @@ -85,6 +92,7 @@ "cmd.pipeline.run.short": "运行流水线工作流", "cmd.pipeline.runs.short": "列出流水线运行记录", "cmd.pipeline.save-yaml.short": "保存可视化流水线 YAML 图", + "cmd.pipeline.short": "流水线操作", "cmd.pipeline.view.short": "查看流水线详情", "cmd.pr.close.short": "关闭拉取请求", "cmd.pr.comment.short": "给拉取请求添加评论", @@ -142,11 +150,13 @@ "cmd.wiki.create.short": "创建 wiki 页面", "cmd.wiki.delete.short": "删除 wiki 页面", "cmd.wiki.list.short": "列出 wiki 页面", + "cmd.wiki.short": "Wiki 页面管理", "cmd.wiki.update.short": "更新已有 wiki 页面", "cmd.wiki.view.short": "按页面名查看 wiki 页面", "cmd.workflow.health.short": "用本地工作流规则为仓库健康度打分", "cmd.workflow.pr-summary.short": "生成只读的 PR 评审摘要", "cmd.workflow.repo-report.short": "生成只读的仓库工作流报告", + "cmd.workflow.short": "AI 智能体工作流分析", "cmd.workflow.triage.short": "用本地工作流分诊规则分析 issue", "error.auth.delete_token_failed": "删除 Token 失败:{message}", "error.auth.login_failed": "登录失败:{message}", diff --git a/shortcuts/register.go b/shortcuts/register.go index c34b92e..82446ac 100644 --- a/shortcuts/register.go +++ b/shortcuts/register.go @@ -63,11 +63,11 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) { descriptions := map[string]string{ "repo": tr.T("cmd.repo.short"), "issue": tr.T("cmd.issue.short"), - "label": "Issue label operations", - "license": "License operations", - "member": "Repository member operations", - "milestone": "Milestone operations", - "pipeline": "Pipeline operations", + "label": tr.T("cmd.label.short"), + "license": tr.T("cmd.license.short"), + "member": tr.T("cmd.member.short"), + "milestone": tr.T("cmd.milestone.short"), + "pipeline": tr.T("cmd.pipeline.short"), "pr": tr.T("cmd.pr.short"), "profile": tr.T("cmd.profile.short"), "release": tr.T("cmd.release.short"), @@ -76,13 +76,13 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) { "user": tr.T("cmd.user.short"), "search": tr.T("cmd.search.short"), "ci": tr.T("cmd.ci.short"), - "compare": "Compare branches, tags, or commits", + "compare": tr.T("cmd.compare.short"), "dataset": tr.T("cmd.dataset.short"), "webhook": tr.T("cmd.webhook.short"), - "wiki": "Wiki page management", - "health": "Project health data collection", + "wiki": tr.T("cmd.wiki.short"), + "health": tr.T("cmd.health.short"), "ignore": tr.T("cmd.ignore.short"), - "workflow": "AI agent workflow analysis", + "workflow": tr.T("cmd.workflow.short"), } for name, shortcuts := range groups { diff --git a/shortcuts/register_test.go b/shortcuts/register_test.go index 00f4c57..54e4f4d 100644 --- a/shortcuts/register_test.go +++ b/shortcuts/register_test.go @@ -1,6 +1,7 @@ package shortcuts import ( + "strings" "testing" "github.com/spf13/cobra" @@ -60,6 +61,9 @@ func TestRegisterAllGroupDescriptions(t *testing.T) { if cmd.Short == "" { t.Fatal("Short description is empty") } + if strings.HasPrefix(cmd.Short, "cmd.") { + t.Fatalf("Short description leaks raw i18n key: %q", cmd.Short) + } }) } }