feat: embed CLI locale files, wire i18n ExtraFS
Some checks failed
Deploy / build (push) Failing after 7s
Security Scan / security (push) Successful in 20s

- Added locales/en.json with 90 translation keys for doctor, pkg commands
- Main() embeds CLI locales automatically
- MainWithLocales() accepts additional FSSource for consuming binaries
- Ecosystem packages can ship their own locale files

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-17 00:28:52 +00:00
parent 77c7d19402
commit bf994fab17
2 changed files with 163 additions and 1 deletions

View file

@ -1,7 +1,9 @@
package cli
import (
"embed"
"fmt"
"io/fs"
"os"
"runtime/debug"
@ -11,6 +13,9 @@ import (
"github.com/spf13/cobra"
)
//go:embed locales/*.json
var cliLocaleFS embed.FS
// AppName is the default CLI application name.
// Override with WithAppName before calling Main.
var AppName = "core"
@ -65,7 +70,21 @@ func WithAppName(name string) {
// )
//
// Exits with code 1 on error or panic.
// LocaleSource pairs a filesystem with a directory for loading translations.
type LocaleSource = i18n.FSSource
// WithLocales returns a locale source for use with MainWithLocales.
func WithLocales(fsys fs.FS, dir string) LocaleSource {
return LocaleSource{FS: fsys, Dir: dir}
}
// Main initialises and runs the CLI with the framework's built-in translations.
func Main(commands ...core.Option) {
MainWithLocales(nil, commands...)
}
// MainWithLocales initialises and runs the CLI with additional translation sources.
func MainWithLocales(locales []LocaleSource, commands ...core.Option) {
// Recovery from panics
defer func() {
if r := recover(); r != nil {
@ -75,9 +94,17 @@ func Main(commands ...core.Option) {
}
}()
// Build locale sources: framework built-in + caller's extras
extraFS := []i18n.FSSource{
{FS: cliLocaleFS, Dir: "locales"},
}
extraFS = append(extraFS, locales...)
// Core services load first, then command services
services := []core.Option{
core.WithName("i18n", i18n.NewCoreService(i18n.ServiceOptions{})),
core.WithName("i18n", i18n.NewCoreService(i18n.ServiceOptions{
ExtraFS: extraFS,
})),
}
services = append(services, commands...)

135
pkg/cli/locales/en.json Normal file
View file

@ -0,0 +1,135 @@
{
"cmd": {
"doctor": {
"short": "Check development environment",
"long": "Diagnose your development environment and report missing tools, configuration issues, and connectivity problems.",
"verbose_flag": "Show detailed output",
"required": "Required tools:",
"optional": "Optional tools:",
"github": "GitHub integration:",
"workspace": "Workspace:",
"ready": "Environment is ready",
"install_missing": "Install missing tools:",
"install_macos": "brew install",
"install_macos_cask": "brew install --cask",
"install_linux_header": "Install on Linux:",
"install_linux_git": "sudo apt install git",
"install_linux_node": "curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt install -y nodejs",
"install_linux_php": "sudo apt install php php-cli php-mbstring php-xml php-curl",
"install_linux_pnpm": "npm install -g pnpm",
"install_linux_gh": "See https://github.com/cli/cli/blob/trunk/docs/install_linux.md",
"install_other": "See tool documentation for installation",
"issues": "Open issues assigned to you:",
"issues_error": "Failed to fetch issues",
"cli_auth": "GitHub CLI authenticated",
"cli_auth_missing": "GitHub CLI not authenticated — run: gh auth login",
"ssh_found": "SSH key found",
"ssh_missing": "SSH key not found — run: ssh-keygen",
"repos_yaml_found": "Workspace registry found: {{.Path}}",
"repos_cloned": "{{.Cloned}}/{{.Total}} repos cloned",
"no_repos_yaml": "No repos.yaml found (run from workspace root)",
"check": {
"git": { "name": "Git", "description": "Version control" },
"docker": { "name": "Docker", "description": "Container runtime" },
"node": { "name": "Node.js", "description": "JavaScript runtime" },
"php": { "name": "PHP", "description": "PHP interpreter" },
"composer": { "name": "Composer", "description": "PHP package manager" },
"pnpm": { "name": "pnpm", "description": "Node package manager" },
"gh": { "name": "GitHub CLI", "description": "GitHub integration" },
"claude": { "name": "Claude Code", "description": "AI coding assistant" }
}
},
"pkg": {
"short": "Manage packages",
"long": "Install, list, search, update, and remove packages from the Core ecosystem.",
"no_description": "(no description)",
"error": {
"repo_required": "Repository argument required (e.g., core/go-io)",
"invalid_repo_format": "Invalid format — use org/repo (e.g., core/go-io)",
"no_repos_yaml": "No repos.yaml found",
"no_repos_yaml_workspace": "No repos.yaml found in workspace",
"specify_package": "Specify a package name",
"auth_failed": "Authentication failed",
"gh_not_authenticated": "GitHub CLI not authenticated — run: gh auth login",
"search_failed": "Search failed"
},
"install": {
"short": "Install a package",
"long": "Clone a package from the Git forge into your workspace.",
"installing_label": "Installing",
"already_exists": "{{.Name}} already exists at {{.Path}}",
"installed": "{{.Name}} installed successfully",
"add_to_registry": "Adding to registry",
"added_to_registry": "Added to repos.yaml",
"flag": {
"dir": "Target directory (default: workspace base path)",
"add": "Add to repos.yaml registry after install"
}
},
"list": {
"short": "List installed packages",
"long": "Show all packages registered in repos.yaml with their status.",
"title": "Installed packages",
"no_packages": "No packages found",
"summary": "{{.Count}} packages",
"install_missing": "Install missing: core pkg install"
},
"search": {
"short": "Search available packages",
"long": "Search the forge for available packages by name or pattern.",
"fetching_label": "Searching",
"cache_label": "Cached",
"found_repos": "Found {{.Count}} repositories",
"no_repos_found": "No matching repositories found",
"private_label": "private",
"gh_token_unset": "GITHUB_TOKEN not set",
"gh_token_warning": "Set GITHUB_TOKEN for private repo access",
"flag": {
"org": "Organisation to search (default: core)",
"pattern": "Filter by name pattern",
"type": "Filter by type (package, application, template)",
"limit": "Maximum results",
"refresh": "Refresh cache"
}
},
"update": {
"short": "Update a package",
"long": "Pull latest changes for a package or all packages.",
"updating": "Updating {{.Name}}",
"not_installed": "{{.Name}} is not installed",
"summary": "{{.Updated}}/{{.Total}} updated",
"flag": {
"all": "Update all packages"
}
},
"outdated": {
"short": "Show outdated packages",
"long": "Check which packages have unpulled commits.",
"all_up_to_date": "All packages are up to date",
"commits_behind": "{{.Count}} commits behind",
"update_with": "Update with: core pkg update {{.Name}}",
"summary": "{{.Outdated}}/{{.Total}} outdated"
}
}
},
"common": {
"hint": {
"install_with": "Install with: {{.Command}}"
},
"progress": {
"checking": "Checking {{.Item}}...",
"checking_updates": "Checking for updates..."
},
"status": {
"cloning": "Cloning",
"up_to_date": "Up to date"
}
},
"i18n": {
"fail": {
"create": "Failed to create {{.Item}}",
"load": "Failed to load {{.Item}}",
"parse": "Failed to parse {{.Item}}"
}
}
}