mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
7.0 KiB
218 lines
7.0 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using Squidex.Infrastructure;
|
|
|
|
namespace Squidex.Domain.Apps.Core
|
|
{
|
|
public sealed class LanguagesConfig : IFieldPartitioning
|
|
{
|
|
private readonly ImmutableDictionary<Language, LanguageConfig> languages;
|
|
private readonly LanguageConfig master;
|
|
|
|
public static readonly LanguagesConfig Empty = Create();
|
|
|
|
public LanguageConfig Master
|
|
{
|
|
get { return master; }
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { return languages.Count; }
|
|
}
|
|
|
|
IFieldPartitionItem IFieldPartitioning.Master
|
|
{
|
|
get { return Master; }
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return languages.Values.GetEnumerator();
|
|
}
|
|
|
|
IEnumerator<IFieldPartitionItem> IEnumerable<IFieldPartitionItem>.GetEnumerator()
|
|
{
|
|
return languages.Values.GetEnumerator();
|
|
}
|
|
|
|
private LanguagesConfig(ImmutableDictionary<Language, LanguageConfig> languages, LanguageConfig master)
|
|
{
|
|
this.languages = ValidateLanguages(languages);
|
|
|
|
this.master = master;
|
|
}
|
|
|
|
public static LanguagesConfig Create(ICollection<LanguageConfig> languageConfigs)
|
|
{
|
|
Guard.NotNull(languageConfigs, nameof(languageConfigs));
|
|
|
|
var validated = ValidateLanguages(languageConfigs.ToImmutableDictionary(c => c.Language));
|
|
|
|
return new LanguagesConfig(validated, languageConfigs.FirstOrDefault());
|
|
}
|
|
|
|
public static LanguagesConfig Create(params Language[] languages)
|
|
{
|
|
Guard.NotNull(languages, nameof(languages));
|
|
|
|
var languageConfigs = languages.Select(l => new LanguageConfig(l)).ToList();
|
|
|
|
return Create(languageConfigs);
|
|
}
|
|
|
|
public LanguagesConfig MakeMaster(Language language)
|
|
{
|
|
ThrowIfNotFound(language);
|
|
|
|
return new LanguagesConfig(languages, languages[language]);
|
|
}
|
|
|
|
public LanguagesConfig Add(Language language)
|
|
{
|
|
ThrowIfFound(language, () => $"Cannot add language '{language.Iso2Code}'.");
|
|
|
|
var newLanguages = languages.Add(language, new LanguageConfig(language));
|
|
|
|
return new LanguagesConfig(newLanguages, master ?? newLanguages.Values.First());
|
|
}
|
|
|
|
public LanguagesConfig Update(Language language, bool isOptional, bool isMaster, IEnumerable<Language> fallback)
|
|
{
|
|
ThrowIfNotFound(language);
|
|
|
|
if (isOptional)
|
|
{
|
|
ThrowIfMaster(language, isMaster, () => $"Cannot cannot make language '{language.Iso2Code}' optional");
|
|
}
|
|
|
|
var newLanguage = new LanguageConfig(language, isOptional, fallback);
|
|
var newLanguages = ValidateLanguages(languages.SetItem(language, newLanguage));
|
|
|
|
return new LanguagesConfig(newLanguages, isMaster ? newLanguage : master);
|
|
}
|
|
|
|
public LanguagesConfig Remove(Language language)
|
|
{
|
|
ThrowIfNotFound(language);
|
|
ThrowIfMaster(language, false, () => $"Cannot remove language '{language.Iso2Code}'");
|
|
|
|
var newLanguages = languages.Remove(language);
|
|
|
|
foreach (var languageConfig in newLanguages.Values)
|
|
{
|
|
if (languageConfig.LanguageFallbacks.Contains(language))
|
|
{
|
|
newLanguages =
|
|
newLanguages.SetItem(languageConfig.Language,
|
|
new LanguageConfig(
|
|
languageConfig.Language,
|
|
languageConfig.IsOptional,
|
|
languageConfig.LanguageFallbacks.Remove(language)));
|
|
}
|
|
}
|
|
|
|
return new LanguagesConfig(newLanguages, master);
|
|
}
|
|
|
|
public bool Contains(Language language)
|
|
{
|
|
return language != null && languages.ContainsKey(language);
|
|
}
|
|
|
|
public bool TryGetConfig(Language language, out LanguageConfig config)
|
|
{
|
|
return languages.TryGetValue(language, out config);
|
|
}
|
|
|
|
public bool TryGetItem(string key, out IFieldPartitionItem item)
|
|
{
|
|
if (Language.IsValidLanguage(key) && languages.TryGetValue(key, out var value))
|
|
{
|
|
item = value;
|
|
|
|
return true;
|
|
}
|
|
|
|
item = null;
|
|
|
|
return false;
|
|
}
|
|
|
|
private static ImmutableDictionary<Language, LanguageConfig> ValidateLanguages(ImmutableDictionary<Language, LanguageConfig> languages)
|
|
{
|
|
var errors = new List<ValidationError>();
|
|
|
|
foreach (var languageConfig in languages.Values)
|
|
{
|
|
foreach (var fallback in languageConfig.LanguageFallbacks)
|
|
{
|
|
if (!languages.ContainsKey(fallback))
|
|
{
|
|
var message = $"Config for language '{languageConfig.Language.Iso2Code}' contains unsupported fallback language '{fallback.Iso2Code}'";
|
|
|
|
errors.Add(new ValidationError(message));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (errors.Count > 0)
|
|
{
|
|
throw new ValidationException("Cannot configure language.", errors);
|
|
}
|
|
|
|
return languages;
|
|
}
|
|
|
|
private void ThrowIfNotFound(Language language)
|
|
{
|
|
if (!Contains(language))
|
|
{
|
|
throw new DomainObjectNotFoundException(language, "Languages", typeof(LanguagesConfig));
|
|
}
|
|
}
|
|
|
|
private void ThrowIfFound(Language language, Func<string> message)
|
|
{
|
|
if (Contains(language))
|
|
{
|
|
var error = new ValidationError("Language is already part of the app.", "Language");
|
|
|
|
throw new ValidationException(message(), error);
|
|
}
|
|
}
|
|
|
|
private void ThrowIfMaster(Language language, bool isMaster, Func<string> message)
|
|
{
|
|
if (master?.Language == language || isMaster)
|
|
{
|
|
var error = new ValidationError("Language is the master language.", "Language");
|
|
|
|
throw new ValidationException(message(), error);
|
|
}
|
|
}
|
|
|
|
public PartitionResolver ToResolver()
|
|
{
|
|
return partitioning =>
|
|
{
|
|
if (partitioning.Equals(Partitioning.Invariant))
|
|
{
|
|
return InvariantPartitioning.Instance;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|