From 0abea784c4da9dd4489a50a48e15085d2aae8c96 Mon Sep 17 00:00:00 2001 From: Goutte Date: Tue, 4 Apr 2023 09:04:29 +0200 Subject: [PATCH] feat(i18n): translate the usage template as well This should keep backwards compat'. --- args_test.go | 8 +-- command.go | 21 ++++--- localizer.go | 113 ++++++++++++++++++++++++++++++++++++ translations/active.en.toml | 40 +++++++++++++ translations/active.fr.toml | 50 ++++++++++++++++ 5 files changed, 219 insertions(+), 13 deletions(-) diff --git a/args_test.go b/args_test.go index 90d174cc..c156b475 100644 --- a/args_test.go +++ b/args_test.go @@ -68,7 +68,7 @@ func minimumNArgsWithLessArgs(err error, t *testing.T) { t.Fatal("Expected an error") } got := err.Error() - expected := "requires at least 2 arg(s), only received 1" + expected := "requires at least 2 args, only received 1" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } @@ -79,7 +79,7 @@ func maximumNArgsWithMoreArgs(err error, t *testing.T) { t.Fatal("Expected an error") } got := err.Error() - expected := "accepts at most 2 arg(s), received 3" + expected := "accepts at most 2 args, received 3" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } @@ -90,7 +90,7 @@ func exactArgsWithInvalidCount(err error, t *testing.T) { t.Fatal("Expected an error") } got := err.Error() - expected := "accepts 2 arg(s), received 3" + expected := "accepts 2 args, received 3" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } @@ -101,7 +101,7 @@ func rangeArgsWithInvalidCount(err error, t *testing.T) { t.Fatal("Expected an error") } got := err.Error() - expected := "accepts between 2 and 4 arg(s), received 1" + expected := "accepts between 2 and 4 args, received 1" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } diff --git a/command.go b/command.go index 237d2238..92b659b4 100644 --- a/command.go +++ b/command.go @@ -252,6 +252,8 @@ type Command struct { // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. // Must be > 0. SuggestionsMinimumDistance int + + I18n *i18nCommandGlossary } // Context returns underlying command context. If command was executed @@ -542,6 +544,7 @@ func (c *Command) NamePadding() int { // UsageTemplate returns usage template for the command. func (c *Command) UsageTemplate() string { + c.I18n = getCommandGlossary() if c.usageTemplate != "" { return c.usageTemplate } @@ -549,35 +552,35 @@ func (c *Command) UsageTemplate() string { if c.HasParent() { return c.parent.UsageTemplate() } - return `Usage:{{if .Runnable}} + return `{{.I18n.SectionUsage}}:{{if .Runnable}} {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} -Aliases: +{{.I18n.SectionAliases}}: {{.NameAndAliases}}{{end}}{{if .HasExample}} -Examples: +{{.I18n.SectionExamples}}: {{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}} -Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}} +{{.I18n.SectionAvailableCommands}}:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}} {{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}} -Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}} +{{.I18n.SectionAdditionalCommands}}:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} -Flags: +{{.I18n.SectionFlags}}: {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} -Global Flags: +{{.I18n.SectionGlobalFlags}}: {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} +{{.I18n.SectionAdditionalHelpTopics}}:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} -Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} +{{.I18n.Use}} "{{.CommandPath}} [command] --help" {{.I18n.ForInfoAboutCommand}}.{{end}} ` } diff --git a/localizer.go b/localizer.go index 3097eeb5..1a13d546 100644 --- a/localizer.go +++ b/localizer.go @@ -27,6 +27,119 @@ var localeFS embed.FS // Localizer can be used to fetch localized messages var localizer *i18n.Localizer +type i18nCommandGlossary struct { + SectionUsage string + SectionAliases string + SectionExamples string + SectionAvailableCommands string + SectionAdditionalCommands string + SectionFlags string + SectionGlobalFlags string + SectionAdditionalHelpTopics string + Use string + ForInfoAboutCommand string +} + +var commonCommandGlossary *i18nCommandGlossary + +func getCommandGlossary() *i18nCommandGlossary { + if commonCommandGlossary == nil { + commonCommandGlossary = &i18nCommandGlossary{ + SectionUsage: i18nSectionUsage(), + SectionAliases: i18nSectionAliases(), + SectionExamples: i18nSectionExamples(), + SectionAvailableCommands: i18nSectionAvailableCommands(), + SectionAdditionalCommands: i18nSectionAdditionalCommands(), + SectionFlags: i18nSectionFlags(), + SectionGlobalFlags: i18nSectionGlobalFlags(), + SectionAdditionalHelpTopics: i18nSectionAdditionalHelpTopics(), + Use: i18nUse(), + ForInfoAboutCommand: i18nForInfoAboutCommand(), + } + } + return commonCommandGlossary +} + +func i18nSectionUsage() string { + return localizeMessage(&i18n.Message{ + ID: "SectionUsage", + Description: "title of the section in the usage template", + Other: "Usage", + }) +} + +func i18nSectionAliases() string { + return localizeMessage(&i18n.Message{ + ID: "SectionAliases", + Description: "title of the section in the usage template", + Other: "Aliases", + }) +} + +func i18nSectionExamples() string { + return localizeMessage(&i18n.Message{ + ID: "SectionExamples", + Description: "title of the section in the usage template", + Other: "Examples", + }) +} + +func i18nSectionAvailableCommands() string { + return localizeMessage(&i18n.Message{ + ID: "SectionAvailableCommands", + Description: "title of the section in the usage template", + Other: "Available Commands", + }) +} + +func i18nSectionAdditionalCommands() string { + return localizeMessage(&i18n.Message{ + ID: "SectionAdditionalCommands", + Description: "title of the section in the usage template", + Other: "Additional Commands", + }) +} + +func i18nSectionFlags() string { + return localizeMessage(&i18n.Message{ + ID: "SectionFlags", + Description: "title of the section in the usage template", + Other: "Flags", + }) +} + +func i18nSectionGlobalFlags() string { + return localizeMessage(&i18n.Message{ + ID: "SectionGlobalFlags", + Description: "title of the section in the usage template", + Other: "Global Flags", + }) +} + +func i18nSectionAdditionalHelpTopics() string { + return localizeMessage(&i18n.Message{ + ID: "SectionAdditionalHelpTopics", + Description: "title of the section in the usage template", + Other: "Additional Help Topics", + }) +} + +func i18nUse() string { + return localizeMessage(&i18n.Message{ + ID: "Use", + Description: "beginning of a sentence like 'Use to do '", + Other: "Use", + }) +} + +func i18nForInfoAboutCommand() string { + return localizeMessage(&i18n.Message{ + ID: "ForInfoAboutCommand", + Description: "end of a sentence", + Other: "for more information about a command", + }) +} + func i18nError() string { return localizeMessage(&i18n.Message{ ID: "Error", diff --git a/translations/active.en.toml b/translations/active.en.toml index 9c7405de..605656a3 100644 --- a/translations/active.en.toml +++ b/translations/active.en.toml @@ -11,6 +11,10 @@ other = "accepts %d args, received %d" description = "error shown when multiple exclusive flags are provided (group flags, offending flags)" other = "if any flags in the group [%v] are set none of the others can be; %v were all set" +[ForInfoAboutCommand] +description = "end of a sentence" +other = "for more information about a command" + [LegacyArgsValidationError] description = "error shown when args are not understood (subcmd, cmd, suggestion)" other = "unknown command %q for %q%s" @@ -41,3 +45,39 @@ other = "accepts between %d and %d args, received %d" [RunHelpTip] description = "tip shown when a command fails (command path)" other = "Run '%v --help' for usage." + +[SectionAdditionalCommands] +description = "title of the section in the usage template" +other = "Additional Commands" + +[SectionAdditionalHelpTopics] +description = "title of the section in the usage template" +other = "Additional Help Topics" + +[SectionAliases] +description = "title of the section in the usage template" +other = "Aliases" + +[SectionAvailableCommands] +description = "title of the section in the usage template" +other = "Available Commands" + +[SectionExamples] +description = "title of the section in the usage template" +other = "Examples" + +[SectionFlags] +description = "title of the section in the usage template" +other = "Flags" + +[SectionGlobalFlags] +description = "title of the section in the usage template" +other = "Global Flags" + +[SectionUsage] +description = "title of the section in the usage template" +other = "Usage" + +[Use] +description = "beginning of a sentence like 'Use to do '" +other = "Use" diff --git a/translations/active.fr.toml b/translations/active.fr.toml index e6b2005f..701dba14 100644 --- a/translations/active.fr.toml +++ b/translations/active.fr.toml @@ -14,6 +14,11 @@ description = "error shown when multiple exclusive flags are provided (group fla hash = "sha1-221b98bada52cfc2932f9aa5142b653b46baded6" other = "les options [%v] sont exclusives, mais les options %v ont été fournies" +[ForInfoAboutCommand] +description = "end of a sentence" +hash = "sha1-923f6d48908b3a6981fb5504b0e5078700a312c0" +other = "pour plus d'information au sujet d'une commande" + [LegacyArgsValidationError] description = "error shown when args are not understood (subcmd, cmd, suggestion)" hash = "sha1-c601c68bdcb9687109e793112b789b1858953b15" @@ -51,3 +56,48 @@ other = "accepte entre %d et %d args, mais en a reçu %d" description = "tip shown when a command fails (command path)" hash = "sha1-e1d2c4cccd484df365c3249347d5172981929b88" other = "Essayez '%v --help' pour obtenir de l'aide." + +[SectionAdditionalCommands] +description = "title of the section in the usage template" +hash = "sha1-730484f22c7ce0885ca13a3b8222b231dc29a4a9" +other = "Commandes Connexes" + +[SectionAdditionalHelpTopics] +description = "title of the section in the usage template" +hash = "sha1-615c9551f4dcd30836fbe04506e0b807c59dd901" +other = "Autres Sujets" + +[SectionAliases] +description = "title of the section in the usage template" +hash = "sha1-3c66c036f454cb3d23f757c430a5c05b148dc01f" +other = "Alias" + +[SectionAvailableCommands] +description = "title of the section in the usage template" +hash = "sha1-fc33c38777373e51c9c84c8594efb5de4df0f23e" +other = "Commandes Disponibles" + +[SectionExamples] +description = "title of the section in the usage template" +hash = "sha1-6e2f0c7dddc3ce6aacb1184b3b21694492d6595a" +other = "Exemples" + +[SectionFlags] +description = "title of the section in the usage template" +hash = "sha1-5513ed25ed4e1ad2e569ff4c963bba347320e9f7" +other = "Options" + +[SectionGlobalFlags] +description = "title of the section in the usage template" +hash = "sha1-705f1ebcdce1374e23f41bc8e0e14e5197ac1742" +other = "Options Globales" + +[SectionUsage] +description = "title of the section in the usage template" +hash = "sha1-5fdae7bd171315a453063384887ee4300363cf20" +other = "Usage" + +[Use] +description = "beginning of a sentence like 'Use to do '" +hash = "sha1-f42c92acc9934eec952161dfa338a95ec0f02b75" +other = "Utilisez"