diff --git a/src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs index eee020eee7..f98c0f1e71 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs @@ -50,6 +50,8 @@ namespace Umbraco.Core.Persistence.Repositories foreach (var textDto in dto.LanguageTextDtos) { var language = _languageRepository.Get(textDto.LanguageId); + if (language == null) + continue; var translationFactory = new DictionaryTranslationFactory(dto.UniqueId, language); list.Add(translationFactory.BuildEntity(textDto)); } diff --git a/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs index d52a2549f4..0c891d512d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs @@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories var sql = GetBaseQuery(false); sql.Where(GetBaseWhereClause(), new { Id = id }); - var languageDto = Database.First(sql); + var languageDto = Database.FirstOrDefault(sql); if (languageDto == null) return null; diff --git a/src/Umbraco.Tests/Persistence/Repositories/DictionaryRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DictionaryRepositoryTest.cs index 6619478aaf..a81d91fc11 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DictionaryRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DictionaryRepositoryTest.cs @@ -67,6 +67,38 @@ namespace Umbraco.Tests.Persistence.Repositories } + [Test] + public void Get_Ignores_Item_WhenLanguageMissing() + { + // Arrange + var language = ServiceContext.LocalizationService.GetLanguageByCultureCode("en-US"); + var itemMissingLanguage = new DictionaryItem("I have invalid language"); + var translations = new List + { + new DictionaryTranslation(new Language("") { Id = 0 }, ""), + new DictionaryTranslation(language, "I have language") + }; + itemMissingLanguage.Translations = translations; + ServiceContext.LocalizationService.Save(itemMissingLanguage);//Id 3? + + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + LanguageRepository languageRepository; + using (var repository = CreateRepository(unitOfWork, out languageRepository)) + { + // Act + var dictionaryItem = repository.Get(3); + + // Assert + Assert.That(dictionaryItem, Is.Not.Null); + Assert.That(dictionaryItem.ItemKey, Is.EqualTo("I have invalid language")); + Assert.That(dictionaryItem.Translations.Any(), Is.True); + Assert.That(dictionaryItem.Translations.Any(x => x == null), Is.False); + Assert.That(dictionaryItem.Translations.First().Value, Is.EqualTo("I have language")); + Assert.That(dictionaryItem.Translations.Count(), Is.EqualTo(1)); + } + } + [Test] public void Can_Perform_GetAll_On_DictionaryRepository() { diff --git a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs index 037848a911..bbc5d1ff22 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs @@ -60,6 +60,22 @@ namespace Umbraco.Tests.Persistence.Repositories } } + [Test] + public void Get_WhenIdDoesntExist_ReturnsNull() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + // Act + var language = repository.Get(0); + + // Assert + Assert.That(language, Is.Null); + } + } + [Test] public void Can_Perform_GetAll_On_LanguageRepository() { diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index e91dc4c90d..94574a7f75 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -2,6 +2,8 @@ using System.Net; using System.Web.Http; using AutoMapper; +using Umbraco.Core; +using Umbraco.Core.Dictionary; using Umbraco.Core.Models; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Mapping; @@ -24,6 +26,8 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class ContentTypeController : UmbracoAuthorizedJsonController { + private ICultureDictionary cultureDictionary; + /// /// Constructor /// @@ -47,28 +51,56 @@ namespace Umbraco.Web.Editors /// public IEnumerable GetAllowedChildren(int contentId) { + IEnumerable types; if (contentId == Core.Constants.System.Root) { - var types = Services.ContentTypeService.GetAllContentTypes(); + types = Services.ContentTypeService.GetAllContentTypes().ToList(); //if no allowed root types are set, just return everythibg if(types.Any(x => x.AllowedAsRoot)) types = types.Where(x => x.AllowedAsRoot); - - return types.Select(Mapper.Map); } - - var contentItem = Services.ContentService.GetById(contentId); - if (contentItem == null) + else { - throw new HttpResponseException(HttpStatusCode.NotFound); + var contentItem = Services.ContentService.GetById(contentId); + if (contentItem == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + types = contentItem.ContentType.AllowedContentTypes + .Select(x => Services.ContentTypeService.GetContentType(x.Id.Value)) + .ToList(); } + var basics = types.Select(Mapper.Map).ToList(); - return contentItem.ContentType.AllowedContentTypes - .Select(x => Services.ContentTypeService.GetContentType(x.Id.Value)) - .Select(Mapper.Map); - + foreach (var basic in basics) + { + basic.Name = TranslateItem(basic.Name); + basic.Description = TranslateItem(basic.Description); + } + + return basics; + } + + // This should really be centralized and used anywhere globalization applies. + internal string TranslateItem(string text) + { + if (!text.StartsWith("#")) + return text; + + text = text.Substring(1); + return CultureDictionary[text].IfNullOrWhiteSpace(text); + } + + private ICultureDictionary CultureDictionary + { + get + { + return + cultureDictionary ?? + (cultureDictionary = CultureDictionaryFactoryResolver.Current.Factory.CreateDictionary()); + } } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index e291ab17ea..95a46b0e27 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using AutoMapper; using Umbraco.Core; +using Umbraco.Core.Dictionary; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Web.Models.ContentEditing; @@ -15,6 +16,7 @@ namespace Umbraco.Web.Models.Mapping /// internal class TabsAndPropertiesResolver : ValueResolver>> { + private ICultureDictionary cultureDictionary; protected IEnumerable IgnoreProperties { get; set; } public TabsAndPropertiesResolver() @@ -92,7 +94,7 @@ namespace Umbraco.Web.Models.Mapping { Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = ui.Text("content", "documentType"), - Value = display.ContentTypeName, + Value = TranslateItem(display.ContentTypeName, CreateDictionary()), View = labelEditor } }; @@ -165,6 +167,13 @@ namespace Umbraco.Web.Models.Mapping Mapper.Map, IEnumerable>( propsForGroup)); } + + // Not sure whether it's a good idea to add this to the ContentPropertyDisplay mapper + foreach (var prop in aggregateProperties) + { + prop.Label = TranslateItem(prop.Label); + prop.Description = TranslateItem(prop.Description); + } //then we'll just use the root group's data to make the composite tab var rootGroup = propertyGroups.Single(x => x.ParentId == null); @@ -172,7 +181,7 @@ namespace Umbraco.Web.Models.Mapping { Id = rootGroup.Id, Alias = rootGroup.Name, - Label = TranslateTab(rootGroup.Name), + Label = TranslateItem(rootGroup.Name), Properties = aggregateProperties, IsActive = false }); @@ -198,33 +207,35 @@ namespace Umbraco.Web.Models.Mapping return aggregateTabs; } - private string TranslateTab(string tabName) + // This should really be centralized and used anywhere globalization applies. + internal string TranslateItem(string text) { - - if (!tabName.StartsWith("#")) - return tabName; + var cultureDictionary = CultureDictionary; + return TranslateItem(text, cultureDictionary); + } - return tabName.Substring(1); + private static string TranslateItem(string text, ICultureDictionary cultureDictionary) + { + if (!text.StartsWith("#")) + return text; - /* - * The below currently doesnt work on my machine, since the dictonary always creates an entry with lang id = 0, but I dont have a lang id zero - * so the query always fails, which is odd - * - var local = ApplicationContext.Current.Services.LocalizationService; - var dic = local.GetDictionaryItemByKey(tabName); - if (dic == null || !dic.Translations.Any()) - return tabName; + text = text.Substring(1); + return cultureDictionary[text].IfNullOrWhiteSpace(text); + } - var lang = local.GetLanguageByCultureCode(UmbracoContext.Current.Security.CurrentUser.Language); - if (lang == null) - return tabName; + private ICultureDictionary CultureDictionary + { + get + { + return + cultureDictionary ?? + (cultureDictionary = CreateDictionary()); + } + } - - var translation = dic.Translations.Where(x => x.Language == lang).FirstOrDefault(); - if (translation == null) - return tabName; - - return translation.Value;*/ + private static ICultureDictionary CreateDictionary() + { + return CultureDictionaryFactoryResolver.Current.Factory.CreateDictionary(); } } }