I18n через jsonb-поля

This commit is contained in:
2025-04-24 15:53:05 +04:00
parent 35b571eb57
commit 31ad99ade5
33 changed files with 409 additions and 264 deletions
+2 -4
View File
@@ -2,6 +2,7 @@
using Pf2eModel.Model.Base.Keywords;
using Pf2eModel.Model.Base.Source;
using Pf2eModel.Model.Base.Targets;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure;
using System.ComponentModel.DataAnnotations;
@@ -16,9 +17,8 @@ public class Entity
public int Id { get; set; }
[Column(Order = 2)]
[MaxLength(Pf2eDbContext.NameLength)]
[Comment("Отображаемое имя")]
public string Name { get; set; } = null!;
public LocaleString Name { get; set; } = new();
[Column(Order = 3)]
[Comment("Тип объекта")]
@@ -53,8 +53,6 @@ public class Entity
public virtual ICollection<Keyword> Keywords { get; set; } = [];
public virtual ICollection<EntityAlias> Aliases { get; set; } = [];
public virtual ICollection<EntitySource> Sources { get; set; } = [];
public virtual ICollection<EntityExternal> Externals { get; set; } = [];
-24
View File
@@ -1,24 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Pf2eModel.Model.Enum;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Base;
[PrimaryKey(nameof(EntityId), nameof(Type))]
public partial class EntityAlias
{
[Column(Order = 1)]
public int EntityId { get; set; }
[Column(Order = 2)]
public AliasType Type { get; set; } = AliasType.Other;
[Column(Order = 3)]
[MaxLength(Pf2eDbContext.NameLength)]
public string Alias { get; set; } = null!;
[JsonIgnore]
public virtual Entity Entity { get; set; } = null!;
}
@@ -0,0 +1,46 @@
using Microsoft.EntityFrameworkCore;
using Pf2eModel.Model.Base;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;
namespace Pf2eModel.Model.Common.I18n;
public static class LocaleExtension
{
public static string GetTypeString(this LocaleType localeType)
{
FieldInfo fi = localeType.GetType().GetField(localeType.ToString())!;
DescriptionAttribute[] attributes = (DescriptionAttribute[]) fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length != 0 ? attributes.FirstOrDefault()?.Description : null) ?? localeType.ToString();
}
public static LocaleType GetTypeByString(this string localeType)
{
foreach (System.Reflection.FieldInfo field in typeof(LocaleType).GetFields())
{
if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute descriptionAttribute)
{
if (descriptionAttribute.Description == localeType)
{
return (LocaleType) field.GetValue(null)!;
}
}
}
throw new InvalidEnumArgumentException();
}
/*
public static IQueryable<T> WhereLocale(
this IQueryable<T> query, Expression<Func<T, LocaleString>> expression, string searchTerm) where T : class
{
return query.Where(e => DbContext.LocaleSearch(e.Name.ToJson(), searchTerm));
}
public static IQueryable<Entity> WhereLocale(
this IQueryable<Entity> query, ICollection<string> searchTerms)
{
return query.Where(e => EF.Functions.LocaleSearchArray(e.Name.ToJson(), searchTerms));
}*/
}
+10
View File
@@ -0,0 +1,10 @@
namespace Pf2eModel.Model.Common.I18n;
public class LocaleItem(LocaleType type, string value)
{
public LocaleType Locale { get; set; } = type;
public string Value { get; set; } = value;
public LocaleItem(KeyValuePair<string, string> item) : this(LocaleExtension.GetTypeByString(item.Key), item.Value) { }
}
+148
View File
@@ -0,0 +1,148 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
namespace Pf2eModel.Model.Common.I18n;
public class LocaleString : ICollection<LocaleItem>
{
private readonly List<LocaleItem> _items = [];
private void AssureDefault()
{
if (_items.Count == 0)
{
_items.Add(new LocaleItem(LocaleType.English, string.Empty));
}
}
public int Count => _items.Count;
public bool IsReadOnly => false;
public ICollection<LocaleType> Types => _items.Select(c => c.Locale).ToList();
public LocaleString()
{
AssureDefault();
}
private LocaleType _E(string localeString) => LocaleExtension.GetTypeByString(localeString);
private LocaleType RealLocale(LocaleType locale) => Contains(locale) ? locale : LocaleType.English;
private LocaleType RealLocale(string localeString) => RealLocale(_E(localeString));
public LocaleItem GetItem(LocaleType locale) => this.First(c => c.Locale == RealLocale(locale));
public LocaleItem GetItem(string locale) => this.First(c => c.Locale == RealLocale(locale));
public string this[LocaleType locale]
{
get => GetItem(locale).Value;
set
{
if (Types.Contains(locale))
{
GetItem(locale).Value = value;
}
else
{
_items.Add(new LocaleItem(locale, value));
}
}
}
public string this[string localeString]
{
get => this[_E(localeString)];
set => this[_E(localeString)] = value;
}
public void Add(LocaleItem item)
{
this[item.Locale] = item.Value;
}
public void Add(LocaleType locale, string value)
{
this[locale] = value;
}
public void Clear()
{
_items.Clear();
AssureDefault();
}
public bool Contains(LocaleItem item)
{
return _items.Contains(item);
}
public bool Contains(LocaleType locale)
{
return Types.Contains(locale);
}
public bool Contains(string value)
{
return this.Any(item => item.Value == value);
}
public void CopyTo(LocaleItem[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(LocaleItem item)
{
bool result = _items.Remove(item);
if (Count == 0)
{
AssureDefault();
return false;
}
return result;
}
public IEnumerator<LocaleItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override string ToString()
{
return this[LocaleType.English];
}
public string Serialize()
{
JObject json = [];
foreach (LocaleItem item in _items)
{
json.Add(item.Locale.GetTypeString(), item.Value);
}
return json.ToString();
}
public static LocaleString Deserialize(string input)
{
JObject json = JObject.Parse(input);
LocaleString result = new();
foreach (var item in json)
{
result[item.Key] = item.ToString();
}
return result;
}
}
+24
View File
@@ -0,0 +1,24 @@
using System.ComponentModel;
namespace Pf2eModel.Model.Common.I18n;
public enum LocaleType
{
[Description("en")]
English,
[Description("en.legacy")]
LegacyEnglish,
[Description("ru")]
Russian,
[Description("ru.legacy")]
Legacy,
[Description("ru.hobby")]
Hobby,
[Description("other")]
Other,
}
-21
View File
@@ -1,21 +0,0 @@
using NpgsqlTypes;
namespace Pf2eModel.Model.Enum;
public enum AliasType
{
[PgName("legacy")]
Legacy,
[PgName("english")]
English,
[PgName("legacy_english")]
LegacyEnglish,
[PgName("hobby")]
Hobby,
[PgName("other")]
Other,
}
+1 -1
View File
@@ -16,7 +16,7 @@ public partial class Ancestry : IEntity
public Entity Entity { get; set; } = null!;
[Column(Order = 2)]
public Size[] Size { get; set; }
public Size[] Size { get; set; } = [];
[Column(Order = 3)]
public int Hp { get; set; }