diff --git a/src/Umbraco.Cms.Api.Management/Extensions/HtmlHelperBackOfficeExtensions.cs b/src/Umbraco.Cms.Api.Management/Extensions/HtmlHelperBackOfficeExtensions.cs
index f501b7f312..963b176018 100644
--- a/src/Umbraco.Cms.Api.Management/Extensions/HtmlHelperBackOfficeExtensions.cs
+++ b/src/Umbraco.Cms.Api.Management/Extensions/HtmlHelperBackOfficeExtensions.cs
@@ -1,4 +1,4 @@
-using System.Text;
+using System.Text;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using Umbraco.Cms.Core;
@@ -24,29 +24,18 @@ public static class HtmlHelperBackOfficeExtensions
IBackOfficePathGenerator backOfficePathGenerator,
IPackageManifestService packageManifestService)
{
- try
- {
- PackageManifestImportmap packageImports = await packageManifestService.GetPackageManifestImportmapAsync();
+ PackageManifestImportmap packageImports = await packageManifestService.GetPackageManifestImportmapAsync();
- var sb = new StringBuilder();
- sb.AppendLine("""");
+ var sb = new StringBuilder();
+ sb.AppendLine("""");
- // Inject the BackOffice cache buster into the import string to handle BackOffice assets
- var importmapScript = sb.ToString()
- .Replace(backOfficePathGenerator.BackOfficeVirtualDirectory, backOfficePathGenerator.BackOfficeAssetsPath)
- .Replace(Constants.Web.CacheBusterToken, backOfficePathGenerator.BackOfficeCacheBustHash);
+ // Inject the BackOffice cache buster into the import string to handle BackOffice assets
+ var importmapScript = sb.ToString()
+ .Replace(backOfficePathGenerator.BackOfficeVirtualDirectory, backOfficePathGenerator.BackOfficeAssetsPath)
+ .Replace(Constants.Web.CacheBusterToken, backOfficePathGenerator.BackOfficeCacheBustHash);
- return html.Raw(importmapScript);
- }
- catch (NotSupportedException ex)
- {
- throw new NotSupportedException("Failed to serialize the BackOffice import map", ex);
- }
- catch (Exception ex)
- {
- throw new Exception("Failed to generate the BackOffice import map", ex);
- }
+ return html.Raw(importmapScript);
}
}
diff --git a/src/Umbraco.Cms.Api.Management/Factories/DictionaryPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/DictionaryPresentationFactory.cs
index 65c97b1131..3462d44802 100644
--- a/src/Umbraco.Cms.Api.Management/Factories/DictionaryPresentationFactory.cs
+++ b/src/Umbraco.Cms.Api.Management/Factories/DictionaryPresentationFactory.cs
@@ -1,4 +1,5 @@
-using Umbraco.Cms.Core.Mapping;
+using Umbraco.Cms.Core.Extensions;
+using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Api.Management.Models;
@@ -23,8 +24,7 @@ public class DictionaryPresentationFactory : IDictionaryPresentationFactory
{
DictionaryItemResponseModel dictionaryResponseModel = _umbracoMapper.Map(dictionaryItem)!;
- var validLanguageIsoCodes = (await _languageService.GetAllAsync())
- .Select(language => language.IsoCode)
+ var validLanguageIsoCodes = (await _languageService.GetAllIsoCodesAsync())
.ToArray();
IDictionaryTranslation[] validTranslations = dictionaryItem.Translations
.Where(t => validLanguageIsoCodes.Contains(t.LanguageIsoCode))
diff --git a/src/Umbraco.Cms.Api.Management/Factories/UserGroupPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/UserGroupPresentationFactory.cs
index 099074aba5..b040d6334c 100644
--- a/src/Umbraco.Cms.Api.Management/Factories/UserGroupPresentationFactory.cs
+++ b/src/Umbraco.Cms.Api.Management/Factories/UserGroupPresentationFactory.cs
@@ -211,11 +211,7 @@ public class UserGroupPresentationFactory : IUserGroupPresentationFactory
private async Task, UserGroupOperationStatus>> MapLanguageIdsToIsoCodeAsync(IEnumerable ids)
{
- IEnumerable languages = await _languageService.GetAllAsync();
- string[] isoCodes = languages
- .Where(x => ids.Contains(x.Id))
- .Select(x => x.IsoCode)
- .ToArray();
+ string[] isoCodes = await _languageService.GetIsoCodesByIdsAsync(ids.ToArray());
// if a language id does not exist, it simply not returned.
// We do this so we don't have to clean up user group data when deleting languages and to make it easier to restore accidentally removed languages
diff --git a/src/Umbraco.Core/Extensions/LanguageServiceExtensions.cs b/src/Umbraco.Core/Extensions/LanguageServiceExtensions.cs
new file mode 100644
index 0000000000..982aa01497
--- /dev/null
+++ b/src/Umbraco.Core/Extensions/LanguageServiceExtensions.cs
@@ -0,0 +1,16 @@
+using Umbraco.Cms.Core.Services;
+
+namespace Umbraco.Cms.Core.Extensions;
+
+///
+/// Provides extension methods for .
+///
+public static class LanguageServiceExtensions
+{
+ ///
+ /// Retrieves all ISO codes of all languages.
+ ///
+ /// The .
+ /// A collection of language ISO codes.
+ public static async Task> GetAllIsoCodesAsync(this ILanguageService service) => (await service.GetAllAsync()).Select(x => x.IsoCode);
+}
diff --git a/src/Umbraco.Core/Persistence/Repositories/ILanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ILanguageRepository.cs
index 849d789f3a..f0cc9ed73e 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ILanguageRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ILanguageRepository.cs
@@ -38,5 +38,11 @@ public interface ILanguageRepository : IReadWriteQueryRepository
///
int? GetDefaultId();
+ ///
+ /// Gets multiple language ISO codes from the provided Ids.
+ ///
+ /// The language Ids.
+ /// Indicates whether to throw an exception if the provided Id is not found as a language.
+ ///
string[] GetIsoCodesByIds(ICollection ids, bool throwOnNotFound = true);
}
diff --git a/src/Umbraco.Core/Routing/PublishedUrlInfoProvider.cs b/src/Umbraco.Core/Routing/PublishedUrlInfoProvider.cs
index c861d9ba01..c75108232e 100644
--- a/src/Umbraco.Core/Routing/PublishedUrlInfoProvider.cs
+++ b/src/Umbraco.Core/Routing/PublishedUrlInfoProvider.cs
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
+using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
@@ -42,7 +43,7 @@ public class PublishedUrlInfoProvider : IPublishedUrlInfoProvider
public async Task> GetAllAsync(IContent content)
{
HashSet urlInfos = [];
- var cultures = (await _languageService.GetAllAsync()).Select(x => x.IsoCode).ToArray();
+ IEnumerable cultures = await _languageService.GetAllIsoCodesAsync();
// First we get the urls of all cultures, using the published router, meaning we respect any extensions.
foreach (var culture in cultures)
diff --git a/src/Umbraco.Core/Routing/UrlProviderExtensions.cs b/src/Umbraco.Core/Routing/UrlProviderExtensions.cs
index c36eb478d1..ba90635790 100644
--- a/src/Umbraco.Core/Routing/UrlProviderExtensions.cs
+++ b/src/Umbraco.Core/Routing/UrlProviderExtensions.cs
@@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
@@ -66,7 +67,7 @@ public static class UrlProviderExtensions
// and, not only for those assigned to domains in the branch, because we want
// to show what GetUrl() would return, for every culture.
var urls = new HashSet();
- var cultures = (await languageService.GetAllAsync()).Select(x => x.IsoCode).ToList();
+ IEnumerable cultures = await languageService.GetAllIsoCodesAsync();
// get all URLs for all cultures
// in a HashSet, so de-duplicates too
diff --git a/src/Umbraco.Core/Services/ContentEditingService.cs b/src/Umbraco.Core/Services/ContentEditingService.cs
index f4b41ac8da..9b4f92615b 100644
--- a/src/Umbraco.Core/Services/ContentEditingService.cs
+++ b/src/Umbraco.Core/Services/ContentEditingService.cs
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
+using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Models.Membership;
@@ -96,8 +97,8 @@ internal sealed class ContentEditingService
{
// If no cultures are provided, we are asking to validate all cultures. But if the user doesn't have access to all, we
// should only validate the ones they do.
- var allCultures = (await _languageService.GetAllAsync()).Select(x => x.IsoCode).ToList();
- return allowedCultures.Count == allCultures.Count ? null : allowedCultures;
+ IEnumerable allCultures = await _languageService.GetAllIsoCodesAsync();
+ return allowedCultures.Count == allCultures.Count() ? null : allowedCultures;
}
// If explicit cultures are provided, we should only validate the ones the user has access to.
diff --git a/src/Umbraco.Core/Services/ContentPublishingService.cs b/src/Umbraco.Core/Services/ContentPublishingService.cs
index b235fd8c14..8903cac4f0 100644
--- a/src/Umbraco.Core/Services/ContentPublishingService.cs
+++ b/src/Umbraco.Core/Services/ContentPublishingService.cs
@@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Events;
+using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Models.ContentPublishing;
@@ -165,7 +166,7 @@ internal sealed class ContentPublishingService : IContentPublishingService
return Attempt.FailWithStatus(ContentPublishingOperationStatus.CannotPublishInvariantWhenVariant, new ContentPublishingResult());
}
- IEnumerable validCultures = (await _languageService.GetAllAsync()).Select(x => x.IsoCode);
+ IEnumerable validCultures = await _languageService.GetAllIsoCodesAsync();
if (validCultures.ContainsAll(cultures) is false)
{
scope.Complete();
@@ -478,7 +479,7 @@ internal sealed class ContentPublishingService : IContentPublishingService
return Attempt.Fail(ContentPublishingOperationStatus.CannotPublishVariantWhenNotVariant);
}
- var validCultures = (await _languageService.GetAllAsync()).Select(x => x.IsoCode).ToArray();
+ var validCultures = (await _languageService.GetAllIsoCodesAsync()).ToArray();
foreach (var culture in cultures)
{
diff --git a/src/Umbraco.Core/Services/ContentValidationServiceBase.cs b/src/Umbraco.Core/Services/ContentValidationServiceBase.cs
index 37b32847ad..137962b84c 100644
--- a/src/Umbraco.Core/Services/ContentValidationServiceBase.cs
+++ b/src/Umbraco.Core/Services/ContentValidationServiceBase.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
+using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Models.ContentEditing.Validation;
@@ -137,7 +138,7 @@ internal abstract class ContentValidationServiceBase
return invalidCultures.IsCollectionEmpty();
}
- private async Task GetCultureCodes() => (await _languageService.GetAllAsync()).Select(language => language.IsoCode).ToArray();
+ private async Task GetCultureCodes() => (await _languageService.GetAllIsoCodesAsync()).ToArray();
private IEnumerable ValidateProperty(IPropertyType propertyType, PropertyValueModel? propertyValueModel, PropertyValidationContext validationContext)
{
diff --git a/src/Umbraco.Core/Services/ILanguageService.cs b/src/Umbraco.Core/Services/ILanguageService.cs
index f1285b74a5..6ee7e5beba 100644
--- a/src/Umbraco.Core/Services/ILanguageService.cs
+++ b/src/Umbraco.Core/Services/ILanguageService.cs
@@ -1,4 +1,4 @@
-using Umbraco.Cms.Core.Models;
+using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Core.Services;
@@ -32,9 +32,9 @@ public interface ILanguageService
Task GetDefaultIsoCodeAsync();
///
- /// Gets all available languages
+ /// Gets all available languages.
///
- /// An enumerable list of objects
+ /// An enumerable list of objects.
Task> GetAllAsync();
///
@@ -44,29 +44,29 @@ public interface ILanguageService
Task> GetMultipleAsync(IEnumerable isoCodes);
///
- /// Updates an existing object
+ /// Updates an existing object.
///
/// to update
/// Key of the user saving the language
Task> UpdateAsync(ILanguage language, Guid userKey);
///
- /// Creates a new object
+ /// Creates a new object.
///
- /// to create
- /// Key of the user creating the language
+ /// to create.
+ /// Key of the user creating the language.
Task> CreateAsync(ILanguage language, Guid userKey);
///
- /// Deletes a by removing it and its usages from the db
+ /// Deletes a by removing it and its usages from the database.
///
- /// The ISO code of the to delete
- /// Key of the user deleting the language
+ /// The ISO code of the to delete.
+ /// Key of the user deleting the language.
Task> DeleteAsync(string isoCode, Guid userKey);
///
- /// Retrieves the isoCodes of configured languages by their Ids
+ /// Retrieves the ISO codes of configured languages by their Ids.
///
/// The ids of the configured s
/// The ISO codes of the s
diff --git a/src/Umbraco.Core/Services/LanguageService.cs b/src/Umbraco.Core/Services/LanguageService.cs
index da27567695..96d4417fc4 100644
--- a/src/Umbraco.Core/Services/LanguageService.cs
+++ b/src/Umbraco.Core/Services/LanguageService.cs
@@ -1,4 +1,3 @@
-using System.Globalization;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
diff --git a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs
index 8894a80cb4..21b79ca938 100644
--- a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs
+++ b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs
@@ -11,6 +11,7 @@ using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
@@ -196,9 +197,7 @@ public class BackOfficeExamineSearcher : IBackOfficeExamineSearcher
// then nodeName will be matched normally with wildcards
// the rest will be normal without wildcards
- var allLangs = _languageService.GetAllAsync().GetAwaiter().GetResult()
- .Select(x => x.IsoCode.ToLowerInvariant())
- .ToList();
+ var allLangs = _languageService.GetAllIsoCodesAsync().GetAwaiter().GetResult().Select(x => x.ToLowerInvariant()).ToList();
// the chars [*-_] in the query will mess everything up so let's remove those
// However we cannot just remove - and _ since these signify a space, so we instead replace them with that.
diff --git a/src/Umbraco.Infrastructure/Manifest/PackageManifestReader.cs b/src/Umbraco.Infrastructure/Manifest/PackageManifestReader.cs
index 7d4a502a35..c188694bfb 100644
--- a/src/Umbraco.Infrastructure/Manifest/PackageManifestReader.cs
+++ b/src/Umbraco.Infrastructure/Manifest/PackageManifestReader.cs
@@ -1,4 +1,5 @@
-using System.Text;
+using System.Text;
+using System.Text.Json;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.IO;
@@ -92,10 +93,15 @@ internal class PackageManifestReader : IPackageManifestReader
packageManifests.Add(packageManifest);
}
}
+ catch (JsonException ex)
+ {
+ throw new InvalidOperationException(
+ $"The package manifest file {fileInfo.PhysicalPath} could not be parsed as it does not contain valid JSON. Please see the inner exception for details.", ex);
+ }
catch (Exception ex)
{
- _logger.LogError(ex, "Unable to load package manifest file: {FileName}", fileInfo.Name);
- throw;
+ throw new InvalidOperationException(
+ $"The package manifest file {fileInfo.PhysicalPath} could not be parsed due to an unexpected error. Please see the inner exception for details.", ex);
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/manager/content-data-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/manager/content-data-manager.ts
index 3f9086dc02..7c2d0b0d4d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/content/content/manager/content-data-manager.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/manager/content-data-manager.ts
@@ -89,6 +89,7 @@ export class UmbContentWorkspaceDataManager<
const currentData = this.getCurrent();
if (!currentData) throw new Error('Data is missing');
+ // If varies by segment:
if (!variantId.isSegmentInvariant()) {
// The server requires a segment name. It doesn't matter what it is as long as it is not empty. The server will overwrite it with the name of the default.
update = { ...update, name: 'Segment' } as ModelVariantType;
diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/manager/element-data-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/manager/element-data-manager.ts
index 7241448362..9f0485b76d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/content/content/manager/element-data-manager.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/manager/element-data-manager.ts
@@ -83,10 +83,14 @@ export class UmbElementWorkspaceDataManager x.segment);
+ const dataSegments = data.values.map((x) => x.segment).filter((x) => x) as Array;
variantsToStore = [
...variantsToStore,
...dataSegments.flatMap((segment) => variantsToStore.map((variant) => variant.toSegment(segment))),
@@ -98,12 +102,7 @@ export class UmbElementWorkspaceDataManager value !== unique);
this.setSelection(newSelection);
+ this.#itemManager.removeStatus(unique);
this.getHostElement().dispatchEvent(new UmbChangeEvent());
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts
index 9be473dfc7..f2352d1407 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts
@@ -106,6 +106,11 @@ export class UmbRepositoryItemsManager exte
return this.#items.asObservablePart((items) => items.find((item) => item.unique === unique));
}
+ removeStatus(unique: string) {
+ const newStatuses = this.#statuses.getValue().filter((status) => status.unique !== unique);
+ this.#statuses.setValue(newStatuses);
+ }
+
async getItemByUnique(unique: string) {
// TODO: Make an observeOnce feature, to avoid this amount of code: [NL]
const ctrl = this.observe(this.itemByUnique(unique), () => {}, null);
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
index 8c0b26eea3..eaf5b8d4d7 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
@@ -497,7 +497,11 @@ export class UmbWorkspaceSplitViewVariantSelectorElement<
return variantOption?.segmentInfo?.name ?? this._labelDefault;
}
- return variantOption.variant?.name ?? variantOption.language.name;
+ if (variantOption.variant?.name && variantOption.variant?.name.trim() !== '') {
+ return variantOption.variant?.name;
+ }
+
+ return variantOption.language.name;
}
#getVariantSpecInfo(variantOption: VariantOptionModelType | undefined) {
diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/preview/input-upload-field-svg.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/preview/input-upload-field-svg.element.ts
index 5ba66a4ce5..e5639485f4 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/preview/input-upload-field-svg.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/preview/input-upload-field-svg.element.ts
@@ -30,6 +30,7 @@ export default class UmbInputUploadFieldSvgElement extends UmbLitElement impleme
background-image: url('data:image/svg+xml;charset=utf-8,');
background-repeat: repeat;
background-size: 10px 10px;
+ max-width: 100%;
}
`,
];
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/ExamineExternalIndexSearcherTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/ExamineExternalIndexSearcherTest.cs
index d3f27e5c16..31fa6adb3c 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/ExamineExternalIndexSearcherTest.cs
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/ExamineExternalIndexSearcherTest.cs
@@ -9,12 +9,11 @@ using Examine.Search;
using Lucene.Net.QueryParsers.Classic;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
-using Umbraco.Cms.Core.Mapping;
+using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Models.Entities;
using Umbraco.Cms.Core.Models.Membership;
-using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Examine;
@@ -160,7 +159,7 @@ internal sealed class ExamineExternalIndexSearcherTest : IExamineExternalIndexSe
// then nodeName will be matched normally with wildcards
// the rest will be normal without wildcards
- var allLanguages = (await _languageService.GetAllAsync()).Select(x => x.IsoCode.ToLowerInvariant()).ToList();
+ var allLanguages = (await _languageService.GetAllIsoCodesAsync()).Select(x => x.ToLowerInvariant()).ToList();
// the chars [*-_] in the query will mess everything up so let's remove those
// However we cannot just remove - and _ since these signify a space, so we instead replace them with that.
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/LanguageServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/LanguageServiceTests.cs
index 9710512515..85a1779585 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/LanguageServiceTests.cs
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/LanguageServiceTests.cs
@@ -1,5 +1,6 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
@@ -28,6 +29,14 @@ internal sealed class LanguageServiceTests : UmbracoIntegrationTest
Assert.That(languages.Count(), Is.EqualTo(3));
}
+ [Test]
+ public async Task Can_Get_All_Language_Iso_Codes()
+ {
+ var isoCodes = await LanguageService.GetAllIsoCodesAsync();
+ Assert.That(isoCodes.Count(), Is.EqualTo(3));
+ Assert.AreEqual("da-DK,en-GB,en-US", string.Join(",", isoCodes.OrderBy(x => x)));
+ }
+
[Test]
public async Task Can_GetLanguageByIsoCode()
{
diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/PackageManifestReaderTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/PackageManifestReaderTests.cs
index db23529c67..ff69213b3e 100644
--- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/PackageManifestReaderTests.cs
+++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/PackageManifestReaderTests.cs
@@ -186,8 +186,9 @@ public class PackageManifestReaderTests
.Setup(f => f.GetEnumerator())
.Returns(new List { CreatePackageManifestFile(content) }.GetEnumerator());
- Assert.ThrowsAsync(() => _reader.ReadPackageManifestsAsync());
- EnsureLogErrorWasCalled();
+ var exception = Assert.ThrowsAsync(() => _reader.ReadPackageManifestsAsync());
+ Assert.NotNull(exception);
+ Assert.IsInstanceOf(exception.InnerException);
}
[Test]
@@ -202,8 +203,9 @@ public class PackageManifestReaderTests
.Setup(f => f.GetEnumerator())
.Returns(new List { CreatePackageManifestFile(content) }.GetEnumerator());
- Assert.ThrowsAsync(() => _reader.ReadPackageManifestsAsync());
- EnsureLogErrorWasCalled();
+ var exception = Assert.ThrowsAsync(() => _reader.ReadPackageManifestsAsync());
+ Assert.NotNull(exception);
+ Assert.IsInstanceOf(exception.InnerException);
}
[Test]
@@ -224,8 +226,9 @@ public class PackageManifestReaderTests
.Setup(f => f.GetEnumerator())
.Returns(new List { CreatePackageManifestFile(content) }.GetEnumerator());
- Assert.ThrowsAsync(() => _reader.ReadPackageManifestsAsync());
- EnsureLogErrorWasCalled();
+ var exception = Assert.ThrowsAsync(() => _reader.ReadPackageManifestsAsync());
+ Assert.NotNull(exception);
+ Assert.IsInstanceOf(exception.InnerException);
}
[TestCase("This is not JSON")]
@@ -236,20 +239,11 @@ public class PackageManifestReaderTests
.Setup(f => f.GetEnumerator())
.Returns(new List { CreatePackageManifestFile(content) }.GetEnumerator());
- Assert.ThrowsAsync(() => _reader.ReadPackageManifestsAsync());
- EnsureLogErrorWasCalled();
+ var exception = Assert.ThrowsAsync(() => _reader.ReadPackageManifestsAsync());
+ Assert.NotNull(exception);
+ Assert.IsInstanceOf(exception.InnerException);
}
- private void EnsureLogErrorWasCalled(int numberOfTimes = 1) =>
- _loggerMock.Verify(
- x => x.Log(
- It.Is(l => l == LogLevel.Error),
- It.IsAny(),
- It.Is((v, t) => true),
- It.IsAny(),
- It.Is>((v, t) => true)),
- Times.Exactly(numberOfTimes));
-
private IFileInfo CreateDirectoryMock(string path, params IFileInfo[] children)
{
var directoryContentsMock = new Mock();