diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs index 709c37daaa..7e53eb764a 100644 --- a/src/Umbraco.Core/Models/Property.cs +++ b/src/Umbraco.Core/Models/Property.cs @@ -271,6 +271,10 @@ namespace Umbraco.Core.Models /// public void SetValue(object value, string culture = null, string segment = null) { + if (PropertyType.Variations == ContentVariation.InvariantNeutral) + { + culture = null; + } PropertyType.ValidateVariation(culture, segment, true); (var pvalue, var change) = GetPValue(culture, segment, true); diff --git a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs index a402a7cb0a..9139b28528 100644 --- a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs +++ b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs @@ -3,6 +3,7 @@ using Moq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Routing; namespace Umbraco.Tests.Routing @@ -266,7 +267,7 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - SettingsForTests.ConfigureSettings(globalSettings.Object); + SettingsForTests.ConfigureSettings(globalSettings.Object); var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings.Object); var publishedRouter = CreatePublishedRouter(Container); @@ -335,10 +336,10 @@ namespace Umbraco.Tests.Routing Assert.IsTrue(result); Assert.AreEqual(expectedCulture, frequest.Culture.Name); Assert.AreEqual(frequest.PublishedContent.Id, expectedNode); - } - - // domains such as "/en" are natively supported, and when instanciating - // DomainAndUri for them, the host will come from the current request + } + + // domains such as "/en" are natively supported, and when instanciating + // DomainAndUri for them, the host will come from the current request // private void SetDomains3() { @@ -360,12 +361,12 @@ namespace Umbraco.Tests.Routing } }); } - + #region Cases [TestCase("http://domain1.com/en", "en-US", 10011)] [TestCase("http://domain1.com/en/1001-1-1", "en-US", 100111)] [TestCase("http://domain1.com/fr", "fr-FR", 10012)] - [TestCase("http://domain1.com/fr/1001-2-1", "fr-FR", 100121)] + [TestCase("http://domain1.com/fr/1001-2-1", "fr-FR", 100121)] #endregion public void DomainGeneric(string inputUrl, string expectedCulture, int expectedNode) { @@ -380,7 +381,7 @@ namespace Umbraco.Tests.Routing var frequest = publishedRouter.CreateRequest(umbracoContext); // lookup domain - publishedRouter.FindDomain(frequest); + publishedRouter.FindDomain(frequest); Assert.IsNotNull(frequest.Domain); Assert.AreEqual(expectedCulture, frequest.Culture.Name); @@ -391,5 +392,43 @@ namespace Umbraco.Tests.Routing Assert.IsTrue(result); Assert.AreEqual(frequest.PublishedContent.Id, expectedNode); } + + [Test] + public void WithDefaultCulture() + { + SetupDomainServiceMock(new[] + { + new UmbracoDomain("localhost:9000/en") + { + Id = 1, + LanguageId = LangEngId, + RootContentId = 10011, + LanguageIsoCode = "en-US" + }, + new UmbracoDomain("localhost:9000/fr") + { + Id = 1, + LanguageId = LangFrId, + RootContentId = 10012, + LanguageIsoCode = "fr-FR" + } + }); + + var requestUrl = "http://localhost:9000/fr/1001-2-2"; + + var defaultCultureAccessor = (TestDefaultCultureAccessor) DefaultCultureAccessor; + defaultCultureAccessor.DefaultCulture = "en-US"; + + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext(requestUrl, globalSettings:globalSettings.Object); + var publishedRouter = CreatePublishedRouter(Container); + var publishedRequest = publishedRouter.CreateRequest(umbracoContext); + + var domain = publishedRouter.FindDomain(publishedRequest); + Assert.AreEqual("fr-FR", publishedRequest.Culture.Name); + } } } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index 63bdb9c92e..080e224b9d 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -4,7 +4,7 @@ function ContentEditController($rootScope, $scope, $routeParams, $q, $timeout, $window, $location, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, - keyboardService, umbModelMapper, editorState, $http, eventsService, relationResource, overlayService) { + keyboardService, umbModelMapper, editorState, $http, eventsService, relationResource, overlayService, localizationService) { var evts = []; @@ -304,7 +304,7 @@ //before we launch the dialog we want to execute all client side validations first if (formHelper.submitForm({ scope: $scope, action: "publish" })) { var dialog = { - title: "Ready to Publish?", //TODO: localize + title: localizationService.localize("content_readyToPublish"), view: "publish", variants: $scope.content.variants, //set a model property for the dialog skipFormValidation: true, //when submitting the overlay form, skip any client side validation @@ -400,7 +400,7 @@ var target = null; var error = { headline: "Cannot automatically restore this item", content: "Use the Move menu item to move it manually" }; - if (data.length == 0) { + if (data.length === 0) { notificationsService.error(error.headline, "There is no 'restore' relation found for this node. Use the Move menu item to move it manually."); $scope.page.buttonRestore = "error"; return; @@ -408,7 +408,7 @@ relation = data[0]; - if (relation.parentId == -1) { + if (relation.parentId === -1) { target = { id: -1, name: "Root" }; moveNode(content, target); } else { @@ -465,7 +465,6 @@ $scope.editors[editorIndex].content = angular.copy($scope.content); $scope.editors[editorIndex].content.name = "What a variant"; // set selected variant on split view content - console.log($scope.editors[editorIndex].content.variants); angular.forEach($scope.editors[editorIndex].content.variants, function (variant) { if (variant.culture === selectedVariant.culture) { variant.current = true; diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index b8df84ad25..f5b890bd8c 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -235,7 +235,7 @@ What languages would you like to publish? No languages available to be published. Published Languages. - + Ready to Publish? Create a new Content Template from '%0%' diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs index 10fec19b38..aec5c375d9 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs @@ -46,12 +46,17 @@ namespace Umbraco.Web.Models.Mapping editor = _propertyEditors[Constants.PropertyEditors.Aliases.NoEdit]; } - var culture = context.GetCulture(); + var culture = context.GetCulture(); if (culture == null && property.PropertyType.Variations == ContentVariation.CultureNeutral) { //a language Id needs to be set for a property type that can be varried by language throw new InvalidOperationException($"No languageId found in mapping operation when one is required for the culture neutral property type {property.PropertyType.Alias}"); + } + if (property.PropertyType.Variations == ContentVariation.InvariantNeutral) + { + culture = null; + } var result = new TDestination diff --git a/src/Umbraco.Web/PropertyEditors/EmailAddressConfiguration.cs b/src/Umbraco.Web/PropertyEditors/EmailAddressConfiguration.cs index de7756266f..4039a0e3a2 100644 --- a/src/Umbraco.Web/PropertyEditors/EmailAddressConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/EmailAddressConfiguration.cs @@ -7,7 +7,7 @@ namespace Umbraco.Web.PropertyEditors /// public class EmailAddressConfiguration { - [ConfigurationField("Required?", "boolean")] + [ConfigurationField("IsRequired", "Required?", "boolean")] public bool IsRequired { get; set; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/Routing/DomainHelper.cs b/src/Umbraco.Web/Routing/DomainHelper.cs index 14779848bb..e3e214a144 100644 --- a/src/Umbraco.Web/Routing/DomainHelper.cs +++ b/src/Umbraco.Web/Routing/DomainHelper.cs @@ -147,8 +147,10 @@ namespace Umbraco.Web.Routing // else we have a uri, // try to match that uri, else filter - // pick domains for cultures - var cultureDomains = SelectByCulture(domainsAndUris, culture, defaultCulture); + // if a culture is specified, then try to get domains for that culture + // (else cultureDomains will be null) + // do NOT specify a default culture, else it would pick those domains + var cultureDomains = SelectByCulture(domainsAndUris, culture, defaultCulture: null); IReadOnlyCollection considerForBaseDomains = domainsAndUris; if (cultureDomains != null) {