diff --git a/src/Umbraco.Core/Collections/CompositeIntStringKey.cs b/src/Umbraco.Core/Collections/CompositeIntStringKey.cs
index eb9db80990..74ef4e45e1 100644
--- a/src/Umbraco.Core/Collections/CompositeIntStringKey.cs
+++ b/src/Umbraco.Core/Collections/CompositeIntStringKey.cs
@@ -2,6 +2,7 @@
namespace Umbraco.Core.Collections
{
+
///
/// Represents a composite key of (int, string) for fast dictionaries.
///
@@ -40,4 +41,4 @@ namespace Umbraco.Core.Collections
public static bool operator !=(CompositeIntStringKey key1, CompositeIntStringKey key2)
=> key1._key2 != key2._key2 || key1._key1 != key2._key1;
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Core/Collections/IReadOnlyKeyedCollection.cs b/src/Umbraco.Core/Collections/IReadOnlyKeyedCollection.cs
new file mode 100644
index 0000000000..8d78241275
--- /dev/null
+++ b/src/Umbraco.Core/Collections/IReadOnlyKeyedCollection.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Umbraco.Core.Collections
+{
+ ///
+ /// A readonly keyed collection
+ ///
+ ///
+ public interface IReadOnlyKeyedCollection : IReadOnlyList
+ {
+ IEnumerable Keys { get; }
+ bool TryGetValue(TKey key, out TVal val);
+ TVal this[string key] { get; }
+ bool Contains(TKey key);
+ }
+}
diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs
index e36731a8cb..4f88c2b803 100644
--- a/src/Umbraco.Core/ContentExtensions.cs
+++ b/src/Umbraco.Core/ContentExtensions.cs
@@ -133,7 +133,7 @@ namespace Umbraco.Core
}
#endregion
-
+
///
/// Removes characters that are not valide XML characters from all entity properties
/// of type string. See: http://stackoverflow.com/a/961504/5018
diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs
index 238d87b186..2ee6762e61 100644
--- a/src/Umbraco.Core/Models/Content.cs
+++ b/src/Umbraco.Core/Models/Content.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
+using Umbraco.Core.Collections;
using Umbraco.Core.Exceptions;
namespace Umbraco.Core.Models
@@ -20,8 +21,8 @@ namespace Umbraco.Core.Models
private PublishedState _publishedState;
private DateTime? _releaseDate;
private DateTime? _expireDate;
- private Dictionary _publishInfos;
- private Dictionary _publishInfosOrig;
+ private CultureNameCollection _publishInfos;
+ private CultureNameCollection _publishInfosOrig;
private HashSet _editedCultures;
private static readonly Lazy Ps = new Lazy();
@@ -221,13 +222,13 @@ namespace Umbraco.Core.Models
public bool IsCulturePublished(string culture)
// just check _publishInfos
// a non-available culture could not become published anyways
- => _publishInfos != null && _publishInfos.ContainsKey(culture);
+ => _publishInfos != null && _publishInfos.Contains(culture);
///
public bool WasCulturePublished(string culture)
// just check _publishInfosOrig - a copy of _publishInfos
// a non-available culture could not become published anyways
- => _publishInfosOrig != null && _publishInfosOrig.ContainsKey(culture);
+ => _publishInfosOrig != null && _publishInfosOrig.Contains(culture);
///
public bool IsCultureEdited(string culture)
@@ -237,7 +238,7 @@ namespace Umbraco.Core.Models
///
[IgnoreDataMember]
- public IReadOnlyDictionary PublishNames => _publishInfos?.ToDictionary(x => x.Key, x => x.Value.Name, StringComparer.OrdinalIgnoreCase) ?? NoNames;
+ public IReadOnlyKeyedCollection PublishNames => _publishInfos ?? NoNames;
///
public string GetPublishName(string culture)
@@ -267,9 +268,11 @@ namespace Umbraco.Core.Models
throw new ArgumentNullOrEmptyException(nameof(culture));
if (_publishInfos == null)
- _publishInfos = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _publishInfos = new CultureNameCollection();
- _publishInfos[culture.ToLowerInvariant()] = (name, date);
+ //TODO: Track changes?
+
+ _publishInfos.AddOrUpdate(culture, name, date);
}
private void ClearPublishInfos()
@@ -430,7 +433,11 @@ namespace Umbraco.Core.Models
// take care of publish infos
_publishInfosOrig = _publishInfos == null
? null
- : new Dictionary(_publishInfos, StringComparer.OrdinalIgnoreCase);
+ : new CultureNameCollection(_publishInfos);
+
+ if (_publishInfos != null)
+ foreach (var cultureName in _publishInfos)
+ cultureName.ResetDirtyProperties(rememberDirty);
}
///
diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs
index bf2fd580d9..2336188c50 100644
--- a/src/Umbraco.Core/Models/ContentBase.cs
+++ b/src/Umbraco.Core/Models/ContentBase.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Web;
+using Umbraco.Core.Collections;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Models.Entities;
@@ -19,14 +20,14 @@ namespace Umbraco.Core.Models
[DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentTypeBase.Alias}")]
public abstract class ContentBase : TreeEntityBase, IContentBase
{
- protected static readonly Dictionary NoNames = new Dictionary();
+ protected static readonly CultureNameCollection NoNames = new CultureNameCollection();
private static readonly Lazy Ps = new Lazy();
private int _contentTypeId;
protected IContentTypeComposition ContentTypeBase;
private int _writerId;
private PropertyCollection _properties;
- private Dictionary _cultureInfos;
+ private CultureNameCollection _cultureInfos;
///
/// Initializes a new instance of the class.
@@ -69,7 +70,7 @@ namespace Umbraco.Core.Models
public readonly PropertyInfo DefaultContentTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeId);
public readonly PropertyInfo PropertyCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.Properties);
public readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo(x => x.WriterId);
- public readonly PropertyInfo NamesSelector = ExpressionHelper.GetPropertyInfo>(x => x.CultureNames);
+ public readonly PropertyInfo CultureNamesSelector = ExpressionHelper.GetPropertyInfo>(x => x.CultureNames);
}
protected void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e)
@@ -147,18 +148,18 @@ namespace Umbraco.Core.Models
///
public IEnumerable AvailableCultures
- => _cultureInfos?.Select(x => x.Key) ?? Enumerable.Empty();
+ => _cultureInfos?.Keys ?? Enumerable.Empty();
///
public bool IsCultureAvailable(string culture)
- => _cultureInfos != null && _cultureInfos.ContainsKey(culture);
+ => _cultureInfos != null && _cultureInfos.Contains(culture);
///
[DataMember]
- public virtual IReadOnlyDictionary CultureNames => _cultureInfos?.ToDictionary(x => x.Key, x => x.Value.Name, StringComparer.OrdinalIgnoreCase) ?? NoNames;
-
+ public virtual IReadOnlyKeyedCollection CultureNames => _cultureInfos ?? NoNames;
+
///
- public virtual string GetCultureName(string culture)
+ public string GetCultureName(string culture)
{
if (culture.IsNullOrWhiteSpace()) return Name;
if (!ContentTypeBase.VariesByCulture()) return null;
@@ -176,7 +177,7 @@ namespace Umbraco.Core.Models
}
///
- public virtual void SetCultureName(string name, string culture)
+ public void SetCultureName(string name, string culture)
{
if (ContentTypeBase.VariesByCulture()) // set on variant content type
{
@@ -202,16 +203,18 @@ namespace Umbraco.Core.Models
}
}
+ //fixme: this isn't used anywhere
internal void TouchCulture(string culture)
{
if (ContentTypeBase.VariesByCulture() && _cultureInfos != null && _cultureInfos.TryGetValue(culture, out var infos))
- _cultureInfos[culture] = (infos.Name, DateTime.Now);
+ _cultureInfos.AddOrUpdate(culture, infos.Name, DateTime.Now);
}
protected void ClearCultureInfos()
{
+ if (_cultureInfos != null)
+ _cultureInfos.Clear();
_cultureInfos = null;
- OnPropertyChanged(Ps.Value.NamesSelector);
}
protected void ClearCultureInfo(string culture)
@@ -223,7 +226,6 @@ namespace Umbraco.Core.Models
_cultureInfos.Remove(culture);
if (_cultureInfos.Count == 0)
_cultureInfos = null;
- OnPropertyChanged(Ps.Value.NamesSelector);
}
// internal for repository
@@ -236,10 +238,22 @@ namespace Umbraco.Core.Models
throw new ArgumentNullOrEmptyException(nameof(culture));
if (_cultureInfos == null)
- _cultureInfos = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ {
+ _cultureInfos = new CultureNameCollection();
+ _cultureInfos.CollectionChanged += CultureNamesCollectionChanged;
+ }
- _cultureInfos[culture.ToLowerInvariant()] = (name, date);
- OnPropertyChanged(Ps.Value.NamesSelector);
+ _cultureInfos.AddOrUpdate(culture, name, date);
+ }
+
+ ///
+ /// Event handler for when the culture names collection is modified
+ ///
+ ///
+ ///
+ private void CultureNamesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ OnPropertyChanged(Ps.Value.CultureNamesSelector);
}
#endregion
@@ -387,6 +401,11 @@ namespace Umbraco.Core.Models
// also reset dirty changes made to user's properties
foreach (var prop in Properties)
prop.ResetDirtyProperties(rememberDirty);
+
+ // take care of culture names
+ if (_cultureInfos != null)
+ foreach (var cultureName in _cultureInfos)
+ cultureName.ResetDirtyProperties(rememberDirty);
}
///
diff --git a/src/Umbraco.Core/Models/CultureName.cs b/src/Umbraco.Core/Models/CultureName.cs
new file mode 100644
index 0000000000..64db50c36d
--- /dev/null
+++ b/src/Umbraco.Core/Models/CultureName.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Umbraco.Core.Models.Entities;
+
+namespace Umbraco.Core.Models
+{
+ ///
+ /// The name of a content variant for a given culture
+ ///
+ public class CultureName : BeingDirtyBase, IDeepCloneable, IEquatable
+ {
+ private DateTime _date;
+ private string _name;
+ private static readonly Lazy Ps = new Lazy();
+
+ public CultureName(string culture, string name, DateTime date)
+ {
+ if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("message", nameof(culture));
+ Culture = culture;
+ _name = name;
+ _date = date;
+ }
+
+ public string Culture { get; private set; }
+
+ public string Name
+ {
+ get => _name;
+ set => SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector);
+ }
+
+ public DateTime Date
+ {
+ get => _date;
+ set => SetPropertyValueAndDetectChanges(value, ref _date, Ps.Value.DateSelector);
+ }
+
+ public object DeepClone()
+ {
+ return new CultureName(Culture, Name, Date);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is CultureName && Equals((CultureName)obj);
+ }
+
+ public bool Equals(CultureName other)
+ {
+ return Culture == other.Culture &&
+ Name == other.Name;
+ }
+
+ public override int GetHashCode()
+ {
+ var hashCode = 479558943;
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Culture);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name);
+ return hashCode;
+ }
+
+ ///
+ /// Allows deconstructing into culture and name
+ ///
+ ///
+ ///
+ public void Deconstruct(out string culture, out string name)
+ {
+ culture = Culture;
+ name = Name;
+ }
+
+ // ReSharper disable once ClassNeverInstantiated.Local
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo CultureSelector = ExpressionHelper.GetPropertyInfo(x => x.Culture);
+ public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
+ public readonly PropertyInfo DateSelector = ExpressionHelper.GetPropertyInfo(x => x.Date);
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Models/CultureNameCollection.cs b/src/Umbraco.Core/Models/CultureNameCollection.cs
new file mode 100644
index 0000000000..3c00603c88
--- /dev/null
+++ b/src/Umbraco.Core/Models/CultureNameCollection.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Linq;
+using Umbraco.Core.Collections;
+
+namespace Umbraco.Core.Models
+{
+
+
+ ///
+ /// The culture names of a content's variants
+ ///
+ public class CultureNameCollection : KeyedCollection, INotifyCollectionChanged, IDeepCloneable, IReadOnlyKeyedCollection
+ {
+ ///
+ /// Creates a new collection from another collection
+ ///
+ ///
+ public CultureNameCollection(IEnumerable names) : base(StringComparer.InvariantCultureIgnoreCase)
+ {
+ foreach (var n in names)
+ Add(n);
+ }
+
+ ///
+ /// Creates a new collection
+ ///
+ public CultureNameCollection() : base(StringComparer.InvariantCultureIgnoreCase)
+ {
+ }
+
+ ///
+ /// Returns all keys in the collection
+ ///
+ public IEnumerable Keys => Dictionary != null ? Dictionary.Keys : this.Select(x => x.Culture);
+
+ public bool TryGetValue(string culture, out CultureName name)
+ {
+ name = this.FirstOrDefault(x => x.Culture.InvariantEquals(culture));
+ return name != null;
+ }
+
+ ///
+ /// Add or update the
+ ///
+ ///
+ public void AddOrUpdate(string culture, string name, DateTime date)
+ {
+ culture = culture.ToLowerInvariant();
+ if (TryGetValue(culture, out var found))
+ {
+ found.Name = name;
+ found.Date = date;
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, found, found));
+ }
+ else
+ Add(new CultureName(culture, name, date));
+ }
+
+ ///
+ /// Gets the index for a specified culture
+ ///
+ public int IndexOfKey(string key)
+ {
+ for (var i = 0; i < Count; i++)
+ {
+ if (this[i].Culture.InvariantEquals(key))
+ return i;
+ }
+ return -1;
+ }
+
+ public event NotifyCollectionChangedEventHandler CollectionChanged;
+
+ protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
+ {
+ CollectionChanged?.Invoke(this, args);
+ }
+
+ public object DeepClone()
+ {
+ var clone = new CultureNameCollection();
+ foreach (var name in this)
+ {
+ clone.Add((CultureName)name.DeepClone());
+ }
+ return clone;
+ }
+
+ protected override string GetKeyForItem(CultureName item)
+ {
+ return item.Culture;
+ }
+
+ ///
+ /// Resets the collection to only contain the instances referenced in the parameter.
+ ///
+ /// The property groups.
+ ///
+ internal void Reset(IEnumerable names)
+ {
+ Clear();
+ foreach (var name in names)
+ Add(name);
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+ }
+
+ protected override void SetItem(int index, CultureName item)
+ {
+ base.SetItem(index, item);
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
+ }
+
+ protected override void RemoveItem(int index)
+ {
+ var removed = this[index];
+ base.RemoveItem(index);
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
+ }
+
+ protected override void InsertItem(int index, CultureName item)
+ {
+ base.InsertItem(index, item);
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
+ }
+
+ protected override void ClearItems()
+ {
+ base.ClearItems();
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+ }
+
+ }
+}
diff --git a/src/Umbraco.Core/Models/IContent.cs b/src/Umbraco.Core/Models/IContent.cs
index d9bc32aaf0..3ddffe8f75 100644
--- a/src/Umbraco.Core/Models/IContent.cs
+++ b/src/Umbraco.Core/Models/IContent.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using Umbraco.Core.Collections;
namespace Umbraco.Core.Models
{
@@ -132,7 +133,7 @@ namespace Umbraco.Core.Models
/// Because a dictionary key cannot be null this cannot get the invariant
/// name, which must be get via the property.
///
- IReadOnlyDictionary PublishNames { get; }
+ IReadOnlyKeyedCollection PublishNames { get; }
///
/// Gets the published cultures.
diff --git a/src/Umbraco.Core/Models/IContentBase.cs b/src/Umbraco.Core/Models/IContentBase.cs
index 460bd521d4..811cbf74f3 100644
--- a/src/Umbraco.Core/Models/IContentBase.cs
+++ b/src/Umbraco.Core/Models/IContentBase.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using Umbraco.Core.Collections;
using Umbraco.Core.Models.Entities;
namespace Umbraco.Core.Models
@@ -57,7 +58,7 @@ namespace Umbraco.Core.Models
/// Because a dictionary key cannot be null this cannot contain the invariant
/// culture name, which must be get or set via the property.
///
- IReadOnlyDictionary CultureNames { get; }
+ IReadOnlyKeyedCollection CultureNames { get; }
///
/// Gets the available cultures.
diff --git a/src/Umbraco.Core/Models/PropertyGroupCollection.cs b/src/Umbraco.Core/Models/PropertyGroupCollection.cs
index d10b375285..80b663fa05 100644
--- a/src/Umbraco.Core/Models/PropertyGroupCollection.cs
+++ b/src/Umbraco.Core/Models/PropertyGroupCollection.cs
@@ -8,6 +8,7 @@ using System.Threading;
namespace Umbraco.Core.Models
{
+
///
/// Represents a collection of objects
///
@@ -168,7 +169,7 @@ namespace Umbraco.Core.Models
var clone = new PropertyGroupCollection();
foreach (var group in this)
{
- clone.Add((PropertyGroup) group.DeepClone());
+ clone.Add((PropertyGroup)group.DeepClone());
}
return clone;
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
index bf41cd1ad1..83d9e80f5f 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
@@ -1172,8 +1172,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// using the default culture if it has a name, otherwise anything we can
var defaultCulture = LanguageRepository.GetDefaultIsoCode();
content.Name = defaultCulture != null && content.CultureNames.TryGetValue(defaultCulture, out var cultureName)
- ? cultureName
- : content.CultureNames.First().Value;
+ ? cultureName.Name
+ : content.CultureNames[0].Name;
}
else
{
@@ -1234,7 +1234,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// update the name, and the publish name if published
content.SetCultureName(uniqueName, culture);
- if (publishing && content.PublishNames.ContainsKey(culture))
+ if (publishing && content.PublishNames.Contains(culture))
content.SetPublishInfo(culture, uniqueName, DateTime.Now);
}
}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index aef18e59db..0eba543e0d 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -109,6 +109,7 @@
+
@@ -374,6 +375,8 @@
+
+
diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs
index 32fbd37d0e..a7d0f2f050 100644
--- a/src/Umbraco.Tests/Models/ContentTests.cs
+++ b/src/Umbraco.Tests/Models/ContentTests.cs
@@ -42,6 +42,33 @@ namespace Umbraco.Tests.Models
Container.Register(_ => Mock.Of());
}
+ [Test]
+ public void Variant_Names_Track_Dirty_Changes()
+ {
+ var contentType = new ContentType(-1) { Alias = "contentType" };
+ var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 };
+
+ const string langFr = "fr-FR";
+
+ contentType.Variations = ContentVariation.Culture;
+
+ Assert.IsFalse(content.IsPropertyDirty("CultureNames")); //hasn't been changed
+
+ content.SetCultureName("name-fr", langFr);
+ Assert.IsTrue(content.IsPropertyDirty("CultureNames")); //now it will be changed since the collection has changed
+ var frCultureName = content.CultureNames[langFr];
+ Assert.IsFalse(frCultureName.IsPropertyDirty("Date")); //this won't be dirty because it wasn't actually updated, just created
+
+ content.ResetDirtyProperties();
+
+ Assert.IsFalse(content.IsPropertyDirty("CultureNames")); //it's been reset
+ Assert.IsTrue(content.WasPropertyDirty("CultureNames"));
+
+ content.SetCultureName("name-fr", langFr);
+ Assert.IsTrue(frCultureName.IsPropertyDirty("Date")); //this will be dirty because it was already created and now has been updated
+ Assert.IsTrue(content.IsPropertyDirty("CultureNames")); //it's true now since we've updated a name
+ }
+
[Test]
public void Get_Non_Grouped_Properties()
{
diff --git a/src/Umbraco.Tests/Models/VariationTests.cs b/src/Umbraco.Tests/Models/VariationTests.cs
index 8d566e81f2..0e62c41f46 100644
--- a/src/Umbraco.Tests/Models/VariationTests.cs
+++ b/src/Umbraco.Tests/Models/VariationTests.cs
@@ -237,10 +237,10 @@ namespace Umbraco.Tests.Models
// variant dictionary of names work
Assert.AreEqual(2, content.CultureNames.Count);
- Assert.IsTrue(content.CultureNames.ContainsKey(langFr));
- Assert.AreEqual("name-fr", content.CultureNames[langFr]);
- Assert.IsTrue(content.CultureNames.ContainsKey(langUk));
- Assert.AreEqual("name-uk", content.CultureNames[langUk]);
+ Assert.IsTrue(content.CultureNames.Contains(langFr));
+ Assert.AreEqual("name-fr", content.CultureNames[langFr].Name);
+ Assert.IsTrue(content.CultureNames.Contains(langUk));
+ Assert.AreEqual("name-uk", content.CultureNames[langUk].Name);
}
[Test]
diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs
index 68e29c4efe..62c3116ab1 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs
@@ -767,7 +767,7 @@ namespace Umbraco.Tests.Persistence.Repositories
foreach (var r in result)
{
var isInvariant = r.ContentType.Alias == "umbInvariantTextpage";
- var name = isInvariant ? r.Name : r.CultureNames["en-US"];
+ var name = isInvariant ? r.Name : r.CultureNames["en-US"].Name;
var namePrefix = isInvariant ? "INV" : "VAR";
//ensure the correct name (invariant vs variant) is in the result
diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
index 8b23763763..4557dfb1bd 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
@@ -132,7 +132,7 @@ namespace Umbraco.Web.Models.Mapping
// if we don't have a name for a culture, it means the culture is not available, and
// hey we should probably not be mapping it, but it's too late, return a fallback name
- return source.CultureNames.TryGetValue(culture, out var name) && !name.IsNullOrWhiteSpace() ? name : $"(({source.Name}))";
+ return source.CultureNames.TryGetValue(culture, out var name) && !name.Name.IsNullOrWhiteSpace() ? name.Name : $"(({source.Name}))";
}
}
}
diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs
index ac35c336b2..91cf690996 100644
--- a/src/Umbraco.Web/umbraco.presentation/page.cs
+++ b/src/Umbraco.Web/umbraco.presentation/page.cs
@@ -396,7 +396,7 @@ namespace umbraco
return _cultureInfos;
return _cultureInfos = _inner.PublishNames
- .ToDictionary(x => x.Key, x => new PublishedCultureInfo(x.Key, x.Value, _inner.GetPublishDate(x.Key) ?? DateTime.MinValue));
+ .ToDictionary(x => x.Culture, x => new PublishedCultureInfo(x.Culture, x.Name, x.Date));
}
}