using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services.OperationStatus; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Services; /// /// Represents the Localization Service, which is an easy access to operations involving and /// /// [Obsolete("Please use ILanguageService and IDictionaryItemService for localization. Will be removed in V15.")] internal class LocalizationService : RepositoryService, ILocalizationService { private readonly IDictionaryRepository _dictionaryRepository; private readonly ILanguageRepository _languageRepository; private readonly ILanguageService _languageService; private readonly IDictionaryItemService _dictionaryItemService; private readonly IUserIdKeyResolver _userIdKeyResolver; [Obsolete("Please use constructor with language, dictionary and user services. Will be removed in V15")] public LocalizationService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDictionaryRepository dictionaryRepository, ILanguageRepository languageRepository) : this( provider, loggerFactory, eventMessagesFactory, dictionaryRepository, languageRepository, StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService()) { } [Obsolete("Please use ILanguageService and IDictionaryItemService for localization. Will be removed in V15.")] public LocalizationService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDictionaryRepository dictionaryRepository, ILanguageRepository languageRepository, ILanguageService languageService, IDictionaryItemService dictionaryItemService, IUserIdKeyResolver userIdKeyResolver) : base(provider, loggerFactory, eventMessagesFactory) { _dictionaryRepository = dictionaryRepository; _languageRepository = languageRepository; _languageService = languageService; _dictionaryItemService = dictionaryItemService; _userIdKeyResolver = userIdKeyResolver; } /// /// Adds or updates a translation for a dictionary item and language /// /// /// /// /// /// /// This does not save the item, that needs to be done explicitly /// [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public void AddOrUpdateDictionaryValue(IDictionaryItem item, ILanguage? language, string value) { if (item == null) { throw new ArgumentNullException(nameof(item)); } if (language == null) { throw new ArgumentNullException(nameof(language)); } item.AddOrUpdateDictionaryValue(language, value); } /// /// Creates and saves a new dictionary item and assigns a value to all languages if defaultValue is specified. /// /// /// /// /// [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IDictionaryItem CreateDictionaryItemWithIdentity(string key, Guid? parentId, string? defaultValue = null) { IEnumerable translations = defaultValue.IsNullOrWhiteSpace() ? Array.Empty() : GetAllLanguages() .Select(language => new DictionaryTranslation(language, defaultValue!)) .ToArray(); Attempt result = _dictionaryItemService .CreateAsync(new DictionaryItem(parentId, key) { Translations = translations }, Constants.Security.SuperUserKey) .GetAwaiter() .GetResult(); // mimic old service behavior return result.Success || result.Status == DictionaryItemOperationStatus.CancelledByNotification ? result.Result : throw new ArgumentException($"Could not create a dictionary item with key: {key} under parent: {parentId}"); } /// /// Gets a by its id /// /// Id of the /// /// /// [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IDictionaryItem? GetDictionaryItemById(int id) { using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true)) { return _dictionaryRepository.Get(id); } } /// /// Gets a by its id /// /// Id of the /// /// /// [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IDictionaryItem? GetDictionaryItemById(Guid id) => _dictionaryItemService.GetAsync(id).GetAwaiter().GetResult(); /// /// Gets a collection by their ids /// /// Ids of the /// /// A collection of /// [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IEnumerable GetDictionaryItemsByIds(params Guid[] ids) => _dictionaryItemService.GetManyAsync(ids).GetAwaiter().GetResult(); /// /// Gets a by its key /// /// Key of the /// /// /// [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IDictionaryItem? GetDictionaryItemByKey(string key) => _dictionaryItemService.GetAsync(key).GetAwaiter().GetResult(); /// /// Gets a collection of by their keys /// /// Keys of the /// /// A collection of /// [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IEnumerable GetDictionaryItemsByKeys(params string[] keys) => _dictionaryItemService.GetManyAsync(keys).GetAwaiter().GetResult(); /// /// Gets a list of children for a /// /// Id of the parent /// An enumerable list of objects [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IEnumerable GetDictionaryItemChildren(Guid parentId) => _dictionaryItemService.GetChildrenAsync(parentId).GetAwaiter().GetResult(); /// /// Gets a list of descendants for a /// /// Id of the parent, null will return all dictionary items /// An enumerable list of objects [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IEnumerable GetDictionaryItemDescendants(Guid? parentId) => _dictionaryItemService.GetDescendantsAsync(parentId).GetAwaiter().GetResult(); /// /// Gets the root/top objects /// /// An enumerable list of objects [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public IEnumerable GetRootDictionaryItems() => _dictionaryItemService.GetAtRootAsync().GetAwaiter().GetResult(); /// /// Checks if a with given key exists /// /// Key of the /// True if a exists, otherwise false [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public bool DictionaryItemExists(string key) => _dictionaryItemService.ExistsAsync(key).GetAwaiter().GetResult(); /// /// Saves a object /// /// to save /// Optional id of the user saving the dictionary item [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public void Save(IDictionaryItem dictionaryItem, int userId = Constants.Security.SuperUserId) { Guid currentUserKey = _userIdKeyResolver.GetAsync(userId).GetAwaiter().GetResult(); if (dictionaryItem.Id > 0) { _dictionaryItemService.UpdateAsync(dictionaryItem, currentUserKey).GetAwaiter().GetResult(); } else { _dictionaryItemService.CreateAsync(dictionaryItem, currentUserKey).GetAwaiter().GetResult(); } } /// /// Deletes a object and its related translations /// as well as its children. /// /// to delete /// Optional id of the user deleting the dictionary item [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public void Delete(IDictionaryItem dictionaryItem, int userId = Constants.Security.SuperUserId) { Guid currentUserKey = _userIdKeyResolver.GetAsync(userId).GetAwaiter().GetResult(); _dictionaryItemService.DeleteAsync(dictionaryItem.Key, currentUserKey).GetAwaiter().GetResult(); } /// /// Gets a by its id /// /// Id of the /// /// /// [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public ILanguage? GetLanguageById(int id) { using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true)) { return _languageRepository.Get(id); } } /// /// Gets a by its iso code /// /// Iso Code of the language (ie. en-US) /// /// /// [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public ILanguage? GetLanguageByIsoCode(string? isoCode) { ArgumentException.ThrowIfNullOrEmpty(isoCode); return _languageService.GetAsync(isoCode).GetAwaiter().GetResult(); } /// [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public int? GetLanguageIdByIsoCode(string isoCode) => _languageService.GetAsync(isoCode).GetAwaiter().GetResult()?.Id; /// [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public string? GetLanguageIsoCodeById(int id) { using (ScopeProvider.CreateCoreScope(autoComplete: true)) { return _languageRepository.GetIsoCodeById(id); } } /// [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public string GetDefaultLanguageIsoCode() => _languageService.GetDefaultIsoCodeAsync().GetAwaiter().GetResult(); /// [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public int? GetDefaultLanguageId() { using (ScopeProvider.CreateCoreScope(autoComplete: true)) { return _languageRepository.GetDefaultId(); } } /// /// Gets all available languages /// /// An enumerable list of objects [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public IEnumerable GetAllLanguages() => _languageService.GetAllAsync().GetAwaiter().GetResult(); /// /// Saves a object /// /// to save /// Optional id of the user saving the language [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public void Save(ILanguage language, int userId = Constants.Security.SuperUserId) { Guid currentUserKey = _userIdKeyResolver.GetAsync(userId).GetAwaiter().GetResult(); Attempt result = language.Id > 0 ? _languageService.UpdateAsync(language, currentUserKey).GetAwaiter().GetResult() : _languageService.CreateAsync(language, currentUserKey).GetAwaiter().GetResult(); // mimic old Save behavior if (result.Status == LanguageOperationStatus.InvalidFallback) { throw new InvalidOperationException($"Cannot save language {language.IsoCode} with fallback {language.FallbackIsoCode}."); } } /// /// Deletes a by removing it (but not its usages) from the db /// /// to delete /// Optional id of the user deleting the language [Obsolete("Please use ILanguageService for language operations. Will be removed in V15.")] public void Delete(ILanguage language, int userId = Constants.Security.SuperUserId) { Guid currentUserKey = _userIdKeyResolver.GetAsync(userId).GetAwaiter().GetResult(); _languageService.DeleteAsync(language.IsoCode, currentUserKey).GetAwaiter().GetResult(); } [Obsolete("Please use IDictionaryItemService for dictionary item operations. Will be removed in V15.")] public Dictionary GetDictionaryItemKeyMap() { using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true)) { return _dictionaryRepository.GetDictionaryItemKeyMap(); } } }