Updates UI to allow updating a culture for a language and warn the user if they are changing it, updates the controller to be able to udpate a culture on a lang

This commit is contained in:
Shannon
2019-10-14 10:04:51 +02:00
committed by Bjarke Berg
parent a7eb693053
commit 37fce725ff
6 changed files with 2280 additions and 2211 deletions

View File

@@ -1,7 +1,7 @@
(function () {
"use strict";
function LanguagesEditController($scope, $timeout, $location, $routeParams, navigationService, notificationsService, localizationService, languageResource, contentEditingHelper, formHelper, eventsService) {
function LanguagesEditController($scope, $q, $timeout, $location, $routeParams, overlayService, navigationService, notificationsService, localizationService, languageResource, contentEditingHelper, formHelper, eventsService) {
var vm = this;
@@ -20,6 +20,8 @@
vm.toggleMandatory = toggleMandatory;
vm.toggleDefault = toggleDefault;
var currCulture = null;
function init() {
// localize labels
@@ -32,7 +34,8 @@
"languages_addLanguage",
"languages_noFallbackLanguageOption",
"languages_fallbackLanguageDescription",
"languages_fallbackLanguage"
"languages_fallbackLanguage",
"defaultdialogs_confirmSure"
];
localizationService.localizeMany(labelKeys).then(function (values) {
@@ -43,6 +46,7 @@
vm.labels.defaultLanguageHelp = values[4];
vm.labels.addLanguage = values[5];
vm.labels.noFallbackLanguageOption = values[6];
vm.labels.areYouSure = values[9];
$scope.properties = {
fallbackLanguage: {
@@ -53,46 +57,56 @@
};
if ($routeParams.create) {
vm.page.name = vm.labels.addLanguage;
languageResource.getCultures().then(function (culturesDictionary) {
var cultures = [];
angular.forEach(culturesDictionary, function (value, key) {
cultures.push({
name: key,
displayName: value
});
});
vm.availableCultures = cultures;
});
vm.page.name = vm.labels.addLanguage;
}
});
vm.loading = true;
languageResource.getAll().then(function (languages) {
var promises = [];
//load all culture/languages
promises.push(languageResource.getCultures().then(function (culturesDictionary) {
var cultures = [];
angular.forEach(culturesDictionary, function (value, key) {
cultures.push({
name: key,
displayName: value
});
});
vm.availableCultures = cultures;
}));
//load all possible fallback languages
promises.push(languageResource.getAll().then(function (languages) {
vm.availableLanguages = languages.filter(function (l) {
return $routeParams.id != l.id;
});
vm.loading = false;
});
}));
if (!$routeParams.create) {
vm.loading = true;
languageResource.getById($routeParams.id).then(function(lang) {
promises.push(languageResource.getById($routeParams.id).then(function(lang) {
vm.language = lang;
vm.page.name = vm.language.name;
/* we need to store the initial default state so we can disabel the toggle if it is the default.
/* we need to store the initial default state so we can disable the toggle if it is the default.
we need to prevent from not having a default language. */
vm.initIsDefault = angular.copy(vm.language.isDefault);
vm.loading = false;
makeBreadcrumbs();
});
//store to check if we are changing the lang culture
currCulture = vm.language.culture;
}));
}
$q.all(promises, function () {
vm.loading = false;
});
$timeout(function () {
navigationService.syncTree({ tree: "languages", path: "-1" });
});
@@ -103,31 +117,54 @@
if (formHelper.submitForm({ scope: $scope })) {
vm.page.saveButtonState = "busy";
languageResource.save(vm.language).then(function (lang) {
//check if the culture is being changed
if (currCulture && vm.language.culture !== currCulture) {
formHelper.resetForm({ scope: $scope });
const changeCultureAlert = {
title: vm.labels.areYouSure,
view: "views/languages/overlays/change.html",
submitButtonLabelKey: "general_continue",
submit: function (model) {
saveLanguage();
overlayService.close();
},
close: function () {
overlayService.close();
vm.page.saveButtonState = "init";
}
};
vm.language = lang;
vm.page.saveButtonState = "success";
localizationService.localize("speechBubbles_languageSaved").then(function(value){
notificationsService.success(value);
});
// emit event when language is created or updated/saved
var args = { language: lang, isNew: $routeParams.create ? true : false };
eventsService.emit("editors.languages.languageSaved", args);
back();
}, function (err) {
vm.page.saveButtonState = "error";
formHelper.handleError(err);
});
overlayService.open(changeCultureAlert);
}
else {
saveLanguage();
}
}
}
function saveLanguage() {
languageResource.save(vm.language).then(function (lang) {
formHelper.resetForm({ scope: $scope });
vm.language = lang;
vm.page.saveButtonState = "success";
localizationService.localize("speechBubbles_languageSaved").then(function (value) {
notificationsService.success(value);
});
// emit event when language is created or updated/saved
var args = { language: lang, isNew: $routeParams.create ? true : false };
eventsService.emit("editors.languages.languageSaved", args);
back();
}, function (err) {
vm.page.saveButtonState = "error";
formHelper.handleError(err);
});
}
function back() {

View File

@@ -0,0 +1,7 @@
<div>
<div class="umb-alert umb-alert--warning mb2">
<localize key="defaultdialogs_languageChangeWarning">Changing the culture for a language may be an expensive operation and will result in the content cache and indexes being rebuilt</localize>.
</div>
</div>

View File

@@ -414,6 +414,7 @@
<key alias="insertMacro">Click to add a Macro</key>
<key alias="inserttable">Insert table</key>
<key alias="languagedeletewarning">This will delete the language</key>
<key alias="languageChangeWarning">Changing the culture for a language may be an expensive operation and will result in the content cache and indexes being rebuilt</key>
<key alias="lastEdited">Last Edited</key>
<key alias="link">Link</key>
<key alias="linkinternal">Internal link:</key>

File diff suppressed because it is too large Load Diff

View File

@@ -266,13 +266,21 @@ namespace Umbraco.Web.Cache
public static void RefreshLanguageCache(this DistributedCache dc, ILanguage language)
{
if (language == null) return;
dc.Refresh(LanguageCacheRefresher.UniqueId, language.Id);
var payload = new LanguageCacheRefresher.JsonPayload(language.Id, language.IsoCode,
language.WasPropertyDirty(nameof(ILanguage.IsoCode))
? LanguageCacheRefresher.JsonPayload.LanguageChangeType.ChangeCulture
: LanguageCacheRefresher.JsonPayload.LanguageChangeType.Update);
dc.RefreshByPayload(LanguageCacheRefresher.UniqueId, new[] { payload });
}
public static void RemoveLanguageCache(this DistributedCache dc, ILanguage language)
{
if (language == null) return;
dc.Remove(LanguageCacheRefresher.UniqueId, language.Id);
var payload = new LanguageCacheRefresher.JsonPayload(language.Id, language.IsoCode, LanguageCacheRefresher.JsonPayload.LanguageChangeType.Remove);
dc.RefreshByPayload(LanguageCacheRefresher.UniqueId, new[] { payload });
}
#endregion

View File

@@ -99,24 +99,28 @@ namespace Umbraco.Web.Editors
throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState));
// this is prone to race conditions but the service will not let us proceed anyways
var existing = Services.LocalizationService.GetLanguageByIsoCode(language.IsoCode);
var existingByCulture = Services.LocalizationService.GetLanguageByIsoCode(language.IsoCode);
// the localization service might return the generic language even when queried for specific ones (e.g. "da" when queried for "da-DK")
// - we need to handle that explicitly
if (existing?.IsoCode != language.IsoCode)
if (existingByCulture?.IsoCode != language.IsoCode)
{
existing = null;
existingByCulture = null;
}
if (existing != null && language.Id != existing.Id)
if (existingByCulture != null && language.Id != existingByCulture.Id)
{
//someone is trying to create a language that already exist
ModelState.AddModelError("IsoCode", "The language " + language.IsoCode + " already exists");
throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState));
}
if (existing == null)
var existingById = language.Id != default ? Services.LocalizationService.GetLanguageById(language.Id) : null;
if (existingById == null)
{
//Creating a new lang...
CultureInfo culture;
try
{
@@ -141,38 +145,39 @@ namespace Umbraco.Web.Editors
return Mapper.Map<Language>(newLang);
}
existing.IsMandatory = language.IsMandatory;
existingById.IsMandatory = language.IsMandatory;
// note that the service will prevent the default language from being "un-defaulted"
// but does not hurt to test here - though the UI should prevent it too
if (existing.IsDefault && !language.IsDefault)
if (existingById.IsDefault && !language.IsDefault)
{
ModelState.AddModelError("IsDefault", "Cannot un-default the default language.");
throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState));
}
existing.IsDefault = language.IsDefault;
existing.FallbackLanguageId = language.FallbackLanguageId;
existingById.IsDefault = language.IsDefault;
existingById.FallbackLanguageId = language.FallbackLanguageId;
existingById.IsoCode = language.IsoCode;
// modifying an existing language can create a fallback, verify
// note that the service will check again, dealing with race conditions
if (existing.FallbackLanguageId.HasValue)
if (existingById.FallbackLanguageId.HasValue)
{
var languages = Services.LocalizationService.GetAllLanguages().ToDictionary(x => x.Id, x => x);
if (!languages.ContainsKey(existing.FallbackLanguageId.Value))
if (!languages.ContainsKey(existingById.FallbackLanguageId.Value))
{
ModelState.AddModelError("FallbackLanguage", "The selected fall back language does not exist.");
throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState));
}
if (CreatesCycle(existing, languages))
if (CreatesCycle(existingById, languages))
{
ModelState.AddModelError("FallbackLanguage", $"The selected fall back language {languages[existing.FallbackLanguageId.Value].IsoCode} would create a circular path.");
ModelState.AddModelError("FallbackLanguage", $"The selected fall back language {languages[existingById.FallbackLanguageId.Value].IsoCode} would create a circular path.");
throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState));
}
}
Services.LocalizationService.Save(existing);
return Mapper.Map<Language>(existing);
Services.LocalizationService.Save(existingById);
return Mapper.Map<Language>(existingById);
}
// see LocalizationService