V12: Add ISO codes to make the migration from language IDs easier (#14567)
* Change the obsoletion messages for language IDs to target V14 instead of V13. * Wrong Language file * Add ISO codes required to migrate custom code from language IDs * Population of the new language FallbackIsoCode prop * Changing obsoletion msgs from v13 to v14 * Fix breaking changes
This commit is contained in:
committed by
GitHub
parent
103a792074
commit
ba423a0108
@@ -22,7 +22,7 @@ public class Language
|
||||
[DataMember(Name = "isMandatory")]
|
||||
public bool IsMandatory { get; set; }
|
||||
|
||||
[Obsolete("This will be replaced by fallback language ISO code in V13.")]
|
||||
[Obsolete("This will be replaced by fallback language ISO code in V14.")]
|
||||
[DataMember(Name = "fallbackLanguageId")]
|
||||
public int? FallbackLanguageId { get; set; }
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class DictionaryItem : EntityBase, IDictionaryItem
|
||||
_translations = new List<IDictionaryTranslation>();
|
||||
}
|
||||
|
||||
[Obsolete("This will be removed in V13.")]
|
||||
[Obsolete("This will be removed in V14.")]
|
||||
public Func<int, ILanguage?>? GetLanguage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,7 +10,7 @@ public static class DictionaryItemExtensions
|
||||
/// <param name="d"></param>
|
||||
/// <param name="languageId"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("This will be replaced in V13 by a corresponding method accepting language ISO code instead of language ID.")]
|
||||
[Obsolete("This will be replaced in V14 by a corresponding method accepting language ISO code instead of language ID.")]
|
||||
public static string? GetTranslatedValue(this IDictionaryItem d, int languageId)
|
||||
{
|
||||
IDictionaryTranslation? trans = d.Translations.FirstOrDefault(x => x.LanguageId == languageId);
|
||||
@@ -22,7 +22,7 @@ public static class DictionaryItemExtensions
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Warning: This method ONLY works in very specific scenarios. It will be removed in V13.")]
|
||||
[Obsolete("Warning: This method ONLY works in very specific scenarios. It will be removed in V14.")]
|
||||
public static string? GetDefaultValue(this IDictionaryItem d)
|
||||
{
|
||||
IDictionaryTranslation? defaultTranslation = d.Translations.FirstOrDefault(x => x.Language?.Id == 1);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System.Runtime.Serialization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models;
|
||||
|
||||
@@ -11,6 +14,7 @@ namespace Umbraco.Cms.Core.Models;
|
||||
public class DictionaryTranslation : EntityBase, IDictionaryTranslation
|
||||
{
|
||||
private ILanguage? _language;
|
||||
private string? _languageIsoCode;
|
||||
|
||||
// note: this will be memberwise cloned
|
||||
private string _value;
|
||||
@@ -20,6 +24,7 @@ public class DictionaryTranslation : EntityBase, IDictionaryTranslation
|
||||
_language = language ?? throw new ArgumentNullException("language");
|
||||
LanguageId = _language.Id;
|
||||
_value = value;
|
||||
LanguageIsoCode = language.IsoCode;
|
||||
}
|
||||
|
||||
public DictionaryTranslation(ILanguage language, string value, Guid uniqueId)
|
||||
@@ -27,17 +32,18 @@ public class DictionaryTranslation : EntityBase, IDictionaryTranslation
|
||||
_language = language ?? throw new ArgumentNullException("language");
|
||||
LanguageId = _language.Id;
|
||||
_value = value;
|
||||
LanguageIsoCode = language.IsoCode;
|
||||
Key = uniqueId;
|
||||
}
|
||||
|
||||
[Obsolete("Please use constructor that accepts ILanguage. This will be removed in V13.")]
|
||||
[Obsolete("Please use constructor that accepts ILanguage. This will be removed in V14.")]
|
||||
public DictionaryTranslation(int languageId, string value)
|
||||
{
|
||||
LanguageId = languageId;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
[Obsolete("Please use constructor that accepts ILanguage. This will be removed in V13.")]
|
||||
[Obsolete("Please use constructor that accepts ILanguage. This will be removed in V14.")]
|
||||
public DictionaryTranslation(int languageId, string value, Guid uniqueId)
|
||||
{
|
||||
LanguageId = languageId;
|
||||
@@ -58,7 +64,7 @@ public class DictionaryTranslation : EntityBase, IDictionaryTranslation
|
||||
/// returned
|
||||
/// on a callback.
|
||||
/// </remarks>
|
||||
[Obsolete("This will be removed in V13. From V13 onwards you should get languages by ISO code from ILanguageService.")]
|
||||
[Obsolete("This will be removed in V14. From V14 onwards you should get languages by ISO code from ILanguageService.")]
|
||||
[DataMember]
|
||||
[DoNotClone]
|
||||
public ILanguage? Language
|
||||
@@ -86,7 +92,7 @@ public class DictionaryTranslation : EntityBase, IDictionaryTranslation
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("This will be replaced by language ISO code in V13.")]
|
||||
[Obsolete("This will be replaced by language ISO code in V14.")]
|
||||
public int LanguageId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -99,6 +105,24 @@ public class DictionaryTranslation : EntityBase, IDictionaryTranslation
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _value!, nameof(Value));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string LanguageIsoCode
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO: this won't be necessary after obsoleted ctors are removed in v14.
|
||||
if (_languageIsoCode is null)
|
||||
{
|
||||
var _languageService = StaticServiceProvider.Instance.GetRequiredService<ILocalizationService>();
|
||||
_languageIsoCode = _languageService.GetLanguageById(LanguageId)?.IsoCode ?? string.Empty;
|
||||
}
|
||||
|
||||
return _languageIsoCode;
|
||||
}
|
||||
|
||||
private set => SetPropertyValueAndDetectChanges(value, ref _languageIsoCode!, nameof(LanguageIsoCode));
|
||||
}
|
||||
|
||||
protected override void PerformDeepClone(object clone)
|
||||
{
|
||||
base.PerformDeepClone(clone);
|
||||
|
||||
@@ -6,18 +6,24 @@ namespace Umbraco.Cms.Core.Models;
|
||||
public interface IDictionaryTranslation : IEntity, IRememberBeingDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Language" /> for the translation
|
||||
/// Gets or sets the <see cref="Language" /> for the translation.
|
||||
/// </summary>
|
||||
[Obsolete("This will be removed in V13. From V13 onwards you should get languages by ISO code from ILanguageService.")]
|
||||
[Obsolete("This will be removed in V14. From V14 onwards you should get languages by ISO code from ILanguageService.")]
|
||||
[DataMember]
|
||||
ILanguage? Language { get; set; }
|
||||
|
||||
[Obsolete("This will be replaced by language ISO code in V13.")]
|
||||
[Obsolete("This will be replaced by language ISO code in V14.")]
|
||||
int LanguageId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the translated text
|
||||
/// Gets or sets the translated text.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ISO code of the language.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
string LanguageIsoCode => Language?.IsoCode ?? string.Empty;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,24 @@ public interface ILanguage : IEntity, IRememberBeingDirty
|
||||
/// define fallback strategies when a value does not exist for a requested language.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete("This will be replaced by fallback language ISO code in V13.")]
|
||||
[Obsolete("This will be replaced by fallback language ISO code in V14.")]
|
||||
[DataMember]
|
||||
int? FallbackLanguageId { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ISO code of a fallback language.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The fallback language can be used in multi-lingual scenarios, to help
|
||||
/// define fallback strategies when a value does not exist for a requested language.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
string? FallbackIsoCode
|
||||
{
|
||||
get => null;
|
||||
set { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models;
|
||||
@@ -14,6 +13,7 @@ public class Language : EntityBase, ILanguage
|
||||
{
|
||||
private string _cultureName;
|
||||
private int? _fallbackLanguageId;
|
||||
private string? _fallbackLanguageIsoCode;
|
||||
private bool _isDefaultVariantLanguage;
|
||||
private string _isoCode;
|
||||
private bool _mandatory;
|
||||
@@ -74,10 +74,17 @@ public class Language : EntityBase, ILanguage
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("This will be replaced by fallback language ISO code in V13.")]
|
||||
[Obsolete("This will be replaced by fallback language ISO code in V14.")]
|
||||
public int? FallbackLanguageId
|
||||
{
|
||||
get => _fallbackLanguageId;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _fallbackLanguageId, nameof(FallbackLanguageId));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? FallbackIsoCode
|
||||
{
|
||||
get => _fallbackLanguageIsoCode;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _fallbackLanguageIsoCode, nameof(FallbackIsoCode));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories;
|
||||
|
||||
internal static class LanguageFactory
|
||||
{
|
||||
public static ILanguage BuildEntity(LanguageDto dto)
|
||||
public static ILanguage BuildEntity(LanguageDto dto, string? fallbackIsoCode)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dto);
|
||||
if (dto.IsoCode is null)
|
||||
@@ -22,6 +22,7 @@ internal static class LanguageFactory
|
||||
IsDefault = dto.IsDefault,
|
||||
IsMandatory = dto.IsMandatory,
|
||||
FallbackLanguageId = dto.FallbackLanguageId,
|
||||
FallbackIsoCode = fallbackIsoCode
|
||||
};
|
||||
|
||||
// Reset dirty initial properties
|
||||
|
||||
@@ -120,7 +120,19 @@ internal class LanguageRepository : EntityRepositoryBase<int, ILanguage>, ILangu
|
||||
new FullDataSetRepositoryCachePolicy<ILanguage, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
|
||||
|
||||
protected ILanguage ConvertFromDto(LanguageDto dto)
|
||||
=> LanguageFactory.BuildEntity(dto);
|
||||
{
|
||||
// yes, we want to lock _codeIdMap
|
||||
lock (_codeIdMap)
|
||||
{
|
||||
string? fallbackIsoCode = null;
|
||||
if (dto.FallbackLanguageId.HasValue && _idCodeMap.TryGetValue(dto.FallbackLanguageId.Value, out fallbackIsoCode) == false)
|
||||
{
|
||||
throw new ArgumentException($"The ISO code map did not contain ISO code for fallback language ID: {dto.FallbackLanguageId}. Please reload the caches.");
|
||||
}
|
||||
|
||||
return LanguageFactory.BuildEntity(dto, fallbackIsoCode);
|
||||
}
|
||||
}
|
||||
|
||||
// do NOT leak that language, it's not deep-cloned!
|
||||
private ILanguage GetDefault()
|
||||
@@ -172,20 +184,25 @@ internal class LanguageRepository : EntityRepositoryBase<int, ILanguage>, ILangu
|
||||
sql.OrderBy<LanguageDto>(x => x.Id);
|
||||
|
||||
// get languages
|
||||
var languages = Database.Fetch<LanguageDto>(sql).Select(ConvertFromDto).OrderBy(x => x.Id).ToList();
|
||||
List<LanguageDto>? languageDtos = Database.Fetch<LanguageDto>(sql) ?? new List<LanguageDto>();
|
||||
|
||||
// initialize the code-id map
|
||||
lock (_codeIdMap)
|
||||
// initialize the code-id map if we've reloaded the entire set of languages
|
||||
if (ids?.Any() == false)
|
||||
{
|
||||
_codeIdMap.Clear();
|
||||
_idCodeMap.Clear();
|
||||
foreach (ILanguage language in languages)
|
||||
lock (_codeIdMap)
|
||||
{
|
||||
_codeIdMap[language.IsoCode] = language.Id;
|
||||
_idCodeMap[language.Id] = language.IsoCode.ToLowerInvariant();
|
||||
_codeIdMap.Clear();
|
||||
_idCodeMap.Clear();
|
||||
foreach (LanguageDto languageDto in languageDtos)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrEmpty(languageDto.IsoCode, nameof(LanguageDto.IsoCode));
|
||||
_codeIdMap[languageDto.IsoCode] = languageDto.Id;
|
||||
_idCodeMap[languageDto.Id] = languageDto.IsoCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var languages = languageDtos.Select(ConvertFromDto).OrderBy(x => x.Id).ToList();
|
||||
return languages;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ public class LanguageBuilder<TParent>
|
||||
return this;
|
||||
}
|
||||
|
||||
[Obsolete("This will be replaced in V13 by a corresponding method accepting language ISO code instead of language ID.")]
|
||||
[Obsolete("This will be replaced in V14 by a corresponding method accepting language ISO code instead of language ID.")]
|
||||
public LanguageBuilder<TParent> WithFallbackLanguageId(int fallbackLanguageId)
|
||||
{
|
||||
_fallbackLanguageId = fallbackLanguageId;
|
||||
|
||||
Reference in New Issue
Block a user