diff --git a/src/Tasks/CultureInfoCache.cs b/src/Tasks/CultureInfoCache.cs
-index 6173311..ea61a79 100644
+index 617331138..88992cb07 100644
--- a/src/Tasks/CultureInfoCache.cs
+++ b/src/Tasks/CultureInfoCache.cs
-@@ -916,7 +916,18 @@ namespace Microsoft.Build.Tasks
- "zu",
- "zu-ZA",
- "zh-CHS",
-- "zh-CHT"
-+ "zh-CHT",
-+ "bh-IN",
-+ "bhb-IN",
-+ "ckb-IQ",
-+ "ks-IN",
-+ "ku-Arab-IN",
-+ "mai-IN",
-+ "sat-IN",
-+ "sd-IN",
-+ "tcy-IN",
-+ "tu-IN",
-+ "tl-PH"
+@@ -19,47 +19,8 @@ namespace Microsoft.Build.Tasks
+ /// </summary>
+ internal static class CultureInfoCache
+ {
+- private static readonly HashSet<string> ValidCultureNames = InitializeValidCultureNames();
+-
+- static HashSet<string> InitializeValidCultureNames()
+- {
+-#if !FEATURE_CULTUREINFO_GETCULTURES
+- if (!AssemblyUtilities.CultureInfoHasGetCultures())
+- {
+- return HardcodedCultureNames;
+- }
+-#endif
+- HashSet<string> validCultureNames = new(StringComparer.OrdinalIgnoreCase);
+- foreach (CultureInfo cultureName in AssemblyUtilities.GetAllCultures())
+- {
+- validCultureNames.Add(cultureName.Name);
+- }
+-
+- // https://docs.microsoft.com/en-gb/windows/desktop/Intl/using-pseudo-locales-for-localization-testing
+- // These pseudo-locales are available in versions of Windows from Vista and later.
+- // However, from Windows 10, version 1803, they are not returned when enumerating the
+- // installed cultures, even if the registry keys are set. Therefore, add them to the list manually.
+- string[] pseudoLocales = new[] { "qps-ploc", "qps-ploca", "qps-plocm", "qps-Latn-x-sh" };
+
+- foreach (string pseudoLocale in pseudoLocales)
+- {
+- validCultureNames.Add(pseudoLocale);
+- }
+-
+- return validCultureNames;
+- }
+-
+- /// <summary>
+- /// Determine if a culture string represents a valid <see cref="CultureInfo"/> instance.
+- /// </summary>
+- /// <param name="name">The culture name.</param>
+- /// <returns>True if the culture is determined to be valid.</returns>
+- internal static bool IsValidCultureString(string name)
+- {
+- return ValidCultureNames.Contains(name);
+- }
+-
+-#if !FEATURE_CULTUREINFO_GETCULTURES
++ #if !FEATURE_CULTUREINFO_GETCULTURES
+ // Copied from https://github.com/aspnet/Localization/blob/5e1fb16071affd15f15b9c732833f3ae2ac46e10/src/Microsoft.Framework.Globalization.CultureInfoCache/CultureInfoList.cs
+ // Regenerated using the tool (removed by https://github.com/aspnet/Localization/pull/130)
+ // * Removed the empty string from the list
+@@ -919,5 +880,57 @@ namespace Microsoft.Build.Tasks
+ "zh-CHT"
};
#endif
- }
\ No newline at end of file
++
++ private static readonly HashSet<string> ValidCultureNames = InitializeValidCultureNames();
++
++ static HashSet<string> InitializeValidCultureNames()
++ {
++#if !FEATURE_CULTUREINFO_GETCULTURES
++ if (!AssemblyUtilities.CultureInfoHasGetCultures())
++ {
++ return HardcodedCultureNames;
++ }
++ else
++ {
++ var HardcodedCultureNamesWithTizen = new HashSet<string>(HardcodedCultureNames, StringComparer.OrdinalIgnoreCase);
++ var tizenLocales = new HashSet<string>(StringComparer.OrdinalIgnoreCase) {
++ "bh-IN", "bhb-IN", "ckb-IQ", "ks-IN", "ku-Arab-IN", "mai-IN", "sat-IN", "sd-IN", "tcy-IN", "tu-IN", "tl-PH"};
++ foreach (string tizenLocale in tizenLocales)
++ {
++ HardcodedCultureNamesWithTizen.Add(tizenLocale);
++ }
++ return HardcodedCultureNamesWithTizen;
++ }
++
++#endif
++ HashSet<string> validCultureNames = new(StringComparer.OrdinalIgnoreCase);
++ foreach (CultureInfo cultureName in AssemblyUtilities.GetAllCultures())
++ {
++ validCultureNames.Add(cultureName.Name);
++ }
++
++ // https://docs.microsoft.com/en-gb/windows/desktop/Intl/using-pseudo-locales-for-localization-testing
++ // These pseudo-locales are available in versions of Windows from Vista and later.
++ // However, from Windows 10, version 1803, they are not returned when enumerating the
++ // installed cultures, even if the registry keys are set. Therefore, add them to the list manually.
++ string[] pseudoLocales = new[] { "qps-ploc", "qps-ploca", "qps-plocm", "qps-Latn-x-sh" };
++
++ foreach (string pseudoLocale in pseudoLocales)
++ {
++ validCultureNames.Add(pseudoLocale);
++ }
++
++ return validCultureNames;
++ }
++
++ /// <summary>
++ /// Determine if a culture string represents a valid <see cref="CultureInfo"/> instance.
++ /// </summary>
++ /// <param name="name">The culture name.</param>
++ /// <returns>True if the culture is determined to be valid.</returns>
++ internal static bool IsValidCultureString(string name)
++ {
++ return ValidCultureNames.Contains(name);
++ }
+ }
+ }