diff --git a/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs b/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs index 292f8c585e..7885443ec8 100644 --- a/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs +++ b/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs @@ -2,10 +2,10 @@ using System.Globalization; using System.Linq; using System.Threading; +using Umbraco.Core.Dictionary; namespace Umbraco.Core.Services { - /// /// Extension methods for ILocalizedTextService /// @@ -61,5 +61,34 @@ namespace Umbraco.Core.Services return variables.Select((s, i) => new { index = i.ToString(CultureInfo.InvariantCulture), value = s }) .ToDictionary(keyvals => keyvals.index, keyvals => keyvals.value); } + + private static ICultureDictionary _cultureDictionary; + + internal static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text) + { + var cultureDictionary = CultureDictionary; + return UmbracoDictionaryTranslate(text, cultureDictionary); + } + + private static string UmbracoDictionaryTranslate(string text, ICultureDictionary cultureDictionary) + { + if (text == null) + return null; + + if (text.StartsWith("#") == false) + return text; + + text = text.Substring(1); + return cultureDictionary[text].IfNullOrWhiteSpace(text); + } + + private static ICultureDictionary CultureDictionary + { + get + { + return _cultureDictionary + ?? (_cultureDictionary = CultureDictionaryFactoryResolver.Current.Factory.CreateDictionary()); + } + } } } diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 4c2ea733b6..89d6f49d6d 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -1,18 +1,14 @@ using System.Collections.Generic; +using System.Linq; using System.Net; using System.Web.Http; using AutoMapper; -using Umbraco.Core; -using Umbraco.Core.Dictionary; using Umbraco.Core.Models; +using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Models.Mapping; using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using System.Linq; -using Umbraco.Web.WebApi.Filters; using Constants = Umbraco.Core.Constants; -using Newtonsoft.Json; +using Umbraco.Core.Services; namespace Umbraco.Web.Editors { @@ -27,8 +23,6 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class ContentTypeController : ContentTypeControllerBase { - private ICultureDictionary _cultureDictionary; - /// /// Constructor /// @@ -91,38 +85,13 @@ namespace Umbraco.Web.Editors var basics = types.Select(Mapper.Map).ToList(); + var localizedTextService = Services.TextService; foreach (var basic in basics) { - basic.Name = TranslateItem(basic.Name); - basic.Description = TranslateItem(basic.Description); + basic.Name = localizedTextService.UmbracoDictionaryTranslate(basic.Name); + basic.Description = localizedTextService.UmbracoDictionaryTranslate(basic.Description); } - return basics; } - - // TODO: This should really be centralized and used anywhere globalization applies. - internal string TranslateItem(string text) - { - if (text == null) - { - return null; - } - - if (text.StartsWith("#") == false) - 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/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index 4405f257c4..0788ba43eb 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -135,7 +135,7 @@ namespace Umbraco.Web.Editors ParentId = -1 }; - TabsAndPropertiesResolver.AddListView(display, "member", Services.DataTypeService); + TabsAndPropertiesResolver.AddListView(display, "member", Services.DataTypeService, Services.TextService); return display; } @@ -343,12 +343,13 @@ namespace Umbraco.Web.Editors //lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403 HandleInvalidModelState(display); + var localizedTextService = Services.TextService; //put the correct msgs in switch (contentItem.Action) { case ContentSaveAction.Save: case ContentSaveAction.SaveNew: - display.AddSuccessNotification(ui.Text("speechBubbles", "editMemberSaved"), ui.Text("speechBubbles", "editMemberSaved")); + display.AddSuccessNotification(localizedTextService.Localize("speechBubbles/editMemberSaved"), localizedTextService.Localize("speechBubbles/editMemberSaved")); break; } diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index b9a0cabdae..b152c3bbee 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -6,6 +6,7 @@ using System.Web; using System.Web.Mvc; using System.Web.Routing; using AutoMapper; +using umbraco; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; @@ -14,6 +15,7 @@ using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Trees; using Umbraco.Web.Routing; using umbraco.BusinessLogic.Actions; +using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.Models.Mapping { @@ -65,7 +67,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Notifications, expression => expression.Ignore()) .ForMember(display => display.Errors, expression => expression.Ignore()) .ForMember(display => display.Alias, expression => expression.Ignore()) - .ForMember(display => display.Tabs, expression => expression.ResolveUsing()) + .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService))) .ForMember(display => display.AllowedActions, expression => expression.ResolveUsing( new ActionButtonsResolver(new Lazy(() => applicationContext.Services.UserService)))) .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService, @@ -159,11 +161,18 @@ namespace Umbraco.Web.Models.Mapping if (content.ContentType.IsContainer) { - TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService); + TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, localizedText); } - + var properties = new List { + new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = localizedText.Localize("content/documentType"), + Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName), + View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + }, new ContentPropertyDisplay { Alias = string.Format("{0}releasedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), @@ -181,7 +190,7 @@ namespace Umbraco.Web.Models.Mapping new ContentPropertyDisplay { Alias = string.Format("{0}template", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = "Template", //TODO: localize this? + Label = localizedText.Localize("template/template"), Value = display.TemplateAlias, View = "dropdown", //TODO: Hard coding until we make a real dropdown property editor to lookup Config = new Dictionary @@ -198,7 +207,7 @@ namespace Umbraco.Web.Models.Mapping } }; - TabsAndPropertiesResolver.MapGenericProperties(content, display, properties.ToArray(), + TabsAndPropertiesResolver.MapGenericProperties(content, display, localizedText, properties.ToArray(), genericProperties => { //TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs index 3c27d0f183..9a71686c28 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs @@ -7,6 +7,7 @@ using System.Web; using System.Web.Mvc; using System.Web.Routing; using AutoMapper; +using umbraco; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; @@ -50,8 +51,8 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Updater, expression => expression.Ignore()) .ForMember(display => display.Alias, expression => expression.Ignore()) .ForMember(display => display.IsContainer, expression => expression.Ignore()) - .ForMember(display => display.Tabs, expression => expression.ResolveUsing()) - .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService)); + .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService))) + .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService)); //FROM IMedia TO ContentItemBasic config.CreateMap>() @@ -82,7 +83,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.Alias, expression => expression.Ignore()); } - private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService) + private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText) { // Adapted from ContentModelMapper //map the IsChildOfListView (this is actually if it is a descendant of a list view!) @@ -121,10 +122,21 @@ namespace Umbraco.Web.Models.Mapping if (media.ContentType.IsContainer) { - TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService); + TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService, localizedText); } + + var genericProperties = new List + { + new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = localizedText.Localize("content/mediatype"), + Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName), + View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + } + }; - TabsAndPropertiesResolver.MapGenericProperties(media, display); + TabsAndPropertiesResolver.MapGenericProperties(media, display, localizedText, genericProperties); } } diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs index 6b033f4a01..52fadd7a6a 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using umbraco; using System.Linq; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; using Umbraco.Web.Trees; @@ -75,7 +76,7 @@ namespace Umbraco.Web.Models.Mapping expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember(display => display.Properties, expression => expression.Ignore()) .ForMember(display => display.Tabs, - expression => expression.ResolveUsing()) + expression => expression.ResolveUsing(new MemberTabsAndPropertiesResolver(applicationContext.Services.TextService))) .ForMember(display => display.MemberProviderFieldMapping, expression => expression.ResolveUsing()) .ForMember(display => display.MembershipScenario, @@ -89,7 +90,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Trashed, expression => expression.Ignore()) .ForMember(display => display.IsContainer, expression => expression.Ignore()) .ForMember(display => display.TreeNodeUrl, expression => expression.Ignore()) - .AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, member, display)); + .AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, member, display, applicationContext.Services.TextService)); //FROM IMember TO MemberBasic config.CreateMap() @@ -163,10 +164,11 @@ namespace Umbraco.Web.Models.Mapping /// /// /// + /// /// /// If this is a new entity and there is an approved field then we'll set it to true by default. /// - private static void MapGenericCustomProperties(IMemberService memberService, IMember member, MemberDisplay display) + private static void MapGenericCustomProperties(IMemberService memberService, IMember member, MemberDisplay display, ILocalizedTextService localizedText) { var membersProvider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); @@ -177,14 +179,21 @@ namespace Umbraco.Web.Models.Mapping var url = urlHelper.GetUmbracoApiService(controller => controller.GetTreeNode(display.Key.ToString("N"), null)); display.TreeNodeUrl = url; } - + var genericProperties = new List { - GetLoginProperty(memberService, member, display), + new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = localizedText.Localize("content/membertype"), + Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName), + View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + }, + GetLoginProperty(memberService, member, display, localizedText), new ContentPropertyDisplay { Alias = string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("general", "email"), + Label = localizedText.Localize("general/email"), Value = display.Email, View = "email", Validation = {Mandatory = true} @@ -192,7 +201,7 @@ namespace Umbraco.Web.Models.Mapping new ContentPropertyDisplay { Alias = string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("password"), + Label = localizedText.Localize("password"), //NOTE: The value here is a json value - but the only property we care about is the generatedPassword one if it exists, the newPassword exists // only when creating a new member and we want to have a generated password pre-filled. Value = new Dictionary @@ -212,15 +221,16 @@ namespace Umbraco.Web.Models.Mapping new ContentPropertyDisplay { Alias = string.Format("{0}membergroup", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "membergroup"), + Label = localizedText.Localize("content/membergroup"), Value = GetMemberGroupValue(display.Username), View = "membergroups", Config = new Dictionary {{"IsRequired", true}} } }; - TabsAndPropertiesResolver.MapGenericProperties(member, display, genericProperties); + TabsAndPropertiesResolver.MapGenericProperties(member, display, localizedText, genericProperties); + //check if there's an approval field var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider; if (member.HasIdentity == false && provider != null) @@ -247,12 +257,12 @@ namespace Umbraco.Web.Models.Mapping /// the membership provider is a custom one, we cannot allow chaning the username because MembershipProvider's do not actually natively /// allow that. /// - internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, MemberDisplay display) + internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, MemberDisplay display, ILocalizedTextService localizedText) { var prop = new ContentPropertyDisplay { Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("login"), + Label = localizedText.Localize("login"), Value = display.Username }; @@ -321,6 +331,20 @@ namespace Umbraco.Web.Models.Mapping /// internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver { + private readonly ILocalizedTextService _localizedTextService; + + public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService) + : base(localizedTextService) + { + _localizedTextService = localizedTextService; + } + + public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService, + IEnumerable ignoreProperties) : base(localizedTextService, ignoreProperties) + { + _localizedTextService = localizedTextService; + } + protected override IEnumerable> ResolveCore(IContentBase content) { var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); @@ -339,7 +363,7 @@ namespace Umbraco.Web.Models.Mapping if (isLockedOutProperty != null && isLockedOutProperty.Value.ToString() != "1") { isLockedOutProperty.View = "readonlyvalue"; - isLockedOutProperty.Value = ui.Text("general", "no"); + isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); } return result; @@ -355,7 +379,7 @@ namespace Umbraco.Web.Models.Mapping if (isLockedOutProperty != null && isLockedOutProperty.Value.ToString() != "1") { isLockedOutProperty.View = "readonlyvalue"; - isLockedOutProperty.Value = ui.Text("general", "no"); + isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); } return result; diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index ecf5e2da42..fc053e6cda 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -1,11 +1,8 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; -using System.Web; using AutoMapper; using Umbraco.Core; -using Umbraco.Core.Dictionary; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -18,16 +15,19 @@ namespace Umbraco.Web.Models.Mapping /// Creates the tabs collection with properties assigned for display models /// internal class TabsAndPropertiesResolver : ValueResolver>> - { - private ICultureDictionary _cultureDictionary; + { + private readonly ILocalizedTextService _localizedTextService; protected IEnumerable IgnoreProperties { get; set; } - public TabsAndPropertiesResolver() + public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService) { + if (localizedTextService == null) throw new ArgumentNullException("localizedTextService"); + _localizedTextService = localizedTextService; IgnoreProperties = new List(); } - public TabsAndPropertiesResolver(IEnumerable ignoreProperties) + public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService, IEnumerable ignoreProperties) + : this(localizedTextService) { if (ignoreProperties == null) throw new ArgumentNullException("ignoreProperties"); IgnoreProperties = ignoreProperties; @@ -38,6 +38,7 @@ namespace Umbraco.Web.Models.Mapping /// /// /// + /// /// /// Any additional custom properties to assign to the generic properties tab. /// @@ -49,6 +50,7 @@ namespace Umbraco.Web.Models.Mapping public static void MapGenericProperties( TPersisted content, ContentItemDisplayBase display, + ILocalizedTextService localizedTextService, IEnumerable customProperties = null, Action> onGenericPropertiesMapped = null) where TPersisted : IContentBase @@ -72,33 +74,26 @@ namespace Umbraco.Web.Models.Mapping new ContentPropertyDisplay { Alias = string.Format("{0}creator", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "createBy"), - Description = ui.Text("content", "createByDesc"), //TODO: Localize this + Label = localizedTextService.Localize("content/createBy"), + Description = localizedTextService.Localize("content/createByDesc"), Value = display.Owner.Name, View = labelEditor }, new ContentPropertyDisplay { Alias = string.Format("{0}createdate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "createDate"), - Description = ui.Text("content", "createDateDesc"), + Label = localizedTextService.Localize("content/createDate"), + Description = localizedTextService.Localize("content/createDateDesc"), Value = display.CreateDate.ToIsoString(), View = labelEditor }, new ContentPropertyDisplay { Alias = string.Format("{0}updatedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "updateDate"), - Description = ui.Text("content", "updateDateDesc"), + Label = localizedTextService.Localize("content/updateDate"), + Description = localizedTextService.Localize("content/updateDateDesc"), Value = display.UpdateDate.ToIsoString(), View = labelEditor - }, - new ContentPropertyDisplay - { - Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "documentType"), - Value = TranslateItem(display.ContentTypeName, CreateDictionary()), - View = labelEditor } }; @@ -131,7 +126,7 @@ namespace Umbraco.Web.Models.Mapping /// /// This must be either 'content' or 'media' /// - internal static void AddListView(TabbedContentItem display, string entityType, IDataTypeService dataTypeService) + internal static void AddListView(TabbedContentItem display, string entityType, IDataTypeService dataTypeService, ILocalizedTextService localizedTextService) where TPersisted : IContentBase { int dtdId; @@ -171,7 +166,7 @@ namespace Umbraco.Web.Models.Mapping var listViewTab = new Tab(); listViewTab.Alias = Constants.Conventions.PropertyGroups.ListViewGroupName; - listViewTab.Label = ui.Text("content", "childItems"); + listViewTab.Label = localizedTextService.Localize("content/childItems"); listViewTab.Id = 25; listViewTab.IsActive = true; @@ -227,11 +222,12 @@ namespace Umbraco.Web.Models.Mapping //then we'll just use the root group's data to make the composite tab var rootGroup = propertyGroups.First(x => x.ParentId == null); + aggregateTabs.Add(new Tab { Id = rootGroup.Id, Alias = rootGroup.Name, - Label = TranslateItem(rootGroup.Name), + Label = _localizedTextService.UmbracoDictionaryTranslate(rootGroup.Name), Properties = aggregateProperties, IsActive = false }); @@ -248,7 +244,7 @@ namespace Umbraco.Web.Models.Mapping aggregateTabs.Add(new Tab { Id = 0, - Label = ui.Text("general", "properties"), + Label = _localizedTextService.Localize("general/properties"), Alias = "Generic properties", Properties = genericproperties }); @@ -264,45 +260,9 @@ namespace Umbraco.Web.Models.Mapping // Not sure whether it's a good idea to add this to the ContentPropertyDisplay mapper foreach (var prop in properties) { - prop.Label = TranslateItem(prop.Label); - prop.Description = TranslateItem(prop.Description); + prop.Label = _localizedTextService.UmbracoDictionaryTranslate(prop.Label); + prop.Description = _localizedTextService.UmbracoDictionaryTranslate(prop.Description); } } - - // TODO: This should really be centralized and used anywhere globalization applies. - internal string TranslateItem(string text) - { - var cultureDictionary = CultureDictionary; - return TranslateItem(text, cultureDictionary); - } - - private static string TranslateItem(string text, ICultureDictionary cultureDictionary) - { - if (text == null) - { - return null; - } - - if (text.StartsWith("#") == false) - return text; - - text = text.Substring(1); - return cultureDictionary[text].IfNullOrWhiteSpace(text); - } - - private ICultureDictionary CultureDictionary - { - get - { - return - _cultureDictionary ?? - (_cultureDictionary = CreateDictionary()); - } - } - - private static ICultureDictionary CreateDictionary() - { - return CultureDictionaryFactoryResolver.Current.Factory.CreateDictionary(); - } } }