/// <summary> /// Returns a list of cultures that have any validation errors /// </summary> /// <param name="modelState"></param> /// <param name="localizationService"></param> /// <param name="cultureForInvariantErrors">The culture to affiliate invariant errors with</param> /// <returns> /// A list of cultures that have validation errors. The default culture will be returned for any invariant errors. /// </returns> internal static IReadOnlyList <(string culture, string segment)> GetVariantsWithErrors(this System.Web.Http.ModelBinding.ModelStateDictionary modelState, string cultureForInvariantErrors) { var propertyVariantErrors = modelState.GetVariantsWithPropertyErrors(cultureForInvariantErrors); //now check the other special variant errors that are var genericVariantErrors = modelState.Keys .Where(x => x.StartsWith("_content_variant_") && x.EndsWith("_")) .Select(x => x.TrimStart("_content_variant_").TrimEnd("_")) .Select(x => { // Format "<culture>_<segment>" var cs = x.Split(new[] { '_' }); return(culture: cs[0], segment: cs[1]); }) .Where(x => !x.culture.IsNullOrWhiteSpace()) //if it's marked "invariant" than return the default language, this is because we can only edit invariant properties on the default language //so errors for those must show up under the default lang. //if the segment is marked "null" then return an actual null .Select(x => { var culture = x.culture == "invariant" ? cultureForInvariantErrors : x.culture; var segment = x.segment == "null" ? null : x.segment; return(culture, segment); }) .Distinct(); return(propertyVariantErrors.Union(genericVariantErrors).Distinct().ToList()); }