263 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
namespace gehGassi.Domain.Localization
{
/// <summary>
/// Basis-Klasse für eine Entität die Übersetzungen für String-Felder ermöglicht
/// </summary>
public class LocalizableBase : ILocalizable
{
private string _language = string.Empty;
/// <summary>
/// In welcher Sprache sollen die übersetzbaren Felder abgerufen oder gesetzt werden?
/// </summary>
/// <param name="language">ISO2 codierte Sprache</param>
public void SetLanguage(string language)
{
if (GetAvailableLanguages().Contains(language.ToUpper()))
_language = language.ToUpper();
}
/// <summary>
/// Gibt die gewählte Sprache intern zurück.
/// Wenn diese nicht verfügbar ist, wird versucht die aktuelle Culture zu verwenden.
/// Wenn diese auch nicht verfügbar ist, wird die Default-Sprache verwendet
/// </summary>
/// <returns>Sprache als ISO2</returns>
protected string GetLanguage()
{
if (string.IsNullOrWhiteSpace(_language))
{
var lang = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
_language = GetAvailableLanguages().Contains(lang.ToUpper()) ? lang.ToUpper() : DefaultLanguage;
}
return _language;
}
/// <summary>
/// Setzt eine Übersetzung direkt für ein Feld mittels Reflection
/// </summary>
/// <param name="property">Name der Eigenschaft</param>
/// <param name="language">ISO2 codierte Sprache</param>
/// <param name="value">Zu setzender Wert</param>
public void Set(string property, string language, string value)
{
property = property + "Localized";
language = language.ToUpper();
var serialized = GetPropValue(GetType(), property, this);
Dictionary<string, string> dictionary;
if (serialized != null)
{
try
{
dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(serialized.ToString());
}
catch
{
dictionary = new Dictionary<string, string>();
}
}
else
dictionary = new Dictionary<string, string>();
if (dictionary.ContainsKey(language))
dictionary[language] = value;
else
dictionary.Add(language, value);
var serializedDict = JsonConvert.SerializeObject(dictionary);
SetPropValue(GetType(), property, serializedDict, this);
}
/// <summary>
/// Setzt alle übersetzungen für ein Feld mittels Reflection.
/// Achtung: das gesamte Dictionary wird ersetzt
/// </summary>
/// <param name="property">Name der Eigenschaft</param>
/// <param name="dictionary">Zu setzendes Dictionary</param>
public void Set(string property, Dictionary<string, string> dictionary)
{
property = property + "Localized";
var serializedDict = JsonConvert.SerializeObject(dictionary);
SetPropValue(GetType(), property, serializedDict, this);
}
/// <summary>
/// Ruft eine Übersetzung direkt für ein Feld mittels Reflection
/// </summary>
/// <param name="property">Name der Eigenschaft</param>
/// <param name="language">ISO2 codierte Sprache</param>
/// <param name="allowEmpty">Gibt an ob leer als Rückgabe gültig ist und nicht die Default-Werte genommen werden sollen wenn eine Übersetzung fehlt</param>
/// <returns>Wert</returns>
public string Get(string property, string language, bool allowEmpty = false)
{
property = property + "Localized";
language = language.ToUpper();
var serialized = GetPropValue(GetType(), property, this);
if (serialized != null)
{
try
{
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(serialized.ToString());
if (dictionary != null)
{
if (dictionary.ContainsKey(language) && !string.IsNullOrWhiteSpace(dictionary[language]))
return dictionary[language];
if (allowEmpty)
return string.Empty;
if (dictionary.ContainsKey(DefaultLanguage))
return dictionary[DefaultLanguage];
return dictionary.First().Value;
}
}
catch
{
// ignored
}
}
return string.Empty;
}
/// <summary>
/// Ruft alle Übersetzungen direkt für ein Feld mittels Reflection
/// </summary>
/// <param name="property">Name der Eigenschaft</param>
/// <returns>Dictionary mit allen Übersetzungen</returns>
public Dictionary<string, string> Get(string property)
{
property = property + "Localized";
var serialized = GetPropValue(GetType(), property, this);
if (serialized != null)
{
try
{
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(serialized.ToString());
if (dictionary != null)
{
return dictionary;
}
}
catch
{
// ignored
}
}
return new Dictionary<string, string>();
}
/// <summary>
/// Gibt eine Liste aller verfügbaren Sprachen für ein Feld zurück.
/// Basiert auf den bereits gesetzten Sprachen
/// </summary>
/// <param name="property">Name der Eigenschaft</param>
/// <returns>Liste verfügbarer Sprachen</returns>
public List<string> GetLanguages(string property)
{
property = property + "Localized";
var serialized = GetPropValue(GetType(), property, this);
if (serialized != null)
{
try
{
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(serialized.ToString());
if (dictionary != null)
{
return dictionary.Select(c => c.Key).ToList();
}
}
catch
{
// ignored
}
}
return new List<string>();
}
#region private
/// <summary>
/// Ruft die Liste aller verfügbaren Sprachen mittels App-Settings ab.
/// </summary>
/// <returns>Liste verfügbare Sprachen ISO2 codiert</returns>
protected static IEnumerable<string> GetAvailableLanguages()
{
var languages = LocalizableHelper.Languages;
if (string.IsNullOrWhiteSpace(languages))
{
return new[] { LocalizableHelper.DefaultLanguage };
}
return languages.ToUpper().Split(',');
}
/// <summary>
/// Gibt die Standard-Sprache zurück
/// </summary>
protected static string DefaultLanguage => LocalizableHelper.DefaultLanguage;
/// <summary>
/// Hilfsfunktion die den Wert einer Eigenschaft aus einem Objekt sucht und zurückgibt
/// </summary>
/// <param name="baseType">Basis-Typ des Objekts</param>
/// <param name="propertyName">Gesuchte Eigenschaft</param>
/// <param name="targetObject">Objekt das die Eigenschaft beinhaltet</param>
/// <param name="depth">Tiefe der Rekursion</param>
/// <returns>Wert der Eigenschaft oder null, wenn nicht gefunden</returns>
protected static object GetPropValue(Type baseType, string propertyName, object targetObject, int depth = 0)
{
if (depth >= 100)
throw new Exception("Recursion detected.");
string[] parts = propertyName.Split('.');
if (parts.Length > 1)
return GetPropValue(baseType.GetProperty(parts[0])?.PropertyType, parts.Skip(1).Aggregate((a, i) => a + "." + i), baseType.GetProperty(parts[0])?.GetValue(targetObject, null), depth + 1);
var properties = baseType.GetProperties(BindingFlags.SetProperty | BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).ToList();
if (properties.Count > 0)
{
var property = properties.FirstOrDefault(c => c.Name == propertyName);
if (property != null)
return property.GetValue(targetObject, null);
}
return null;
}
/// <summary>
/// Hilfsfunktion die versucht den Wert einer Eigenschaft zu setzen
/// </summary>
/// <param name="baseType">Basis-Typ des Objektes</param>
/// <param name="propertyName">Name der Eigenschaft</param>
/// <param name="value">Zu setzender Wert</param>
/// <param name="targetObject">Ziel-Objekt</param>
/// <param name="depth">Tiefe der Rekursion</param>
protected static void SetPropValue(Type baseType, string propertyName, object value, object targetObject, int depth = 0)
{
if (depth >= 100)
throw new Exception("Recursion detected.");
string[] parts = propertyName.Split('.');
if (parts.Length > 1)
SetPropValue(baseType.GetProperty(parts[0])?.PropertyType, parts.Skip(1).Aggregate((a, i) => a + "." + i), value, baseType.GetProperty(parts[0])?.GetValue(targetObject, null), depth + 1);
var properties = baseType.GetProperties(BindingFlags.SetProperty | BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).ToList();
if (properties.Count > 0)
{
var property = properties.FirstOrDefault(c => c.Name == propertyName);
if (property != null)
property.SetValue(targetObject, value);
}
}
#endregion
}
}