Skip to content

Commit 2f15c7e

Browse files
authored
Localization (#2041)
* make LocalizationResources internal and static * make sure LocalizationResources does not use any S.CL internals, so it can be included in the .Tests project * include LocalizationResources and S.CL resources in the test projects in order to be able to validate localized the strings in tests * add translations from SDK repo * remove unused LocalizationResources methods and resources
1 parent 8e8c69a commit 2f15c7e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+373
-955
lines changed

src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ System.CommandLine
8181
public static CommandLineBuilder UseHelp(this CommandLineBuilder builder, System.String[] helpAliases)
8282
public static CommandLineBuilder UseHelp(this CommandLineBuilder builder, System.Action<System.CommandLine.Help.HelpContext> customize, System.Nullable<System.Int32> maxWidth = null)
8383
public static TBuilder UseHelpBuilder<TBuilder>(this TBuilder builder, System.Func<System.CommandLine.Binding.BindingContext,System.CommandLine.Help.HelpBuilder> getHelpBuilder)
84-
public static CommandLineBuilder UseLocalizationResources(this CommandLineBuilder builder, LocalizationResources validationMessages)
8584
public static CommandLineBuilder UseParseDirective(this CommandLineBuilder builder, System.Int32 errorExitCode = 1)
8685
public static CommandLineBuilder UseParseErrorReporting(this CommandLineBuilder builder, System.Int32 errorExitCode = 1)
8786
public static CommandLineBuilder UseSuggestDirective(this CommandLineBuilder builder)
@@ -90,11 +89,10 @@ System.CommandLine
9089
public static CommandLineBuilder UseVersionOption(this CommandLineBuilder builder)
9190
public static CommandLineBuilder UseVersionOption(this CommandLineBuilder builder, System.String[] aliases)
9291
public class CommandLineConfiguration
93-
.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)
92+
.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)
9493
public System.Boolean EnableDirectives { get; }
9594
public System.Boolean EnablePosixBundling { get; }
9695
public System.Boolean EnableTokenReplacement { get; }
97-
public LocalizationResources LocalizationResources { get; }
9896
public Command RootCommand { get; }
9997
public System.Void ThrowIfInvalid()
10098
public class CommandLineConfigurationException : System.Exception, System.Runtime.Serialization.ISerializable
@@ -141,46 +139,6 @@ System.CommandLine
141139
public System.Collections.Generic.IReadOnlyCollection<System.String> Aliases { get; }
142140
public System.Void AddAlias(System.String alias)
143141
public System.Boolean HasAlias(System.String alias)
144-
public class LocalizationResources
145-
public static LocalizationResources Instance { get; }
146-
public System.String ArgumentConversionCannotParse(System.String value, System.Type expectedType)
147-
public System.String ArgumentConversionCannotParseForCommand(System.String value, System.String commandAlias, System.Type expectedType)
148-
public System.String ArgumentConversionCannotParseForCommand(System.String value, System.String commandAlias, System.Type expectedType, System.Collections.Generic.IEnumerable<System.String> completions)
149-
public System.String ArgumentConversionCannotParseForOption(System.String value, System.String optionAlias, System.Type expectedType)
150-
public System.String ArgumentConversionCannotParseForOption(System.String value, System.String optionAlias, System.Type expectedType, System.Collections.Generic.IEnumerable<System.String> completions)
151-
public System.String DirectoryDoesNotExist(System.String path)
152-
public System.String ErrorReadingResponseFile(System.String filePath, System.IO.IOException e)
153-
public System.String ExceptionHandlerHeader()
154-
public System.String ExpectsFewerArguments(System.CommandLine.Parsing.Token token, System.Int32 providedNumberOfValues, System.Int32 maximumNumberOfValues)
155-
public System.String ExpectsOneArgument(System.CommandLine.Parsing.SymbolResult symbolResult)
156-
public System.String FileDoesNotExist(System.String filePath)
157-
public System.String FileOrDirectoryDoesNotExist(System.String path)
158-
protected System.String GetResourceString(System.String resourceString, System.Object[] formatArguments)
159-
public System.String HelpAdditionalArgumentsDescription()
160-
public System.String HelpAdditionalArgumentsTitle()
161-
public System.String HelpArgumentDefaultValueLabel()
162-
public System.String HelpArgumentsTitle()
163-
public System.String HelpCommandsTitle()
164-
public System.String HelpDescriptionTitle()
165-
public System.String HelpOptionDescription()
166-
public System.String HelpOptionsRequiredLabel()
167-
public System.String HelpOptionsTitle()
168-
public System.String HelpUsageAdditionalArguments()
169-
public System.String HelpUsageCommand()
170-
public System.String HelpUsageOptions()
171-
public System.String HelpUsageTitle()
172-
public System.String InvalidCharactersInFileName(System.Char invalidChar)
173-
public System.String InvalidCharactersInPath(System.Char invalidChar)
174-
public System.String NoArgumentProvided(System.CommandLine.Parsing.SymbolResult symbolResult)
175-
public System.String RequiredArgumentMissing(System.CommandLine.Parsing.SymbolResult symbolResult)
176-
public System.String RequiredCommandWasNotProvided()
177-
public System.String RequiredOptionWasNotProvided(Option option)
178-
public System.String ResponseFileNotFound(System.String filePath)
179-
public System.String SuggestionsTokenNotMatched(System.String token)
180-
public System.String UnrecognizedArgument(System.String unrecognizedArg, System.Collections.Generic.IReadOnlyCollection<System.String> allowedValues)
181-
public System.String UnrecognizedCommandOrArgument(System.String arg)
182-
public System.String VersionOptionCannotBeCombinedWithOtherArguments(System.String optionAlias)
183-
public System.String VersionOptionDescription()
184142
public abstract class Option : IdentifierSymbol, System.CommandLine.Binding.IValueDescriptor
185143
public System.Boolean AllowMultipleArgumentsPerToken { get; set; }
186144
public System.Boolean AppliesToSelfAndChildren { get; set; }
@@ -284,8 +242,7 @@ System.CommandLine.Completions
284242
public class TokenCompletionContext : CompletionContext
285243
System.CommandLine.Help
286244
public class HelpBuilder
287-
.ctor(System.CommandLine.LocalizationResources localizationResources, System.Int32 maxWidth = 2147483647)
288-
public System.CommandLine.LocalizationResources LocalizationResources { get; }
245+
.ctor(System.Int32 maxWidth = 2147483647)
289246
public System.Int32 MaxWidth { get; }
290247
public System.Void CustomizeLayout(System.Func<HelpContext,System.Collections.Generic.IEnumerable<System.Action<HelpContext>>> getLayout)
291248
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)
@@ -329,7 +286,6 @@ System.CommandLine.Invocation
329286
public System.Int32 ExitCode { get; set; }
330287
public System.CommandLine.Help.HelpBuilder HelpBuilder { get; }
331288
public System.Action<InvocationContext> InvocationResult { get; set; }
332-
public System.CommandLine.LocalizationResources LocalizationResources { get; }
333289
public System.CommandLine.Parsing.Parser Parser { get; }
334290
public System.CommandLine.ParseResult ParseResult { get; set; }
335291
public T GetValue<T>(Option<T> option)
@@ -420,7 +376,6 @@ System.CommandLine.Parsing
420376
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)
421377
public static System.CommandLine.ParseResult Parse(this Parser parser, System.String commandLine)
422378
public abstract class SymbolResult
423-
public System.CommandLine.LocalizationResources LocalizationResources { get; }
424379
public SymbolResult Parent { get; }
425380
public System.Collections.Generic.IReadOnlyList<Token> Tokens { get; }
426381
public System.Void AddError(System.String errorMessage)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Globalization;
2+
using System.Linq;
3+
using Xunit;
4+
5+
namespace System.CommandLine.ApiCompatibility.Tests
6+
{
7+
public class LocalizationTests
8+
{
9+
private const string CommandName = "the-command";
10+
11+
[Theory]
12+
[InlineData("es", $"Falta el argumento requerido para el comando: '{CommandName}'.")]
13+
[InlineData("en-US", $"Required argument missing for command: '{CommandName}'.")]
14+
public void ErrorMessages_AreLocalized(string cultureName, string expectedMessage)
15+
{
16+
CultureInfo uiCultureBefore = CultureInfo.CurrentUICulture;
17+
18+
try
19+
{
20+
CultureInfo.CurrentUICulture = new CultureInfo(cultureName);
21+
22+
Command command = new(CommandName)
23+
{
24+
new Argument<string>()
25+
};
26+
27+
ParseResult parseResult = command.Parse(CommandName);
28+
29+
Assert.Equal(expectedMessage, parseResult.Errors.Single().Message);
30+
}
31+
finally
32+
{
33+
CultureInfo.CurrentUICulture = uiCultureBefore;
34+
}
35+
}
36+
}
37+
}

src/System.CommandLine.Tests/Help/HelpBuilderTests.Customization.cs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ public Customization()
2828
_indentation = new string(' ', IndentationWidth);
2929
}
3030

31-
private HelpBuilder GetHelpBuilder(int maxWidth) =>
32-
new(LocalizationResources.Instance,
33-
maxWidth);
31+
private HelpBuilder GetHelpBuilder(int maxWidth) => new (maxWidth);
3432

3533
[Fact]
3634
public void Option_can_customize_default_value()
@@ -89,7 +87,7 @@ public void Option_can_customize_first_column_text_based_on_parse_result()
8987
var optionAFirstColumnText = "option a help";
9088
var optionBFirstColumnText = "option b help";
9189

92-
var helpBuilder = new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth);
90+
var helpBuilder = new HelpBuilder(LargeMaxWidth);
9391
helpBuilder.CustomizeSymbol(option, firstColumnText: ctx =>
9492
ctx.Command.Equals(commandA)
9593
? optionAFirstColumnText
@@ -127,7 +125,7 @@ public void Option_can_customize_second_column_text_based_on_parse_result()
127125
var optionADescription = "option a help";
128126
var optionBDescription = "option b help";
129127

130-
var helpBuilder = new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth);
128+
var helpBuilder = new HelpBuilder(LargeMaxWidth);
131129
helpBuilder.CustomizeSymbol(option, secondColumnText: ctx =>
132130
ctx.Command.Equals(commandA)
133131
? optionADescription
@@ -226,7 +224,7 @@ public void Command_arguments_can_customize_default_value()
226224
[Fact]
227225
public void Customize_throws_when_symbol_is_null()
228226
{
229-
Action action = () => new HelpBuilder(LocalizationResources.Instance).CustomizeSymbol(null!, "");
227+
Action action = () => new HelpBuilder().CustomizeSymbol(null!, "");
230228
action.Should().Throw<ArgumentNullException>();
231229
}
232230

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

244242
command.Options.Add(option);
245243

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

281279
command.Arguments.Add(argument);
282280

283-
var helpBuilder = new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth);
281+
var helpBuilder = new HelpBuilder(LargeMaxWidth);
284282
helpBuilder.CustomizeSymbol(argument,
285283
firstColumnText: ctx => conditionA ? "custom 1st" : HelpBuilder.Default.GetArgumentUsageLabel(argument),
286284
secondColumnText: ctx => conditionB ? "custom 2nd" : HelpBuilder.Default.GetArgumentDescription(argument),
@@ -297,15 +295,5 @@ public void Argument_can_fallback_to_default_when_customizing(
297295
console.Out.ToString().Should().MatchRegex(expected);
298296
}
299297
}
300-
301-
private class CustomLocalizationResources : LocalizationResources
302-
{
303-
public string OverrideHelpDescriptionTitle { get; set; }
304-
305-
public override string HelpDescriptionTitle()
306-
{
307-
return OverrideHelpDescriptionTitle ?? base.HelpDescriptionTitle();
308-
}
309-
}
310298
}
311299
}

src/System.CommandLine.Tests/Help/HelpBuilderTests.cs

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ public HelpBuilderTests()
3333
_executableName = RootCommand.ExecutableName;
3434
}
3535

36-
private HelpBuilder GetHelpBuilder(int maxWidth = SmallMaxWidth) =>
37-
new(LocalizationResources.Instance,
38-
maxWidth);
36+
private HelpBuilder GetHelpBuilder(int maxWidth = SmallMaxWidth) => new(maxWidth);
3937

4038
#region Synopsis
4139

@@ -93,26 +91,6 @@ public void Command_name_in_synopsis_can_be_specified()
9391
_console.ToString().Should().NotContain(_executableName);
9492
}
9593

96-
[Fact]
97-
public void Synopsis_section_properly_uses_localized_HelpDescriptionTitle()
98-
{
99-
var command = new RootCommand("test description");
100-
101-
var customLocalization = new CustomLocalizationResources
102-
{
103-
OverrideHelpDescriptionTitle = "Custom Description:"
104-
};
105-
HelpBuilder helpBuilder = new(
106-
customLocalization,
107-
LargeMaxWidth
108-
);
109-
helpBuilder.Write(command, _console);
110-
111-
var expected = $"Custom Description:{NewLine}{_indentation}test description{NewLine}";
112-
113-
_console.ToString().Should().Contain(expected);
114-
}
115-
11694
#endregion Synopsis
11795

11896
#region Usage
@@ -146,7 +124,7 @@ public void Usage_section_shows_arguments_if_there_are_arguments_for_command_whe
146124
var rootCommand = new RootCommand();
147125
rootCommand.Subcommands.Add(command);
148126

149-
new HelpBuilder(LocalizationResources.Instance, LargeMaxWidth).Write(command, _console);
127+
new HelpBuilder(LargeMaxWidth).Write(command, _console);
150128

151129
var expected =
152130
$"Usage:{NewLine}" +
@@ -1638,7 +1616,7 @@ public void Help_describes_default_values_for_subcommand_with_multiple_defaultab
16381616
[InlineData(int.MinValue)]
16391617
public void Constructor_ignores_non_positive_max_width(int maxWidth)
16401618
{
1641-
var helpBuilder = new HelpBuilder(LocalizationResources.Instance, maxWidth);
1619+
var helpBuilder = new HelpBuilder(maxWidth);
16421620
Assert.Equal(int.MaxValue, helpBuilder.MaxWidth);
16431621
}
16441622

@@ -1651,14 +1629,13 @@ public void Commands_without_arguments_do_not_produce_extra_newlines_between_usa
16511629
};
16521630

16531631
var helpBuilder = GetHelpBuilder();
1654-
var resources = helpBuilder.LocalizationResources;
16551632

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

16591636
var output = writer.ToString();
16601637

1661-
output.Should().Contain($"{resources.HelpUsageOptions()}{NewLine}{NewLine}{resources.HelpOptionsTitle()}");
1638+
output.Should().Contain($"{LocalizationResources.HelpUsageOptions()}{NewLine}{NewLine}{LocalizationResources.HelpOptionsTitle()}");
16621639
}
16631640
}
16641641
}

src/System.CommandLine.Tests/Invocation/InvocationPipelineTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ public async Task When_help_builder_factory_is_specified_it_is_used_to_create_th
320320
.UseHelpBuilder(context =>
321321
{
322322
factoryWasCalled = true;
323-
return createdHelpBuilder = new HelpBuilder(context.ParseResult.Parser.Configuration.LocalizationResources);
323+
return createdHelpBuilder = new HelpBuilder();
324324
})
325325
.Build();
326326

src/System.CommandLine.Tests/OptionTests.MultipleArgumentsPerToken.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ public void Subsequent_matched_arguments_result_in_errors()
191191
var result = command.Parse("--option 1 2");
192192

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

197197
[Fact]

src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ public void When_there_are_not_enough_tokens_for_all_arguments_then_the_correct_
307307
var numberOfMissingArgs =
308308
result
309309
.Errors
310-
.Count(e => e.Message == LocalizationResources.Instance.RequiredArgumentMissing(result.CommandResult));
310+
.Count(e => e.Message == LocalizationResources.RequiredArgumentMissing(result.CommandResult));
311311

312312
numberOfMissingArgs
313313
.Should()

src/System.CommandLine.Tests/ParserTests.RootCommandAndArg0.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void When_parsing_a_string_array_input_then_a_full_path_to_an_executable_
4646
parserResult
4747
.Errors
4848
.Should()
49-
.ContainSingle(e => e.Message == LocalizationResources.Instance.UnrecognizedCommandOrArgument(RootCommand.ExecutablePath));
49+
.ContainSingle(e => e.Message == LocalizationResources.UnrecognizedCommandOrArgument(RootCommand.ExecutablePath));
5050
}
5151

5252
[Fact]

0 commit comments

Comments
 (0)