Skip to content

Commit

Permalink
Add support for aliased cultures
Browse files Browse the repository at this point in the history
  • Loading branch information
0xced committed Jan 4, 2021
1 parent 1c88d13 commit d406b08
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 1 deletion.
50 changes: 50 additions & 0 deletions src/Tasks.UnitTests/AssignCulture_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,56 @@ public void PseudoLocalization(string culture)
Assert.Equal($"MyResource.{culture}.resx", t.AssignedFiles[0].ItemSpec);
Assert.Equal("MyResource.resx", t.CultureNeutralAssignedFiles[0].ItemSpec);
}

/*
* Method: AliasedCulture
*
* Test that an aliased culture (e.g. zh-CN or zh-TW) which is _not_ returned by CultureInfo.GetCultures(CultureTypes.AllCultures)
* on Unix-based systems is still considered valid.
* See also https://github.com/dotnet/msbuild/issues/3897 (Cultures aliased by ICU cannot be used for resource localization on non-Windows environments)
*/
[Theory]
[InlineData("zh-CN")]
[InlineData("zh-TW")]
public void AliasedCulture(string culture)
{
AssignCulture t = new AssignCulture();
t.BuildEngine = new MockEngine();
ITaskItem i = new TaskItem($"MyResource.{culture}.resx");
t.Files = new ITaskItem[] { i };
t.Execute();

Assert.Single(t.AssignedFiles);
Assert.Single(t.CultureNeutralAssignedFiles);
Assert.Equal(culture, t.AssignedFiles[0].GetMetadata("Culture"));
Assert.Equal($"MyResource.{culture}.resx", t.AssignedFiles[0].ItemSpec);
Assert.Equal("MyResource.resx", t.CultureNeutralAssignedFiles[0].ItemSpec);
}

/*
* Method: InvalidCulture
*
* Test for invalid culture (i.e. throwing an exception when using new CultureInfo())
* and unknown culture (i.e. a culture not known by the operating system but which can be created with new CultureInfo())
*/
[Theory]
[InlineData("\U0001F4A5")]
[InlineData("xx")]
public void InvalidCulture(string culture)
{
AssignCulture t = new AssignCulture();
t.BuildEngine = new MockEngine();
ITaskItem i = new TaskItem($"MyResource.{culture}.resx");
t.Files = new ITaskItem[] { i };
t.Execute();

Assert.Single(t.AssignedFiles);
Assert.Single(t.CultureNeutralAssignedFiles);
Assert.Equal(String.Empty, t.AssignedFiles[0].GetMetadata("Culture"));
Assert.Equal("false", t.AssignedFiles[0].GetMetadata("WithCulture"));
Assert.Equal($"MyResource.{culture}.resx", t.AssignedFiles[0].ItemSpec);
Assert.Equal($"MyResource.{culture}.resx", t.CultureNeutralAssignedFiles[0].ItemSpec);
}
}
}

Expand Down
32 changes: 31 additions & 1 deletion src/Tasks/CultureInfoCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ namespace Microsoft.Build.Tasks
internal static class CultureInfoCache
{
private static readonly HashSet<string> ValidCultureNames;
private static readonly HashSet<string> InvalidCultureNames;

static CultureInfoCache()
{
ValidCultureNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
InvalidCultureNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

#if !FEATURE_CULTUREINFO_GETCULTURES
if (!AssemblyUtilities.CultureInfoHasGetCultures())
Expand Down Expand Up @@ -55,7 +57,35 @@ static CultureInfoCache()
/// <returns>True if the culture is determined to be valid.</returns>
internal static bool IsValidCultureString(string name)
{
return ValidCultureNames.Contains(name);
var isValid = ValidCultureNames.Contains(name);
if (isValid)
return true;

var isInvalid = InvalidCultureNames.Contains(name);
if (isInvalid)
return false;

CultureInfo culture;
try
{
culture = new CultureInfo(name);
}
catch (Exception)
{
InvalidCultureNames.Add(name);
return false;
}

// See https://docs.microsoft.com/en-us/dotnet/api/System.Globalization.CultureInfo.LCID#remarks
const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
if (culture.LCID == LOCALE_CUSTOM_UNSPECIFIED)
{
InvalidCultureNames.Add(name);
return false;
}

ValidCultureNames.Add(name);
return true;
}

#if !FEATURE_CULTUREINFO_GETCULTURES
Expand Down

0 comments on commit d406b08

Please sign in to comment.