Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localization #2041

Merged
merged 9 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ System.CommandLine
public static CommandLineBuilder UseHelp(this CommandLineBuilder builder, System.String[] helpAliases)
public static CommandLineBuilder UseHelp(this CommandLineBuilder builder, System.Action<System.CommandLine.Help.HelpContext> customize, System.Nullable<System.Int32> maxWidth = null)
public static TBuilder UseHelpBuilder<TBuilder>(this TBuilder builder, System.Func<System.CommandLine.Binding.BindingContext,System.CommandLine.Help.HelpBuilder> getHelpBuilder)
public static CommandLineBuilder UseLocalizationResources(this CommandLineBuilder builder, LocalizationResources validationMessages)
public static CommandLineBuilder UseParseDirective(this CommandLineBuilder builder, System.Int32 errorExitCode = 1)
public static CommandLineBuilder UseParseErrorReporting(this CommandLineBuilder builder, System.Int32 errorExitCode = 1)
public static CommandLineBuilder UseSuggestDirective(this CommandLineBuilder builder)
Expand All @@ -90,11 +89,10 @@ System.CommandLine
public static CommandLineBuilder UseVersionOption(this CommandLineBuilder builder)
public static CommandLineBuilder UseVersionOption(this CommandLineBuilder builder, System.String[] aliases)
public class CommandLineConfiguration
.ctor(Command command, System.Boolean enablePosixBundling = True, System.Boolean enableDirectives = True, System.Boolean enableTokenReplacement = True, LocalizationResources resources = null, System.Collections.Generic.IReadOnlyList<System.CommandLine.Invocation.InvocationMiddleware> middlewarePipeline = null, System.Func<System.CommandLine.Binding.BindingContext,System.CommandLine.Help.HelpBuilder> helpBuilderFactory = null, System.CommandLine.Parsing.TryReplaceToken tokenReplacer = null)
.ctor(Command command, System.Boolean enablePosixBundling = True, System.Boolean enableDirectives = True, System.Boolean enableTokenReplacement = True, System.Collections.Generic.IReadOnlyList<System.CommandLine.Invocation.InvocationMiddleware> middlewarePipeline = null, System.Func<System.CommandLine.Binding.BindingContext,System.CommandLine.Help.HelpBuilder> helpBuilderFactory = null, System.CommandLine.Parsing.TryReplaceToken tokenReplacer = null)
public System.Boolean EnableDirectives { get; }
public System.Boolean EnablePosixBundling { get; }
public System.Boolean EnableTokenReplacement { get; }
public LocalizationResources LocalizationResources { get; }
public Command RootCommand { get; }
public System.Void ThrowIfInvalid()
public class CommandLineConfigurationException : System.Exception, System.Runtime.Serialization.ISerializable
Expand Down Expand Up @@ -141,46 +139,6 @@ System.CommandLine
public System.Collections.Generic.IReadOnlyCollection<System.String> Aliases { get; }
public System.Void AddAlias(System.String alias)
public System.Boolean HasAlias(System.String alias)
public class LocalizationResources
public static LocalizationResources Instance { get; }
public System.String ArgumentConversionCannotParse(System.String value, System.Type expectedType)
public System.String ArgumentConversionCannotParseForCommand(System.String value, System.String commandAlias, System.Type expectedType)
public System.String ArgumentConversionCannotParseForCommand(System.String value, System.String commandAlias, System.Type expectedType, System.Collections.Generic.IEnumerable<System.String> completions)
public System.String ArgumentConversionCannotParseForOption(System.String value, System.String optionAlias, System.Type expectedType)
public System.String ArgumentConversionCannotParseForOption(System.String value, System.String optionAlias, System.Type expectedType, System.Collections.Generic.IEnumerable<System.String> completions)
public System.String DirectoryDoesNotExist(System.String path)
public System.String ErrorReadingResponseFile(System.String filePath, System.IO.IOException e)
public System.String ExceptionHandlerHeader()
public System.String ExpectsFewerArguments(System.CommandLine.Parsing.Token token, System.Int32 providedNumberOfValues, System.Int32 maximumNumberOfValues)
public System.String ExpectsOneArgument(System.CommandLine.Parsing.SymbolResult symbolResult)
public System.String FileDoesNotExist(System.String filePath)
public System.String FileOrDirectoryDoesNotExist(System.String path)
protected System.String GetResourceString(System.String resourceString, System.Object[] formatArguments)
public System.String HelpAdditionalArgumentsDescription()
public System.String HelpAdditionalArgumentsTitle()
public System.String HelpArgumentDefaultValueLabel()
public System.String HelpArgumentsTitle()
public System.String HelpCommandsTitle()
public System.String HelpDescriptionTitle()
public System.String HelpOptionDescription()
public System.String HelpOptionsRequiredLabel()
public System.String HelpOptionsTitle()
public System.String HelpUsageAdditionalArguments()
public System.String HelpUsageCommand()
public System.String HelpUsageOptions()
public System.String HelpUsageTitle()
public System.String InvalidCharactersInFileName(System.Char invalidChar)
public System.String InvalidCharactersInPath(System.Char invalidChar)
public System.String NoArgumentProvided(System.CommandLine.Parsing.SymbolResult symbolResult)
public System.String RequiredArgumentMissing(System.CommandLine.Parsing.SymbolResult symbolResult)
public System.String RequiredCommandWasNotProvided()
public System.String RequiredOptionWasNotProvided(Option option)
public System.String ResponseFileNotFound(System.String filePath)
public System.String SuggestionsTokenNotMatched(System.String token)
public System.String UnrecognizedArgument(System.String unrecognizedArg, System.Collections.Generic.IReadOnlyCollection<System.String> allowedValues)
public System.String UnrecognizedCommandOrArgument(System.String arg)
public System.String VersionOptionCannotBeCombinedWithOtherArguments(System.String optionAlias)
public System.String VersionOptionDescription()
public abstract class Option : IdentifierSymbol, System.CommandLine.Binding.IValueDescriptor
public System.Boolean AllowMultipleArgumentsPerToken { get; set; }
public System.Boolean AppliesToSelfAndChildren { get; set; }
Expand Down Expand Up @@ -284,8 +242,7 @@ System.CommandLine.Completions
public class TokenCompletionContext : CompletionContext
System.CommandLine.Help
public class HelpBuilder
.ctor(System.CommandLine.LocalizationResources localizationResources, System.Int32 maxWidth = 2147483647)
public System.CommandLine.LocalizationResources LocalizationResources { get; }
.ctor(System.Int32 maxWidth = 2147483647)
public System.Int32 MaxWidth { get; }
public System.Void CustomizeLayout(System.Func<HelpContext,System.Collections.Generic.IEnumerable<System.Action<HelpContext>>> getLayout)
public System.Void CustomizeSymbol(System.CommandLine.Symbol symbol, System.Func<HelpContext,System.String> firstColumnText = null, System.Func<HelpContext,System.String> secondColumnText = null, System.Func<HelpContext,System.String> defaultValue = null)
Expand Down Expand Up @@ -329,7 +286,6 @@ System.CommandLine.Invocation
public System.Int32 ExitCode { get; set; }
public System.CommandLine.Help.HelpBuilder HelpBuilder { get; }
public System.Action<InvocationContext> InvocationResult { get; set; }
public System.CommandLine.LocalizationResources LocalizationResources { get; }
public System.CommandLine.Parsing.Parser Parser { get; }
public System.CommandLine.ParseResult ParseResult { get; set; }
public T GetValue<T>(Option<T> option)
Expand Down Expand Up @@ -420,7 +376,6 @@ System.CommandLine.Parsing
public static System.Threading.Tasks.Task<System.Int32> InvokeAsync(this Parser parser, System.String[] args, System.CommandLine.IConsole console = null, System.Threading.CancellationToken cancellationToken = null)
public static System.CommandLine.ParseResult Parse(this Parser parser, System.String commandLine)
public abstract class SymbolResult
public System.CommandLine.LocalizationResources LocalizationResources { get; }
public SymbolResult Parent { get; }
public System.Collections.Generic.IReadOnlyList<Token> Tokens { get; }
public System.Void AddError(System.String errorMessage)
Expand Down
37 changes: 37 additions & 0 deletions src/System.CommandLine.ApiCompatibility.Tests/LocalizationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Globalization;
using System.Linq;
using Xunit;

namespace System.CommandLine.ApiCompatibility.Tests
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added this type to a different project than System.CommandLine.Tests to ensure that it does not use the resources included in that project.

{
public class LocalizationTests
{
private const string CommandName = "the-command";

[Theory]
[InlineData("es", $"Falta el argumento requerido para el comando: '{CommandName}'.")]
[InlineData("en-US", $"Required argument missing for command: '{CommandName}'.")]
public void ErrorMessages_AreLocalized(string cultureName, string expectedMessage)
{
CultureInfo uiCultureBefore = CultureInfo.CurrentUICulture;

try
{
CultureInfo.CurrentUICulture = new CultureInfo(cultureName);

Command command = new(CommandName)
{
new Argument<string>()
};

ParseResult parseResult = command.Parse(CommandName);

Assert.Equal(expectedMessage, parseResult.Errors.Single().Message);
}
finally
{
CultureInfo.CurrentUICulture = uiCultureBefore;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ public Customization()
_indentation = new string(' ', IndentationWidth);
}

private HelpBuilder GetHelpBuilder(int maxWidth) =>
new(LocalizationResources.Instance,
maxWidth);
private HelpBuilder GetHelpBuilder(int maxWidth) => new (maxWidth);

[Fact]
public void Option_can_customize_default_value()
Expand Down Expand Up @@ -89,7 +87,7 @@ public void Option_can_customize_first_column_text_based_on_parse_result()
var optionAFirstColumnText = "option a help";
var optionBFirstColumnText = "option b help";

var helpBuilder = new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth);
var helpBuilder = new HelpBuilder(LargeMaxWidth);
helpBuilder.CustomizeSymbol(option, firstColumnText: ctx =>
ctx.Command.Equals(commandA)
? optionAFirstColumnText
Expand Down Expand Up @@ -127,7 +125,7 @@ public void Option_can_customize_second_column_text_based_on_parse_result()
var optionADescription = "option a help";
var optionBDescription = "option b help";

var helpBuilder = new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth);
var helpBuilder = new HelpBuilder(LargeMaxWidth);
helpBuilder.CustomizeSymbol(option, secondColumnText: ctx =>
ctx.Command.Equals(commandA)
? optionADescription
Expand Down Expand Up @@ -226,7 +224,7 @@ public void Command_arguments_can_customize_default_value()
[Fact]
public void Customize_throws_when_symbol_is_null()
{
Action action = () => new HelpBuilder(LocalizationResources.Instance).CustomizeSymbol(null!, "");
Action action = () => new HelpBuilder().CustomizeSymbol(null!, "");
action.Should().Throw<ArgumentNullException>();
}

Expand All @@ -243,7 +241,7 @@ public void Option_can_fallback_to_default_when_customizing(bool conditionA, boo

command.Options.Add(option);

var helpBuilder = new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth);
var helpBuilder = new HelpBuilder(LargeMaxWidth);
helpBuilder.CustomizeSymbol(option,
firstColumnText: ctx => conditionA ? "custom 1st" : HelpBuilder.Default.GetIdentifierSymbolUsageLabel(option, ctx),
secondColumnText: ctx => conditionB ? "custom 2nd" : HelpBuilder.Default.GetIdentifierSymbolDescription(option));
Expand Down Expand Up @@ -280,7 +278,7 @@ public void Argument_can_fallback_to_default_when_customizing(

command.Arguments.Add(argument);

var helpBuilder = new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth);
var helpBuilder = new HelpBuilder(LargeMaxWidth);
helpBuilder.CustomizeSymbol(argument,
firstColumnText: ctx => conditionA ? "custom 1st" : HelpBuilder.Default.GetArgumentUsageLabel(argument),
secondColumnText: ctx => conditionB ? "custom 2nd" : HelpBuilder.Default.GetArgumentDescription(argument),
Expand All @@ -297,15 +295,5 @@ public void Argument_can_fallback_to_default_when_customizing(
console.Out.ToString().Should().MatchRegex(expected);
}
}

private class CustomLocalizationResources : LocalizationResources
{
public string OverrideHelpDescriptionTitle { get; set; }

public override string HelpDescriptionTitle()
{
return OverrideHelpDescriptionTitle ?? base.HelpDescriptionTitle();
}
}
}
}
31 changes: 4 additions & 27 deletions src/System.CommandLine.Tests/Help/HelpBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ public HelpBuilderTests()
_executableName = RootCommand.ExecutableName;
}

private HelpBuilder GetHelpBuilder(int maxWidth = SmallMaxWidth) =>
new(LocalizationResources.Instance,
maxWidth);
private HelpBuilder GetHelpBuilder(int maxWidth = SmallMaxWidth) => new(maxWidth);

#region Synopsis

Expand Down Expand Up @@ -93,26 +91,6 @@ public void Command_name_in_synopsis_can_be_specified()
_console.ToString().Should().NotContain(_executableName);
}

[Fact]
public void Synopsis_section_properly_uses_localized_HelpDescriptionTitle()
{
var command = new RootCommand("test description");

var customLocalization = new CustomLocalizationResources
{
OverrideHelpDescriptionTitle = "Custom Description:"
};
HelpBuilder helpBuilder = new(
customLocalization,
LargeMaxWidth
);
helpBuilder.Write(command, _console);

var expected = $"Custom Description:{NewLine}{_indentation}test description{NewLine}";

_console.ToString().Should().Contain(expected);
}

#endregion Synopsis

#region Usage
Expand Down Expand Up @@ -146,7 +124,7 @@ public void Usage_section_shows_arguments_if_there_are_arguments_for_command_whe
var rootCommand = new RootCommand();
rootCommand.Subcommands.Add(command);

new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth).Write(command, _console);
new HelpBuilder(LargeMaxWidth).Write(command, _console);

var expected =
$"Usage:{NewLine}" +
Expand Down Expand Up @@ -1638,7 +1616,7 @@ public void Help_describes_default_values_for_subcommand_with_multiple_defaultab
[InlineData(int.MinValue)]
public void Constructor_ignores_non_positive_max_width(int maxWidth)
{
var helpBuilder = new HelpBuilder(LocalizationResources.Instance, maxWidth);
var helpBuilder = new HelpBuilder(maxWidth);
Assert.Equal(int.MaxValue, helpBuilder.MaxWidth);
}

Expand All @@ -1651,14 +1629,13 @@ public void Commands_without_arguments_do_not_produce_extra_newlines_between_usa
};

var helpBuilder = GetHelpBuilder();
var resources = helpBuilder.LocalizationResources;

using var writer = new StringWriter();
helpBuilder.Write(command, writer);

var output = writer.ToString();

output.Should().Contain($"{resources.HelpUsageOptions()}{NewLine}{NewLine}{resources.HelpOptionsTitle()}");
output.Should().Contain($"{LocalizationResources.HelpUsageOptions()}{NewLine}{NewLine}{LocalizationResources.HelpOptionsTitle()}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ public async Task When_help_builder_factory_is_specified_it_is_used_to_create_th
.UseHelpBuilder(context =>
{
factoryWasCalled = true;
return createdHelpBuilder = new HelpBuilder(context.ParseResult.Parser.Configuration.LocalizationResources);
return createdHelpBuilder = new HelpBuilder();
})
.Build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public void Subsequent_matched_arguments_result_in_errors()
var result = command.Parse("--option 1 2");

result.UnmatchedTokens.Should().BeEquivalentTo(new[] { "2" });
result.Errors.Should().Contain(e => e.Message == LocalizationResources.Instance.UnrecognizedCommandOrArgument("2"));
result.Errors.Should().Contain(e => e.Message == LocalizationResources.UnrecognizedCommandOrArgument("2"));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ public void When_there_are_not_enough_tokens_for_all_arguments_then_the_correct_
var numberOfMissingArgs =
result
.Errors
.Count(e => e.Message == LocalizationResources.Instance.RequiredArgumentMissing(result.CommandResult));
.Count(e => e.Message == LocalizationResources.RequiredArgumentMissing(result.CommandResult));

numberOfMissingArgs
.Should()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void When_parsing_a_string_array_input_then_a_full_path_to_an_executable_
parserResult
.Errors
.Should()
.ContainSingle(e => e.Message == LocalizationResources.Instance.UnrecognizedCommandOrArgument(RootCommand.ExecutablePath));
.ContainSingle(e => e.Message == LocalizationResources.UnrecognizedCommandOrArgument(RootCommand.ExecutablePath));
}

[Fact]
Expand Down
Loading