Skip to content

Commit edb1d2f

Browse files
authored
Expand Locale parser to support three-character language codes (#6124)
1 parent d02004a commit edb1d2f

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

src/NuGet.Core/NuGet.Packaging/ContentModel/ManagedCodeConventions.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ private static object CodeLanguage_Parser(ReadOnlyMemory<char> name, PatternTabl
160160
/// If matchOnly is true, then an empty string may be returned as a performance optimization.
161161
/// If matchOnly is false, the parsed result will be returned.
162162
/// </summary>
163-
private static object Locale_Parser(ReadOnlyMemory<char> name, PatternTable table, bool matchOnly)
163+
internal static object Locale_Parser(ReadOnlyMemory<char> name, PatternTable table, bool matchOnly)
164164
{
165165
if (table != null)
166166
{
@@ -171,22 +171,40 @@ private static object Locale_Parser(ReadOnlyMemory<char> name, PatternTable tabl
171171
}
172172
}
173173

174-
if (name.Length == 2)
174+
// We use a heuristic here for common locale codes. Locale codes are often
175+
// * two characters for the language: en, es, fr, de
176+
// * three characters for the language: agq
177+
if (name.Length == 2 || name.Length == 3)
175178
{
176179
if (matchOnly)
177180
{
178181
return string.Empty;
179182
}
180183
return name.ToString();
181184
}
182-
else if (name.Length >= 4 && name.Span[2] == '-')
185+
186+
// * a language portion that is two or three characters followed by a '-' and a country code
187+
else if (name.Length >= 4 && name.Span[2] == '-') // e.g. en-US
183188
{
184189
if (matchOnly)
185190
{
186191
return string.Empty;
187192
}
188193
return name.ToString();
189194
}
195+
else if (name.Length >= 5 && name.Span[3] == '-') // e.g agq-CM
196+
{
197+
if (matchOnly)
198+
{
199+
return string.Empty;
200+
}
201+
return name.ToString();
202+
}
203+
204+
// there are other variations, but this heuristic doesn't cover them all. A future-proof implementation would make
205+
// use of the .NET CultureInfo APIs to compare the locale against the underlying system ICU database. This would
206+
// be correct, but potentially more expensive because the CultureInfo APIs are lazily-loaded and throw if an
207+
// invalid/unknown locale is used.
190208

191209
return null;
192210
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Globalization;
7+
using System.Linq;
8+
using Xunit;
9+
10+
namespace NuGet.Client.Test
11+
{
12+
public class ContentModelResourceTests
13+
{
14+
[MemberData(nameof(AllCultures))]
15+
[Theory]
16+
public void CanParseEverySystemKnownCultureResource(CultureInfo culture)
17+
{
18+
var result = ManagedCodeConventions.Locale_Parser(culture.Name.AsMemory(), null, false);
19+
Assert.Equal(culture.Name, result as string);
20+
}
21+
22+
public static IEnumerable<object[]> AllCultures()
23+
{
24+
return CultureInfo.GetCultures(CultureTypes.AllCultures).Where(c => !string.IsNullOrEmpty(c.Name)).Select(culture => new[] { culture });
25+
}
26+
}
27+
}
28+

0 commit comments

Comments
 (0)