From d6ed0816a9e8f179fdf61e14b718171fca31adfe Mon Sep 17 00:00:00 2001 From: Goutte Date: Tue, 4 Apr 2023 05:33:08 +0200 Subject: [PATCH] feat(i18n): add translations for args validation --- args.go | 14 +++---- localizer.go | 78 ++++++++++++++++++++++++++++++++++++- translations/active.en.toml | 32 +++++++++++++++ translations/active.fr.toml | 39 +++++++++++++++++++ 4 files changed, 155 insertions(+), 8 deletions(-) diff --git a/args.go b/args.go index e79ec33a..63830733 100644 --- a/args.go +++ b/args.go @@ -33,7 +33,7 @@ func legacyArgs(cmd *Command, args []string) error { // root command with subcommands, do subcommand checking. if !cmd.HasParent() && len(args) > 0 { - return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) + return fmt.Errorf(i18nLegacyArgsValidationError(), args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) } return nil } @@ -41,7 +41,7 @@ func legacyArgs(cmd *Command, args []string) error { // NoArgs returns an error if any args are included. func NoArgs(cmd *Command, args []string) error { if len(args) > 0 { - return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) + return fmt.Errorf(i18nNoArgsValidationError(), args[0], cmd.CommandPath()) } return nil } @@ -58,7 +58,7 @@ func OnlyValidArgs(cmd *Command, args []string) error { } for _, v := range args { if !stringInSlice(v, validArgs) { - return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) + return fmt.Errorf(i18nOnlyValidArgsValidationError(), v, cmd.CommandPath(), cmd.findSuggestions(args[0])) } } } @@ -74,7 +74,7 @@ func ArbitraryArgs(cmd *Command, args []string) error { func MinimumNArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) < n { - return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args)) + return fmt.Errorf(i18nMinimumNArgsValidationError(n), n, len(args)) } return nil } @@ -84,7 +84,7 @@ func MinimumNArgs(n int) PositionalArgs { func MaximumNArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) > n { - return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args)) + return fmt.Errorf(i18nMaximumNArgsValidationError(n), n, len(args)) } return nil } @@ -94,7 +94,7 @@ func MaximumNArgs(n int) PositionalArgs { func ExactArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) != n { - return fmt.Errorf("accepts %d arg(s), received %d", n, len(args)) + return fmt.Errorf(i18nExactArgsValidationError(n), n, len(args)) } return nil } @@ -104,7 +104,7 @@ func ExactArgs(n int) PositionalArgs { func RangeArgs(min int, max int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) < min || len(args) > max { - return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args)) + return fmt.Errorf(i18nRangeArgsValidationError(max), min, max, len(args)) } return nil } diff --git a/localizer.go b/localizer.go index 9a563ecc..3097eeb5 100644 --- a/localizer.go +++ b/localizer.go @@ -35,6 +35,66 @@ func i18nError() string { }) } +func i18nLegacyArgsValidationError() string { + return localizeMessage(&i18n.Message{ + ID: "LegacyArgsValidationError", + Description: "error shown when args are not understood (subcmd, cmd, suggestion)", + Other: "unknown command %q for %q%s", + }) +} + +func i18nNoArgsValidationError() string { + return localizeMessage(&i18n.Message{ + ID: "NoArgsValidationError", + Description: "error shown when args are present but should not (subcmd, cmd)", + Other: "unknown command %q for %q", + }) +} + +func i18nOnlyValidArgsValidationError() string { + return localizeMessage(&i18n.Message{ + ID: "OnlyValidArgsValidationError", + Description: "error shown when arg is invalid (arg, cmd, suggestion)", + Other: "invalid argument %q for %q%s", + }) +} + +func i18nMinimumNArgsValidationError(amountRequired int) string { + return localizeMessageWithPlural(&i18n.Message{ + ID: "MinimumNArgsValidationError", + Description: "error shown when arg count is too low (expected amount, actual amount)", + Other: "requires at least %d args, only received %d", + One: "requires at least %d arg, only received %d", + }, amountRequired) +} + +func i18nMaximumNArgsValidationError(amountRequired int) string { + return localizeMessageWithPlural(&i18n.Message{ + ID: "MaximumNArgsValidationError", + Description: "error shown when arg count is too low (expected amount, actual amount)", + Other: "accepts at most %d args, received %d", + One: "accepts at most %d arg, received %d", + }, amountRequired) +} + +func i18nExactArgsValidationError(amountRequired int) string { + return localizeMessageWithPlural(&i18n.Message{ + ID: "ExactArgsValidationError", + Description: "error shown when arg count is not exact (expected amount, actual amount)", + Other: "accepts %d args, received %d", + One: "accepts %d arg, received %d", + }, amountRequired) +} + +func i18nRangeArgsValidationError(amountMax int) string { + return localizeMessageWithPlural(&i18n.Message{ + ID: "RangeArgsValidationError", + Description: "error shown when arg count is not in range (expected min, expected max, actual amount)", + Other: "accepts between %d and %d args, received %d", + One: "accepts between %d and %d arg, received %d", + }, amountMax) +} + func i18nRunHelpTip() string { return localizeMessage(&i18n.Message{ ID: "RunHelpTip", @@ -64,6 +124,18 @@ func localizeMessage(message *i18n.Message) string { return localizedValue } +func localizeMessageWithPlural(message *i18n.Message, pluralCount int) string { + localizedValue, err := localizer.Localize(&i18n.LocalizeConfig{ + PluralCount: pluralCount, + DefaultMessage: message, + }) + if err != nil { + return message.Other + } + + return localizedValue +} + func loadTranslationFiles(bundle *i18n.Bundle, langs []string) { for _, lang := range langs { _, _ = bundle.LoadMessageFileFS(localeFS, fmt.Sprintf("translations/active.%s.toml", lang)) @@ -92,7 +164,7 @@ func appendLang(langs *[]string, lang language.Tag) { *langs = append(*langs, langBase.String()) } -func init() { +func setupLocalizer() { bundle := i18n.NewBundle(defaultLanguage) bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) detectedLangs := detectLangs() @@ -100,3 +172,7 @@ func init() { loadTranslationFiles(bundle, detectedLangs) localizer = i18n.NewLocalizer(bundle, detectedLangs...) } + +func init() { + setupLocalizer() // FIXME: perhaps hook this somewhere else? (not init) +} diff --git a/translations/active.en.toml b/translations/active.en.toml index 8484267e..9c7405de 100644 --- a/translations/active.en.toml +++ b/translations/active.en.toml @@ -2,10 +2,42 @@ description = "prefix of error messages" other = "Error" +[ExactArgsValidationError] +description = "error shown when arg count is not exact (expected amount, actual amount)" +one = "accepts %d arg, received %d" +other = "accepts %d args, received %d" + [ExclusiveFlagsValidationError] 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" +[LegacyArgsValidationError] +description = "error shown when args are not understood (subcmd, cmd, suggestion)" +other = "unknown command %q for %q%s" + +[MaximumNArgsValidationError] +description = "error shown when arg count is too low (expected amount, actual amount)" +one = "accepts at most %d arg, received %d" +other = "accepts at most %d args, received %d" + +[MinimumNArgsValidationError] +description = "error shown when arg count is too low (expected amount, actual amount)" +one = "requires at least %d arg, only received %d" +other = "requires at least %d args, only received %d" + +[NoArgsValidationError] +description = "error shown when args are present but should not (subcmd, cmd)" +other = "unknown command %q for %q" + +[OnlyValidArgsValidationError] +description = "error shown when arg is invalid (arg, cmd, suggestion)" +other = "invalid argument %q for %q%s" + +[RangeArgsValidationError] +description = "error shown when arg count is not in range (expected min, expected max, actual amount)" +one = "accepts between %d and %d arg, received %d" +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." diff --git a/translations/active.fr.toml b/translations/active.fr.toml index a869d332..e6b2005f 100644 --- a/translations/active.fr.toml +++ b/translations/active.fr.toml @@ -3,11 +3,50 @@ description = "prefix of error messages" hash = "sha1-7dcb56355a3ddc7ff7e5ccd6522507999ca7f238" other = "Erreur" +[ExactArgsValidationError] +description = "error shown when arg count is not exact (expected amount, actual amount)" +hash = "sha1-207d771f1d5dc4ed5c4094dcd29a4c80e31a6260" +one = "accepte %d arg, mais en a reçu %d" +other = "accepte %d args, mais en en reçu %d" + [ExclusiveFlagsValidationError] description = "error shown when multiple exclusive flags are provided (group flags, offending flags)" hash = "sha1-221b98bada52cfc2932f9aa5142b653b46baded6" other = "les options [%v] sont exclusives, mais les options %v ont été fournies" +[LegacyArgsValidationError] +description = "error shown when args are not understood (subcmd, cmd, suggestion)" +hash = "sha1-c601c68bdcb9687109e793112b789b1858953b15" +other = "commande %q inconnue pour %q%s" + +[MaximumNArgsValidationError] +description = "error shown when arg count is too low (expected amount, actual amount)" +hash = "sha1-86d71b8bc054ea8aad7006808bc9d96551052ab4" +one = "accepte au plus %d arg, mais en a reçu %d" +other = "accepte au plus %d args, mais en a reçu %d" + +[MinimumNArgsValidationError] +description = "error shown when arg count is too low (expected amount, actual amount)" +hash = "sha1-7cc9093bf167d6f0601dd0763a8d3f10d71c8889" +one = "requiert au moins %d arg, mais en a reçu %d" +other = "requiert au moins %d args, mais en a reçu %d" + +[NoArgsValidationError] +description = "error shown when args are present but should not (subcmd, cmd)" +hash = "sha1-551d8d237dc2ab9a853fcfbe7ef85318a0f78720" +other = "commande %q inconnue pour %q" + +[OnlyValidArgsValidationError] +description = "error shown when arg is invalid (arg, cmd, suggestion)" +hash = "sha1-60b40e5782dd252c78ef3d585065cb99197ec22e" +other = "argument %q invalide pour %q%s" + +[RangeArgsValidationError] +description = "error shown when arg count is not in range (expected min, expected max, actual amount)" +hash = "sha1-aa81e0aee17a3439b479cdf47169eb194706cd14" +one = "accepte entre %d et %d arg, mais en a reçu %d" +other = "accepte entre %d et %d args, mais en a reçu %d" + [RunHelpTip] description = "tip shown when a command fails (command path)" hash = "sha1-e1d2c4cccd484df365c3249347d5172981929b88"