Merge pull request #7021 from nguerrera/loc-override

Allow CLI UI language to be overridden by an environment variable
This commit is contained in:
Nick Guerrera 2017-07-19 13:28:12 -07:00 committed by GitHub
commit 86d9577606
8 changed files with 111 additions and 11 deletions

View file

@ -28,6 +28,7 @@ namespace Microsoft.DotNet.Cli.Build
private IEnumerable<string> _environmentVariablesToKeep = new string []
{
"DOTNET_CLI_TELEMETRY_SESSIONID",
"DOTNET_CLI_UI_LANGUAGE",
"DOTNET_MULTILEVEL_LOOKUP",
"DOTNET_RUNTIME_ID",
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE",

View file

@ -7,7 +7,7 @@ namespace Microsoft.DotNet.Cli.Utils
{
public class Product
{
public static readonly string LongName = LocalizableStrings.DotNetCommandLineTools;
public static string LongName => LocalizableStrings.DotNetCommandLineTools;
public static readonly string Version = GetProductVersion();
private static string GetProductVersion()

View file

@ -198,6 +198,8 @@ namespace Microsoft.DotNet.Cli
// by default, .NET Core doesn't have all code pages needed for Console apps.
// see the .NET Core Notes in https://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
UILanguageOverride.Setup();
}
internal static bool TryGetBuiltInCommand(string commandName, out BuiltInCommandMetadata builtInCommand)

View file

@ -0,0 +1,81 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Globalization;
namespace Microsoft.DotNet.Cli
{
internal static class UILanguageOverride
{
private const string DOTNET_CLI_UI_LANGUAGE = nameof(DOTNET_CLI_UI_LANGUAGE);
private const string VSLANG = nameof(VSLANG);
private const string PreferredUILang = nameof(PreferredUILang);
public static void Setup()
{
CultureInfo language = GetOverriddenUILanguage();
if (language != null)
{
ApplyOverrideToCurrentProcess(language);
FlowOverrideToChildProcesses(language);
}
}
private static void ApplyOverrideToCurrentProcess(CultureInfo language)
{
CultureInfo.DefaultThreadCurrentUICulture = language;
}
private static void FlowOverrideToChildProcesses(CultureInfo language)
{
// Do not override any environment variables that are already set as we do not want to clobber a more granular setting with our global setting.
SetIfNotAlreadySet(DOTNET_CLI_UI_LANGUAGE, language.Name);
SetIfNotAlreadySet(VSLANG, language.LCID); // for tools following VS guidelines to just work in CLI
SetIfNotAlreadySet(PreferredUILang, language.Name); // for C#/VB targets that pass $(PreferredUILang) to compiler
}
private static CultureInfo GetOverriddenUILanguage()
{
// DOTNET_CLI_UI_LANGUAGE=<culture name> is the main way for users to customize the CLI's UI language.
string dotnetCliLanguage = Environment.GetEnvironmentVariable(DOTNET_CLI_UI_LANGUAGE);
if (dotnetCliLanguage != null)
{
try
{
return new CultureInfo(dotnetCliLanguage);
}
catch (CultureNotFoundException) { }
}
// VSLANG=<lcid> is set by VS and we respect that as well so that we will respect the VS
// language preference if we're invoked by VS.
string vsLang = Environment.GetEnvironmentVariable(VSLANG);
if (vsLang != null && int.TryParse(vsLang, out int vsLcid))
{
try
{
return new CultureInfo(vsLcid);
}
catch (ArgumentOutOfRangeException) { }
catch (CultureNotFoundException) { }
}
return null;
}
private static void SetIfNotAlreadySet(string environmentVariableName, string value)
{
string currentValue = Environment.GetEnvironmentVariable(environmentVariableName);
if (currentValue == null)
{
Environment.SetEnvironmentVariable(environmentVariableName, value);
}
}
private static void SetIfNotAlreadySet(string environmentVariableName, int value)
{
SetIfNotAlreadySet(environmentVariableName, value.ToString());
}
}
}

View file

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -23,6 +24,15 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private TempRoot _temp;
private static TestAssets s_testAssets;
static TestBase()
{
// set culture of test process to match CLI sub-processes when the UI language is overriden.
string overriddenUILanguage = Environment.GetEnvironmentVariable("DOTNET_CLI_UI_LANGUAGE");
if (overriddenUILanguage != null)
{
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(overriddenUILanguage);
}
}
protected static string RepoRoot
{

View file

@ -7,7 +7,7 @@ using Xunit;
namespace Microsoft.DotNet.New.Tests
{
public class NewCommandTests
public class NewCommandTests : TestBase
{
[Fact]
public void WhenSwitchIsSkippedThenItPrintsError()
@ -16,7 +16,10 @@ namespace Microsoft.DotNet.New.Tests
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().StartWith("No templates matched the input template name: Web1.1.");
if (!DotnetUnderTest.IsLocalized())
{
cmd.StdErr.Should().StartWith("No templates matched the input template name: Web1.1.");
}
}
[Fact]
@ -26,7 +29,10 @@ namespace Microsoft.DotNet.New.Tests
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().StartWith("Unable to determine the desired template from the input template name: c.");
if (!DotnetUnderTest.IsLocalized())
{
cmd.StdErr.Should().StartWith("Unable to determine the desired template from the input template name: c.");
}
}
}
}

View file

@ -7,6 +7,8 @@ using Microsoft.DotNet.TestFramework;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
using LocalizableStrings = Microsoft.DotNet.Tools.Run.LocalizableStrings;
namespace Microsoft.DotNet.Cli.Run.Tests
{
public class GivenDotnetRunBuildsCsproj : TestBase
@ -280,7 +282,7 @@ namespace Microsoft.DotNet.Cli.Run.Tests
.ExecuteWithCapturedOutput("--launch-profile test")
.Should().Pass()
.And.HaveStdOutContaining("Hello World!")
.And.HaveStdErrContaining("The specified launch profile could not be located.");
.And.HaveStdErrContaining(LocalizableStrings.RunCommandExceptionCouldNotLocateALaunchSettingsFile);
}
[Fact]
@ -368,7 +370,7 @@ namespace Microsoft.DotNet.Cli.Run.Tests
.ExecuteWithCapturedOutput("--launch-profile Third")
.Should().Pass()
.And.HaveStdOutContaining("(NO MESSAGE)")
.And.HaveStdErrContaining("The launch profile \"Third\" could not be applied.");
.And.HaveStdErrContaining(string.Format(LocalizableStrings.RunCommandExceptionCouldNotApplyLaunchSettings, "Third", "").Trim());
}
[Fact]
@ -396,7 +398,7 @@ namespace Microsoft.DotNet.Cli.Run.Tests
.ExecuteWithCapturedOutput("--launch-profile \"IIS Express\"")
.Should().Pass()
.And.HaveStdOutContaining("(NO MESSAGE)")
.And.HaveStdErrContaining("The launch profile \"IIS Express\" could not be applied.");
.And.HaveStdErrContaining(string.Format(LocalizableStrings.RunCommandExceptionCouldNotApplyLaunchSettings, "IIS Express", "").Trim());
}
[Fact]
@ -485,7 +487,7 @@ namespace Microsoft.DotNet.Cli.Run.Tests
cmd.Should().Pass()
.And.HaveStdOutContaining("(NO MESSAGE)")
.And.HaveStdErrContaining("The launch profile \"(Default)\" could not be applied.");
.And.HaveStdErrContaining(string.Format(LocalizableStrings.RunCommandExceptionCouldNotApplyLaunchSettings, LocalizableStrings.DefaultLaunchProfileDisplayName, "").Trim());
}
[Fact]
@ -514,7 +516,7 @@ namespace Microsoft.DotNet.Cli.Run.Tests
cmd.Should().Pass()
.And.HaveStdOutContaining("(NO MESSAGE)")
.And.HaveStdErrContaining("The launch profile \"(Default)\" could not be applied.");
.And.HaveStdErrContaining(string.Format(LocalizableStrings.RunCommandExceptionCouldNotApplyLaunchSettings, LocalizableStrings.DefaultLaunchProfileDisplayName, "").Trim());
}
}
}

View file

@ -11,8 +11,6 @@ namespace Microsoft.DotNet.Tests.ParserTests
{
public class ValidationMessageTests
{
private readonly ITestOutputHelper output;
[Fact]
public void ValidationMessagesFormatCorrectly()
{