diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/LanguageColumns.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/LanguageColumns.cs
new file mode 100644
index 0000000000..18246ac14b
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/LanguageColumns.cs
@@ -0,0 +1,15 @@
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
+{
+ public class LanguageColumns : MigrationBase
+ {
+ protected LanguageColumns(IMigrationContext context) : base(context)
+ {
+ }
+
+ public override void Migrate()
+ {
+ Create.Column("isDefaultVariantLang").OnTable(Constants.DatabaseSchema.Tables.Language).AsBoolean().NotNullable();
+ Create.Column("mandatory").OnTable(Constants.DatabaseSchema.Tables.Language).AsBoolean().NotNullable();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
index ba29880e79..3ea761016b 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
@@ -1,5 +1,6 @@
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
+
public class SuperZero : MigrationBase
{
public SuperZero(IMigrationContext context)
diff --git a/src/Umbraco.Core/Models/ILanguage.cs b/src/Umbraco.Core/Models/ILanguage.cs
index 8eb9063302..23cef54180 100644
--- a/src/Umbraco.Core/Models/ILanguage.cs
+++ b/src/Umbraco.Core/Models/ILanguage.cs
@@ -23,5 +23,15 @@ namespace Umbraco.Core.Models
///
[IgnoreDataMember]
CultureInfo CultureInfo { get; }
+
+ ///
+ /// Defines if this language is the default variant language when language variants are in use
+ ///
+ bool IsDefaultVariantLanguage { get; set; }
+
+ ///
+ /// If true, a variant node cannot be published unless this language variant is created
+ ///
+ bool Mandatory { get; set; }
}
}
diff --git a/src/Umbraco.Core/Models/Language.cs b/src/Umbraco.Core/Models/Language.cs
index 6dfe59778f..a143a8c457 100644
--- a/src/Umbraco.Core/Models/Language.cs
+++ b/src/Umbraco.Core/Models/Language.cs
@@ -17,6 +17,8 @@ namespace Umbraco.Core.Models
private string _isoCode;
private string _cultureName;
+ private bool _isDefaultVariantLanguage;
+ private bool _mandatory;
public Language(string isoCode)
{
@@ -28,6 +30,8 @@ namespace Umbraco.Core.Models
{
public readonly PropertyInfo IsoCodeSelector = ExpressionHelper.GetPropertyInfo(x => x.IsoCode);
public readonly PropertyInfo CultureNameSelector = ExpressionHelper.GetPropertyInfo(x => x.CultureName);
+ public readonly PropertyInfo IsDefaultVariantLanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.IsDefaultVariantLanguage);
+ public readonly PropertyInfo MandatorySelector = ExpressionHelper.GetPropertyInfo(x => x.Mandatory);
}
///
@@ -55,5 +59,17 @@ namespace Umbraco.Core.Models
///
[IgnoreDataMember]
public CultureInfo CultureInfo => CultureInfo.GetCultureInfo(IsoCode);
+
+ public bool IsDefaultVariantLanguage
+ {
+ get => _isDefaultVariantLanguage;
+ set => SetPropertyValueAndDetectChanges(value, ref _isDefaultVariantLanguage, Ps.Value.IsDefaultVariantLanguageSelector);
+ }
+
+ public bool Mandatory
+ {
+ get => _mandatory;
+ set => SetPropertyValueAndDetectChanges(value, ref _mandatory, Ps.Value.MandatorySelector);
+ }
}
}
diff --git a/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs b/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs
index 83745a2bfe..f88d9fbb5c 100644
--- a/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs
+++ b/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs
@@ -22,5 +22,17 @@ namespace Umbraco.Core.Persistence.Dtos
[NullSetting(NullSetting = NullSettings.Null)]
[Length(100)]
public string CultureName { get; set; }
+
+ ///
+ /// Defines if this language is the default variant language when language variants are in use
+ ///
+ [Column("isDefaultVariantLang")]
+ public bool IsDefaultVariantLanguage { get; set; }
+
+ ///
+ /// If true, a variant node cannot be published unless this language variant is created
+ ///
+ [Column("mandatory")]
+ public bool Mandatory { get; set; }
}
}
diff --git a/src/Umbraco.Core/Persistence/Factories/LanguageFactory.cs b/src/Umbraco.Core/Persistence/Factories/LanguageFactory.cs
index f15313622b..f79dab1bbd 100644
--- a/src/Umbraco.Core/Persistence/Factories/LanguageFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/LanguageFactory.cs
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Persistence.Factories
{
public ILanguage BuildEntity(LanguageDto dto)
{
- var lang = new Language(dto.IsoCode) { CultureName = dto.CultureName, Id = dto.Id };
+ var lang = new Language(dto.IsoCode) { CultureName = dto.CultureName, Id = dto.Id, IsDefaultVariantLanguage = dto.IsDefaultVariantLanguage, Mandatory = dto.Mandatory };
// reset dirty initial properties (U4-1946)
lang.ResetDirtyProperties(false);
return lang;
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Factories
public LanguageDto BuildDto(ILanguage entity)
{
- var dto = new LanguageDto { CultureName = entity.CultureName, IsoCode = entity.IsoCode };
+ var dto = new LanguageDto { CultureName = entity.CultureName, IsoCode = entity.IsoCode, IsDefaultVariantLanguage = entity.IsDefaultVariantLanguage, Mandatory = entity.Mandatory };
if (entity.HasIdentity)
dto.Id = short.Parse(entity.Id.ToString(CultureInfo.InvariantCulture));
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs
index 784191279d..1397d79ea8 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs
@@ -107,6 +107,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
((EntityBase)entity).AddingEntity();
+ if (entity.IsDefaultVariantLanguage)
+ {
+ //if this entity is flagged as the default, we need to set all others to false
+ Database.Execute($"UPDATE {SqlSyntax.GetQuotedColumnName(Constants.DatabaseSchema.Tables.Language)} SET {SqlSyntax.GetQuotedColumnName("isDefaultVariantLang")} = 0");
+ //We need to clear the whole cache since all languages will be updated
+ IsolatedCache.ClearAllCache();
+ }
+
var factory = new LanguageFactory();
var dto = factory.BuildDto(entity);
@@ -114,12 +122,21 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
entity.Id = id;
entity.ResetDirtyProperties();
+
}
protected override void PersistUpdatedItem(ILanguage entity)
{
((EntityBase)entity).UpdatingEntity();
+ if (entity.IsDefaultVariantLanguage)
+ {
+ //if this entity is flagged as the default, we need to set all others to false
+ Database.Execute($"UPDATE {SqlSyntax.GetQuotedColumnName(Constants.DatabaseSchema.Tables.Language)} SET {SqlSyntax.GetQuotedColumnName("isDefaultVariantLang")} = 0");
+ //We need to clear the whole cache since all languages will be updated
+ IsolatedCache.ClearAllCache();
+ }
+
var factory = new LanguageFactory();
var dto = factory.BuildDto(entity);
diff --git a/src/Umbraco.Core/Services/Implement/LocalizationService.cs b/src/Umbraco.Core/Services/Implement/LocalizationService.cs
index 70103d9a06..1af053b787 100644
--- a/src/Umbraco.Core/Services/Implement/LocalizationService.cs
+++ b/src/Umbraco.Core/Services/Implement/LocalizationService.cs
@@ -411,7 +411,7 @@ namespace Umbraco.Core.Services.Implement
}
}
- #region Event Handlers
+ #region Events
///
/// Occurs before Delete
///
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 00f1a85d79..7089d164bc 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -315,6 +315,7 @@
+
diff --git a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs
index 3d0b484a50..0033c2524b 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs
@@ -219,6 +219,59 @@ namespace Umbraco.Tests.Persistence.Repositories
// Assert
Assert.That(languageBR.HasIdentity, Is.True);
Assert.That(languageBR.Id, Is.EqualTo(6)); //With 5 existing entries the Id should be 6
+ Assert.IsFalse(languageBR.IsDefaultVariantLanguage);
+ Assert.IsFalse(languageBR.Mandatory);
+ }
+ }
+
+ [Test]
+ public void Can_Perform_Add_On_LanguageRepository_With_Boolean_Properties()
+ {
+ // Arrange
+ var provider = TestObjects.GetScopeProvider(Logger);
+ using (var scope = provider.CreateScope())
+ {
+ var repository = CreateRepository(provider);
+
+ // Act
+ var languageBR = new Language("pt-BR") { CultureName = "pt-BR", IsDefaultVariantLanguage = true, Mandatory = true };
+ repository.Save(languageBR);
+
+ // Assert
+ Assert.That(languageBR.HasIdentity, Is.True);
+ Assert.That(languageBR.Id, Is.EqualTo(6)); //With 5 existing entries the Id should be 6
+ Assert.IsTrue(languageBR.IsDefaultVariantLanguage);
+ Assert.IsTrue(languageBR.Mandatory);
+ }
+ }
+
+ [Test]
+ public void Can_Perform_Add_On_LanguageRepository_With_New_Deafult()
+ {
+ // Arrange
+ var provider = TestObjects.GetScopeProvider(Logger);
+ using (var scope = provider.CreateScope())
+ {
+ var repository = CreateRepository(provider);
+
+ var languageBR = (ILanguage)new Language("pt-BR") { CultureName = "pt-BR", IsDefaultVariantLanguage = true, Mandatory = true };
+ repository.Save(languageBR);
+ var languageEN = new Language("en-AU") { CultureName = "en-AU" };
+ repository.Save(languageEN);
+
+ Assert.IsTrue(languageBR.IsDefaultVariantLanguage);
+ Assert.IsTrue(languageBR.Mandatory);
+
+ // Act
+
+ var languageNZ = new Language("en-NZ") { CultureName = "en-NZ", IsDefaultVariantLanguage = true, Mandatory = true };
+ repository.Save(languageNZ);
+ languageBR = repository.Get(languageBR.Id);
+
+ // Assert
+
+ Assert.IsFalse(languageBR.IsDefaultVariantLanguage);
+ Assert.IsTrue(languageNZ.IsDefaultVariantLanguage);
}
}
diff --git a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs b/src/Umbraco.Tests/Services/LocalizationServiceTests.cs
index b7f958cb8e..e39ebfee8e 100644
--- a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs
+++ b/src/Umbraco.Tests/Services/LocalizationServiceTests.cs
@@ -364,6 +364,28 @@ namespace Umbraco.Tests.Services
Assert.NotNull(result);
}
+ [Test]
+ public void Set_Default_Language()
+ {
+ var localizationService = ServiceContext.LocalizationService;
+ var language = new Core.Models.Language("en-AU");
+ language.IsDefaultVariantLanguage = true;
+ localizationService.Save(language);
+ var result = localizationService.GetLanguageById(language.Id);
+
+ Assert.IsTrue(result.IsDefaultVariantLanguage);
+
+ var language2 = new Core.Models.Language("en-NZ");
+ language2.IsDefaultVariantLanguage = true;
+ localizationService.Save(language2);
+ var result2 = localizationService.GetLanguageById(language2.Id);
+ //re-get
+ result = localizationService.GetLanguageById(language.Id);
+
+ Assert.IsTrue(result2.IsDefaultVariantLanguage);
+ Assert.IsFalse(result.IsDefaultVariantLanguage);
+ }
+
[Test]
public void Deleted_Language_Should_Not_Exist()
{