diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 4d1f12baaa..6262f99c56 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -358,12 +358,28 @@ namespace Umbraco.Core.Packaging Key = key }; + // Handle culture specific node names + const string nodeNamePrefix = "nodeName-"; + // Get the installed culture iso names, we create a localized content node with a culture that does not exist in the project + // We have to use Invariant comparisons, because when we get them from ContentBase in EntityXmlSerializer they're all lowercase. + var installedLanguages = _localizationService.GetAllLanguages().Select(l => l.IsoCode).ToArray(); + foreach (var localizedNodeName in element.Attributes().Where(a => a.Name.LocalName.InvariantStartsWith(nodeNamePrefix))) + { + var newCulture = localizedNodeName.Name.LocalName.Substring(nodeNamePrefix.Length); + // Skip the culture if it does not exist in the current project + if (installedLanguages.InvariantContains(newCulture)) + { + content.SetCultureName(localizedNodeName.Value, newCulture); + } + } + //Here we make sure that we take composition properties in account as well //otherwise we would skip them and end up losing content var propTypes = contentType.CompositionPropertyTypes.Any() ? contentType.CompositionPropertyTypes.ToDictionary(x => x.Alias, x => x) : contentType.PropertyTypes.ToDictionary(x => x.Alias, x => x); + var foundLanguages = new HashSet(); foreach (var property in properties) { string propertyTypeAlias = property.Name.LocalName; @@ -371,14 +387,30 @@ namespace Umbraco.Core.Packaging { var propertyValue = property.Value; + // Handle properties language attributes + var propertyLang = property.Attribute(XName.Get("lang"))?.Value; + foundLanguages.Add(propertyLang); if (propTypes.TryGetValue(propertyTypeAlias, out var propertyType)) { - //set property value - content.SetValue(propertyTypeAlias, propertyValue); + // set property value + // Skip unsupported language variation, otherwise we'll get a "not supported error" + // We allow null, because that's invariant + if (installedLanguages.InvariantContains(propertyLang) || propertyLang is null) + { + content.SetValue(propertyTypeAlias, propertyValue, propertyLang); + } } } } + foreach (var propertyLang in foundLanguages) + { + if (string.IsNullOrEmpty(content.GetCultureName(propertyLang)) && installedLanguages.InvariantContains(propertyLang)) + { + content.SetCultureName(nodeName, propertyLang); + } + } + return content; } diff --git a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs index 4d7694d1b8..8cfcaa1182 100644 --- a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs @@ -77,7 +77,7 @@ namespace Umbraco.Core.Services.Implement var children = _contentService.GetPagedChildren(content.Id, page++, pageSize, out total); SerializeChildren(children, xml, published); } - + } return xml; @@ -488,7 +488,7 @@ namespace Umbraco.Core.Services.Implement new XElement("Alias", propertyType.Alias), new XElement("Key", propertyType.Key), new XElement("Type", propertyType.PropertyEditorAlias), - new XElement("Definition", definition.Key), + new XElement("Definition", definition.Key), new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), new XElement("SortOrder", propertyType.SortOrder), new XElement("Mandatory", propertyType.Mandatory.ToString()), @@ -553,6 +553,13 @@ namespace Umbraco.Core.Services.Implement new XAttribute("path", contentBase.Path), new XAttribute("isDoc", "")); + + // Add culture specific node names + foreach (var culture in contentBase.AvailableCultures) + { + xml.Add(new XAttribute("nodeName-" + culture, contentBase.GetCultureName(culture))); + } + foreach (var property in contentBase.Properties) xml.Add(SerializeProperty(property, published));