From 7099ce8b5941e019d0c9b994612248c8b34b53de Mon Sep 17 00:00:00 2001 From: Nicholas Mayne Date: Mon, 25 Aug 2014 11:07:13 +0100 Subject: [PATCH] Adding changes from Dunross and also hooking up Cache to ListCultures for perf --- .../Controllers/AdminController.cs | 81 ++++++++++++------- .../Drivers/LocalizationPartDriver.cs | 26 +++--- .../Handlers/LocalizationPartHandler.cs | 2 +- .../Services/ILocalizationService.cs | 10 ++- .../Services/LocalizationService.cs | 71 +++++++++++----- .../ViewModels/AddLocalizationViewModel.cs | 2 +- .../Views/CultureSelection.cshtml | 6 +- ...calization.ContentTranslations.Edit.cshtml | 50 +++++++----- ...on.ContentTranslations.SummaryAdmin.cshtml | 13 ++- .../Services/DefaultCultureManager.cs | 20 +++-- 10 files changed, 177 insertions(+), 104 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Localization/Controllers/AdminController.cs index d477a7d17..243af3cc2 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Controllers/AdminController.cs @@ -39,37 +39,53 @@ namespace Orchard.Localization.Controllers { public ActionResult Translate(int id, string to) { var contentItem = _contentManager.Get(id, VersionOptions.Latest); - // only support translations from the site culture, at the moment at least if (contentItem == null) return HttpNotFound(); - if (!contentItem.Is() || contentItem.As().MasterContentItem != null) { - var metadata = _contentManager.GetItemMetadata(contentItem); - return RedirectToAction(Convert.ToString(metadata.EditorRouteValues["action"]), metadata.EditorRouteValues); - } + var lp = contentItem.As(); + + if (lp == null) + return HttpNotFound(); + + string contentItemCulture = _localizationService.GetContentCulture(contentItem); + var localizations = _localizationService.GetLocalizations(lp, VersionOptions.Latest); - var siteCultures = _cultureManager.ListCultures().Where(s => s != _localizationService.GetContentCulture(contentItem) && s != _cultureManager.GetSiteCulture()); - var selectedCulture = siteCultures.SingleOrDefault(s => string.Equals(s, to, StringComparison.OrdinalIgnoreCase)) - ?? _cultureManager.GetCurrentCulture(HttpContext); // could be null but the person doing the translating might be translating into their current culture + var siteCultures = _cultureManager.ListCultures(); - //todo: need a better solution for modifying some parts when translating - or go with a completely different experience - /* - if (contentItem.Has()) { - RoutePart routePart = contentItem.As(); - routePart.Slug = string.Format("{0}{2}{1}", routePart.Slug, siteCultures.Any(s => string.Equals(s, selectedCulture, StringComparison.OrdinalIgnoreCase)) ? selectedCulture : "", !string.IsNullOrWhiteSpace(routePart.Slug) ? "-" : ""); - routePart.Path = null; - }*/ + var missingCultures = siteCultures.Where(s => + s != contentItemCulture + && !localizations.Any(l => s == l.Culture.Culture)) + .ToList(); - if (contentItem.As().Culture != null) - contentItem.As().Culture.Culture = null; + string selectedCulture = null; + + if (!String.IsNullOrEmpty(to)) { + + if (!siteCultures.Any(c => String.Equals(c, to, StringComparison.OrdinalIgnoreCase))) + return HttpNotFound(); + + var existingLocalization = String.Equals(contentItemCulture, to, StringComparison.OrdinalIgnoreCase) + ? lp + : localizations.FirstOrDefault(l => string.Equals(l.Culture.Culture, to, StringComparison.OrdinalIgnoreCase)); + + if (existingLocalization != null) { + var metadata = _contentManager.GetItemMetadata(existingLocalization); + return RedirectToAction(Convert.ToString(metadata.EditorRouteValues["action"]), metadata.EditorRouteValues); + } + + selectedCulture = missingCultures.SingleOrDefault(s => string.Equals(s, to, StringComparison.OrdinalIgnoreCase)); + } + + if (lp.Culture != null) + lp.Culture.Culture = null; var model = new AddLocalizationViewModel { Id = id, SelectedCulture = selectedCulture, - SiteCultures = siteCultures, + MissingCultures = missingCultures, Content = _contentManager.BuildEditor(contentItem) }; - // Cancel transaction so that the routepart is not modified. + // Cancel transaction so that the LocalizationPart is not modified. Services.TransactionManager.Cancel(); return View(model); @@ -92,6 +108,7 @@ namespace Orchard.Localization.Controllers { public ActionResult TranslatePOST(int id, Action conditionallyPublish) { var contentItem = _contentManager.Get(id, VersionOptions.Latest); + var originalLp = contentItem.As(); if (contentItem == null) return HttpNotFound(); @@ -107,9 +124,17 @@ namespace Orchard.Localization.Controllers { } else { // create contentItemTranslation = _contentManager.New(contentItem.ContentType); - if (contentItemTranslation.Has() && contentItem.Has()) { - contentItemTranslation.As().Container = contentItem.As().Container; - } + + LocalizationPart translationLp = contentItemTranslation.As(); + + translationLp.MasterContentItem = originalLp.MasterContentItem != null + ? originalLp.MasterContentItem + : contentItem; + + if (!string.IsNullOrWhiteSpace(model.SelectedCulture)) + { + translationLp.Culture = _cultureManager.GetCultureByName(model.SelectedCulture); + } _contentManager.Create(contentItemTranslation, VersionOptions.Draft); } @@ -118,8 +143,10 @@ namespace Orchard.Localization.Controllers { if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); - model.SiteCultures = _cultureManager.ListCultures().Where(s => s != _localizationService.GetContentCulture(contentItem) && s != _cultureManager.GetSiteCulture()); - var culture = contentItem.As().Culture; + model.MissingCultures = _cultureManager.ListCultures().Where(s => s != _localizationService.GetContentCulture(contentItem) && s != _cultureManager.GetSiteCulture()); + + var culture = originalLp.Culture; + if (culture != null) { culture.Culture = null; } @@ -131,12 +158,6 @@ namespace Orchard.Localization.Controllers { Services.Notifier.Information(T("Edited content item translation.")); } else { - LocalizationPart localized = contentItemTranslation.As(); - localized.MasterContentItem = contentItem; - if (!string.IsNullOrWhiteSpace(model.SelectedCulture)) { - localized.Culture = _cultureManager.GetCultureByName(model.SelectedCulture); - } - conditionallyPublish(contentItemTranslation); Services.Notifier.Information(T("Created content item translation.")); diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Drivers/LocalizationPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Localization/Drivers/LocalizationPartDriver.cs index 10f16f86f..7777c9f9c 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Drivers/LocalizationPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Drivers/LocalizationPartDriver.cs @@ -22,30 +22,27 @@ namespace Orchard.Localization.Drivers { } protected override DriverResult Display(LocalizationPart part, string displayType, dynamic shapeHelper) { - if (!IsActivatable()) - return null; - var masterId = part.MasterContentItem != null ? part.MasterContentItem.Id : part.Id; + + var siteCultures = _cultureManager.ListCultures(); + return Combined( ContentShape("Parts_Localization_ContentTranslations", - () => shapeHelper.Parts_Localization_ContentTranslations(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Published))), + () => shapeHelper.Parts_Localization_ContentTranslations(Id: part.ContentItem.Id, MasterId: masterId, Culture: GetCulture(part), Localizations: GetDisplayLocalizations(part, VersionOptions.Published))), ContentShape("Parts_Localization_ContentTranslations_Summary", - () => shapeHelper.Parts_Localization_ContentTranslations_Summary(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Published))), + () => shapeHelper.Parts_Localization_ContentTranslations_Summary(Id: part.ContentItem.Id, MasterId: masterId, Culture: GetCulture(part), Localizations: GetDisplayLocalizations(part, VersionOptions.Published))), ContentShape("Parts_Localization_ContentTranslations_SummaryAdmin", - () => shapeHelper.Parts_Localization_ContentTranslations_SummaryAdmin(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Latest))) + () => shapeHelper.Parts_Localization_ContentTranslations_SummaryAdmin(Id: part.ContentItem.Id, MasterId: masterId, Culture: GetCulture(part), Localizations: GetDisplayLocalizations(part, VersionOptions.Latest), SiteCultures: siteCultures)) ); } protected override DriverResult Editor(LocalizationPart part, dynamic shapeHelper) { - if (!IsActivatable()) - return null; - var localizations = GetEditorLocalizations(part).ToList(); var model = new EditLocalizationViewModel { - SelectedCulture = part.Culture != null ? part.Culture.Culture : null, - SiteCultures = _cultureManager.ListCultures().Where(s => s != _cultureManager.GetSiteCulture() && !localizations.Select(l => l.Culture.Culture).Contains(s)), + SelectedCulture = GetCulture(part), + SiteCultures = _cultureManager.ListCultures().Where(s => !localizations.Any(l => l.Culture.Culture == s)).ToList(), ContentItem = part, MasterContentItem = part.MasterContentItem, ContentLocalizations = new ContentLocalizationsViewModel(part) { Localizations = localizations } @@ -56,9 +53,6 @@ namespace Orchard.Localization.Drivers { } protected override DriverResult Editor(LocalizationPart part, IUpdateModel updater, dynamic shapeHelper) { - if (!IsActivatable()) - return null; - var model = new EditLocalizationViewModel(); if (updater != null && updater.TryUpdateModel(model, TemplatePrefix, null, null)) { _localizationService.SetContentCulture(part, model.SelectedCulture); @@ -67,8 +61,8 @@ namespace Orchard.Localization.Drivers { return Editor(part, shapeHelper); } - private bool IsActivatable() { - return _cultureManager.ListCultures().Count() > 1; + private static string GetCulture(LocalizationPart part) { + return part.Culture != null ? part.Culture.Culture : null; } private IEnumerable GetDisplayLocalizations(LocalizationPart part, VersionOptions versionOptions) { diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs index 32b87b863..affd63b33 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs @@ -48,7 +48,7 @@ namespace Orchard.Localization.Handlers { _cultureManager.GetCultureById(localizationPart.Record.CultureId)); localizationPart.MasterContentItemField.Loader(ctx => - _contentManager.Get(localizationPart.Record.MasterContentItemId, localizationPart.IsPublished() ? VersionOptions.Published : VersionOptions.Latest)); + _contentManager.Get(localizationPart.Record.MasterContentItemId, VersionOptions.AllVersions)); } } } diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Services/ILocalizationService.cs b/src/Orchard.Web/Modules/Orchard.Localization/Services/ILocalizationService.cs index 681a7227b..bafcaa44c 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Services/ILocalizationService.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Services/ILocalizationService.cs @@ -4,9 +4,11 @@ using Orchard.Localization.Models; namespace Orchard.Localization.Services { public interface ILocalizationService : IDependency { - LocalizationPart GetLocalizedContentItem(IContent masterContentItem, string culture); - string GetContentCulture(IContent contentItem); - void SetContentCulture(IContent contentItem, string culture); - IEnumerable GetLocalizations(IContent contentItem, VersionOptions versionOptions); + LocalizationPart GetLocalizedContentItem(IContent content, string culture); + LocalizationPart GetLocalizedContentItem(IContent content, string culture, VersionOptions versionOptions); + string GetContentCulture(IContent content); + void SetContentCulture(IContent content, string culture); + IEnumerable GetLocalizations(IContent content); + IEnumerable GetLocalizations(IContent content, VersionOptions versionOptions); } } diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Services/LocalizationService.cs b/src/Orchard.Web/Modules/Orchard.Localization/Services/LocalizationService.cs index 3d2a311a4..46bc3146d 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Services/LocalizationService.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Services/LocalizationService.cs @@ -14,49 +14,82 @@ namespace Orchard.Localization.Services { } LocalizationPart ILocalizationService.GetLocalizedContentItem(IContent content, string culture) { + // Warning: Returns only the first of same culture localizations. + return ((ILocalizationService) this).GetLocalizedContentItem(content, culture, null); + } + + LocalizationPart ILocalizationService.GetLocalizedContentItem(IContent content, string culture, VersionOptions versionOptions) { var cultureRecord = _cultureManager.GetCultureByName(culture); if (cultureRecord == null) return null; - return _contentManager.Query(content.ContentItem.ContentType) - .Where(l => l.MasterContentItemId == content.ContentItem.Id && l.CultureId == cultureRecord.Id) + var localized = content.As(); + + if (localized == null) + return null; + + var query = versionOptions == null + ? _contentManager.Query(content.ContentItem.ContentType) + : _contentManager.Query(versionOptions, content.ContentItem.ContentType); + + // Warning: Returns only the first of same culture localizations. + return query.Where(l => + (l.Id == content.ContentItem.Id || l.MasterContentItemId == content.ContentItem.Id) + && l.CultureId == cultureRecord.Id) .List() .Select(i => i.As()) - .SingleOrDefault(); + .FirstOrDefault(); } string ILocalizationService.GetContentCulture(IContent content) { var localized = content.As(); return localized != null && localized.Culture != null - ? localized.Culture.Culture - : _cultureManager.GetSiteCulture(); + ? localized.Culture.Culture + : _cultureManager.GetSiteCulture(); } void ILocalizationService.SetContentCulture(IContent content, string culture) { var localized = content.As(); - if (localized == null || localized.MasterContentItem == null) + if (localized == null) return; - localized.Culture = _cultureManager.GetCultureByName(culture); + var cultureRecord = _cultureManager.GetCultureByName(culture); + + localized.Culture = cultureRecord; + } + + IEnumerable ILocalizationService.GetLocalizations(IContent content) { + // Warning: May contain more than one localization of the same culture. + return ((ILocalizationService) this).GetLocalizations(content, null); } IEnumerable ILocalizationService.GetLocalizations(IContent content, VersionOptions versionOptions) { + if (content.ContentItem.Id == 0) + return Enumerable.Empty(); + var localized = content.As(); - if (localized.MasterContentItem != null) - return _contentManager.Query(versionOptions, localized.ContentItem.ContentType) - .Where(l => - l.Id != localized.ContentItem.Id - && (l.Id == localized.MasterContentItem.ContentItem.Id - || l.MasterContentItemId == localized.MasterContentItem.ContentItem.Id)) - .List() - .Select(i => i.As()); + var query = versionOptions == null + ? _contentManager.Query(localized.ContentItem.ContentType) + : _contentManager.Query(versionOptions, localized.ContentItem.ContentType); - return _contentManager.Query(versionOptions, localized.ContentItem.ContentType) - .Where(l => l.MasterContentItemId == localized.ContentItem.Id) - .List() - .Select(i => i.As()); + int contentItemId = localized.ContentItem.Id; + + if (localized.MasterContentItem != null) { + int masterContentItemId = localized.MasterContentItem.ContentItem.Id; + + query = query.Where(l => + l.Id != contentItemId // Exclude the content + && (l.Id == masterContentItemId || l.MasterContentItemId == masterContentItemId)); + } + else { + query = query.Where(l => + l.MasterContentItemId == contentItemId); + } + + // Warning: May contain more than one localization of the same culture. + return query.List().Select(i => i.As()); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Localization/ViewModels/AddLocalizationViewModel.cs b/src/Orchard.Web/Modules/Orchard.Localization/ViewModels/AddLocalizationViewModel.cs index c7725c827..fd259d4a3 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/ViewModels/AddLocalizationViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/ViewModels/AddLocalizationViewModel.cs @@ -7,7 +7,7 @@ namespace Orchard.Localization.ViewModels { public int Id { get; set; } [Required] public string SelectedCulture { get; set; } - public IEnumerable SiteCultures { get; set; } + public IEnumerable MissingCultures { get; set; } public IContent Content { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Views/CultureSelection.cshtml b/src/Orchard.Web/Modules/Orchard.Localization/Views/CultureSelection.cshtml index fdc51025c..5cedde574 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Views/CultureSelection.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Localization/Views/CultureSelection.cshtml @@ -4,13 +4,9 @@ }
- @{ - var siteCultures = Model.SiteCultures.ToList(); - siteCultures.Insert(0, ""); - }
@T("This is the {0} variation of {1}", - Html.DropDownList("SelectedCulture", new SelectList(siteCultures, Model.SelectedCulture)), + Html.DropDownList("SelectedCulture", new SelectList(Model.MissingCultures, Model.SelectedCulture)), Html.ItemEditLink(Model.Content))
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Views/EditorTemplates/Parts/Localization.ContentTranslations.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Localization/Views/EditorTemplates/Parts/Localization.ContentTranslations.Edit.cshtml index b4e9126e9..497b8f166 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Views/EditorTemplates/Parts/Localization.ContentTranslations.Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Localization/Views/EditorTemplates/Parts/Localization.ContentTranslations.Edit.cshtml @@ -1,22 +1,36 @@ @model Orchard.Localization.ViewModels.EditLocalizationViewModel -
-@if (Model.ContentItem.ContentItem.Id > 0 && Model.SelectedCulture != null && Model.ContentLocalizations.Localizations.Count() > 0) { +@using System.Linq; +@{ Style.Require("LocalizationAdmin"); -
- -
@T("This is the {0} variation of {1}.", - Html.Encode(Model.SelectedCulture), - Html.ItemEditLink(Model.MasterContentItem ?? Model.ContentItem))
- @Html.Hidden("SelectedCulture", Model.SelectedCulture) -
- if (Model.ContentLocalizations.Localizations.Count() > 0) { -
-
@T("Other translations:")
-
- @Html.UnorderedList(Model.ContentLocalizations.Localizations, (c, i) => Html.ItemEditLink(c.Culture.Culture, c), "localizations") -
-
+ var siteCultures = Model.SiteCultures.ToList(); +} +
+ @if (Model.ContentItem.ContentItem.Id == 0 || Model.ContentLocalizations.Localizations.Count() == 0) { +
+ +
+ @T("This is the {0} variation of the content", + Html.DropDownList("SelectedCulture", new SelectList(siteCultures, Model.SelectedCulture))) +
+
+ } else { +
+ +
+ @T("This is the {0} variation of the content.", + Html.Encode(Model.SelectedCulture)) +
+ @Html.Hidden("SelectedCulture", Model.SelectedCulture) +
+
+
@T("Other translations:")
+
+ @Html.UnorderedList(Model.ContentLocalizations.Localizations, (c, i) => Html.ItemEditLink(c.Culture.Culture, c), "localizations") +
+
+ } + + @if (Model.SelectedCulture != null && !siteCultures.All(c => c == Model.SelectedCulture || Model.ContentLocalizations.Localizations.Any(l => c == l.Culture.Culture))) { +
@Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new { area = "Orchard.Localization", id = Model.ContentItem.Id }, null)
} -} -
@Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new { area = "Orchard.Localization", id = Model.ContentItem.Id }, null)
diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Views/Parts/Localization.ContentTranslations.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.Localization/Views/Parts/Localization.ContentTranslations.SummaryAdmin.cshtml index ed47211d7..735dade3a 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Views/Parts/Localization.ContentTranslations.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Localization/Views/Parts/Localization.ContentTranslations.SummaryAdmin.cshtml @@ -5,9 +5,18 @@ Style.Require("LocalizationAdmin"); IEnumerable localizations = Model.Localizations; var localizationLinks = Html.UnorderedList(localizations, (c, i) => Html.ItemEditLink(c.Culture.Culture, c), "localizations");
- @if (localizations.Count() > 0) { + @if (Model.Culture != null) { +
@T("Culture: {0}", Model.Culture)
+ } else { +
@T("Culture: {0}", T("Undefined"))
+ } + @if (localizations.Count() > 0) + {

@T("Translations:")

@localizationLinks
} -
@Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new { area = "Orchard.Localization", id = Model.MasterId }, null)
+ @if (Model.Culture != null && !((IEnumerable)Model.SiteCultures).All(c => c == Model.Culture || localizations.Any(l => c == l.Culture.Culture))) + { +
@Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new { area = "Orchard.Localization", id = Model.Id }, null)
+ }
} \ No newline at end of file diff --git a/src/Orchard/Localization/Services/DefaultCultureManager.cs b/src/Orchard/Localization/Services/DefaultCultureManager.cs index d31d41052..6ebc1ed6d 100644 --- a/src/Orchard/Localization/Services/DefaultCultureManager.cs +++ b/src/Orchard/Localization/Services/DefaultCultureManager.cs @@ -12,30 +12,34 @@ namespace Orchard.Localization.Services { private readonly IEnumerable _cultureSelectors; private readonly ISignals _signals; private readonly IWorkContextAccessor _workContextAccessor; + private readonly ICacheManager _cacheManager; public DefaultCultureManager(IRepository cultureRepository, IEnumerable cultureSelectors, ISignals signals, - IWorkContextAccessor workContextAccessor) { + IWorkContextAccessor workContextAccessor, + ICacheManager cacheManager) { _cultureRepository = cultureRepository; _cultureSelectors = cultureSelectors; _signals = signals; _workContextAccessor = workContextAccessor; + _cacheManager = cacheManager; } public IEnumerable ListCultures() { - var query = from culture in _cultureRepository.Table select culture.Culture; - return query.ToList(); + return _cacheManager.Get("Cultures", context => { + context.Monitor(_signals.When("culturesChanged")); + + return _cultureRepository.Table.Select(o => o.Culture).ToList(); + }); } public void AddCulture(string cultureName) { if (!IsValidCulture(cultureName)) { throw new ArgumentException("cultureName"); } - - var culture = _cultureRepository.Get(cr => cr.Culture == cultureName); - if (culture != null) { + if (ListCultures().Any(culture => culture == cultureName)) { return; } @@ -48,8 +52,8 @@ namespace Orchard.Localization.Services { throw new ArgumentException("cultureName"); } - var culture = _cultureRepository.Get(cr => cr.Culture == cultureName); - if (culture != null) { + if (ListCultures().Any(culture => culture == cultureName)) { + var culture = _cultureRepository.Get(cr => cr.Culture == cultureName); _cultureRepository.Delete(culture); _signals.Trigger("culturesChanged"); }