feat(i18n): add translations for args validation

This commit is contained in:
Goutte 2023-04-04 05:33:08 +02:00
parent 2e90e51710
commit d6ed0816a9
4 changed files with 155 additions and 8 deletions

14
args.go
View file

@ -33,7 +33,7 @@ func legacyArgs(cmd *Command, args []string) error {
// root command with subcommands, do subcommand checking. // root command with subcommands, do subcommand checking.
if !cmd.HasParent() && len(args) > 0 { 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 return nil
} }
@ -41,7 +41,7 @@ func legacyArgs(cmd *Command, args []string) error {
// NoArgs returns an error if any args are included. // NoArgs returns an error if any args are included.
func NoArgs(cmd *Command, args []string) error { func NoArgs(cmd *Command, args []string) error {
if len(args) > 0 { 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 return nil
} }
@ -58,7 +58,7 @@ func OnlyValidArgs(cmd *Command, args []string) error {
} }
for _, v := range args { for _, v := range args {
if !stringInSlice(v, validArgs) { 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 { func MinimumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {
if len(args) < n { 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 return nil
} }
@ -84,7 +84,7 @@ func MinimumNArgs(n int) PositionalArgs {
func MaximumNArgs(n int) PositionalArgs { func MaximumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {
if len(args) > n { 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 return nil
} }
@ -94,7 +94,7 @@ func MaximumNArgs(n int) PositionalArgs {
func ExactArgs(n int) PositionalArgs { func ExactArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {
if len(args) != n { 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 return nil
} }
@ -104,7 +104,7 @@ func ExactArgs(n int) PositionalArgs {
func RangeArgs(min int, max int) PositionalArgs { func RangeArgs(min int, max int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {
if len(args) < min || len(args) > max { 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 return nil
} }

View file

@ -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 { func i18nRunHelpTip() string {
return localizeMessage(&i18n.Message{ return localizeMessage(&i18n.Message{
ID: "RunHelpTip", ID: "RunHelpTip",
@ -64,6 +124,18 @@ func localizeMessage(message *i18n.Message) string {
return localizedValue 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) { func loadTranslationFiles(bundle *i18n.Bundle, langs []string) {
for _, lang := range langs { for _, lang := range langs {
_, _ = bundle.LoadMessageFileFS(localeFS, fmt.Sprintf("translations/active.%s.toml", lang)) _, _ = 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()) *langs = append(*langs, langBase.String())
} }
func init() { func setupLocalizer() {
bundle := i18n.NewBundle(defaultLanguage) bundle := i18n.NewBundle(defaultLanguage)
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
detectedLangs := detectLangs() detectedLangs := detectLangs()
@ -100,3 +172,7 @@ func init() {
loadTranslationFiles(bundle, detectedLangs) loadTranslationFiles(bundle, detectedLangs)
localizer = i18n.NewLocalizer(bundle, detectedLangs...) localizer = i18n.NewLocalizer(bundle, detectedLangs...)
} }
func init() {
setupLocalizer() // FIXME: perhaps hook this somewhere else? (not init)
}

View file

@ -2,10 +2,42 @@
description = "prefix of error messages" description = "prefix of error messages"
other = "Error" 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] [ExclusiveFlagsValidationError]
description = "error shown when multiple exclusive flags are provided (group flags, offending flags)" 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" 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] [RunHelpTip]
description = "tip shown when a command fails (command path)" description = "tip shown when a command fails (command path)"
other = "Run '%v --help' for usage." other = "Run '%v --help' for usage."

View file

@ -3,11 +3,50 @@ description = "prefix of error messages"
hash = "sha1-7dcb56355a3ddc7ff7e5ccd6522507999ca7f238" hash = "sha1-7dcb56355a3ddc7ff7e5ccd6522507999ca7f238"
other = "Erreur" 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] [ExclusiveFlagsValidationError]
description = "error shown when multiple exclusive flags are provided (group flags, offending flags)" description = "error shown when multiple exclusive flags are provided (group flags, offending flags)"
hash = "sha1-221b98bada52cfc2932f9aa5142b653b46baded6" hash = "sha1-221b98bada52cfc2932f9aa5142b653b46baded6"
other = "les options [%v] sont exclusives, mais les options %v ont été fournies" 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] [RunHelpTip]
description = "tip shown when a command fails (command path)" description = "tip shown when a command fails (command path)"
hash = "sha1-e1d2c4cccd484df365c3249347d5172981929b88" hash = "sha1-e1d2c4cccd484df365c3249347d5172981929b88"