diff --git a/src/WingetCreateCLI/LocalizableSentenceBuilder.cs b/src/WingetCreateCLI/LocalizableSentenceBuilder.cs new file mode 100644 index 00000000..1e7436a0 --- /dev/null +++ b/src/WingetCreateCLI/LocalizableSentenceBuilder.cs @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.WingetCreateCLI +{ + /* This implementation is taken from the CommandLineParser reference examples. + * https://github.com/commandlineparser/commandline/tree/master/demo/ReadText.LocalizedDemo + */ + + using System; + using System.Collections.Generic; + using System.Linq; + using CommandLine; + using CommandLine.Text; + + /// + public class LocalizableSentenceBuilder : SentenceBuilder + { + /// + public override Func RequiredWord + { + get { return () => Properties.Resources.SentenceRequiredWord; } + } + + /// + public override Func ErrorsHeadingText + { + // Cannot be pluralized + get { return () => Properties.Resources.SentenceErrorsHeadingText; } + } + + /// + public override Func UsageHeadingText + { + get { return () => Properties.Resources.SentenceUsageHeadingText; } + } + + /// + public override Func OptionGroupWord + { + get { return () => Properties.Resources.SentenceOptionGroupWord; } + } + + /// + public override Func HelpCommandText + { + get + { + return isOption => isOption + ? Properties.Resources.SentenceHelpCommandTextOption + : Properties.Resources.SentenceHelpCommandTextVerb; + } + } + + /// + public override Func VersionCommandText + { + get { return _ => Properties.Resources.SentenceVersionCommandText; } + } + + /// + public override Func FormatError + { + get + { + return error => + { + switch (error.Tag) + { + case ErrorType.BadFormatTokenError: + return string.Format(Properties.Resources.SentenceBadFormatTokenError, ((BadFormatTokenError)error).Token); + + case ErrorType.MissingValueOptionError: + return string.Format(Properties.Resources.SentenceMissingValueOptionError, ((MissingValueOptionError)error).NameInfo.NameText); + + case ErrorType.UnknownOptionError: + return string.Format(Properties.Resources.SentenceUnknownOptionError, ((UnknownOptionError)error).Token); + + case ErrorType.MissingRequiredOptionError: + var errMisssing = (MissingRequiredOptionError)error; + return errMisssing.NameInfo.Equals(NameInfo.EmptyName) ? Properties.Resources.SentenceMissingRequiredValueError + : string.Format(Properties.Resources.SentenceMissingRequiredOptionError, errMisssing.NameInfo.NameText); + + case ErrorType.BadFormatConversionError: + var badFormat = (BadFormatConversionError)error; + return badFormat.NameInfo.Equals(NameInfo.EmptyName) ? Properties.Resources.SentenceBadFormatConversionErrorValue + : string.Format(Properties.Resources.SentenceBadFormatConversionErrorOption, badFormat.NameInfo.NameText); + + case ErrorType.SequenceOutOfRangeError: + var seqOutRange = (SequenceOutOfRangeError)error; + return seqOutRange.NameInfo.Equals(NameInfo.EmptyName) ? Properties.Resources.SentenceSequenceOutOfRangeErrorValue + : string.Format(Properties.Resources.SentenceSequenceOutOfRangeErrorOption, seqOutRange.NameInfo.NameText); + + case ErrorType.BadVerbSelectedError: + return string.Format(Properties.Resources.SentenceBadVerbSelectedError, ((BadVerbSelectedError)error).Token); + + case ErrorType.NoVerbSelectedError: + return Properties.Resources.SentenceNoVerbSelectedError; + + case ErrorType.RepeatedOptionError: + return string.Format(Properties.Resources.SentenceRepeatedOptionError, ((RepeatedOptionError)error).NameInfo.NameText); + + case ErrorType.SetValueExceptionError: + var setValueError = (SetValueExceptionError)error; + return string.Format(Properties.Resources.SentenceSetValueExceptionError, setValueError.NameInfo.NameText, setValueError.Exception.Message); + } + + throw new InvalidOperationException(); + }; + } + } + + /// + public override Func, string> FormatMutuallyExclusiveSetErrors + { + get + { + return errors => + { + var bySet = from e in errors + group e by e.SetName into g + select new { SetName = g.Key, Errors = g.ToList() }; + + var msgs = bySet.Select( + set => + { + var names = string.Join( + string.Empty, + (from e in set.Errors select string.Format("'{0}', ", e.NameInfo.NameText)).ToArray()); + var namesCount = set.Errors.Count(); + + var incompat = string.Join( + string.Empty, + (from x in + (from s in bySet where !s.SetName.Equals(set.SetName) from e in s.Errors select e) + .Distinct() + select string.Format("'{0}', ", x.NameInfo.NameText)).ToArray()); + + // TODO: Pluralize by namesCount + return string.Format( + Properties.Resources.SentenceMutuallyExclusiveSetErrors, + names.Substring(0, names.Length - 2), + incompat.Substring(0, incompat.Length - 2)); + }).ToArray(); + return string.Join(Environment.NewLine, msgs); + }; + } + } + } +} diff --git a/src/WingetCreateCLI/Program.cs b/src/WingetCreateCLI/Program.cs index 33f83e03..6468fbcb 100644 --- a/src/WingetCreateCLI/Program.cs +++ b/src/WingetCreateCLI/Program.cs @@ -27,6 +27,7 @@ private static async Task Main(string[] args) Logger.Initialize(); UserSettings.FirstRunTelemetryConsent(); TelemetryEventListener.EventListener.IsTelemetryEnabled(); + SentenceBuilder.Factory = () => new LocalizableSentenceBuilder(); string arguments = string.Join(' ', Environment.GetCommandLineArgs()); Logger.Trace($"Command line args: {arguments}"); diff --git a/src/WingetCreateCLI/Properties/Resources.Designer.cs b/src/WingetCreateCLI/Properties/Resources.Designer.cs index f64b9da0..459935a5 100644 --- a/src/WingetCreateCLI/Properties/Resources.Designer.cs +++ b/src/WingetCreateCLI/Properties/Resources.Designer.cs @@ -2346,6 +2346,195 @@ public static string SelectRelativeFilePath_Message { } } + /// + /// Looks up a localized string similar to Option '{0}' is defined with a bad format.. + /// + public static string SentenceBadFormatConversionErrorOption { + get { + return ResourceManager.GetString("SentenceBadFormatConversionErrorOption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A value not bound to option name is defined with a bad format.. + /// + public static string SentenceBadFormatConversionErrorValue { + get { + return ResourceManager.GetString("SentenceBadFormatConversionErrorValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Token '{0}' is not recognized.. + /// + public static string SentenceBadFormatTokenError { + get { + return ResourceManager.GetString("SentenceBadFormatTokenError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Verb '{0}' is not recognized.. + /// + public static string SentenceBadVerbSelectedError { + get { + return ResourceManager.GetString("SentenceBadVerbSelectedError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ERROR(S):. + /// + public static string SentenceErrorsHeadingText { + get { + return ResourceManager.GetString("SentenceErrorsHeadingText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Display this help screen.. + /// + public static string SentenceHelpCommandTextOption { + get { + return ResourceManager.GetString("SentenceHelpCommandTextOption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Display more information on a specific command.. + /// + public static string SentenceHelpCommandTextVerb { + get { + return ResourceManager.GetString("SentenceHelpCommandTextVerb", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Required option '{0}' is missing.. + /// + public static string SentenceMissingRequiredOptionError { + get { + return ResourceManager.GetString("SentenceMissingRequiredOptionError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A required value not bound to option name is missing.. + /// + public static string SentenceMissingRequiredValueError { + get { + return ResourceManager.GetString("SentenceMissingRequiredValueError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Option '{0}' has no value.. + /// + public static string SentenceMissingValueOptionError { + get { + return ResourceManager.GetString("SentenceMissingValueOptionError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Options: {0} are not compatible with {1}.. + /// + public static string SentenceMutuallyExclusiveSetErrors { + get { + return ResourceManager.GetString("SentenceMutuallyExclusiveSetErrors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No verb selected.. + /// + public static string SentenceNoVerbSelectedError { + get { + return ResourceManager.GetString("SentenceNoVerbSelectedError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Group. + /// + public static string SentenceOptionGroupWord { + get { + return ResourceManager.GetString("SentenceOptionGroupWord", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Option '{0}' is defined multiple times.. + /// + public static string SentenceRepeatedOptionError { + get { + return ResourceManager.GetString("SentenceRepeatedOptionError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Required.. + /// + public static string SentenceRequiredWord { + get { + return ResourceManager.GetString("SentenceRequiredWord", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A sequence option '{0}' is defined with fewer or more items than required.. + /// + public static string SentenceSequenceOutOfRangeErrorOption { + get { + return ResourceManager.GetString("SentenceSequenceOutOfRangeErrorOption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A sequence value not bound to option name is defined with fewer items than required.. + /// + public static string SentenceSequenceOutOfRangeErrorValue { + get { + return ResourceManager.GetString("SentenceSequenceOutOfRangeErrorValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error setting value to option '{0}': {1}. + /// + public static string SentenceSetValueExceptionError { + get { + return ResourceManager.GetString("SentenceSetValueExceptionError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Option '{0}' is unknown.. + /// + public static string SentenceUnknownOptionError { + get { + return ResourceManager.GetString("SentenceUnknownOptionError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to USAGE:. + /// + public static string SentenceUsageHeadingText { + get { + return ResourceManager.GetString("SentenceUsageHeadingText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Display version information.. + /// + public static string SentenceVersionCommandText { + get { + return ResourceManager.GetString("SentenceVersionCommandText", resourceCulture); + } + } + /// /// Looks up a localized string similar to Open settings. /// diff --git a/src/WingetCreateCLI/Properties/Resources.resx b/src/WingetCreateCLI/Properties/Resources.resx index 0631b7fe..e7b55e9a 100644 --- a/src/WingetCreateCLI/Properties/Resources.resx +++ b/src/WingetCreateCLI/Properties/Resources.resx @@ -691,15 +691,12 @@ Multiple matches found for {0} {1} installer detected from the url: {2} {0} - will be replaced with installer architecture - {1} - will be replaced with the installer type - {2} - will be replaced with the installer No matches found for {0} {1} installer detected from url: {2} {0} - will be replaced with installer architecture - {1} - will be replaced with the installer type {2} - will be replaced with the installer @@ -961,7 +958,7 @@ Parsing nested installer '{0}' from {1} {0} - will be replaced with RelativeFilePath of the nested installer - {1} - will be replaced by the InstallerUrl +{1} - will be replaced by the InstallerUrl Nested installer not found in zip archive: {0}. Please use the interactive mode to update this package. @@ -1033,13 +1030,11 @@ Multiple matches found for "{0}" from {1}. Please use the interactive mode to update this package. {0} - will be replaced by the name of the nested installer file - {1} - will be replaced by the name of the zip archive. Multiple matches found for "{0}" from {1}. {0} - will be replaced by the name of the nested installer file - {1} - will be replaced by the name of the zip archive. @@ -1105,9 +1100,7 @@ Version {0} does not exist for {1} in the Windows Package Manager repository. {0} - will be replaced with the package version - -{1} - will be replaced with the package ID - +{1} - will be replaced with the package ID Optional. Package version used in conjunction with the replace argument to replace an older version of the manifest from the Windows Package Manager repo. @@ -1121,4 +1114,79 @@ Vanity URL detected. The submission will automatically replace the previous version. + + Option '{0}' is defined with a bad format. + {0} - will be replaced with the provided command-line option + + + A value not bound to option name is defined with a bad format. + + + Token '{0}' is not recognized. + {0} - will be replaced with the unrecognized command-line token + + + Verb '{0}' is not recognized. + {0} - will be replaced with the unrecognized command-line verb + + + ERROR(S): + + + Display this help screen. + + + Display more information on a specific command. + + + Required option '{0}' is missing. + {0} - will be replaced with the required command-line option + + + Option '{0}' has no value. + {0} - will be replaced with the provided command-line option + + + Options: {0} are not compatible with {1}. + {0} - will be replaced with one or more provided command-line option(s) +{1} - will be replaced with one or more provided command-line option(s) + + + No verb selected. + + + Group + + + Option '{0}' is defined multiple times. + {0} - will be replaced with the repeated command-line option + + + Required. + + + A sequence option '{0}' is defined with fewer or more items than required. + {0} - will be replaced with the provided command-line option + + + A sequence value not bound to option name is defined with fewer items than required. + + + Error setting value to option '{0}': {1} + {0} - will be replaced with the provided command-line option +{1} - will be replaced with the provided value for the command-line option + + + Option '{0}' is unknown. + {0} - will be replaced with the unrecognized command-line option + + + USAGE: + + + Display version information. + + + A required value not bound to option name is missing. + \ No newline at end of file